From d6f5e8a2400605fb07005d0a291ddac7b0ae40be Mon Sep 17 00:00:00 2001 From: Vela Date: Sat, 10 Oct 2026 13:52:32 +0530 Subject: [PATCH 01/98] feat(android): floating frosted-glass pill bottom bar The home bottom bar is now a centered floating pill instead of a full-width strip. It blurs whatever is behind it with Haze, carries a hairline edge, and keeps the icons-only design: the current tab shows a filled glyph on a soft indicator pill that springs in, the others stay outlined. Adds the Haze blur dependencies. Signed-off-by: Vela --- CHANGELOG.md | 2 + android/src/android/app/build.gradle.kts | 4 + .../github/nanomuse/ui/home/MuseBottomBar.kt | 88 ++++++++++++++----- .../github/nanomuse/ui/home/NanoMuseHome.kt | 7 +- docs/every-device.md | 2 +- 5 files changed, 79 insertions(+), 24 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ee94150d2..e43307c52 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -229,10 +229,12 @@ Keel: the first stable version. What has been a preview since 2026-09-25 is now - **The connectors' background token refresh runs in one supervised scope**, and two cross-thread flags (the browser hand-over waiter, the profile sync timer) are marked volatile. - Copy buttons use the current Compose clipboard API and the open-in-new icon mirrors in right-to-left layouts; the Android build has no warnings in nanoMuse's code. - CI runs the Android unit tests (`io.github.nanomuse.*`) after building the debug APK. +<<<<<<< HEAD - **The Library shows the signed-in account's files only.** On a phone two accounts share, the Library tab listed the workspaces of the other account's chats as well; it now follows the chat list's rule (the account's own sessions, or the local ones when signed out), and a workspace whose chat is gone is not listed. - **Connector keys and client secrets are masked while typed**, with the eye to show them, like the other key fields in the app. - **The Hands page follows its switch wherever it is flipped**: a change made while the page is open shows at once instead of after reopening it. - **Another device can stop a task it asked this phone to run.** The hub's `stop {call}` / `stop {conversation}` ends the run after the step in flight and the task answers `cancelled`; it used to answer `stopped: false` and let the task run on. Only the device that asked may stop it. +- **The bottom bar is a floating frosted-glass pill.** The five tabs sit in a rounded pill that blurs whatever is behind it, icons only; the current tab shows a filled glyph on a soft indicator that springs in. ### iOS diff --git a/android/src/android/app/build.gradle.kts b/android/src/android/app/build.gradle.kts index 39ccddb82..d11e91e5e 100644 --- a/android/src/android/app/build.gradle.kts +++ b/android/src/android/app/build.gradle.kts @@ -206,6 +206,10 @@ dependencies { implementation("androidx.compose.material3:material3") implementation("androidx.compose.material:material-icons-extended") + // nanoMuse: frosted-glass pill bottom bar — Haze backdrop blur, in the Pixel taskbar's manner. + implementation("dev.chrisbanes.haze:haze:2.0.1") + implementation("dev.chrisbanes.haze:haze-blur:2.0.1") + // nanoMuse: the camera on a video call (a JPEG frame a second to the real-time model). val cameraX = "1.4.2" implementation("androidx.camera:camera-core:$cameraX") diff --git a/android/src/android/app/src/main/java/io/github/nanomuse/ui/home/MuseBottomBar.kt b/android/src/android/app/src/main/java/io/github/nanomuse/ui/home/MuseBottomBar.kt index 1720c13f1..e83a8d874 100644 --- a/android/src/android/app/src/main/java/io/github/nanomuse/ui/home/MuseBottomBar.kt +++ b/android/src/android/app/src/main/java/io/github/nanomuse/ui/home/MuseBottomBar.kt @@ -1,61 +1,105 @@ package io.github.nanomuse.ui.home +import androidx.compose.animation.animateColorAsState +import androidx.compose.animation.core.Spring +import androidx.compose.animation.core.spring import androidx.compose.foundation.background +import androidx.compose.foundation.border +import androidx.compose.foundation.clickable +import androidx.compose.foundation.interaction.MutableInteractionSource import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box -import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.WindowInsets import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.navigationBars +import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.windowInsetsPadding +import androidx.compose.foundation.shape.CircleShape import androidx.compose.material3.Icon -import androidx.compose.material3.IconButton import androidx.compose.material3.MaterialTheme import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.remember import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.clip +import androidx.compose.ui.graphics.Color import androidx.compose.ui.res.stringResource import androidx.compose.ui.unit.dp -import com.openminis.app.ui.theme.ChatColors +import dev.chrisbanes.haze.HazeInput +import dev.chrisbanes.haze.HazeState +import dev.chrisbanes.haze.blur.HazeBlurStyle +import dev.chrisbanes.haze.blur.hazeBlur /** - * Muse's bottom bar: a plain white strip, five glyphs, the current one filled and - * dark, the others outlined and softer. No labels, no indicator pill — the fill is the state. + * nanoMuse's bottom bar: a floating frosted-glass pill, five glyphs, icons only. The pill blurs + * whatever is behind it (Haze, in the Pixel taskbar's manner) and carries a hairline edge. The + * current tab shows a filled glyph on a soft indicator pill that springs in; the others are + * outlined. No labels — the fill and the indicator are the state. */ @Composable fun MuseBottomBar( selected: HomeTab, onSelect: (HomeTab) -> Unit, + hazeState: HazeState, modifier: Modifier = Modifier, ) { - Column( + Box( modifier = modifier .fillMaxWidth() - .background(ChatColors.background) - .windowInsetsPadding(WindowInsets.navigationBars), + .windowInsetsPadding(WindowInsets.navigationBars) + .padding(bottom = 12.dp), + contentAlignment = Alignment.Center, ) { Row( modifier = Modifier - .fillMaxWidth() - .height(56.dp), - horizontalArrangement = Arrangement.SpaceEvenly, + .hazeBlur( + input = HazeInput.Sources(hazeState), + style = HazeBlurStyle { + blurRadius(28.dp) + backgroundColor(MaterialTheme.colorScheme.surfaceContainer.copy(alpha = 0.55f)) + noiseFactor(0.08f) + }, + ) + .clip(CircleShape) + .border( + width = 1.dp, + color = MaterialTheme.colorScheme.outlineVariant.copy(alpha = 0.5f), + shape = CircleShape, + ) + .padding(horizontal = 14.dp, vertical = 8.dp), + horizontalArrangement = Arrangement.spacedBy(2.dp), verticalAlignment = Alignment.CenterVertically, ) { HomeTab.entries.forEach { tab -> val isSelected = tab == selected - IconButton(onClick = { onSelect(tab) }) { - Box(contentAlignment = Alignment.Center) { - Icon( - imageVector = if (isSelected) tab.selectedIcon else tab.icon, - contentDescription = stringResource(tab.label), - tint = if (isSelected) MaterialTheme.colorScheme.onSurface - else MaterialTheme.colorScheme.onSurface.copy(alpha = 0.72f), - modifier = Modifier.size(26.dp), - ) - } + val indicator by animateColorAsState( + targetValue = if (isSelected) MaterialTheme.colorScheme.primaryContainer + else Color.Transparent, + animationSpec = spring(stiffness = Spring.StiffnessMediumLow), + label = "nmTabIndicator", + ) + Box( + modifier = Modifier + .size(width = 60.dp, height = 46.dp) + .clip(CircleShape) + .background(indicator) + .clickable( + interactionSource = remember { MutableInteractionSource() }, + indication = null, + onClick = { onSelect(tab) }, + ), + contentAlignment = Alignment.Center, + ) { + Icon( + imageVector = if (isSelected) tab.selectedIcon else tab.icon, + contentDescription = stringResource(tab.label), + tint = if (isSelected) MaterialTheme.colorScheme.onPrimaryContainer + else MaterialTheme.colorScheme.onSurfaceVariant, + modifier = Modifier.size(26.dp), + ) } } } diff --git a/android/src/android/app/src/main/java/io/github/nanomuse/ui/home/NanoMuseHome.kt b/android/src/android/app/src/main/java/io/github/nanomuse/ui/home/NanoMuseHome.kt index d9a0fbbbe..9d522d93c 100644 --- a/android/src/android/app/src/main/java/io/github/nanomuse/ui/home/NanoMuseHome.kt +++ b/android/src/android/app/src/main/java/io/github/nanomuse/ui/home/NanoMuseHome.kt @@ -52,6 +52,8 @@ import androidx.compose.ui.unit.dp import androidx.compose.ui.zIndex import androidx.lifecycle.viewmodel.compose.viewModel import androidx.navigation.NavHostController +import dev.chrisbanes.haze.hazeSource +import dev.chrisbanes.haze.rememberHazeState import com.openminis.app.R import com.openminis.app.agent.SoulStore import com.openminis.app.data.repository.ChatRepository @@ -329,6 +331,8 @@ fun NanoMuseHome( // The drawer + tab shell, as a local composable so it can share every piece of state above // and still be one branch of the phase switch below. + // nanoMuse: the frosted pill bar blurs this shell's content — the shell is the haze source. + val hazeState = rememberHazeState() val homeShell: @Composable () -> Unit = { ModalNavigationDrawer( drawerState = drawerState, @@ -360,7 +364,7 @@ fun NanoMuseHome( containerColor = ChatColors.background, contentWindowInsets = WindowInsets(0), bottomBar = { - MuseBottomBar(selected = tab, onSelect = { picked -> + MuseBottomBar(selected = tab, hazeState = hazeState, onSelect = { picked -> if (picked == HomeTab.CHAT && tab == HomeTab.CHAT && !isMainChat) { showMain() } else { @@ -374,6 +378,7 @@ fun NanoMuseHome( Box( modifier = Modifier .fillMaxSize() + .hazeSource(hazeState) .padding(bottom = bottom) .consumeWindowInsets(PaddingValues(bottom = bottom)), ) { diff --git a/docs/every-device.md b/docs/every-device.md index 274c6f18d..d7f756fa6 100644 --- a/docs/every-device.md +++ b/docs/every-device.md @@ -17,7 +17,7 @@ Android app is the reference; the others follow its shape, not its pixels: |---|---|---| | A face with a name pill and a status line at the top of the conversation | `HomeShell`, `AgentAvatarDisc` | the web app's chat header, dragon by default | | One main chat, side chats in a drawer | drawer | drawer on narrow windows, a sidebar on wide ones | -| Feed · Ideas · Goals · Library | bottom bar | bottom bar / sidebar | +| Feed · Ideas · Goals · Library | floating frosted-glass pill bar, icons only | bottom bar / sidebar | | Approval cards in the chat, three tiers, *remember* pills | `RiskApprovalCard`, `RiskTier` | the Sentinel's card with the same labels | | Settings → Permissions: what was remembered, by tier | `GrantsSection` | Permissions page, grants by tier | | Settings → Hands: the screen as a hand, off by default | `Hands` | Settings → Hands (this computer's screen) | From a5a20d285479a20a6f167e4d097af965fb9e2c0b Mon Sep 17 00:00:00 2001 From: Vela Date: Sat, 10 Oct 2026 13:56:03 +0530 Subject: [PATCH 02/98] feat(android): debug builds install next to the release app Debug builds now carry the applicationIdSuffix .debug (io.github.nanomuse.app.debug), so a CI debug APK installs alongside the release nanoMuse instead of replacing it. The manifest already uses the applicationId placeholder everywhere; the launcher shortcuts get a debug source-set copy pointing at the debug package. Signed-off-by: Vela --- CHANGELOG.md | 1 + android/src/android/app/build.gradle.kts | 5 ++ .../app/src/debug/res/xml/shortcuts.xml | 48 +++++++++++++++++++ 3 files changed, 54 insertions(+) create mode 100644 android/src/android/app/src/debug/res/xml/shortcuts.xml diff --git a/CHANGELOG.md b/CHANGELOG.md index e43307c52..9d7b07ae1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -235,6 +235,7 @@ Keel: the first stable version. What has been a preview since 2026-09-25 is now - **The Hands page follows its switch wherever it is flipped**: a change made while the page is open shows at once instead of after reopening it. - **Another device can stop a task it asked this phone to run.** The hub's `stop {call}` / `stop {conversation}` ends the run after the step in flight and the task answers `cancelled`; it used to answer `stopped: false` and let the task run on. Only the device that asked may stop it. - **The bottom bar is a floating frosted-glass pill.** The five tabs sit in a rounded pill that blurs whatever is behind it, icons only; the current tab shows a filled glyph on a soft indicator that springs in. +- **Debug builds install next to the release app** (`io.github.nanomuse.app.debug`), so a test APK never replaces the installed nanoMuse. ### iOS diff --git a/android/src/android/app/build.gradle.kts b/android/src/android/app/build.gradle.kts index d11e91e5e..9fcb44d31 100644 --- a/android/src/android/app/build.gradle.kts +++ b/android/src/android/app/build.gradle.kts @@ -92,6 +92,11 @@ android { } buildTypes { + // nanoMuse: debug builds install next to the release app (io.github.nanomuse.app.debug), + // so a CI APK never replaces the store version on a test phone. + debug { + applicationIdSuffix = ".debug" + } release { isMinifyEnabled = true proguardFiles( diff --git a/android/src/android/app/src/debug/res/xml/shortcuts.xml b/android/src/android/app/src/debug/res/xml/shortcuts.xml new file mode 100644 index 000000000..0ba731e59 --- /dev/null +++ b/android/src/android/app/src/debug/res/xml/shortcuts.xml @@ -0,0 +1,48 @@ + + + + + + + + + + + + + + + + From 27adf47c4eb5e732f3c1b32c9be51189c79fb0d6 Mon Sep 17 00:00:00 2001 From: Vela Date: Sat, 10 Oct 2026 14:03:49 +0530 Subject: [PATCH 03/98] fix(android): use Haze 1.6.10 for the frosted pill bar Haze 2.x (and 1.7.x) need compileSdk 37 and the module is on 36, which failed checkDebugAarMetadata in CI. 1.6.10 carries no compileSdk floor and the same backdrop-blur API the bar uses. Signed-off-by: Vela --- android/src/android/app/build.gradle.kts | 4 ++-- .../github/nanomuse/ui/home/MuseBottomBar.kt | 20 +++++++++---------- 2 files changed, 11 insertions(+), 13 deletions(-) diff --git a/android/src/android/app/build.gradle.kts b/android/src/android/app/build.gradle.kts index 9fcb44d31..f900f67e7 100644 --- a/android/src/android/app/build.gradle.kts +++ b/android/src/android/app/build.gradle.kts @@ -212,8 +212,8 @@ dependencies { implementation("androidx.compose.material:material-icons-extended") // nanoMuse: frosted-glass pill bottom bar — Haze backdrop blur, in the Pixel taskbar's manner. - implementation("dev.chrisbanes.haze:haze:2.0.1") - implementation("dev.chrisbanes.haze:haze-blur:2.0.1") + // 1.6.10, not 2.x: Haze 1.7.x and 2.x need compileSdk 37, and this module is on 36. + implementation("dev.chrisbanes.haze:haze-android:1.6.10") // nanoMuse: the camera on a video call (a JPEG frame a second to the real-time model). val cameraX = "1.4.2" diff --git a/android/src/android/app/src/main/java/io/github/nanomuse/ui/home/MuseBottomBar.kt b/android/src/android/app/src/main/java/io/github/nanomuse/ui/home/MuseBottomBar.kt index e83a8d874..b6834f644 100644 --- a/android/src/android/app/src/main/java/io/github/nanomuse/ui/home/MuseBottomBar.kt +++ b/android/src/android/app/src/main/java/io/github/nanomuse/ui/home/MuseBottomBar.kt @@ -28,10 +28,9 @@ import androidx.compose.ui.draw.clip import androidx.compose.ui.graphics.Color import androidx.compose.ui.res.stringResource import androidx.compose.ui.unit.dp -import dev.chrisbanes.haze.HazeInput import dev.chrisbanes.haze.HazeState -import dev.chrisbanes.haze.blur.HazeBlurStyle -import dev.chrisbanes.haze.blur.hazeBlur +import dev.chrisbanes.haze.HazeStyle +import dev.chrisbanes.haze.hazeEffect /** * nanoMuse's bottom bar: a floating frosted-glass pill, five glyphs, icons only. The pill blurs @@ -55,14 +54,13 @@ fun MuseBottomBar( ) { Row( modifier = Modifier - .hazeBlur( - input = HazeInput.Sources(hazeState), - style = HazeBlurStyle { - blurRadius(28.dp) - backgroundColor(MaterialTheme.colorScheme.surfaceContainer.copy(alpha = 0.55f)) - noiseFactor(0.08f) - }, - ) + .hazeEffect(state = hazeState) { + style = HazeStyle( + backgroundColor = MaterialTheme.colorScheme.surfaceContainer.copy(alpha = 0.55f), + blurRadius = 28.dp, + noiseFactor = 0.08f, + ) + } .clip(CircleShape) .border( width = 1.dp, From f20ce06c6e1253ac663a9160388e713e977da63c Mon Sep 17 00:00:00 2001 From: Vela Date: Sat, 10 Oct 2026 14:21:46 +0530 Subject: [PATCH 04/98] fix(android): resolve Haze 1.6.10 API issues in the pill bar - hazeEffect's block is not a @Composable scope in 1.x, so hoist the MaterialTheme surface lookup above it. - Name tints explicitly: HazeStyle has a twin constructor taking tint: HazeTint?, which made the call ambiguous. Signed-off-by: Vela --- .../main/java/io/github/nanomuse/ui/home/MuseBottomBar.kt | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/android/src/android/app/src/main/java/io/github/nanomuse/ui/home/MuseBottomBar.kt b/android/src/android/app/src/main/java/io/github/nanomuse/ui/home/MuseBottomBar.kt index b6834f644..cfc070177 100644 --- a/android/src/android/app/src/main/java/io/github/nanomuse/ui/home/MuseBottomBar.kt +++ b/android/src/android/app/src/main/java/io/github/nanomuse/ui/home/MuseBottomBar.kt @@ -45,6 +45,9 @@ fun MuseBottomBar( hazeState: HazeState, modifier: Modifier = Modifier, ) { + // Hoisted out of the hazeEffect block: Haze 1.x's block is not a @Composable scope, + // so MaterialTheme lookups cannot happen inside it. + val barBackground = MaterialTheme.colorScheme.surfaceContainer.copy(alpha = 0.55f) Box( modifier = modifier .fillMaxWidth() @@ -56,9 +59,11 @@ fun MuseBottomBar( modifier = Modifier .hazeEffect(state = hazeState) { style = HazeStyle( - backgroundColor = MaterialTheme.colorScheme.surfaceContainer.copy(alpha = 0.55f), + backgroundColor = barBackground, blurRadius = 28.dp, noiseFactor = 0.08f, + // tints named explicitly: HazeStyle has a twin constructor taking tint: HazeTint? + tints = emptyList(), ) } .clip(CircleShape) From e3ca5e64d9fca563821f19bae28e16de62f366da Mon Sep 17 00:00:00 2001 From: Vela Date: Sat, 10 Oct 2026 15:11:44 +0530 Subject: [PATCH 05/98] fix(android): clip the pill bar before the haze blur, not after Draw modifiers paint in chain order: with hazeEffect() before clip(), the blurred rect was drawn unclipped and the frost stuck out past the pill's rounded ends, making the sides look rectangular. Clipping first masks the blur to the pill shape. Signed-off-by: Vela --- .../src/main/java/io/github/nanomuse/ui/home/MuseBottomBar.kt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/android/src/android/app/src/main/java/io/github/nanomuse/ui/home/MuseBottomBar.kt b/android/src/android/app/src/main/java/io/github/nanomuse/ui/home/MuseBottomBar.kt index cfc070177..0d8644c2c 100644 --- a/android/src/android/app/src/main/java/io/github/nanomuse/ui/home/MuseBottomBar.kt +++ b/android/src/android/app/src/main/java/io/github/nanomuse/ui/home/MuseBottomBar.kt @@ -57,6 +57,9 @@ fun MuseBottomBar( ) { Row( modifier = Modifier + // Clip first: it must wrap the haze drawing, otherwise the + // blurred rect paints unclipped and the pill's ends look square. + .clip(CircleShape) .hazeEffect(state = hazeState) { style = HazeStyle( backgroundColor = barBackground, @@ -66,7 +69,6 @@ fun MuseBottomBar( tints = emptyList(), ) } - .clip(CircleShape) .border( width = 1.dp, color = MaterialTheme.colorScheme.outlineVariant.copy(alpha = 0.5f), From c02ca4211c5eef6c0b661eaa307e22e1698901f7 Mon Sep 17 00:00:00 2001 From: Vela Date: Sat, 10 Oct 2026 15:24:03 +0530 Subject: [PATCH 06/98] feat(android): sign CI debug builds with a committed debug key Every CI runner mints its own throwaway debug key, so consecutive CI APKs carried different signatures and Android refused to install one over the other ('update incompatible'). The committed ci-debug.keystore uses the stock public debug credentials and is debug-only. Signed-off-by: Vela --- android/src/android/app/build.gradle.kts | 13 +++++++++++++ android/src/android/app/ci-debug.keystore | Bin 0 -> 2626 bytes 2 files changed, 13 insertions(+) create mode 100644 android/src/android/app/ci-debug.keystore diff --git a/android/src/android/app/build.gradle.kts b/android/src/android/app/build.gradle.kts index f900f67e7..8d1f7ce8d 100644 --- a/android/src/android/app/build.gradle.kts +++ b/android/src/android/app/build.gradle.kts @@ -51,6 +51,16 @@ android { keyPassword = props.getProperty("keyPassword") } } + // nanoMuse: committed CI debug key. Every CI runner mints its own throwaway + // debug key, so consecutive CI APKs carry different signatures and Android + // refuses to install one over the other ("update incompatible"). This key + // uses the stock public debug credentials (android/android) and is debug-only. + create("ciDebug") { + storeFile = file("ci-debug.keystore") + storePassword = "android" + keyAlias = "androiddebugkey" + keyPassword = "android" + } } defaultConfig { @@ -96,6 +106,9 @@ android { // so a CI APK never replaces the store version on a test phone. debug { applicationIdSuffix = ".debug" + // nanoMuse: sign with the committed CI key so consecutive CI builds + // share one signature and install over each other (see signingConfigs). + signingConfig = signingConfigs.getByName("ciDebug") } release { isMinifyEnabled = true diff --git a/android/src/android/app/ci-debug.keystore b/android/src/android/app/ci-debug.keystore new file mode 100644 index 0000000000000000000000000000000000000000..59449583c5cbdabdf25d0abacc0a9ff41c0dafa7 GIT binary patch literal 2626 zcmai$XE+-Q7so>)Ld2@Zy=W+nRV7A^x?HOzHDZt2uGk}X(Hfy*@2w(Muc}gNuUaip zMQv@&UTU?q_jtX}`#$Z*`{6w2od5qk&-rwI&q3ko6{)F!C_LRRm`*rKBkBM~MN37( z(=CDUbPJdA3O z^3hbxP+b&}Po0`thX=&~hWu|UH60BAbq!2s6Qx0g1%jxALCk}vv)ba>*LTRUmDd94 zFDPMnVDhAS3(c*Rt2sepFYP0NH`epE;+1#e9pm?HQa!Dk>ZDBAI;*C-({RyW7a=6_ z=+^1qt(ML;$xJ=4l3-BXM}z!KJv_JBMRS5@$F@S#yFT&almXl}qZAr~u{=!Tg$BHo zOn(QGHJ?T3LCajJygnFH)b#nhHneEA zsU~>*n)kX4;0uL%i@2QKD4vw}B(#vOMU+kGit?iil!X9?uTHQ*%?|`AT}3CoL{i8Z9vzoGH2lAKR=@W>u_@lnyXX3?MZrv*0{Lg8E@_^s~K7u_(z%_AbTVZMp zF-A3QOycu45PIp%&SmGopuSTXhyZ5Bv}IXay|-i6V-WI>6j*C>acV|;jdZHI8|EX* z_eT*5%`2a5QY8wcL^3jc(a`B}!vWP|CQ?r$qq1{8w#vO^$Np)D`AZfgfs7PCGCWy~Es**|anH=Os>s7ecX*&N-x17PCpV6dPmTJs?lP z@Im@%Q=5tTbXpG_Y-D&IvYTEDXe3Aumm;btoRn(a@M`Yc z(1OLZz%M8T_m%E8i+$UZcC_2+xjJaS#S9;tuTgFRpBd%Pe!OjEvZ0>^Vi$-pt6rN@ zET~T5+8Oji$m)yqT28-8lvUd93VfX&nXGoEv#&v{Ppy+NC`mn8ywb<^op2|2IJI^t zgZbHKHvIJb${jyxj&g|L$#?jDE`~qF_3F1zMWoH{Mli82aD7>yOk{8<{86U=I?Sd- z{Uu|Mx;{KP0%PyGEW9}y@K$9e#^fo@toH4>Q4h%)9dXUPB%4kizD)J{(8tN9K1{hW zbz-*310>E7qRK>jtks2VEx_MX`fPd|Bkj4e^R5?!!qc?;yz~EpgQfz6rzyLXOD=;1 zhW?)^4D?jgm!{mMc>CW#vHT$7WHxnPPBI5g?t;)j{uLBHdQC&Y3L}j(%$0@0vW|Hm zJZKn8wzk!(LUwq$&Pm5icV{W^%g1Tfv#er~*-JOyVLA(d|3s%uXm&%aSO#zI-)Eo+ zc^{KZKA%=yb~Lyq$e}N-?T(ap9Kb=z8>SYM=5+oh*u@X(cidb33?^3tR?6-g(8k5J zz^<%42=bfW$;k$?XjDC{h6>5HO87SRB^Egsddr5-+3PC9RRi1WILu;+ycHG3vnY(6 zb>wCoS}8{00`54~40=Gm_k+jhJKuGVGFSmf*G2}jzH@L6cCO`v);xXT{z*hVt0OJ9 zo}dq(bF0s(-7);0wWBH+GC-_@wXh9SWhwQr zP~k*@JA&_h6MA4>6wsM=-W-AI!xbTOE5sDgFK@-=lG;KtgR>25u0cra)H~KV)d=`+j;)dbxl;C$6F$;#hcZuG5=}4Dx#Z9|6 zvjQZ&Ynq>YcK1Fkp{dw{cEH|FcWgHXNZZ7v7+2_5Eh24!6%}4w_>IB>0{d-sM4Wo+ zo|MN{rpN~#ZIMZ?TB^(f>d!tL6maL*y(wRcq!>KKMtW3; zGFm@Bl<&D2^emHqRcGcbFkR=)B1Uhbsyd?||Hj*~!7X`yW7OVup@VJCnZYUHgD(8W z$lG&5P2PkKJ!`Fq

4RVCW;ZnZV{0AA}F+`(2_=bNQXU944h5Mzc@5PaniNu*5} zT3)GFfkz@$rB6d+Ir)P!5>d$?9&`yB}FZdX6Poi`c>j!<{GkdV9P zg(1TpJBTS61~*5{z0E2Wt#&{MFcacSQ~Tawj={{92sKvu61Jw8a2`o?;u)aWeG6bI zw4|7No=BcgK@SHDI^Wb(d# zN|=gx7ca`{^ZfY?Viu2oRVT7QuO22BJbiq&6cC|WH>5be8E`z$xht_qSKjZ?6zgDV z6n5hMHR`+yUUoP@Fv=Mp_Mbk77lhzkzyQvs84jPn226-9&jNeygWK_^M{f;wU8R|A zBIzl!rJl9PrmQ68HbZt{?nmF&LNtpvT%L7poyR5-F=TR85WxSyeuJibUMGG-#FEw?72e_4a_8L zIb>@5>}#OfJMlaD;ll1=?2b)R`a7nCvKII?!inc0)P7pr5XJWsv~*X+;UG5a_l@7v zqs&4j3}6-VBIJm|V-_jYtzScI;yefhz!u;Eum^YpJOR#^*&cue*a7?ijsVxoDiEcN z5=X&)eqGd5Gyo6}Hg4iTC{Iw&{AnY?qk4SC9CwvJ(&uAdPH193K+zWjf*d3ap6m!? K<*BJ5fd2rSSieaC literal 0 HcmV?d00001 From 86562db3552d6a5d3540f2bdfbdac9918534abfa Mon Sep 17 00:00:00 2001 From: Vela Date: Sun, 11 Oct 2026 09:44:59 +0530 Subject: [PATCH 07/98] style(android): menus go pure black like the drawer MinisMenu's container was surfaceContainerHigh grey; now it's the chat canvas (pure black in dark, white in light) with a slightly stronger hairline. Cherry-picked from m3e/chat-meta-ai-polish for upstream. Signed-off-by: Vela --- .../java/com/openminis/app/ui/components/MinisMenu.kt | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/android/src/android/app/src/main/java/com/openminis/app/ui/components/MinisMenu.kt b/android/src/android/app/src/main/java/com/openminis/app/ui/components/MinisMenu.kt index 41f0cef88..cded3f341 100644 --- a/android/src/android/app/src/main/java/com/openminis/app/ui/components/MinisMenu.kt +++ b/android/src/android/app/src/main/java/com/openminis/app/ui/components/MinisMenu.kt @@ -71,7 +71,9 @@ fun MinisMenu( // in dark, a subtle shade in light) so the menu pops out — same fix already // validated on the text-selection toolbar (T-android-text-toolbar-dark- // visibility). The dark-mode `border` below adds the extra edge definition. - containerColor: Color = if (ChatColors.isDark) MaterialTheme.colorScheme.surfaceContainerHigh else Color.White, + // nanoMuse: pure canvas like the drawer and chat — black in dark, white in + // light. The hairline border carries the definition. + containerColor: Color = ChatColors.background, tonalElevation: Dp = 3.dp, // [T-android-menu-launcher-shadow] Analyzed against the Pixel Launcher // long-press popup (screenshot sample): its shadow is a WIDE, very @@ -86,10 +88,12 @@ fun MinisMenu( // Light mode now also gets a hairline (was null): with the launcher-style // soft halo replacing the old tight shadow, the popup's edge needs a // subtle line of its own to stay crisply bounded on light surfaces. + // nanoMuse: a touch stronger in dark so the black menu stays defined + // against the black chat. border: BorderStroke? = if (ChatColors.isDark) { - BorderStroke(0.5.dp, MaterialTheme.colorScheme.outlineVariant) + BorderStroke(0.75.dp, Color.White.copy(alpha = 0.14f)) } else { - BorderStroke(0.5.dp, Color.Black.copy(alpha = 0.05f)) + BorderStroke(0.5.dp, Color.Black.copy(alpha = 0.08f)) }, minWidth: Dp = 180.dp, // T238: when true, anchor the menu's RIGHT edge to the anchor box's From 272c8af8acc046da54bdec3ab79395165d93af62 Mon Sep 17 00:00:00 2001 From: Vela Date: Sun, 11 Oct 2026 09:45:12 +0530 Subject: [PATCH 08/98] feat(android): restyle the chats drawer in Muse's visual language Pure black canvas, large agent-name header, uppercase section labels, quiet monochrome pills for selected rows, circular settings/search/new chat buttons. Cherry-picked from m3e/chat-meta-ai-polish for upstream. Signed-off-by: Vela --- .../github/nanomuse/ui/home/NanoMuseHome.kt | 16 +- .../github/nanomuse/ui/home/SideChatDrawer.kt | 137 +++++++++++------- 2 files changed, 102 insertions(+), 51 deletions(-) diff --git a/android/src/android/app/src/main/java/io/github/nanomuse/ui/home/NanoMuseHome.kt b/android/src/android/app/src/main/java/io/github/nanomuse/ui/home/NanoMuseHome.kt index 9d522d93c..d0b7e3d12 100644 --- a/android/src/android/app/src/main/java/io/github/nanomuse/ui/home/NanoMuseHome.kt +++ b/android/src/android/app/src/main/java/io/github/nanomuse/ui/home/NanoMuseHome.kt @@ -339,7 +339,8 @@ fun NanoMuseHome( gesturesEnabled = drawerState.isOpen || tab == HomeTab.CHAT, drawerContent = { ModalDrawerSheet( - drawerContainerColor = MuseTones.surface, + // nanoMuse: pure canvas like Muse's drawer, not the grey sheet. + drawerContainerColor = com.openminis.app.ui.theme.ChatColors.background, drawerShape = androidx.compose.foundation.shape.RoundedCornerShape(topEnd = 24.dp, bottomEnd = 24.dp), ) { SideChatDrawer( @@ -375,11 +376,16 @@ fun NanoMuseHome( }, ) { padding -> val bottom = padding.calculateBottomPadding() + // Scaffold measures the entire bar, including its floating gap and + // navigation inset, before laying out this content. Use that same + // inset for placement and IME consumption, without a frame-late callback. Box( modifier = Modifier .fillMaxSize() .hazeSource(hazeState) - .padding(bottom = bottom) + // nanoMuse: no bottom inset — the pill bar is an overlay and the + // content slides behind it for the frosted blur. Each tab pads + // its own scrollable content above the pill. .consumeWindowInsets(PaddingValues(bottom = bottom)), ) { // Chat tab — always composed, hidden while another tab is on top. @@ -420,6 +426,9 @@ fun NanoMuseHome( }, onModelGroupsClick = { navController.safeNavigate(Routes.MODEL_GROUPS) }, nmHome = NmHomeChrome(isMainChat = isMainChat, onOpenDrawer = { openDrawer() }), + // nanoMuse: preserve the full-size blur source, but keep + // the chat footer above the bar measured by Scaffold. + nmBottomOverlay = bottom, ) } } @@ -437,6 +446,9 @@ fun NanoMuseHome( ) { Surface( color = ChatColors.background, + // nanoMuse: no bottom padding — tab content flows behind + // the pill overlay like the chat does. Tabs handle their + // own bottom contentPadding internally. modifier = Modifier.fillMaxSize(), ) { // Pages cross-fade; the header sits at the same spot on every page, diff --git a/android/src/android/app/src/main/java/io/github/nanomuse/ui/home/SideChatDrawer.kt b/android/src/android/app/src/main/java/io/github/nanomuse/ui/home/SideChatDrawer.kt index a121ea873..8cb49f4b5 100644 --- a/android/src/android/app/src/main/java/io/github/nanomuse/ui/home/SideChatDrawer.kt +++ b/android/src/android/app/src/main/java/io/github/nanomuse/ui/home/SideChatDrawer.kt @@ -48,6 +48,7 @@ import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip +import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.SolidColor import androidx.compose.ui.res.pluralStringResource import androidx.compose.ui.res.stringResource @@ -59,6 +60,7 @@ import androidx.compose.ui.unit.sp import com.openminis.app.R import com.openminis.app.data.db.ChatSessionEntity import com.openminis.app.data.repository.ChatRepository +import com.openminis.app.ui.theme.ChatColors import java.text.DateFormat import java.util.Date @@ -108,16 +110,22 @@ fun SideChatDrawer( Column( modifier = Modifier .fillMaxSize() - .background(MuseTones.surface) + .background(ChatColors.background) .statusBarsPadding() .navigationBarsPadding(), ) { + // nanoMuse: Muse's drawer voice — the agent name big and plain, rows in + // quiet pills, everything monochrome. + val nmDark = ChatColors.isDark + val nmRowSelected = if (nmDark) Color.White.copy(alpha = 0.09f) else Color.Black.copy(alpha = 0.06f) + val nmInk = ChatColors.primaryText + val nmMuted = ChatColors.secondaryText Text( text = agentName, - fontSize = 24.sp, + fontSize = 28.sp, fontWeight = FontWeight.Bold, - color = MaterialTheme.colorScheme.onSurface, - modifier = Modifier.padding(start = 20.dp, top = 18.dp, end = 20.dp, bottom = 14.dp), + color = nmInk, + modifier = Modifier.padding(start = 20.dp, top = 22.dp, end = 20.dp, bottom = 18.dp), ) // Main chat row — selected when it is what the chat tab shows. @@ -127,18 +135,18 @@ fun SideChatDrawer( modifier = Modifier .padding(horizontal = 12.dp) .fillMaxWidth() - .clip(RoundedCornerShape(14.dp)) - .background(if (mainSelected) MuseTones.fill else MuseTones.surface) + .clip(RoundedCornerShape(12.dp)) + .background(if (mainSelected) nmRowSelected else Color.Transparent) .clickable(onClick = onOpenMain) - .padding(horizontal = 14.dp, vertical = 14.dp), + .padding(horizontal = 14.dp, vertical = 13.dp), ) { - Icon(Icons.Outlined.Home, contentDescription = null, modifier = Modifier.size(20.dp), tint = MaterialTheme.colorScheme.onSurface) - Spacer(Modifier.size(12.dp)) + Icon(Icons.Outlined.Home, contentDescription = null, modifier = Modifier.size(22.dp), tint = nmInk) + Spacer(Modifier.size(14.dp)) Text( text = stringResource(R.string.nm_drawer_main_chat), fontSize = 16.sp, fontWeight = FontWeight.Medium, - color = MaterialTheme.colorScheme.onSurface, + color = nmInk, ) } @@ -149,17 +157,17 @@ fun SideChatDrawer( modifier = Modifier .padding(horizontal = 12.dp) .fillMaxWidth() - .clip(RoundedCornerShape(14.dp)) + .clip(RoundedCornerShape(12.dp)) .clickable(onClick = onDevices) - .padding(horizontal = 14.dp, vertical = 14.dp), + .padding(horizontal = 14.dp, vertical = 13.dp), ) { - Icon(Icons.Outlined.Devices, contentDescription = null, modifier = Modifier.size(20.dp), tint = MaterialTheme.colorScheme.onSurface) - Spacer(Modifier.size(12.dp)) + Icon(Icons.Outlined.Devices, contentDescription = null, modifier = Modifier.size(22.dp), tint = nmInk) + Spacer(Modifier.size(14.dp)) Text( text = stringResource(R.string.nm_devices_title), fontSize = 16.sp, fontWeight = FontWeight.Medium, - color = MaterialTheme.colorScheme.onSurface, + color = nmInk, modifier = Modifier.weight(1f), ) Text( @@ -169,7 +177,7 @@ fun SideChatDrawer( else -> pluralStringResource(R.plurals.nm_hub_service_devices, othersOnline, othersOnline) }, fontSize = 13.sp, - color = MaterialTheme.colorScheme.onSurfaceVariant, + color = nmMuted, ) } } @@ -181,43 +189,44 @@ fun SideChatDrawer( modifier = Modifier .padding(horizontal = 12.dp) .fillMaxWidth() - .clip(RoundedCornerShape(14.dp)) + .clip(RoundedCornerShape(12.dp)) .clickable(onClick = onCoding) - .padding(horizontal = 14.dp, vertical = 14.dp), + .padding(horizontal = 14.dp, vertical = 13.dp), ) { - Icon(Icons.Outlined.Terminal, contentDescription = null, modifier = Modifier.size(20.dp), tint = MaterialTheme.colorScheme.onSurface) - Spacer(Modifier.size(12.dp)) + Icon(Icons.Outlined.Terminal, contentDescription = null, modifier = Modifier.size(22.dp), tint = nmInk) + Spacer(Modifier.size(14.dp)) Text( text = stringResource(R.string.nm_coding_title), fontSize = 16.sp, fontWeight = FontWeight.Medium, - color = MaterialTheme.colorScheme.onSurface, + color = nmInk, modifier = Modifier.weight(1f), ) Text( text = codingComputers.toString(), fontSize = 13.sp, - color = MaterialTheme.colorScheme.onSurfaceVariant, + color = nmMuted, ) } } Row( verticalAlignment = Alignment.CenterVertically, - modifier = Modifier.padding(start = 26.dp, end = 12.dp, top = 12.dp), + modifier = Modifier.padding(start = 26.dp, end = 12.dp, top = 14.dp), ) { Text( - text = stringResource(R.string.nm_drawer_side_chats), - fontSize = 14.sp, - fontWeight = FontWeight.Medium, - color = MaterialTheme.colorScheme.onSurfaceVariant, + text = stringResource(R.string.nm_drawer_side_chats).uppercase(), + fontSize = 12.sp, + fontWeight = FontWeight.SemiBold, + letterSpacing = 1.sp, + color = nmMuted, modifier = Modifier.weight(1f), ) IconButton(onClick = onAllChats) { Icon( Icons.Outlined.Archive, contentDescription = stringResource(R.string.nm_drawer_all_chats), - tint = MaterialTheme.colorScheme.onSurfaceVariant, + tint = nmMuted, modifier = Modifier.size(20.dp), ) } @@ -232,7 +241,7 @@ fun SideChatDrawer( Icon( Icons.Outlined.Forum, contentDescription = null, - tint = MaterialTheme.colorScheme.onSurfaceVariant, + tint = nmMuted, modifier = Modifier.size(30.dp), ) Spacer(Modifier.height(10.dp)) @@ -240,13 +249,13 @@ fun SideChatDrawer( text = stringResource(R.string.nm_drawer_empty_title), fontSize = 17.sp, fontWeight = FontWeight.SemiBold, - color = MaterialTheme.colorScheme.onSurface, + color = nmInk, ) Spacer(Modifier.height(4.dp)) Text( text = stringResource(R.string.nm_drawer_empty_body), fontSize = 13.sp, - color = MaterialTheme.colorScheme.onSurfaceVariant, + color = nmMuted, textAlign = TextAlign.Center, ) } @@ -256,6 +265,9 @@ fun SideChatDrawer( SideChatRow( session = session, selected = session.id == currentSessionId, + selectedFill = nmRowSelected, + ink = nmInk, + muted = nmMuted, onClick = { onOpenSession(session.id) }, onSetMain = { onSetMain(session.id) }, ) @@ -263,37 +275,53 @@ fun SideChatDrawer( } } - // Bottom strip: settings · search · new + // Bottom strip: settings · search · new — Muse's circular buttons round a search pill. Row( verticalAlignment = Alignment.CenterVertically, modifier = Modifier .fillMaxWidth() - .padding(start = 8.dp, end = 8.dp, bottom = 8.dp, top = 6.dp), + .padding(start = 12.dp, end = 12.dp, bottom = 10.dp, top = 6.dp), ) { - IconButton(onClick = onSettings) { - Icon(Icons.Outlined.Settings, contentDescription = stringResource(R.string.nm_drawer_settings), tint = MaterialTheme.colorScheme.onSurface) + Box( + modifier = Modifier + .size(44.dp) + .clip(CircleShape) + .background(nmRowSelected) + .clickable(onClick = onSettings), + contentAlignment = Alignment.Center, + ) { + Icon(Icons.Outlined.Settings, contentDescription = stringResource(R.string.nm_drawer_settings), tint = nmInk, modifier = Modifier.size(22.dp)) } if (onSystemFiles != null) { - IconButton(onClick = onSystemFiles) { - Icon(Icons.Outlined.Description, contentDescription = stringResource(R.string.nm_sysfiles_title), tint = MaterialTheme.colorScheme.onSurface) + Spacer(Modifier.size(8.dp)) + Box( + modifier = Modifier + .size(44.dp) + .clip(CircleShape) + .background(nmRowSelected) + .clickable(onClick = onSystemFiles), + contentAlignment = Alignment.Center, + ) { + Icon(Icons.Outlined.Description, contentDescription = stringResource(R.string.nm_sysfiles_title), tint = nmInk, modifier = Modifier.size(22.dp)) } } + Spacer(Modifier.size(8.dp)) Row( verticalAlignment = Alignment.CenterVertically, modifier = Modifier .weight(1f) - .height(40.dp) + .height(44.dp) .clip(CircleShape) - .background(MuseTones.fill) - .padding(horizontal = 12.dp), + .background(nmRowSelected) + .padding(horizontal = 14.dp), ) { - Icon(Icons.Outlined.Search, contentDescription = null, tint = MaterialTheme.colorScheme.onSurfaceVariant, modifier = Modifier.size(18.dp)) + Icon(Icons.Outlined.Search, contentDescription = null, tint = nmMuted, modifier = Modifier.size(18.dp)) Spacer(Modifier.size(8.dp)) Box(Modifier.weight(1f)) { if (query.isEmpty()) { Text( stringResource(R.string.nm_drawer_search), - color = MaterialTheme.colorScheme.onSurfaceVariant, + color = nmMuted, fontSize = 15.sp, ) } @@ -301,14 +329,22 @@ fun SideChatDrawer( value = query, onValueChange = { query = it }, singleLine = true, - textStyle = LocalTextStyle.current.copy(color = MaterialTheme.colorScheme.onSurface, fontSize = 15.sp), - cursorBrush = SolidColor(MaterialTheme.colorScheme.primary), + textStyle = LocalTextStyle.current.copy(color = nmInk, fontSize = 15.sp), + cursorBrush = SolidColor(nmInk), modifier = Modifier.fillMaxWidth(), ) } } - IconButton(onClick = onNewChat) { - Icon(Icons.Outlined.Edit, contentDescription = stringResource(R.string.nm_drawer_new_chat), tint = MaterialTheme.colorScheme.onSurface) + Spacer(Modifier.size(8.dp)) + Box( + modifier = Modifier + .size(44.dp) + .clip(CircleShape) + .background(nmRowSelected) + .clickable(onClick = onNewChat), + contentAlignment = Alignment.Center, + ) { + Icon(Icons.Outlined.Edit, contentDescription = stringResource(R.string.nm_drawer_new_chat), tint = nmInk, modifier = Modifier.size(22.dp)) } } } @@ -319,6 +355,9 @@ fun SideChatDrawer( private fun SideChatRow( session: ChatSessionEntity, selected: Boolean, + selectedFill: androidx.compose.ui.graphics.Color, + ink: androidx.compose.ui.graphics.Color, + muted: androidx.compose.ui.graphics.Color, onClick: () -> Unit, onSetMain: () -> Unit, ) { @@ -330,7 +369,7 @@ private fun SideChatRow( .padding(horizontal = 12.dp, vertical = 1.dp) .fillMaxWidth() .clip(RoundedCornerShape(12.dp)) - .background(if (selected) MuseTones.fill else MuseTones.surface) + .background(if (selected) selectedFill else Color.Transparent) .combinedClickable(onClick = onClick, onLongClick = { menu = true }) .padding(horizontal = 14.dp, vertical = 11.dp), ) { @@ -338,7 +377,7 @@ private fun SideChatRow( Text( text = session.title?.takeIf { it.isNotBlank() } ?: stringResource(R.string.nm_drawer_untitled), fontSize = 15.sp, - color = MaterialTheme.colorScheme.onSurface, + color = ink, maxLines = 1, overflow = TextOverflow.Ellipsis, ) @@ -347,7 +386,7 @@ private fun SideChatRow( Text( text = relativeDay(androidx.compose.ui.platform.LocalContext.current, session.updatedAt), fontSize = 12.sp, - color = MaterialTheme.colorScheme.onSurfaceVariant, + color = muted, ) } DropdownMenu(expanded = menu, onDismissRequest = { menu = false }) { From 43583d9ff66b6594138844ce029620cd4573b3a4 Mon Sep 17 00:00:00 2001 From: Vela Date: Sun, 11 Oct 2026 09:57:43 +0530 Subject: [PATCH 09/98] revert(android): exclude menu and drawer polish from chat-polishing branch These are sent as separate upstream PRs (upstream/menu-polish, upstream/drawer-polish). This branch keeps only the pill nav and Meta AI chat polish. Signed-off-by: Vela --- CHANGELOG.md | 4 ++++ .../java/io/github/nanomuse/ui/home/NanoMuseHome.kt | 13 ++++++++++++- 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9d7b07ae1..b543a1a7c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -49,6 +49,8 @@ All notable changes to nanoMuse. The format follows [Keep a Changelog](https://k ### Android +- Removed the gap between the chat composer and its fade when scrolling through older messages. The fade now stays hidden while tool or browser controls are visible. +- Fixed the chat composer and tool status bar overlapping the floating navigation pill. The latest messages, scroll controls and bottom fade now follow the measured footer height while the conversation still scrolls behind the pill for its frosted blur. - The sign-in page no longer calls a mainland-China number "outside the mainland" while it is still being typed: seven to ten digits that can still become `1xx xxxx xxxx` (with or without `+86`) show no sentence and keep *Send* on; the sentence comes once the number cannot be a mainland one any more. - The welcome page's *Reach* line says how a computer joins today: install nanoMuse Desktop and sign in with the same account (it said "pair", which left in 0.1.24); the Chinese line under the nanoMuse Cloud provider says 服务商 like every other. - The hands notice when they go round in circles: the same action a third time on a screen that did not change gets a line in the history so the model changes tack, and a sixth ends the run as *infeasible* with the action named. Before, a model repeating one tap kept calling the screen model, a screenshot each time, until the thirty-minute limit or *Stop*. @@ -236,6 +238,8 @@ Keel: the first stable version. What has been a preview since 2026-09-25 is now - **Another device can stop a task it asked this phone to run.** The hub's `stop {call}` / `stop {conversation}` ends the run after the step in flight and the task answers `cancelled`; it used to answer `stopped: false` and let the task run on. Only the device that asked may stop it. - **The bottom bar is a floating frosted-glass pill.** The five tabs sit in a rounded pill that blurs whatever is behind it, icons only; the current tab shows a filled glyph on a soft indicator that springs in. - **Debug builds install next to the release app** (`io.github.nanomuse.app.debug`), so a test APK never replaces the installed nanoMuse. +- **Chat goes Meta AI.** The conversation fades into the background at the top and above the composer instead of sliding under hard edges; your messages are white pills with black ink (black pills in the light theme) and the assistant's replies sit in soft off-black pills; the scroll-to-latest button is a centered white disc with a black arrow; the light theme is white like Meta AI's. The header fade starts at the top edge and melts down through the header; the lower fade appears only while scrolled up, never over the latest message; the send button is monochrome (white disc, black arrow in dark; inverted in light) with no blue accent. +- **The nav bar's selected tab is a white disc with a black glyph** (inverted in the light theme); the frosted blur is unchanged. ### iOS diff --git a/android/src/android/app/src/main/java/io/github/nanomuse/ui/home/NanoMuseHome.kt b/android/src/android/app/src/main/java/io/github/nanomuse/ui/home/NanoMuseHome.kt index 9d522d93c..1429b9b6a 100644 --- a/android/src/android/app/src/main/java/io/github/nanomuse/ui/home/NanoMuseHome.kt +++ b/android/src/android/app/src/main/java/io/github/nanomuse/ui/home/NanoMuseHome.kt @@ -375,11 +375,16 @@ fun NanoMuseHome( }, ) { padding -> val bottom = padding.calculateBottomPadding() + // Scaffold measures the entire bar, including its floating gap and + // navigation inset, before laying out this content. Use that same + // inset for placement and IME consumption, without a frame-late callback. Box( modifier = Modifier .fillMaxSize() .hazeSource(hazeState) - .padding(bottom = bottom) + // nanoMuse: no bottom inset — the pill bar is an overlay and the + // content slides behind it for the frosted blur. Each tab pads + // its own scrollable content above the pill. .consumeWindowInsets(PaddingValues(bottom = bottom)), ) { // Chat tab — always composed, hidden while another tab is on top. @@ -420,6 +425,9 @@ fun NanoMuseHome( }, onModelGroupsClick = { navController.safeNavigate(Routes.MODEL_GROUPS) }, nmHome = NmHomeChrome(isMainChat = isMainChat, onOpenDrawer = { openDrawer() }), + // nanoMuse: preserve the full-size blur source, but keep + // the chat footer above the bar measured by Scaffold. + nmBottomOverlay = bottom, ) } } @@ -437,6 +445,9 @@ fun NanoMuseHome( ) { Surface( color = ChatColors.background, + // nanoMuse: no bottom padding — tab content flows behind + // the pill overlay like the chat does. Tabs handle their + // own bottom contentPadding internally. modifier = Modifier.fillMaxSize(), ) { // Pages cross-fade; the header sits at the same spot on every page, From 979d65a8f039db753c81ef487f37fcf093d2c2a2 Mon Sep 17 00:00:00 2001 From: lgy0404 <2528379691@qq.com> Date: Sun, 11 Oct 2026 15:29:22 +0800 Subject: [PATCH 10/98] revert(android): keep the debug application id and the local debug key Takes back a5a20d28 (debug builds under io.github.nanomuse.app.debug) and c02ca421 (a committed debug keystore for CI): the signing config, the debug build type, ci-debug.keystore, the debug copy of shortcuts.xml and the CHANGELOG line. A debug build keeps installing over the release app, the way it has, and the repository carries no key, not even a public one; how test APKs get a stable signature is a separate conversation from the look. For #329 Signed-off-by: lgy0404 <2528379691@qq.com> --- CHANGELOG.md | 1 - android/src/android/app/build.gradle.kts | 18 ------- android/src/android/app/ci-debug.keystore | Bin 2626 -> 0 bytes .../app/src/debug/res/xml/shortcuts.xml | 48 ------------------ 4 files changed, 67 deletions(-) delete mode 100644 android/src/android/app/ci-debug.keystore delete mode 100644 android/src/android/app/src/debug/res/xml/shortcuts.xml diff --git a/CHANGELOG.md b/CHANGELOG.md index 5932f14b3..b5fa1b9ec 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -332,7 +332,6 @@ Keel: the first stable version. What has been a preview since 2026-09-25 is now - **The Hands page follows its switch wherever it is flipped**: a change made while the page is open shows at once instead of after reopening it. - **Another device can stop a task it asked this phone to run.** The hub's `stop {call}` / `stop {conversation}` ends the run after the step in flight and the task answers `cancelled`; it used to answer `stopped: false` and let the task run on. Only the device that asked may stop it. - **The bottom bar is a floating frosted-glass pill.** The five tabs sit in a rounded pill that blurs whatever is behind it, icons only; the current tab shows a filled glyph on a soft indicator that springs in. -- **Debug builds install next to the release app** (`io.github.nanomuse.app.debug`), so a test APK never replaces the installed nanoMuse. ### iOS diff --git a/android/src/android/app/build.gradle.kts b/android/src/android/app/build.gradle.kts index 585cf3374..ddbb463d8 100644 --- a/android/src/android/app/build.gradle.kts +++ b/android/src/android/app/build.gradle.kts @@ -51,16 +51,6 @@ android { keyPassword = props.getProperty("keyPassword") } } - // nanoMuse: committed CI debug key. Every CI runner mints its own throwaway - // debug key, so consecutive CI APKs carry different signatures and Android - // refuses to install one over the other ("update incompatible"). This key - // uses the stock public debug credentials (android/android) and is debug-only. - create("ciDebug") { - storeFile = file("ci-debug.keystore") - storePassword = "android" - keyAlias = "androiddebugkey" - keyPassword = "android" - } } defaultConfig { @@ -102,14 +92,6 @@ android { } buildTypes { - // nanoMuse: debug builds install next to the release app (io.github.nanomuse.app.debug), - // so a CI APK never replaces the store version on a test phone. - debug { - applicationIdSuffix = ".debug" - // nanoMuse: sign with the committed CI key so consecutive CI builds - // share one signature and install over each other (see signingConfigs). - signingConfig = signingConfigs.getByName("ciDebug") - } release { isMinifyEnabled = true proguardFiles( diff --git a/android/src/android/app/ci-debug.keystore b/android/src/android/app/ci-debug.keystore deleted file mode 100644 index 59449583c5cbdabdf25d0abacc0a9ff41c0dafa7..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2626 zcmai$XE+-Q7so>)Ld2@Zy=W+nRV7A^x?HOzHDZt2uGk}X(Hfy*@2w(Muc}gNuUaip zMQv@&UTU?q_jtX}`#$Z*`{6w2od5qk&-rwI&q3ko6{)F!C_LRRm`*rKBkBM~MN37( z(=CDUbPJdA3O z^3hbxP+b&}Po0`thX=&~hWu|UH60BAbq!2s6Qx0g1%jxALCk}vv)ba>*LTRUmDd94 zFDPMnVDhAS3(c*Rt2sepFYP0NH`epE;+1#e9pm?HQa!Dk>ZDBAI;*C-({RyW7a=6_ z=+^1qt(ML;$xJ=4l3-BXM}z!KJv_JBMRS5@$F@S#yFT&almXl}qZAr~u{=!Tg$BHo zOn(QGHJ?T3LCajJygnFH)b#nhHneEA zsU~>*n)kX4;0uL%i@2QKD4vw}B(#vOMU+kGit?iil!X9?uTHQ*%?|`AT}3CoL{i8Z9vzoGH2lAKR=@W>u_@lnyXX3?MZrv*0{Lg8E@_^s~K7u_(z%_AbTVZMp zF-A3QOycu45PIp%&SmGopuSTXhyZ5Bv}IXay|-i6V-WI>6j*C>acV|;jdZHI8|EX* z_eT*5%`2a5QY8wcL^3jc(a`B}!vWP|CQ?r$qq1{8w#vO^$Np)D`AZfgfs7PCGCWy~Es**|anH=Os>s7ecX*&N-x17PCpV6dPmTJs?lP z@Im@%Q=5tTbXpG_Y-D&IvYTEDXe3Aumm;btoRn(a@M`Yc z(1OLZz%M8T_m%E8i+$UZcC_2+xjJaS#S9;tuTgFRpBd%Pe!OjEvZ0>^Vi$-pt6rN@ zET~T5+8Oji$m)yqT28-8lvUd93VfX&nXGoEv#&v{Ppy+NC`mn8ywb<^op2|2IJI^t zgZbHKHvIJb${jyxj&g|L$#?jDE`~qF_3F1zMWoH{Mli82aD7>yOk{8<{86U=I?Sd- z{Uu|Mx;{KP0%PyGEW9}y@K$9e#^fo@toH4>Q4h%)9dXUPB%4kizD)J{(8tN9K1{hW zbz-*310>E7qRK>jtks2VEx_MX`fPd|Bkj4e^R5?!!qc?;yz~EpgQfz6rzyLXOD=;1 zhW?)^4D?jgm!{mMc>CW#vHT$7WHxnPPBI5g?t;)j{uLBHdQC&Y3L}j(%$0@0vW|Hm zJZKn8wzk!(LUwq$&Pm5icV{W^%g1Tfv#er~*-JOyVLA(d|3s%uXm&%aSO#zI-)Eo+ zc^{KZKA%=yb~Lyq$e}N-?T(ap9Kb=z8>SYM=5+oh*u@X(cidb33?^3tR?6-g(8k5J zz^<%42=bfW$;k$?XjDC{h6>5HO87SRB^Egsddr5-+3PC9RRi1WILu;+ycHG3vnY(6 zb>wCoS}8{00`54~40=Gm_k+jhJKuGVGFSmf*G2}jzH@L6cCO`v);xXT{z*hVt0OJ9 zo}dq(bF0s(-7);0wWBH+GC-_@wXh9SWhwQr zP~k*@JA&_h6MA4>6wsM=-W-AI!xbTOE5sDgFK@-=lG;KtgR>25u0cra)H~KV)d=`+j;)dbxl;C$6F$;#hcZuG5=}4Dx#Z9|6 zvjQZ&Ynq>YcK1Fkp{dw{cEH|FcWgHXNZZ7v7+2_5Eh24!6%}4w_>IB>0{d-sM4Wo+ zo|MN{rpN~#ZIMZ?TB^(f>d!tL6maL*y(wRcq!>KKMtW3; zGFm@Bl<&D2^emHqRcGcbFkR=)B1Uhbsyd?||Hj*~!7X`yW7OVup@VJCnZYUHgD(8W z$lG&5P2PkKJ!`Fq

4RVCW;ZnZV{0AA}F+`(2_=bNQXU944h5Mzc@5PaniNu*5} zT3)GFfkz@$rB6d+Ir)P!5>d$?9&`yB}FZdX6Poi`c>j!<{GkdV9P zg(1TpJBTS61~*5{z0E2Wt#&{MFcacSQ~Tawj={{92sKvu61Jw8a2`o?;u)aWeG6bI zw4|7No=BcgK@SHDI^Wb(d# zN|=gx7ca`{^ZfY?Viu2oRVT7QuO22BJbiq&6cC|WH>5be8E`z$xht_qSKjZ?6zgDV z6n5hMHR`+yUUoP@Fv=Mp_Mbk77lhzkzyQvs84jPn226-9&jNeygWK_^M{f;wU8R|A zBIzl!rJl9PrmQ68HbZt{?nmF&LNtpvT%L7poyR5-F=TR85WxSyeuJibUMGG-#FEw?72e_4a_8L zIb>@5>}#OfJMlaD;ll1=?2b)R`a7nCvKII?!inc0)P7pr5XJWsv~*X+;UG5a_l@7v zqs&4j3}6-VBIJm|V-_jYtzScI;yefhz!u;Eum^YpJOR#^*&cue*a7?ijsVxoDiEcN z5=X&)eqGd5Gyo6}Hg4iTC{Iw&{AnY?qk4SC9CwvJ(&uAdPH193K+zWjf*d3ap6m!? K<*BJ5fd2rSSieaC diff --git a/android/src/android/app/src/debug/res/xml/shortcuts.xml b/android/src/android/app/src/debug/res/xml/shortcuts.xml deleted file mode 100644 index 0ba731e59..000000000 --- a/android/src/android/app/src/debug/res/xml/shortcuts.xml +++ /dev/null @@ -1,48 +0,0 @@ - - - - - - - - - - - - - - - - From 44242e2a773b290c4c46a2ca238dfccced7e6753 Mon Sep 17 00:00:00 2001 From: lgy0404 <2528379691@qq.com> Date: Sun, 11 Oct 2026 15:32:40 +0800 Subject: [PATCH 11/98] docs(changelog): the pill bar lands under Unreleased, with the notices and the Chinese page CHANGELOG.md had a leftover `<<<<<<< HEAD` marker and the new line inside the released 1.0.0 block; the marker is gone and the line sits under Unreleased, Android, now also naming the menus' canvas and the author. THIRD_PARTY_NOTICES.md lists Haze (Apache-2.0) among the Gradle dependencies, docs/zh/every-device.md says what docs/every-device.md says about the bar, and four new code comments read without em dashes. For #329 Signed-off-by: lgy0404 <2528379691@qq.com> --- CHANGELOG.md | 3 +-- THIRD_PARTY_NOTICES.md | 1 + android/src/android/app/build.gradle.kts | 2 +- .../src/main/java/com/openminis/app/ui/components/MinisMenu.kt | 2 +- .../src/main/java/io/github/nanomuse/ui/home/MuseBottomBar.kt | 2 +- .../src/main/java/io/github/nanomuse/ui/home/NanoMuseHome.kt | 2 +- docs/zh/every-device.md | 2 +- 7 files changed, 7 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b5fa1b9ec..54be3ef2a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -20,6 +20,7 @@ All notable changes to nanoMuse. The format follows [Keep a Changelog](https://k ### Android +- **The bottom bar is a floating frosted-glass pill.** The five tabs sit in a rounded pill a little above the bottom edge, icons only and no labels; the pill blurs what is behind it and has a hairline edge. The current tab shows a filled glyph on a soft indicator that springs across, the others stay outlined. The menus take the chat's own canvas, black in dark and white in light, with a hairline edge instead of a tinted surface (thanks @Ichiro786, #329). - **OpenCode Go works on the phone.** Chat and Responses requests to OpenCode's host carry `x-opencode-session`, the chat's prompt cache key (a hash of its first message, the same on every turn), beside the app's own `nanoMuse/` user agent; the ways-on card lists Go from the relay's new `session_providers`, and a provider set up on Go's address is told apart from Zen by the whole address (thanks @PovedaAqui). ### iOS @@ -326,12 +327,10 @@ Keel: the first stable version. What has been a preview since 2026-09-25 is now - **The connectors' background token refresh runs in one supervised scope**, and two cross-thread flags (the browser hand-over waiter, the profile sync timer) are marked volatile. - Copy buttons use the current Compose clipboard API and the open-in-new icon mirrors in right-to-left layouts; the Android build has no warnings in nanoMuse's code. - CI runs the Android unit tests (`io.github.nanomuse.*`) after building the debug APK. -<<<<<<< HEAD - **The Library shows the signed-in account's files only.** On a phone two accounts share, the Library tab listed the workspaces of the other account's chats as well; it now follows the chat list's rule (the account's own sessions, or the local ones when signed out), and a workspace whose chat is gone is not listed. - **Connector keys and client secrets are masked while typed**, with the eye to show them, like the other key fields in the app. - **The Hands page follows its switch wherever it is flipped**: a change made while the page is open shows at once instead of after reopening it. - **Another device can stop a task it asked this phone to run.** The hub's `stop {call}` / `stop {conversation}` ends the run after the step in flight and the task answers `cancelled`; it used to answer `stopped: false` and let the task run on. Only the device that asked may stop it. -- **The bottom bar is a floating frosted-glass pill.** The five tabs sit in a rounded pill that blurs whatever is behind it, icons only; the current tab shows a filled glyph on a soft indicator that springs in. ### iOS diff --git a/THIRD_PARTY_NOTICES.md b/THIRD_PARTY_NOTICES.md index 4828617ba..ed4bd11f2 100644 --- a/THIRD_PARTY_NOTICES.md +++ b/THIRD_PARTY_NOTICES.md @@ -29,6 +29,7 @@ The app is a modified copy of [OpenMinis](https://github.com/OpenMinis/OpenMinis | Coil (coil-compose) | 2.7.0 | **Apache-2.0** | | multiplatform-markdown-renderer (+ m3), mikepenz | 0.33.0 | **Apache-2.0** | | Reorderable (sh.calvin.reorderable) | 2.4.0 | **Apache-2.0** | +| Haze (dev.chrisbanes.haze:haze-android), the blur behind the bottom bar | 1.6.10 | **Apache-2.0** | | ACRA (acra-core) | 5.12.0 | **Apache-2.0** | | Shizuku API + provider (dev.rikka.shizuku) | 13.1.5 | **MIT** | | RealTimeCutVADLibraryForAndroid (JitPack) | see build file | **MIT** (Silero VAD **MIT**, ONNX Runtime **MIT**, WebRTC APM **BSD-3-Clause**) | diff --git a/android/src/android/app/build.gradle.kts b/android/src/android/app/build.gradle.kts index ddbb463d8..953f08c8d 100644 --- a/android/src/android/app/build.gradle.kts +++ b/android/src/android/app/build.gradle.kts @@ -206,7 +206,7 @@ dependencies { implementation("androidx.compose.material3:material3") implementation("androidx.compose.material:material-icons-extended") - // nanoMuse: frosted-glass pill bottom bar — Haze backdrop blur, in the Pixel taskbar's manner. + // nanoMuse: the frosted-glass pill bottom bar: Haze backdrop blur, in the Pixel taskbar's manner. // 1.6.10, not 2.x: Haze 1.7.x and 2.x need compileSdk 37, and this module is on 36. implementation("dev.chrisbanes.haze:haze-android:1.6.10") diff --git a/android/src/android/app/src/main/java/com/openminis/app/ui/components/MinisMenu.kt b/android/src/android/app/src/main/java/com/openminis/app/ui/components/MinisMenu.kt index cded3f341..6fd40f2cb 100644 --- a/android/src/android/app/src/main/java/com/openminis/app/ui/components/MinisMenu.kt +++ b/android/src/android/app/src/main/java/com/openminis/app/ui/components/MinisMenu.kt @@ -71,7 +71,7 @@ fun MinisMenu( // in dark, a subtle shade in light) so the menu pops out — same fix already // validated on the text-selection toolbar (T-android-text-toolbar-dark- // visibility). The dark-mode `border` below adds the extra edge definition. - // nanoMuse: pure canvas like the drawer and chat — black in dark, white in + // nanoMuse: pure canvas like the drawer and chat, black in dark and white in // light. The hairline border carries the definition. containerColor: Color = ChatColors.background, tonalElevation: Dp = 3.dp, diff --git a/android/src/android/app/src/main/java/io/github/nanomuse/ui/home/MuseBottomBar.kt b/android/src/android/app/src/main/java/io/github/nanomuse/ui/home/MuseBottomBar.kt index 0d8644c2c..5e06926c3 100644 --- a/android/src/android/app/src/main/java/io/github/nanomuse/ui/home/MuseBottomBar.kt +++ b/android/src/android/app/src/main/java/io/github/nanomuse/ui/home/MuseBottomBar.kt @@ -36,7 +36,7 @@ import dev.chrisbanes.haze.hazeEffect * nanoMuse's bottom bar: a floating frosted-glass pill, five glyphs, icons only. The pill blurs * whatever is behind it (Haze, in the Pixel taskbar's manner) and carries a hairline edge. The * current tab shows a filled glyph on a soft indicator pill that springs in; the others are - * outlined. No labels — the fill and the indicator are the state. + * outlined. No labels: the fill and the indicator are the state. */ @Composable fun MuseBottomBar( diff --git a/android/src/android/app/src/main/java/io/github/nanomuse/ui/home/NanoMuseHome.kt b/android/src/android/app/src/main/java/io/github/nanomuse/ui/home/NanoMuseHome.kt index 9d522d93c..cd4f74410 100644 --- a/android/src/android/app/src/main/java/io/github/nanomuse/ui/home/NanoMuseHome.kt +++ b/android/src/android/app/src/main/java/io/github/nanomuse/ui/home/NanoMuseHome.kt @@ -331,7 +331,7 @@ fun NanoMuseHome( // The drawer + tab shell, as a local composable so it can share every piece of state above // and still be one branch of the phase switch below. - // nanoMuse: the frosted pill bar blurs this shell's content — the shell is the haze source. + // nanoMuse: the frosted pill bar blurs this shell's content; the shell is the haze source. val hazeState = rememberHazeState() val homeShell: @Composable () -> Unit = { ModalNavigationDrawer( diff --git a/docs/zh/every-device.md b/docs/zh/every-device.md index 088a4b532..7914a8d16 100644 --- a/docs/zh/every-device.md +++ b/docs/zh/every-device.md @@ -10,7 +10,7 @@ |---|---|---| | 对话顶部一张脸、一个名字胶囊、一行状态 | `HomeShell`、`AgentAvatarDisc` | 网页版的聊天头部,默认是小龙 | | 一个主要聊天,旁聊收在抽屉里 | 抽屉 | 窄窗口用抽屉,宽窗口用侧栏 | -| 动态 · 点子 · 目标 · 资源库 | 底栏 | 底栏 / 侧栏 | +| 动态 · 点子 · 目标 · 资源库 | 悬浮的毛玻璃胶囊栏,只有图标 | 底栏 / 侧栏 | | 聊天里的审批卡片,三个层级,「记住」胶囊 | `RiskApprovalCard`、`RiskTier` | 哨兵(Sentinel)的卡片,标签相同 | | 设置 → 权限:记住了什么,按层级列出 | `GrantsSection` | 权限页,按层级列出授权 | | 设置 → Hands:把屏幕当手,默认关 | `Hands` | 设置 → Hands(这台电脑的屏幕) | From a2e907605ceffe9f486d67c581f4e1e767acf180 Mon Sep 17 00:00:00 2001 From: lgy0404 <2528379691@qq.com> Date: Sun, 11 Oct 2026 15:49:56 +0800 Subject: [PATCH 12/98] fix(android): the drawer lands on its own, the content keeps its inset for now The drawer commit also removed the content's bottom inset and passed a `nmBottomOverlay` to the chat screen that nothing on main defines, so the branch did not compile. Those two hunks belong to the chat polish (#331) and come back with it; this PR is the drawer. Also a CHANGELOG line under Unreleased, Android, and two code comments without em dashes. For #330 Signed-off-by: lgy0404 <2528379691@qq.com> --- CHANGELOG.md | 1 + .../java/io/github/nanomuse/ui/home/NanoMuseHome.kt | 13 +------------ .../io/github/nanomuse/ui/home/SideChatDrawer.kt | 4 ++-- 3 files changed, 4 insertions(+), 14 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 54be3ef2a..9ac82f838 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -21,6 +21,7 @@ All notable changes to nanoMuse. The format follows [Keep a Changelog](https://k ### Android - **The bottom bar is a floating frosted-glass pill.** The five tabs sit in a rounded pill a little above the bottom edge, icons only and no labels; the pill blurs what is behind it and has a hairline edge. The current tab shows a filled glyph on a soft indicator that springs across, the others stay outlined. The menus take the chat's own canvas, black in dark and white in light, with a hairline edge instead of a tinted surface (thanks @Ichiro786, #329). +- **The chats drawer sits on the same canvas.** Black in dark and white in light instead of the grey sheet, the agent's name larger at the top, the side chats label in small capitals, the selected row and the main-chat row on a quiet translucent pill, and the settings, system files and new chat buttons as 44 dp discs beside the search field, all in the text colours of the theme rather than a tint (thanks @Ichiro786, #330). - **OpenCode Go works on the phone.** Chat and Responses requests to OpenCode's host carry `x-opencode-session`, the chat's prompt cache key (a hash of its first message, the same on every turn), beside the app's own `nanoMuse/` user agent; the ways-on card lists Go from the relay's new `session_providers`, and a provider set up on Go's address is told apart from Zen by the whole address (thanks @PovedaAqui). ### iOS diff --git a/android/src/android/app/src/main/java/io/github/nanomuse/ui/home/NanoMuseHome.kt b/android/src/android/app/src/main/java/io/github/nanomuse/ui/home/NanoMuseHome.kt index 71e00f32f..e37a54287 100644 --- a/android/src/android/app/src/main/java/io/github/nanomuse/ui/home/NanoMuseHome.kt +++ b/android/src/android/app/src/main/java/io/github/nanomuse/ui/home/NanoMuseHome.kt @@ -376,16 +376,11 @@ fun NanoMuseHome( }, ) { padding -> val bottom = padding.calculateBottomPadding() - // Scaffold measures the entire bar, including its floating gap and - // navigation inset, before laying out this content. Use that same - // inset for placement and IME consumption, without a frame-late callback. Box( modifier = Modifier .fillMaxSize() .hazeSource(hazeState) - // nanoMuse: no bottom inset — the pill bar is an overlay and the - // content slides behind it for the frosted blur. Each tab pads - // its own scrollable content above the pill. + .padding(bottom = bottom) .consumeWindowInsets(PaddingValues(bottom = bottom)), ) { // Chat tab — always composed, hidden while another tab is on top. @@ -426,9 +421,6 @@ fun NanoMuseHome( }, onModelGroupsClick = { navController.safeNavigate(Routes.MODEL_GROUPS) }, nmHome = NmHomeChrome(isMainChat = isMainChat, onOpenDrawer = { openDrawer() }), - // nanoMuse: preserve the full-size blur source, but keep - // the chat footer above the bar measured by Scaffold. - nmBottomOverlay = bottom, ) } } @@ -446,9 +438,6 @@ fun NanoMuseHome( ) { Surface( color = ChatColors.background, - // nanoMuse: no bottom padding — tab content flows behind - // the pill overlay like the chat does. Tabs handle their - // own bottom contentPadding internally. modifier = Modifier.fillMaxSize(), ) { // Pages cross-fade; the header sits at the same spot on every page, diff --git a/android/src/android/app/src/main/java/io/github/nanomuse/ui/home/SideChatDrawer.kt b/android/src/android/app/src/main/java/io/github/nanomuse/ui/home/SideChatDrawer.kt index 8cb49f4b5..1718bc3e3 100644 --- a/android/src/android/app/src/main/java/io/github/nanomuse/ui/home/SideChatDrawer.kt +++ b/android/src/android/app/src/main/java/io/github/nanomuse/ui/home/SideChatDrawer.kt @@ -114,7 +114,7 @@ fun SideChatDrawer( .statusBarsPadding() .navigationBarsPadding(), ) { - // nanoMuse: Muse's drawer voice — the agent name big and plain, rows in + // nanoMuse: Muse's drawer voice: the agent name big and plain, rows in // quiet pills, everything monochrome. val nmDark = ChatColors.isDark val nmRowSelected = if (nmDark) Color.White.copy(alpha = 0.09f) else Color.Black.copy(alpha = 0.06f) @@ -275,7 +275,7 @@ fun SideChatDrawer( } } - // Bottom strip: settings · search · new — Muse's circular buttons round a search pill. + // Bottom strip: settings · search · new, Muse's circular buttons round a search pill. Row( verticalAlignment = Alignment.CenterVertically, modifier = Modifier From c6c4f8f604f5fff8a1071f00835091c1c164a174 Mon Sep 17 00:00:00 2001 From: lgy0404 <2528379691@qq.com> Date: Sun, 11 Oct 2026 15:50:21 +0800 Subject: [PATCH 13/98] feat(ios): the tab bar is a floating frosted-glass pill The five tabs sit in a centred Capsule 12 pt above the bottom safe area, icons only: .ultraThinMaterial under the shell's surface tone at 55 percent, a 1 pt hairline edge, 60 by 46 pt tap boxes. The current tab shows its filled symbol on an indicator capsule in the new NanoMuseTones.tabIndicator tone (Android's primaryContainer, light and dark) that springs to the tab tapped next through matchedGeometryEffect; the others stay outlined in the secondary colour. The full-width strip and its hairline on top are gone. The SF symbols, the accessibility labels and the selected trait are the ones from before, so no string changes. Layout: the pill lies over the rooms and the chat in a ZStack aligned to the bottom. The chat keeps the 0.1.40 rule (plain layout, never an inset of the NavigationStack's ancestor) as bottom padding of the bar's height, so the composer sits above the pill. The rooms are plain SwiftUI scroll views and take the same height as a safeAreaInset, so their content scrolls under the pill and the glass has something to blur. The bar still leaves while the keyboard or the voice panel is up. Follows #329 by @Ichiro786 (Android's MuseBottomBar). Signed-off-by: lgy0404 <2528379691@qq.com> --- CHANGELOG.md | 1 + android/src/ios/NanoMuse/NanoMuseFaces.swift | 5 ++ android/src/ios/NanoMuse/NanoMuseShell.swift | 82 +++++++++++++++----- docs/ios.md | 26 ++++++- docs/zh/ios.md | 20 ++++- 5 files changed, 108 insertions(+), 26 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 74f92bf1c..727f912a8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -26,6 +26,7 @@ All notable changes to nanoMuse. The format follows [Keep a Changelog](https://k - **A voice prompt from the Action Button.** A *Voice Prompt* Shortcut opens the app and starts listening, so a prompt can be spoken instead of typed: bind it to the Action Button, Back Tap or a widget, press, speak, and the words appear in the composer; sending stays a tap on the send button. It is the composer's own voice panel, started for you, with the same microphone and speech permissions; with no session named it lands in the chat that is open, the main chat in the Muse layout. Written by @cypggs (#296, #298). - **OpenCode Go works on the phone.** Chat and Responses requests to OpenCode's host carry `x-opencode-session`, the chat's prompt cache key (a hash of its first message, the same on every turn), beside the app's own `nanoMuse/` user agent; the ways-on card lists Go from the relay's new `session_providers` (thanks @PovedaAqui). +- **The bottom bar is a floating frosted-glass pill.** The five tabs sit in a rounded pill 12 pt above the bottom edge, icons only; the pill blurs what is behind it under the shell's surface tone and has a hairline edge. The current tab shows a filled glyph on a soft indicator capsule that springs across to the tab tapped next, the others stay outlined. The chat's composer keeps its place above the bar, and the rooms' content scrolls under it (follows #329 by @Ichiro786). ### Project diff --git a/android/src/ios/NanoMuse/NanoMuseFaces.swift b/android/src/ios/NanoMuse/NanoMuseFaces.swift index 5f242fb9d..28cef0539 100644 --- a/android/src/ios/NanoMuse/NanoMuseFaces.swift +++ b/android/src/ios/NanoMuse/NanoMuseFaces.swift @@ -459,6 +459,11 @@ enum NanoMuseTones { static let hairline = Color(uiColor: UIColor { $0.userInterfaceStyle == .dark ? UIColor(red: 0.227, green: 0.227, blue: 0.235, alpha: 1) : UIColor(red: 0.898, green: 0.898, blue: 0.918, alpha: 1) }) static let canvas = Color(uiColor: UIColor { $0.userInterfaceStyle == .dark ? .black : UIColor(red: 0.953, green: 0.953, blue: 0.961, alpha: 1) }) static let action = Color(red: 0.039, green: 0.4, blue: 0.894) + /// The bottom bar's indicator capsule under the current tab, and the glyph on it: Android's + /// primaryContainer and onPrimaryContainer (#E5F0FF with #012F80 in light, #1A2B4A with + /// #E5F0FF in dark). + static let tabIndicator = Color(uiColor: UIColor { $0.userInterfaceStyle == .dark ? UIColor(red: 0.102, green: 0.169, blue: 0.29, alpha: 1) : UIColor(red: 0.898, green: 0.941, blue: 1, alpha: 1) }) + static let tabIndicatorGlyph = Color(uiColor: UIColor { $0.userInterfaceStyle == .dark ? UIColor(red: 0.898, green: 0.941, blue: 1, alpha: 1) : UIColor(red: 0.004, green: 0.184, blue: 0.502, alpha: 1) }) } /// Whether the UI runs in Chinese right now (the in-app override wins). diff --git a/android/src/ios/NanoMuse/NanoMuseShell.swift b/android/src/ios/NanoMuse/NanoMuseShell.swift index 7a6a7100e..3e3219f1c 100644 --- a/android/src/ios/NanoMuse/NanoMuseShell.swift +++ b/android/src/ios/NanoMuse/NanoMuseShell.swift @@ -379,24 +379,35 @@ struct NanoMuseHomeView: View { } var body: some View { - // The bottom bar is a row under the rooms, as on Android — not a `safeAreaInset`. - // 0.1.36–0.1.39 had it as one, and an inset on the NavigationStack's ancestor reaches - // the chat inside it through UIKit's safe area. What the device showed (iPad, 0.1.39; - // the maintainer's iPhone, 0.1.36–0.1.38): the chat respected the bar's 56 pt at - // launch, and once the bar had left for the keyboard and come back it no longer did — - // the chat ran under the bar and its composer, bottom-aligned, sat behind it ("the - // input field shows until I dismiss the keyboard, then never again"; the sliver of a - // composer's top edge above the bar in the 0.1.36 screenshot). A VStack row is plain - // layout: the stack above is as tall as what is left over the bar — and over the - // keyboard, which shortens the whole VStack — whether the bar is there or not. - VStack(spacing: 0) { + // The chat never gets the bottom bar as a `safeAreaInset`. 0.1.36 to 0.1.39 had it as + // one, and an inset on the NavigationStack's ancestor reaches the chat inside it through + // UIKit's safe area. What the device showed (iPad, 0.1.39; the maintainer's iPhone, + // 0.1.36 to 0.1.38): the chat respected the bar's 56 pt at launch, and once the bar had + // left for the keyboard and come back it no longer did: the chat ran under the bar and + // its composer, bottom-aligned, sat behind it ("the input field shows until I dismiss + // the keyboard, then never again"; the sliver of a composer's top edge above the bar in + // the 0.1.36 screenshot). 0.1.40 made the bar a VStack row under the rooms, plain layout: + // the chat is as tall as what is left over the bar, and over the keyboard, whether the + // bar is there or not. The floating pill keeps that for the chat as bottom padding of + // the bar's height, the same layout by another name. The rooms are plain SwiftUI + // scroll views with no NavigationStack, so they take the bar's height as a safe-area + // inset instead: their content scrolls under the pill and the glass has something to + // blur. The pill itself lies over both, aligned to the bottom, inside the safe area. + ZStack(alignment: .bottom) { ZStack { chatLayer + .padding(.bottom, bottomBarHidden ? 0 : NanoMuseBottomBar.height) + .background(ChatColors.background.ignoresSafeArea()) .opacity(tab == .chat ? 1 : 0) .allowsHitTesting(tab == .chat) .accessibilityHidden(tab != .chat) if tab != .chat { roomLayer + .safeAreaInset(edge: .bottom, spacing: 0) { + Color.clear + .frame(height: bottomBarHidden ? 0 : NanoMuseBottomBar.height) + .allowsHitTesting(false) + } .transition(.opacity) } } @@ -796,31 +807,60 @@ private struct NanoMuseClassicCover: View { // MARK: - Bottom bar +/// Android's MuseBottomBar: a floating frosted-glass pill a little above the bottom edge, five +/// glyphs and no labels. The pill is `.ultraThinMaterial` under the shell's surface tone at 55 +/// percent, with a 1 pt hairline; the current tab shows its filled glyph on a soft indicator +/// capsule that springs across to the tab tapped next, the others stay outlined and muted. struct NanoMuseBottomBar: View { @Binding var selected: NanoMuseTab var onPick: (NanoMuseTab) -> Void + @Namespace private var indicator + + /// A tab's tap box. + static let tabSize = CGSize(width: 60, height: 46) + /// The pill's padding around the tap boxes. + static let pillPadding: CGFloat = 8 + /// Between the pill and the bottom safe area. + static let bottomGap: CGFloat = 12 + /// How much of the screen the bar takes above the safe area: what the rooms and the chat + /// leave free under their content so nothing lies behind the pill. + static var height: CGFloat { tabSize.height + pillPadding * 2 + bottomGap } var body: some View { - HStack(spacing: 0) { + HStack(spacing: 2) { ForEach(NanoMuseTab.allCases) { tab in + let isSelected = selected == tab Button { onPick(tab) } label: { - Image(systemName: selected == tab ? tab.selectedSymbol : tab.symbol) - .font(.system(size: 22, weight: selected == tab ? .semibold : .regular)) - .foregroundStyle(selected == tab ? Color.primary : Color.secondary) - .frame(maxWidth: .infinity, minHeight: 56) - .contentShape(Rectangle()) + Image(systemName: isSelected ? tab.selectedSymbol : tab.symbol) + .font(.system(size: 22, weight: isSelected ? .semibold : .regular)) + .foregroundStyle(isSelected ? NanoMuseTones.tabIndicatorGlyph : Color.secondary) + .frame(width: Self.tabSize.width, height: Self.tabSize.height) + .background { + if isSelected { + Capsule() + .fill(NanoMuseTones.tabIndicator) + .matchedGeometryEffect(id: "indicator", in: indicator) + } + } + .contentShape(Capsule()) } .buttonStyle(.plain) .accessibilityLabel(Text(tab.title)) - .accessibilityAddTraits(selected == tab ? .isSelected : []) + .accessibilityAddTraits(isSelected ? .isSelected : []) } } - .background(.bar) - .overlay(alignment: .top) { - NanoMuseTones.hairline.frame(height: 0.5) + .padding(.horizontal, 14) + .padding(.vertical, Self.pillPadding) + .background { + Capsule().fill(.ultraThinMaterial) + Capsule().fill(NanoMuseTones.surface.opacity(0.55)) } + .overlay(Capsule().strokeBorder(NanoMuseTones.hairline, lineWidth: 1)) + .animation(.spring(response: 0.35, dampingFraction: 0.8), value: selected) + .frame(maxWidth: .infinity) + .padding(.bottom, Self.bottomGap) } } diff --git a/docs/ios.md b/docs/ios.md index d6310e001..a055c1c95 100644 --- a/docs/ios.md +++ b/docs/ios.md @@ -316,8 +316,10 @@ Ours, in `NanoMuse/`: bottom bar was a `safeAreaInset` on the `NavigationStack`'s ancestor, hidden while the keyboard is up; the chat respected that inset at launch and no longer after the bar had left and come back, so the whole chat ran under the bar and the composer, bottom-aligned, laid out, healthy by every - measure the watchdog had, sat behind it. Since 0.1.40 the **bar is a row under the rooms** (a - `VStack`, as on Android), and the composer column (the cards, the tool strip, the input bar) is + measure the watchdog had, sat behind it. Since 0.1.40 the **bar is laid out under the chat by + plain layout, never as an inset of the chat's ancestor** (a `VStack` row in 0.1.40; since the + floating pill bar, below, bottom padding of the bar's height on the chat layer, which is the same + layout), and the composer column (the cards, the tool strip, the input bar) is likewise **a row under the message list**: `NanoMuseComposerHost` is a plain `VStack`, the list is passed a bottom inset of 0, the `/` and `@` popup is an overlay of the list's bottom edge and so stands on the column's top edge by layout. Nothing lies over the UIKit list and there is no @@ -515,8 +517,26 @@ Ours, in `NanoMuse/`: Status section's footer on the provider page. Before, the switch went off, the Chat row kept naming the account, and the main chat stopped with upstream's *No model configured* error; the *Not set* state is no longer reachable through this switch. A provider of your own switched off - on its page keeps upstream's path: the chat re-resolves through the default group and, when + on its page keeps upstream's path: the chat re-resolves through the default group and, when nothing is left, says *No model configured. Add a provider in Settings.* +- **The bottom bar is a floating pill** (`NanoMuseShell.swift` → `NanoMuseBottomBar`, + `NanoMuseTones.tabIndicator` / `tabIndicatorGlyph` in `NanoMuseFaces.swift`; Android's + `MuseBottomBar`, #329 by @Ichiro786): the five tabs sit in a centred `Capsule` 12 pt above the + bottom safe area, icons only, with the same SF symbols, accessibility labels and selected trait as + before. The pill is `.ultraThinMaterial` under the shell's surface tone at 55 percent opacity (the + tint carries the contrast, the material carries the blur, as Android's 55 percent surface over its + backdrop blur) with a 1 pt `NanoMuseTones.hairline` edge; the old full-width strip and its hairline + on top are gone. Each tab is a 60 by 46 pt tap box; the current one shows the filled symbol in + `tabIndicatorGlyph` on a capsule of `tabIndicator` (Android's primaryContainer and + onPrimaryContainer: `#E5F0FF` with `#012F80` in light, `#1A2B4A` with `#E5F0FF` in dark) that + slides to the tab tapped next with a spring (`matchedGeometryEffect`); the others show the + outlined symbol in the secondary colour. The bar still leaves while the keyboard or the chat's + voice panel is up. Layout: the pill lies over the rooms and the chat in a `ZStack` aligned to the + bottom. The chat keeps the 0.1.40 rule above (bottom padding of the bar's height, 74 pt, so the + composer sits above the pill and nothing is an inset of the `NavigationStack`'s ancestor); the + rooms, plain SwiftUI scroll views, take the same height as a `safeAreaInset`, so their content + scrolls under the pill and the glass has something to blur. Written on Linux without a Mac: the + iOS check compiles it, and no device has shown it yet. ## Voice prompts from the Action Button diff --git a/docs/zh/ios.md b/docs/zh/ios.md index 1310d2661..ebe71a54c 100644 --- a/docs/zh/ios.md +++ b/docs/zh/ios.md @@ -272,8 +272,9 @@ scripts/gen-ios-icons.py the app icon and the four alternates, from asse 上边缘从底栏上方露出来一点。外壳的底栏是 `NavigationStack` 祖先上的一个 `safeAreaInset`, 键盘弹起时隐藏;聊天在启动时尊重这个 inset,底栏离开又回来之后就不再尊重,于是整个聊天 都跑到底栏下面去了,而输入区(贴底对齐、布局完成、按看门狗的每一项指标都正常)正好 - 躲在底栏后面。从 0.1.40 起,**底栏是房间下面的一行**(一个 `VStack`,和 Android 一样), - 输入区这一列(卡片、工具条、输入栏)同样是**消息列表下面的一行**:`NanoMuseComposerHost` + 躲在底栏后面。从 0.1.40 起,**底栏靠普通布局排在聊天下面,绝不做聊天祖先上的 inset** + (0.1.40 是一个 `VStack` 的一行;下文的悬浮胶囊栏之后,是聊天层上一段底栏高度的底部 + padding,布局上是同一回事),输入区这一列(卡片、工具条、输入栏)同样是**消息列表下面的一行**:`NanoMuseComposerHost` 是一个普通的 `VStack`,列表拿到的底部 inset 是 0,`/` 和 `@` 的弹出菜单是列表底边的 overlay,所以从布局上就站在这一列的上边缘。没有任何东西盖在 UIKit 列表上,也没有第二个 宿主可切换。看门狗作为最后一道网留着(聊天在屏幕上时,这一列脱离或者量出 0,就通过 @@ -430,6 +431,21 @@ scripts/gen-ios-icons.py the app icon and the four alternates, from asse 页在「状态」一节的脚注。之前开关会关掉,对话那一行仍写着账号,主要聊天停在上游的*未配置模型* 错误上;现在经这个开关到不了*未设置*的状态。自有服务商在自己页面上关掉仍走上游的路:对话经 默认分组重新解析,什么都不剩时说*未配置模型。请在设置中添加服务商。* +- **底栏是一个悬浮的胶囊**(`NanoMuseShell.swift` → `NanoMuseBottomBar`,`NanoMuseFaces.swift` + 里的 `NanoMuseTones.tabIndicator` / `tabIndicatorGlyph`;对应 Android 的 `MuseBottomBar`, + @Ichiro786 的 #329):五个标签放在一个居中的 `Capsule` 里,离底部安全区 12 pt,只有图标, + SF 符号、无障碍标签和选中特征都和以前一样。胶囊是 `.ultraThinMaterial`,上面盖一层 55% + 不透明度的外壳 surface 色(对比度靠这层色,模糊靠材质,和 Android 在背景模糊上盖 55% surface + 一样),边上一道 1 pt 的 `NanoMuseTones.hairline`;原来那条通栏的条和它顶上的细线没有了。 + 每个标签是 60 × 46 pt 的点击区;当前这个用 `tabIndicatorGlyph` 色显示实心符号,底下一个 + `tabIndicator` 色的胶囊(Android 的 primaryContainer 和 onPrimaryContainer:浅色 `#E5F0FF` + 配 `#012F80`,深色 `#1A2B4A` 配 `#E5F0FF`),点下一个标签时它带着弹簧滑过去 + (`matchedGeometryEffect`);其他标签用次要颜色显示线框符号。键盘弹起或聊天的语音面板打开时, + 底栏仍然离开。布局:胶囊在一个贴底对齐的 `ZStack` 里盖在房间和聊天上面。聊天沿用上面 + 0.1.40 的规矩(聊天层加一段底栏高度、74 pt 的底部 padding,所以输入区在胶囊上面, + `NavigationStack` 的祖先上没有任何 inset);房间是普通的 SwiftUI 滚动视图,同样的高度用 + `safeAreaInset` 给出,于是它们的内容会滚到胶囊下面,玻璃才有东西可模糊。在没有 Mac 的 Linux + 上写的:iOS 检查能编译它,还没有设备显示过它。 ## 用操作按钮说一句 {#voice-prompts-from-the-action-button} From 2c91e374d4f09ae6ca2b3dd0ae5d29cc0a0a1d6f Mon Sep 17 00:00:00 2001 From: lgy0404 <2528379691@qq.com> Date: Sun, 11 Oct 2026 15:50:24 +0800 Subject: [PATCH 14/98] feat(web): the phone layout's tab bar is a floating frosted-glass pill The five tabs sit in a rounded pill 12 px above the bottom edge, over the safe area, icons only and no labels, the same bar the Android app draws since #329: the pill is surface-2 at 55 percent over a backdrop blur with a hairline ring of the border colour at 50 percent; the current tab shows its filled glyph on a soft blue indicator (a new accent-soft pair, light #e5f0ff with #012f80 ink, dark #1a2b4a with #e5f0ff ink), the others stay outlined in muted. The background colour eases over 300 ms. The bar floats over the screen column instead of taking a row of it; the nav lets taps through and only the pill takes them. The screens keep clear of the pill through one place, a tabbar-room utility on
that pads the bottom by the pill's footprint (74 px plus the safe area), given back with wide:pb-0 when the sidebar shows; the chat's composer sits above it, and the toast rises by the safe area so it clears the pill on a phone with a home indicator. Lite keeps the bar at any width, as before. Docs: app.md, design.md and their Chinese twins describe the pill; CHANGELOG under Unreleased, Web. The built app under nanomuse/server/static is regenerated. Follows #329 by @Ichiro786. Signed-off-by: lgy0404 <2528379691@qq.com> --- CHANGELOG.md | 2 ++ docs/app.md | 4 +-- docs/design.md | 2 +- docs/zh/app.md | 4 +-- docs/zh/design.md | 2 +- ...-DvBFnisI.js => AccountScreen-bHMDrVr5.js} | 2 +- ...r-oSjVM8L3.js => AvatarPicker-gR2knlot.js} | 2 +- ...sV3j.js => AvatarStudioScreen-DD2X0R8P.js} | 2 +- ...ackBar-Dli0L0O_.js => BackBar-Dl56jHZM.js} | 2 +- ...Bt6eBqvc.js => ChannelsScreen-mBzj7BLf.js} | 2 +- ...Card-CdydxD3H.js => CloudCard-CtVHK0qc.js} | 2 +- ...n-CTT5Jjn2.js => CodingScreen-C_tutsx0.js} | 2 +- ...bXAf7.js => ConnectionsScreen-CMt7GOff.js} | 2 +- ...-P67eLmyB.js => DevicesScreen-g6FUY327.js} | 2 +- ...en-BGb02qG6.js => GoalsScreen-Dp2fRaLA.js} | 2 +- ...en-BVCFCRSV.js => IdeasScreen-CGfvq5H-.js} | 2 +- ...m-Dhx4FiQY.js => IdentityForm-BTGczGT_.js} | 2 +- ...-U8NV3qaf.js => LibraryScreen-B8JlrC_n.js} | 2 +- ...n-B5a6LPAu.js => MemoryScreen-M8j03G3u.js} | 2 +- ...ing-rP8qAahh.js => Onboarding-CtVO6gdK.js} | 2 +- ...DoXURXet.js => SettingsScreen-CHVg61To.js} | 2 +- ...n-DZP-6db6.js => SkillsScreen-Dr-d7iS7.js} | 2 +- .../{index-BjYzdKkG.js => index-CIdGZ5PB.js} | 4 +-- .../server/static/assets/index-CwUBXfPC.css | 2 ++ .../server/static/assets/index-D-ZnIXbP.css | 2 -- nanomuse/server/static/index.html | 4 +-- web/src/App.tsx | 28 +++++++++++-------- web/src/index.css | 19 ++++++++++++- 28 files changed, 66 insertions(+), 41 deletions(-) rename nanomuse/server/static/assets/{AccountScreen-DvBFnisI.js => AccountScreen-bHMDrVr5.js} (99%) rename nanomuse/server/static/assets/{AvatarPicker-oSjVM8L3.js => AvatarPicker-gR2knlot.js} (97%) rename nanomuse/server/static/assets/{AvatarStudioScreen-C1Q0sV3j.js => AvatarStudioScreen-DD2X0R8P.js} (99%) rename nanomuse/server/static/assets/{BackBar-Dli0L0O_.js => BackBar-Dl56jHZM.js} (92%) rename nanomuse/server/static/assets/{ChannelsScreen-Bt6eBqvc.js => ChannelsScreen-mBzj7BLf.js} (99%) rename nanomuse/server/static/assets/{CloudCard-CdydxD3H.js => CloudCard-CtVHK0qc.js} (97%) rename nanomuse/server/static/assets/{CodingScreen-CTT5Jjn2.js => CodingScreen-C_tutsx0.js} (99%) rename nanomuse/server/static/assets/{ConnectionsScreen-0U0bXAf7.js => ConnectionsScreen-CMt7GOff.js} (99%) rename nanomuse/server/static/assets/{DevicesScreen-P67eLmyB.js => DevicesScreen-g6FUY327.js} (99%) rename nanomuse/server/static/assets/{GoalsScreen-BGb02qG6.js => GoalsScreen-Dp2fRaLA.js} (99%) rename nanomuse/server/static/assets/{IdeasScreen-BVCFCRSV.js => IdeasScreen-CGfvq5H-.js} (99%) rename nanomuse/server/static/assets/{IdentityForm-Dhx4FiQY.js => IdentityForm-BTGczGT_.js} (97%) rename nanomuse/server/static/assets/{LibraryScreen-U8NV3qaf.js => LibraryScreen-B8JlrC_n.js} (98%) rename nanomuse/server/static/assets/{MemoryScreen-B5a6LPAu.js => MemoryScreen-M8j03G3u.js} (98%) rename nanomuse/server/static/assets/{Onboarding-rP8qAahh.js => Onboarding-CtVO6gdK.js} (97%) rename nanomuse/server/static/assets/{SettingsScreen-DoXURXet.js => SettingsScreen-CHVg61To.js} (99%) rename nanomuse/server/static/assets/{SkillsScreen-DZP-6db6.js => SkillsScreen-Dr-d7iS7.js} (99%) rename nanomuse/server/static/assets/{index-BjYzdKkG.js => index-CIdGZ5PB.js} (98%) create mode 100644 nanomuse/server/static/assets/index-CwUBXfPC.css delete mode 100644 nanomuse/server/static/assets/index-D-ZnIXbP.css diff --git a/CHANGELOG.md b/CHANGELOG.md index 74f92bf1c..451606f58 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,8 @@ All notable changes to nanoMuse. The format follows [Keep a Changelog](https://k ### Web +- **The phone layout's tab bar is a floating frosted-glass pill.** The five tabs sit in a rounded pill 12 px above the bottom edge, icons only and no labels; the pill is translucent over a blur of what is behind it and has a hairline edge. The current tab shows its filled glyph on a soft blue indicator, the others stay outlined in grey. The screens and the chat's composer keep clear of the pill, and the toast rises above it; a wide window and the desktop app keep the sidebar (follows #329 by @Ichiro786). + ### Desktop - **OpenCode Go works from the desktop.** Saving a Go key writes the model adapter's own `opencode-go` route (no `api`, no base URL), which sends `x-opencode-session` with the harness's conversation id and reaches each model on its own shape, so the models that route's catalog lists on the Responses and Messages shapes come through as well. A hand-declared route, the way the other own keys are written, sends no session id (thanks @PovedaAqui). diff --git a/docs/app.md b/docs/app.md index 7d39af7a6..180026187 100644 --- a/docs/app.md +++ b/docs/app.md @@ -24,7 +24,7 @@ nanomuse serve --port 9000 --no-qr Library: pages with live previews

-The look follows Meta Muse: near-white and near-black surfaces, one blue accent, grey bubbles for the agent and light blue for you, a small dragon at the top of the chat that changes pose with what the agent is doing, and a floating bar with five icons. The font is [Figtree](https://github.com/erikdkennedy/figtree) (OFL), bundled. The study behind these choices is in [design.md](design.md). +The look follows Meta Muse: near-white and near-black surfaces, one blue accent, grey bubbles for the agent and light blue for you, a small dragon at the top of the chat that changes pose with what the agent is doing, and a floating frosted-glass pill with five icons. The font is [Figtree](https://github.com/erikdkennedy/figtree) (OFL), bundled. The study behind these choices is in [design.md](design.md). ## Getting it onto your phone @@ -50,7 +50,7 @@ On a fresh data directory the app opens with setup instead of the chat. First th ## What is on the screen -Five tabs (Chat, Feed, Ideas, Goals, Library) and a menu behind the avatar. +Five tabs (Chat, Feed, Ideas, Goals, Library) and a menu behind the avatar. At phone width the five sit in a rounded pill that floats 12 px above the bottom edge, icons only and no labels, the same bar the Android app draws: the pill is translucent over a blur of what is behind it and has a hairline edge; the current tab shows its filled glyph on a soft blue indicator, the others stay outlined in grey. The screens and the chat's composer keep clear of it. On a wide window, and in the desktop app at any width, a sidebar takes the bar's place. **Chat.** One main conversation plus side chats (the *Chats* button top right). Messages stream in as they are generated. Tool calls appear as chips: tap one for the arguments and output. Files the agent writes show up as artifact cards that open in the app. When Sentinel needs a decision an approval card appears; when the agent needs information a question card appears. The composer stays open while the agent works; anything you send is folded into the running turn before the next model call. diff --git a/docs/design.md b/docs/design.md index a784163fa..fae0d6985 100644 --- a/docs/design.md +++ b/docs/design.md @@ -27,7 +27,7 @@ A study of Muse's screens (the announcement, the walkthrough and sizzle videos, | Grey / light-blue bubbles, chips for tool use, cards for approvals | The same; chips open to the tool call, cards carry the summary the Sentinel wrote and the scope buttons (once, this conversation, always; on the phone once, this chat, always) | `web/src/screens/ChatScreen.tsx`, `web/src/components/` | | The plush doll that changes pose | The **red panda**, an SVG drawn live with a pose per state; six plush dolls (Sunny, Moss, Sky, Fox, Bolt, Plum) and an emoji as alternatives | `web/src/components/RedPanda.tsx`, `web/public/avatars/` | | Name and status under the avatar; tap for the sheet | The same header; the sheet has the avatar large, the status, *Stop*, four buttons (approvals, activity, permissions, upcoming) and rows for memory, skills, connections, settings | `web/src/components/MuseSheet.tsx` | -| Five-icon floating bar | The same five: Chat, Feed, Ideas, Goals, Library | `web/src/App.tsx` | +| Five-icon floating bar | The same five: Chat, Feed, Ideas, Goals, Library, in a frosted-glass pill 12 px above the bottom edge, translucent over a blur with a hairline edge; the current tab's filled glyph sits on a soft blue indicator (`accent-soft`), the others are outlined in `muted`. The sidebar replaces it on a wide window | `web/src/App.tsx` | | Little motion | Breathing / sway / hop for the dolls and the emoji; the panda's own poses; everything off under `prefers-reduced-motion` | `web/src/index.css`, `RedPanda.css` | ## The red panda diff --git a/docs/zh/app.md b/docs/zh/app.md index 62441b180..f4d1ae37a 100644 --- a/docs/zh/app.md +++ b/docs/zh/app.md @@ -22,7 +22,7 @@ nanomuse serve --port 9000 --no-qr 资源库:带实时预览的页面

-外观跟着 Meta 的 Muse 走:接近纯白和接近纯黑的底色,一种蓝色作强调,智能体的气泡是灰色、你的是浅蓝色,聊天顶部有一只小龙,姿势跟着智能体正在做的事变,底下是一条带五个图标的悬浮栏。字体是 [Figtree](https://github.com/erikdkennedy/figtree)(OFL),已内置。这些选择背后的研究在 [design.md](design.md)。 +外观跟着 Meta 的 Muse 走:接近纯白和接近纯黑的底色,一种蓝色作强调,智能体的气泡是灰色、你的是浅蓝色,聊天顶部有一只小龙,姿势跟着智能体正在做的事变,底下是一枚带五个图标的毛玻璃悬浮药丸栏。字体是 [Figtree](https://github.com/erikdkennedy/figtree)(OFL),已内置。这些选择背后的研究在 [design.md](design.md)。 ## 装到手机上 {#getting-it-onto-your-phone} @@ -48,7 +48,7 @@ nanomuse serve --port 9000 --no-qr ## 屏幕上有什么 {#what-is-on-the-screen} -五个标签页(聊天、动态、点子、目标、资源库)加上形象后面的一个菜单。 +五个标签页(聊天、动态、点子、目标、资源库)加上形象后面的一个菜单。手机宽度下,这五个放在一枚圆角药丸里,悬浮在底边上方 12 px 处,只有图标、没有文字,和 Android 应用画的是同一条栏:药丸半透明,把身后的内容模糊掉,边上有一圈细线;当前标签页显示填充的图形,底下垫一块淡蓝色的指示块,其余的保持灰色描边。各个页面和聊天的输入框都会让开它。宽窗口下,以及桌面应用在任何宽度下,由侧栏代替这条栏。 **聊天。** 一个主要聊天,加上旁聊(右上角的「对话」按钮)。消息一边生成一边流进来。工具调用显示成小标签:点一下看参数和输出。智能体写的文件显示成构件卡片,在应用里就能打开。哨兵(Sentinel)需要你拿主意时出现一张审批卡片;智能体需要信息时出现一张提问卡片。智能体干活时输入框一直开着;你这时发的任何东西都会在下一次调用模型之前并进正在进行的这一轮。 diff --git a/docs/zh/design.md b/docs/zh/design.md index df806763f..022197a7c 100644 --- a/docs/zh/design.md +++ b/docs/zh/design.md @@ -27,7 +27,7 @@ | 灰色 / 浅蓝色气泡,工具用小标签,审批用卡片 | 一样;小标签点开是工具调用,卡片上是哨兵(Sentinel)写的摘要和范围按钮(一次、本次对话、总是;手机上是一次、本聊天、总是) | `web/src/screens/ChatScreen.tsx`、`web/src/components/` | | 会换姿势的毛绒玩偶 | **小熊猫**,一个实时绘制的 SVG,每种状态一个姿势;六只毛绒玩偶(Sunny、Moss、Sky、Fox、Bolt、Plum)和一个 emoji 作为备选 | `web/src/components/RedPanda.tsx`、`web/public/avatars/` | | 形象下面是名字和状态;点开面板 | 同样的头部;面板里是大图的形象、状态、*停止*、四个按钮(审批、活动、权限、日程)以及记忆、技能、连接、设置几行 | `web/src/components/MuseSheet.tsx` | -| 五图标悬浮栏 | 同样的五个:聊天、动态、点子、目标、资源库 | `web/src/App.tsx` | +| 五图标悬浮栏 | 同样的五个:聊天、动态、点子、目标、资源库,放在底边上方 12 px 的一枚毛玻璃药丸里,半透明、带模糊和一圈细线边;当前标签页的填充图形垫在一块淡蓝色指示块上(`accent-soft`),其余的用 `muted` 描边。宽窗口下由侧栏代替 | `web/src/App.tsx` | | 很少的动效 | 玩偶和 emoji 的呼吸 / 摇摆 / 蹦跳;小熊猫自己的姿势;`prefers-reduced-motion` 下全部关闭 | `web/src/index.css`、`RedPanda.css` | ## 小熊猫 {#the-red-panda} diff --git a/nanomuse/server/static/assets/AccountScreen-DvBFnisI.js b/nanomuse/server/static/assets/AccountScreen-bHMDrVr5.js similarity index 99% rename from nanomuse/server/static/assets/AccountScreen-DvBFnisI.js rename to nanomuse/server/static/assets/AccountScreen-bHMDrVr5.js index f09e63f6c..18b7955ab 100644 --- a/nanomuse/server/static/assets/AccountScreen-DvBFnisI.js +++ b/nanomuse/server/static/assets/AccountScreen-bHMDrVr5.js @@ -1 +1 @@ -import{E as e,J as t,K as n,Q as r,R as i,Y as a,b as o,f as s,k as c,q as l,x as u}from"./MuseHeader-Pw-NI98v.js";import{A as d,s as f,t as p}from"./StarNudge-DjXecvWj.js";import{n as m}from"./external-link-Xj5fjR8v.js";import{a as h,i as g}from"./Form-DwKuBk1V.js";import{t as _}from"./clapperboard-BokpXv9J.js";import{t as v}from"./database-zap-CzaFBl6C.js";import{t as y}from"./image-crWy0a06.js";import{$ as b,A as x,G as S,J as C,K as w,V as T,ct as E,gt as D,ot as O,t as k,ut as A}from"./index-BjYzdKkG.js";import{t as j}from"./BackBar-Dli0L0O_.js";var M=t(`gift`,[[`path`,{d:`M12 7v14`,key:`1akyts`}],[`path`,{d:`M20 11v8a2 2 0 0 1-2 2H6a2 2 0 0 1-2-2v-8`,key:`1sqzm4`}],[`path`,{d:`M7.5 7a1 1 0 0 1 0-5A4.8 8 0 0 1 12 7a4.8 8 0 0 1 4.5-5 1 1 0 0 1 0 5`,key:`kc0143`}],[`rect`,{x:`3`,y:`7`,width:`18`,height:`4`,rx:`1`,key:`1hberx`}]]),N=r(a(),1),P=o();function F(){let{state:e,toast:t,setTab:r}=s(),i=n(),a=e.hub?.account??null,[o,c]=(0,N.useState)(null),[l,d]=(0,N.useState)(null),[m,h]=(0,N.useState)(null),[g,_]=(0,N.useState)(!1),v=!!a?.signed_in,y=f(),b=async()=>{if(v){_(!0);try{let[e,t,n]=await Promise.all([u.cloudMe(),u.cloudSessions(),u.cloudEvents(40)]);c(e),d(t.sessions),h(n.events)}catch(e){t(e.message)}finally{_(!1)}}};return(0,N.useEffect)(()=>{b()},[v,a?.has_password]),(0,P.jsxs)(`div`,{className:`flex h-full flex-col`,children:[(0,P.jsx)(j,{title:i(`Account`),description:i(v?`nanoMuse Cloud · one account for all your devices`:`Sign in to nanoMuse Cloud`)}),(0,P.jsx)(`div`,{className:`flex-1 overflow-y-auto px-4 pb-8 space-y-4`,children:v?(0,P.jsxs)(P.Fragment,{children:[(0,P.jsx)(L,{account:a,me:o}),o&&(0,P.jsx)(p,{moment:`signed_in`}),o&&(0,P.jsx)(R,{me:o,onChanged:()=>void b()}),o?.invite?.code&&(0,P.jsx)(B,{invite:o.invite}),o&&(0,P.jsx)(H,{me:o}),o&&(0,P.jsx)(z,{me:o}),(0,P.jsx)(W,{account:a,onChanged:()=>void b()}),(0,P.jsx)(G,{sessions:l,loading:g,onChanged:()=>void b()}),m&&m.length>0&&(0,P.jsx)(q,{events:m}),(0,P.jsx)(J,{account:a,onDone:()=>r(`chat`)})]}):(0,P.jsxs)(I,{children:[(0,P.jsx)(`p`,{className:`text-[13.5px] text-muted leading-relaxed`,children:i(`Free. One account for all your devices, with a model and ¥{allowance} of use to start; a code the first time, a password afterwards if you like.`,{allowance:(y.allowance_cny??10).toFixed(0)})}),(0,P.jsx)(k,{onSignedIn:()=>t(i(`Signed in to nanoMuse Cloud.`))})]})})]})}function I({title:t,children:n,tone:r}){return(0,P.jsxs)(`section`,{className:e(`rounded-3xl border p-4 space-y-3 shadow-sm`,r===`danger`?`border-rose-500/25 bg-rose-500/[0.04]`:`border-border/70 bg-surface`),children:[t&&(0,P.jsx)(`h2`,{className:`text-[12px] font-semibold uppercase tracking-wide text-muted`,children:t}),n]})}function L({account:e,me:t}){let r=n(),a=e?.hint??``,o=t?.account.created_at?new Date(t.account.created_at*1e3):null;return(0,P.jsxs)(`section`,{className:`relative overflow-hidden rounded-3xl border border-border/70 bg-surface p-5 shadow-sm`,children:[(0,P.jsx)(`div`,{className:`pointer-events-none absolute -right-16 -top-20 h-48 w-48 rounded-full bg-accent/15 blur-3xl`}),(0,P.jsxs)(`div`,{className:`flex items-center gap-4`,children:[(0,P.jsx)(`div`,{className:`flex h-14 w-14 shrink-0 items-center justify-center rounded-2xl bg-gradient-to-br from-accent to-sky-400 text-[22px] font-bold text-white shadow-md`,children:(a.replace(/[^a-z0-9]/gi,``).slice(0,1)||`n`).toUpperCase()}),(0,P.jsxs)(`div`,{className:`min-w-0 flex-1`,children:[(0,P.jsx)(`div`,{className:`truncate text-[18px] font-semibold tracking-tight`,children:a}),(0,P.jsxs)(`div`,{className:`mt-0.5 flex flex-wrap items-center gap-x-2 gap-y-0.5 text-[12.5px] text-muted`,children:[(0,P.jsx)(`span`,{children:e?.channel===`phone`||e?.channel===`sms`?r(`Mobile number`):r(`E-mail`)}),o&&(0,P.jsxs)(`span`,{children:[`· `,r(`since {date}`,{date:o.toLocaleDateString(i())})]}),t?.account.member&&(0,P.jsxs)(`span`,{className:`inline-flex items-center gap-1 rounded-full bg-emerald-500/12 px-2 py-0.5 text-[11px] font-medium text-emerald-700 dark:text-emerald-300`,children:[(0,P.jsx)(w,{size:11}),` `,r(`Unlimited`)]})]})]})]}),e?.account_id&&(0,P.jsxs)(`div`,{className:`mt-4 flex items-center justify-between gap-3 rounded-2xl bg-surface-2/70 px-3 py-2 text-[12px]`,children:[(0,P.jsx)(`span`,{className:`text-muted`,children:r(`Account id`)}),(0,P.jsx)(`code`,{className:`truncate font-mono text-[11.5px] text-fg/80`,children:e.account_id})]})]})}function R({me:t,onChanged:r}){let i=n(),a=t.spend,o=a.grant??a.daily_cap??0,s=a.grant===void 0?a.today:a.total,c=a.left??(a.unlimited?null:Math.max(0,o-s)),l=!a.unlimited&&o>0,u=l?Math.min(100,Math.round(s/o*100)):0,f=a.usd_cny??0,p=e=>f>0?` ≈ $${(e/f).toFixed(2)}`:``,m=l&&(c??0)<=0,h=l&&!m&&(a.warn??u>=80),g={left:c,grant:o,invite_url:t.invite?.url,invite_bonus_cny:a.invite_bonus_cny??t.invite?.bonus_cny,invitee_bonus_cny:a.invitee_bonus_cny??t.invite?.invitee_bonus_cny,own_key_docs:a.own_key_docs,guidance:a.guidance};return(0,P.jsxs)(I,{title:i(`Free allowance`),children:[(0,P.jsxs)(`div`,{className:`flex items-end justify-between gap-3`,children:[(0,P.jsxs)(`div`,{children:[(0,P.jsx)(`div`,{className:`text-[28px] font-bold tracking-tight leading-none`,children:l?(0,P.jsxs)(P.Fragment,{children:[`¥`,(c??0).toFixed(2),(0,P.jsxs)(`span`,{className:`text-[14px] font-medium text-muted`,children:[` `,i(`left of ¥{grant}`,{grant:o.toFixed(0)})]})]}):(0,P.jsxs)(P.Fragment,{children:[`¥`,s.toFixed(2)]})}),(0,P.jsx)(`div`,{className:`mt-1 text-[12.5px] text-muted`,children:l?i(`¥{spent} used{usd}; the allowance does not reset.`,{spent:s.toFixed(2),usd:p(s)}):i(`No limit on this account.`)})]}),(0,P.jsxs)(`div`,{className:`text-right text-[12.5px] text-muted`,children:[(0,P.jsx)(`div`,{children:i(`All time`)}),(0,P.jsxs)(`div`,{className:`text-[15px] font-semibold text-fg`,children:[`¥`,a.total.toFixed(2)]}),f>0&&(0,P.jsxs)(`div`,{className:`text-[11.5px]`,children:[`≈ $`,(a.total/f).toFixed(2)]})]})]}),l&&(0,P.jsx)(`div`,{className:`h-2 overflow-hidden rounded-full bg-surface-2`,children:(0,P.jsx)(`div`,{className:e(`h-full rounded-full transition-all`,u>=100?`bg-rose-500`:u>=80?`bg-amber-500`:`bg-accent`),style:{width:`${u}%`}})}),l&&(0,P.jsxs)(`p`,{className:`text-[12.5px] text-muted`,children:[i(`¥{allowance} to start, +¥{invite} for each friend you invite, and +¥{invite} for them; after that, your own key keeps the model going.`,{allowance:(a.allowance_cny??10).toFixed(0),invite:(g.invite_bonus_cny??5).toFixed(0)}),` `,!m&&!h&&d(i,{signed_in:!0,channel:t.account.channel,region:t.account.region})]}),(m||h)&&(0,P.jsx)(x,{info:g,exhausted:m,onChanged:r})]})}function z({me:e}){let t=n(),{setTab:r}=s(),i=e.contribute??{on:!1,samples:0};return(0,P.jsx)(I,{title:t(`Data controls`),children:(0,P.jsxs)(`button`,{type:`button`,onClick:()=>{window.location.hash=`data`,r(`you`)},className:`flex w-full items-center gap-3 text-left`,children:[(0,P.jsx)(`span`,{className:`flex h-9 w-9 shrink-0 items-center justify-center rounded-xl bg-surface-2 text-fg`,children:(0,P.jsx)(v,{size:18})}),(0,P.jsxs)(`span`,{className:`min-w-0 flex-1`,children:[(0,P.jsx)(`span`,{className:`block text-[14px] font-medium`,children:t(`Help improve nanoMuse's AI models`)}),(0,P.jsxs)(`span`,{className:`block text-[12.5px] text-muted`,children:[i.on?t(`On`):t(`Off`),i.samples>0&&` · ${t(`{n} turns kept so far`,{n:String(i.samples)})}`]})]}),(0,P.jsx)(`span`,{className:`text-[13px] font-medium text-accent`,children:t(`Open`)})]})})}function B({invite:t}){let r=n(),{toast:i}=s(),a=t.url||`https://nanomuse.cn/web/?invite=${t.code}`,o=t.earned_cny??t.invites*t.bonus_cny,c=async e=>{try{await navigator.clipboard.writeText(e),i(r(`Copied`))}catch{i(e)}},l=async()=>{let e=r(`Try nanoMuse with me, a fully open-source personal agent, free to use. Sign up with my code {code}: {link}`,{code:t.code,link:a}),n=navigator;if(n.share)try{await n.share({text:e});return}catch{}await c(e)};return(0,P.jsxs)(I,{title:r(`Invite a friend`),children:[(0,P.jsx)(`p`,{className:`text-[12.5px] text-muted`,children:r(`Each new person who signs up with your code adds ¥{bonus} to your allowance, and ¥{bonus} to theirs. It never expires.`,{bonus:t.bonus_cny.toFixed(0)})}),(0,P.jsxs)(`div`,{className:`flex items-center justify-between gap-3 rounded-2xl bg-surface-2/70 px-3 py-2`,children:[(0,P.jsxs)(`div`,{children:[(0,P.jsx)(`div`,{className:`text-[11px] text-muted`,children:r(`Your code`)}),(0,P.jsx)(`code`,{className:`font-mono text-[18px] font-semibold tracking-[0.2em]`,children:t.code})]}),(0,P.jsxs)(`button`,{type:`button`,onClick:()=>void c(t.code),className:e(h,`inline-flex items-center gap-1.5`),children:[(0,P.jsx)(D,{size:14}),` `,r(`Copy`)]})]}),(0,P.jsxs)(`div`,{className:`flex gap-2`,children:[(0,P.jsxs)(`button`,{type:`button`,onClick:()=>void l(),className:e(g,`inline-flex flex-1 items-center justify-center gap-1.5 py-2.5`),children:[(0,P.jsx)(C,{size:14}),` `,r(`Share the link`)]}),(0,P.jsxs)(`button`,{type:`button`,onClick:()=>void c(a),className:e(h,`inline-flex items-center gap-1.5`),children:[(0,P.jsx)(M,{size:14}),` `,r(`Copy the link`)]})]}),(0,P.jsxs)(`p`,{className:`text-[12.5px] text-muted`,children:[r(`{n} friends joined`,{n:String(t.invites)}),o>0&&(0,P.jsxs)(P.Fragment,{children:[` · `,r(`¥{amount} added by invitations`,{amount:o.toFixed(0)})]})]})]})}var V={chat:{label:`Chat`,icon:(0,P.jsx)(O,{size:15}),tone:`bg-accent`},image:{label:`Pictures`,icon:(0,P.jsx)(y,{size:15}),tone:`bg-violet-500`},video:{label:`Clips`,icon:(0,P.jsx)(_,{size:15}),tone:`bg-pink-500`},realtime:{label:`Calls`,icon:(0,P.jsx)(b,{size:15}),tone:`bg-emerald-500`}};function H({me:t}){let r=n(),[i,a]=(0,N.useState)(`today`),o=i===`today`?t.usage.today.by_kind:t.usage.total.by_kind,s=t.usage.kinds.length?t.usage.kinds:[`chat`,`image`,`video`,`realtime`],c=new Map(o.map(e=>[e.kind,e])),l=o.reduce((e,t)=>e+t.cost_cny,0),u=t.usage.total.by_model.slice(0,8);return(0,P.jsxs)(I,{title:r(`Usage`),children:[(0,P.jsxs)(`div`,{className:`flex items-center justify-between`,children:[(0,P.jsx)(`p`,{className:`text-[12.5px] text-muted`,children:r(`Every kind of use is counted, not just the chat model.`)}),(0,P.jsx)(`div`,{className:`flex rounded-full bg-surface-2/80 p-0.5 text-[12px] font-medium`,children:[`today`,`total`].map(t=>(0,P.jsx)(`button`,{type:`button`,onClick:()=>a(t),className:e(`rounded-full px-2.5 py-1 transition`,i===t?`bg-surface shadow-sm`:`text-muted`),children:r(t===`today`?`Today`:`All time`)},t))})]}),l>0&&(0,P.jsx)(`div`,{className:`flex h-2.5 overflow-hidden rounded-full bg-surface-2`,children:s.map(t=>{let n=c.get(t);return!n||n.cost_cny<=0?null:(0,P.jsx)(`div`,{className:e(`h-full`,V[t]?.tone??`bg-fg/40`),style:{width:`${n.cost_cny/l*100}%`},title:r(V[t]?.label??t)},t)})}),(0,P.jsx)(`ul`,{className:`grid grid-cols-2 gap-2`,children:s.map(t=>{let n=c.get(t),i=V[t];return(0,P.jsxs)(`li`,{className:`rounded-2xl bg-surface-2/60 p-3`,children:[(0,P.jsxs)(`div`,{className:`flex items-center gap-1.5 text-[12.5px] text-muted`,children:[(0,P.jsx)(`span`,{className:e(`flex h-5 w-5 items-center justify-center rounded-md text-white`,i?.tone??`bg-fg/40`),children:i?.icon}),r(i?.label??t)]}),(0,P.jsxs)(`div`,{className:`mt-1.5 text-[17px] font-semibold tracking-tight`,children:[`¥`,(n?.cost_cny??0).toFixed(2)]}),(0,P.jsx)(`div`,{className:`text-[11.5px] text-muted`,children:n?t===`realtime`?r(`{n} answers · {tokens} tokens`,{n:n.requests,tokens:U(n.prompt_tokens+n.completion_tokens)}):t===`chat`?r(`{n} requests · {tokens} tokens`,{n:n.requests,tokens:U(n.prompt_tokens+n.completion_tokens)}):r(`{n} requests`,{n:n.requests}):r(`Nothing yet`)})]},t)})}),u.length>0&&(0,P.jsxs)(`div`,{children:[(0,P.jsx)(`div`,{className:`mb-1.5 text-[12px] font-medium text-muted`,children:r(`By model, all time`)}),(0,P.jsx)(`ul`,{className:`divide-y divide-border/60 rounded-2xl border border-border/60`,children:u.map(t=>(0,P.jsxs)(`li`,{className:`flex items-center gap-2 px-3 py-2 text-[12.5px]`,children:[(0,P.jsx)(`span`,{className:e(`h-2 w-2 shrink-0 rounded-full`,V[t.kind]?.tone??`bg-fg/40`)}),(0,P.jsx)(`span`,{className:`min-w-0 flex-1 truncate font-mono text-[12px]`,children:t.model}),(0,P.jsx)(`span`,{className:`text-muted`,children:U(t.prompt_tokens+t.completion_tokens)}),(0,P.jsxs)(`span`,{className:`w-16 text-right font-medium`,children:[`¥`,t.cost_cny.toFixed(2)]})]},`${t.model}-${t.kind}`))})]})]})}function U(e){return e>=1e6?`${(e/1e6).toFixed(1)}M`:e>=1e3?`${(e/1e3).toFixed(e>=1e5?0:1)}k`:String(e)}function W({account:t,onChanged:r}){let i=n(),{toast:a}=s(),o=!!t?.has_password,[c,d]=(0,N.useState)(!1),[f,p]=(0,N.useState)(``),[h,g]=(0,N.useState)(``),[_,v]=(0,N.useState)(``),[y,b]=(0,N.useState)(!1),[x,S]=(0,N.useState)(null),C=async(e=!1)=>{if(!(!e&&(h.length<8||h!==_))){b(!0),S(null);try{await u.cloudPassword(e?``:h,o?f:void 0),a(i(e?`Password removed.`:o?`Password changed.`:`Password set.`)),d(!1),p(``),g(``),v(``),r()}catch(e){S(i(e.message))}finally{b(!1)}}};return(0,P.jsxs)(I,{title:i(`Password`),children:[(0,P.jsxs)(`div`,{className:`flex items-center gap-3`,children:[(0,P.jsx)(`span`,{className:e(`flex h-9 w-9 items-center justify-center rounded-xl`,o?`bg-emerald-500/12 text-emerald-600 dark:text-emerald-300`:`bg-surface-2 text-muted`),children:(0,P.jsx)(A,{size:17})}),(0,P.jsxs)(`div`,{className:`min-w-0 flex-1 text-[13.5px]`,children:[(0,P.jsx)(`div`,{className:`font-medium`,children:i(o?`A password is set`:`No password yet`)}),(0,P.jsx)(`div`,{className:`text-[12.5px] text-muted`,children:i(o?`Sign in with it on a new device, or with a code as before.`:`Optional. With one, a new device can sign in without waiting for a code.`)})]}),!c&&(0,P.jsx)(`button`,{type:`button`,onClick:()=>d(!0),className:e(`flex items-center justify-center gap-1.5 rounded-2xl border border-border px-4 py-2.5 text-[14px] font-medium text-muted disabled:opacity-40`,`shrink-0 px-3 py-2 text-[13px]`),children:i(o?`Change`:`Set`)})]}),c&&(0,P.jsxs)(`form`,{className:`space-y-2.5`,onSubmit:e=>{e.preventDefault(),C()},children:[o&&(0,P.jsx)(`input`,{type:`password`,value:f,onChange:e=>p(e.target.value),placeholder:i(`Current password`),autoComplete:`current-password`,className:`w-full rounded-2xl bg-surface-2 px-3.5 py-2.5 text-[14.5px] outline-none focus:ring-2 focus:ring-accent/40`}),(0,P.jsx)(`input`,{type:`password`,value:h,onChange:e=>g(e.target.value),placeholder:i(`New password (8 characters or more)`),autoComplete:`new-password`,autoFocus:!0,className:`w-full rounded-2xl bg-surface-2 px-3.5 py-2.5 text-[14.5px] outline-none focus:ring-2 focus:ring-accent/40`}),(0,P.jsx)(`input`,{type:`password`,value:_,onChange:e=>v(e.target.value),placeholder:i(`Once more`),autoComplete:`new-password`,className:`w-full rounded-2xl bg-surface-2 px-3.5 py-2.5 text-[14.5px] outline-none focus:ring-2 focus:ring-accent/40`}),_&&h!==_&&(0,P.jsx)(`p`,{className:`text-[12px] text-rose-600 dark:text-rose-300`,children:i(`The two do not match.`)}),x&&(0,P.jsx)(`p`,{className:`rounded-2xl bg-rose-500/12 px-3 py-2 text-[12.5px] text-rose-700 dark:text-rose-300`,children:x}),(0,P.jsxs)(`div`,{className:`flex flex-wrap gap-2`,children:[(0,P.jsxs)(`button`,{type:`submit`,disabled:y||h.length<8||h!==_||o&&!f,className:e(`flex items-center justify-center gap-1.5 rounded-2xl bg-accent text-accent-fg px-4 py-2.5 text-[14px] font-medium disabled:opacity-40`,`flex-1`),children:[y?(0,P.jsx)(l,{size:15,className:`animate-spin`}):(0,P.jsx)(m,{size:15}),` `,i(o?`Change password`:`Set password`)]}),o&&(0,P.jsx)(`button`,{type:`button`,disabled:y||!f,onClick:()=>void C(!0),className:`flex items-center justify-center gap-1.5 rounded-2xl border border-border px-4 py-2.5 text-[14px] font-medium text-muted disabled:opacity-40`,children:i(`Remove`)}),(0,P.jsx)(`button`,{type:`button`,onClick:()=>d(!1),className:`flex items-center justify-center gap-1.5 rounded-2xl border border-border px-4 py-2.5 text-[14px] font-medium text-muted disabled:opacity-40`,children:i(`Cancel`)})]})]})]})}function G({sessions:e,loading:t,onChanged:r}){let a=n(),{toast:o}=s(),[d,f]=(0,N.useState)(null),p=async e=>{if(window.confirm(a(`Sign out {device}? It will need to sign in again.`,{device:e.device||e.prefix}))){f(e.prefix);try{await u.cloudRevokeSession(e.prefix),r()}catch(e){o(e.message)}finally{f(null)}}};return(0,P.jsx)(I,{title:a(`Signed in on`),children:e?(0,P.jsx)(`ul`,{className:`divide-y divide-border/60`,children:e.map(e=>(0,P.jsxs)(`li`,{className:`flex items-center gap-3 py-2.5`,children:[(0,P.jsx)(`span`,{className:`flex h-9 w-9 shrink-0 items-center justify-center rounded-xl bg-surface-2 text-fg/70`,children:(0,P.jsx)(S,{size:17})}),(0,P.jsxs)(`div`,{className:`min-w-0 flex-1`,children:[(0,P.jsxs)(`div`,{className:`flex items-center gap-2 text-[13.5px] font-medium`,children:[(0,P.jsx)(`span`,{className:`truncate`,children:e.device||a(`Unnamed device`)}),e.current&&(0,P.jsx)(`span`,{className:`rounded-full bg-accent/12 px-2 py-0.5 text-[10.5px] font-semibold text-accent`,children:a(`This one`)})]}),(0,P.jsxs)(`div`,{className:`truncate text-[12px] text-muted`,children:[e.via===`password`?a(`password`):a(`code`),` · `,a(`since {date}`,{date:new Date(e.created_at*1e3).toLocaleDateString(i())}),e.last_used_at?` · ${a(`used {when}`,{when:c(e.last_used_at)})}`:``]})]}),!e.current&&(0,P.jsx)(`button`,{type:`button`,disabled:d!==null,onClick:()=>void p(e),className:`rounded-full px-3 py-1.5 text-[12.5px] font-medium text-rose-600 hover:bg-rose-500/10 dark:text-rose-300`,children:d===e.prefix?(0,P.jsx)(l,{size:14,className:`animate-spin`}):a(`Sign out`)})]},e.prefix))}):(0,P.jsx)(`div`,{className:`flex justify-center py-3 text-muted`,children:t?(0,P.jsx)(l,{size:18,className:`animate-spin`}):null})})}var K={"account.created":`Account created`,"sign_in.code":`Signed in with a code`,"sign_in.password":`Signed in with the password`,"sign_in.failed":`A sign-in attempt failed`,sign_out:`Signed out`,"sign_out.all":`Signed out everywhere`,"password.set":`Password set`,"password.changed":`Password changed`,"password.cleared":`Password removed`,"budget.refused":`A request was refused: the allowance is used up`,"call.ended":`Call ended`,"upstream.error":`The model provider returned an error`,"credit.granted":`Allowance added`,"pool.set":`Allowance adjusted`,"invite.accepted":`Signed up with a friend's code`,"invite.used":`A friend signed up with your code`,"invite.unknown":`An invite code was not recognised`,"contribute.default":`Data controls: on for new accounts`,"contribute.on":`Data controls: help improve turned on`,"contribute.off":`Data controls: help improve turned off`,"contribute.deleted":`Data controls: kept conversations deleted`,"profile.put":`Agent's name and look saved`,"profile.clear":`Agent's name and look cleared`};function q({events:e}){let t=n(),[r,i]=(0,N.useState)(!1),a=r?e:e.slice(0,6);return(0,P.jsxs)(I,{title:t(`Recent activity`),children:[(0,P.jsx)(`ul`,{className:`space-y-2`,children:a.map((e,n)=>(0,P.jsxs)(`li`,{className:`flex gap-3 text-[12.5px]`,children:[(0,P.jsx)(`span`,{className:`w-[74px] shrink-0 text-muted`,children:c(e.ts)}),(0,P.jsxs)(`span`,{className:`min-w-0 flex-1`,children:[(0,P.jsx)(`span`,{className:`font-medium`,children:t(K[e.kind]??e.kind)}),e.detail&&(0,P.jsx)(`span`,{className:`ml-1.5 break-all text-muted`,children:e.detail})]})]},`${e.ts}-${n}`))}),e.length>6&&(0,P.jsx)(`button`,{type:`button`,onClick:()=>i(e=>!e),className:`text-[12.5px] font-medium text-accent`,children:r?t(`Show less`):t(`Show all {n}`,{n:e.length})})]})}function J({account:t,onDone:r}){let i=n(),{toast:a}=s(),[o,c]=(0,N.useState)(null),d=async e=>{let t=i(e===`here`?`Sign out of nanoMuse Cloud on this device? The hub and the Cloud model stop working here until you sign in again.`:e===`all`?`Sign out on every device, including this one?`:`Delete the account? The relay forgets your identifier, your devices and your usage. This cannot be undone.`);if(window.confirm(t)&&(e!==`delete`||window.confirm(i(`Really delete it?`)))){c(e);try{e===`here`?await u.cloudSignOut():e===`all`?await u.cloudSignOutAll(!0):await u.cloudDelete(),a(i(e===`delete`?`Account deleted.`:`Signed out.`)),r()}catch(e){a(e.message)}finally{c(null)}}};return(0,P.jsxs)(I,{tone:`danger`,children:[(0,P.jsxs)(`div`,{className:`flex flex-wrap gap-2`,children:[(0,P.jsxs)(`button`,{type:`button`,disabled:o!==null,onClick:()=>void d(`here`),className:e(h,`flex-1`),children:[o===`here`?(0,P.jsx)(l,{size:15,className:`animate-spin`}):(0,P.jsx)(E,{size:15}),` `,i(`Sign out`)]}),(0,P.jsxs)(`button`,{type:`button`,disabled:o!==null,onClick:()=>void d(`all`),className:e(h,`flex-1`),children:[o===`all`?(0,P.jsx)(l,{size:15,className:`animate-spin`}):(0,P.jsx)(S,{size:15}),` `,i(`Sign out everywhere`)]})]}),(0,P.jsxs)(`button`,{type:`button`,disabled:o!==null,onClick:()=>void d(`delete`),className:`flex w-full items-center justify-center gap-1.5 rounded-2xl py-2 text-[13px] font-medium text-rose-600 hover:bg-rose-500/10 dark:text-rose-300`,children:[o===`delete`?(0,P.jsx)(l,{size:15,className:`animate-spin`}):(0,P.jsx)(T,{size:15}),` `,i(`Delete the account`)]}),t?.is_model&&(0,P.jsx)(`p`,{className:`text-center text-[11.5px] text-muted`,children:i(`The Cloud model is in use; after signing out, pick another under Connections.`)})]})}export{F as AccountScreen}; \ No newline at end of file +import{E as e,J as t,K as n,Q as r,R as i,Y as a,b as o,f as s,k as c,q as l,x as u}from"./MuseHeader-Pw-NI98v.js";import{A as d,s as f,t as p}from"./StarNudge-DjXecvWj.js";import{n as m}from"./external-link-Xj5fjR8v.js";import{a as h,i as g}from"./Form-DwKuBk1V.js";import{t as _}from"./clapperboard-BokpXv9J.js";import{t as v}from"./database-zap-CzaFBl6C.js";import{t as y}from"./image-crWy0a06.js";import{$ as b,A as x,G as S,J as C,K as w,V as T,ct as E,gt as D,ot as O,t as k,ut as A}from"./index-CIdGZ5PB.js";import{t as j}from"./BackBar-Dl56jHZM.js";var M=t(`gift`,[[`path`,{d:`M12 7v14`,key:`1akyts`}],[`path`,{d:`M20 11v8a2 2 0 0 1-2 2H6a2 2 0 0 1-2-2v-8`,key:`1sqzm4`}],[`path`,{d:`M7.5 7a1 1 0 0 1 0-5A4.8 8 0 0 1 12 7a4.8 8 0 0 1 4.5-5 1 1 0 0 1 0 5`,key:`kc0143`}],[`rect`,{x:`3`,y:`7`,width:`18`,height:`4`,rx:`1`,key:`1hberx`}]]),N=r(a(),1),P=o();function F(){let{state:e,toast:t,setTab:r}=s(),i=n(),a=e.hub?.account??null,[o,c]=(0,N.useState)(null),[l,d]=(0,N.useState)(null),[m,h]=(0,N.useState)(null),[g,_]=(0,N.useState)(!1),v=!!a?.signed_in,y=f(),b=async()=>{if(v){_(!0);try{let[e,t,n]=await Promise.all([u.cloudMe(),u.cloudSessions(),u.cloudEvents(40)]);c(e),d(t.sessions),h(n.events)}catch(e){t(e.message)}finally{_(!1)}}};return(0,N.useEffect)(()=>{b()},[v,a?.has_password]),(0,P.jsxs)(`div`,{className:`flex h-full flex-col`,children:[(0,P.jsx)(j,{title:i(`Account`),description:i(v?`nanoMuse Cloud · one account for all your devices`:`Sign in to nanoMuse Cloud`)}),(0,P.jsx)(`div`,{className:`flex-1 overflow-y-auto px-4 pb-8 space-y-4`,children:v?(0,P.jsxs)(P.Fragment,{children:[(0,P.jsx)(L,{account:a,me:o}),o&&(0,P.jsx)(p,{moment:`signed_in`}),o&&(0,P.jsx)(R,{me:o,onChanged:()=>void b()}),o?.invite?.code&&(0,P.jsx)(B,{invite:o.invite}),o&&(0,P.jsx)(H,{me:o}),o&&(0,P.jsx)(z,{me:o}),(0,P.jsx)(W,{account:a,onChanged:()=>void b()}),(0,P.jsx)(G,{sessions:l,loading:g,onChanged:()=>void b()}),m&&m.length>0&&(0,P.jsx)(q,{events:m}),(0,P.jsx)(J,{account:a,onDone:()=>r(`chat`)})]}):(0,P.jsxs)(I,{children:[(0,P.jsx)(`p`,{className:`text-[13.5px] text-muted leading-relaxed`,children:i(`Free. One account for all your devices, with a model and ¥{allowance} of use to start; a code the first time, a password afterwards if you like.`,{allowance:(y.allowance_cny??10).toFixed(0)})}),(0,P.jsx)(k,{onSignedIn:()=>t(i(`Signed in to nanoMuse Cloud.`))})]})})]})}function I({title:t,children:n,tone:r}){return(0,P.jsxs)(`section`,{className:e(`rounded-3xl border p-4 space-y-3 shadow-sm`,r===`danger`?`border-rose-500/25 bg-rose-500/[0.04]`:`border-border/70 bg-surface`),children:[t&&(0,P.jsx)(`h2`,{className:`text-[12px] font-semibold uppercase tracking-wide text-muted`,children:t}),n]})}function L({account:e,me:t}){let r=n(),a=e?.hint??``,o=t?.account.created_at?new Date(t.account.created_at*1e3):null;return(0,P.jsxs)(`section`,{className:`relative overflow-hidden rounded-3xl border border-border/70 bg-surface p-5 shadow-sm`,children:[(0,P.jsx)(`div`,{className:`pointer-events-none absolute -right-16 -top-20 h-48 w-48 rounded-full bg-accent/15 blur-3xl`}),(0,P.jsxs)(`div`,{className:`flex items-center gap-4`,children:[(0,P.jsx)(`div`,{className:`flex h-14 w-14 shrink-0 items-center justify-center rounded-2xl bg-gradient-to-br from-accent to-sky-400 text-[22px] font-bold text-white shadow-md`,children:(a.replace(/[^a-z0-9]/gi,``).slice(0,1)||`n`).toUpperCase()}),(0,P.jsxs)(`div`,{className:`min-w-0 flex-1`,children:[(0,P.jsx)(`div`,{className:`truncate text-[18px] font-semibold tracking-tight`,children:a}),(0,P.jsxs)(`div`,{className:`mt-0.5 flex flex-wrap items-center gap-x-2 gap-y-0.5 text-[12.5px] text-muted`,children:[(0,P.jsx)(`span`,{children:e?.channel===`phone`||e?.channel===`sms`?r(`Mobile number`):r(`E-mail`)}),o&&(0,P.jsxs)(`span`,{children:[`· `,r(`since {date}`,{date:o.toLocaleDateString(i())})]}),t?.account.member&&(0,P.jsxs)(`span`,{className:`inline-flex items-center gap-1 rounded-full bg-emerald-500/12 px-2 py-0.5 text-[11px] font-medium text-emerald-700 dark:text-emerald-300`,children:[(0,P.jsx)(w,{size:11}),` `,r(`Unlimited`)]})]})]})]}),e?.account_id&&(0,P.jsxs)(`div`,{className:`mt-4 flex items-center justify-between gap-3 rounded-2xl bg-surface-2/70 px-3 py-2 text-[12px]`,children:[(0,P.jsx)(`span`,{className:`text-muted`,children:r(`Account id`)}),(0,P.jsx)(`code`,{className:`truncate font-mono text-[11.5px] text-fg/80`,children:e.account_id})]})]})}function R({me:t,onChanged:r}){let i=n(),a=t.spend,o=a.grant??a.daily_cap??0,s=a.grant===void 0?a.today:a.total,c=a.left??(a.unlimited?null:Math.max(0,o-s)),l=!a.unlimited&&o>0,u=l?Math.min(100,Math.round(s/o*100)):0,f=a.usd_cny??0,p=e=>f>0?` ≈ $${(e/f).toFixed(2)}`:``,m=l&&(c??0)<=0,h=l&&!m&&(a.warn??u>=80),g={left:c,grant:o,invite_url:t.invite?.url,invite_bonus_cny:a.invite_bonus_cny??t.invite?.bonus_cny,invitee_bonus_cny:a.invitee_bonus_cny??t.invite?.invitee_bonus_cny,own_key_docs:a.own_key_docs,guidance:a.guidance};return(0,P.jsxs)(I,{title:i(`Free allowance`),children:[(0,P.jsxs)(`div`,{className:`flex items-end justify-between gap-3`,children:[(0,P.jsxs)(`div`,{children:[(0,P.jsx)(`div`,{className:`text-[28px] font-bold tracking-tight leading-none`,children:l?(0,P.jsxs)(P.Fragment,{children:[`¥`,(c??0).toFixed(2),(0,P.jsxs)(`span`,{className:`text-[14px] font-medium text-muted`,children:[` `,i(`left of ¥{grant}`,{grant:o.toFixed(0)})]})]}):(0,P.jsxs)(P.Fragment,{children:[`¥`,s.toFixed(2)]})}),(0,P.jsx)(`div`,{className:`mt-1 text-[12.5px] text-muted`,children:l?i(`¥{spent} used{usd}; the allowance does not reset.`,{spent:s.toFixed(2),usd:p(s)}):i(`No limit on this account.`)})]}),(0,P.jsxs)(`div`,{className:`text-right text-[12.5px] text-muted`,children:[(0,P.jsx)(`div`,{children:i(`All time`)}),(0,P.jsxs)(`div`,{className:`text-[15px] font-semibold text-fg`,children:[`¥`,a.total.toFixed(2)]}),f>0&&(0,P.jsxs)(`div`,{className:`text-[11.5px]`,children:[`≈ $`,(a.total/f).toFixed(2)]})]})]}),l&&(0,P.jsx)(`div`,{className:`h-2 overflow-hidden rounded-full bg-surface-2`,children:(0,P.jsx)(`div`,{className:e(`h-full rounded-full transition-all`,u>=100?`bg-rose-500`:u>=80?`bg-amber-500`:`bg-accent`),style:{width:`${u}%`}})}),l&&(0,P.jsxs)(`p`,{className:`text-[12.5px] text-muted`,children:[i(`¥{allowance} to start, +¥{invite} for each friend you invite, and +¥{invite} for them; after that, your own key keeps the model going.`,{allowance:(a.allowance_cny??10).toFixed(0),invite:(g.invite_bonus_cny??5).toFixed(0)}),` `,!m&&!h&&d(i,{signed_in:!0,channel:t.account.channel,region:t.account.region})]}),(m||h)&&(0,P.jsx)(x,{info:g,exhausted:m,onChanged:r})]})}function z({me:e}){let t=n(),{setTab:r}=s(),i=e.contribute??{on:!1,samples:0};return(0,P.jsx)(I,{title:t(`Data controls`),children:(0,P.jsxs)(`button`,{type:`button`,onClick:()=>{window.location.hash=`data`,r(`you`)},className:`flex w-full items-center gap-3 text-left`,children:[(0,P.jsx)(`span`,{className:`flex h-9 w-9 shrink-0 items-center justify-center rounded-xl bg-surface-2 text-fg`,children:(0,P.jsx)(v,{size:18})}),(0,P.jsxs)(`span`,{className:`min-w-0 flex-1`,children:[(0,P.jsx)(`span`,{className:`block text-[14px] font-medium`,children:t(`Help improve nanoMuse's AI models`)}),(0,P.jsxs)(`span`,{className:`block text-[12.5px] text-muted`,children:[i.on?t(`On`):t(`Off`),i.samples>0&&` · ${t(`{n} turns kept so far`,{n:String(i.samples)})}`]})]}),(0,P.jsx)(`span`,{className:`text-[13px] font-medium text-accent`,children:t(`Open`)})]})})}function B({invite:t}){let r=n(),{toast:i}=s(),a=t.url||`https://nanomuse.cn/web/?invite=${t.code}`,o=t.earned_cny??t.invites*t.bonus_cny,c=async e=>{try{await navigator.clipboard.writeText(e),i(r(`Copied`))}catch{i(e)}},l=async()=>{let e=r(`Try nanoMuse with me, a fully open-source personal agent, free to use. Sign up with my code {code}: {link}`,{code:t.code,link:a}),n=navigator;if(n.share)try{await n.share({text:e});return}catch{}await c(e)};return(0,P.jsxs)(I,{title:r(`Invite a friend`),children:[(0,P.jsx)(`p`,{className:`text-[12.5px] text-muted`,children:r(`Each new person who signs up with your code adds ¥{bonus} to your allowance, and ¥{bonus} to theirs. It never expires.`,{bonus:t.bonus_cny.toFixed(0)})}),(0,P.jsxs)(`div`,{className:`flex items-center justify-between gap-3 rounded-2xl bg-surface-2/70 px-3 py-2`,children:[(0,P.jsxs)(`div`,{children:[(0,P.jsx)(`div`,{className:`text-[11px] text-muted`,children:r(`Your code`)}),(0,P.jsx)(`code`,{className:`font-mono text-[18px] font-semibold tracking-[0.2em]`,children:t.code})]}),(0,P.jsxs)(`button`,{type:`button`,onClick:()=>void c(t.code),className:e(h,`inline-flex items-center gap-1.5`),children:[(0,P.jsx)(D,{size:14}),` `,r(`Copy`)]})]}),(0,P.jsxs)(`div`,{className:`flex gap-2`,children:[(0,P.jsxs)(`button`,{type:`button`,onClick:()=>void l(),className:e(g,`inline-flex flex-1 items-center justify-center gap-1.5 py-2.5`),children:[(0,P.jsx)(C,{size:14}),` `,r(`Share the link`)]}),(0,P.jsxs)(`button`,{type:`button`,onClick:()=>void c(a),className:e(h,`inline-flex items-center gap-1.5`),children:[(0,P.jsx)(M,{size:14}),` `,r(`Copy the link`)]})]}),(0,P.jsxs)(`p`,{className:`text-[12.5px] text-muted`,children:[r(`{n} friends joined`,{n:String(t.invites)}),o>0&&(0,P.jsxs)(P.Fragment,{children:[` · `,r(`¥{amount} added by invitations`,{amount:o.toFixed(0)})]})]})]})}var V={chat:{label:`Chat`,icon:(0,P.jsx)(O,{size:15}),tone:`bg-accent`},image:{label:`Pictures`,icon:(0,P.jsx)(y,{size:15}),tone:`bg-violet-500`},video:{label:`Clips`,icon:(0,P.jsx)(_,{size:15}),tone:`bg-pink-500`},realtime:{label:`Calls`,icon:(0,P.jsx)(b,{size:15}),tone:`bg-emerald-500`}};function H({me:t}){let r=n(),[i,a]=(0,N.useState)(`today`),o=i===`today`?t.usage.today.by_kind:t.usage.total.by_kind,s=t.usage.kinds.length?t.usage.kinds:[`chat`,`image`,`video`,`realtime`],c=new Map(o.map(e=>[e.kind,e])),l=o.reduce((e,t)=>e+t.cost_cny,0),u=t.usage.total.by_model.slice(0,8);return(0,P.jsxs)(I,{title:r(`Usage`),children:[(0,P.jsxs)(`div`,{className:`flex items-center justify-between`,children:[(0,P.jsx)(`p`,{className:`text-[12.5px] text-muted`,children:r(`Every kind of use is counted, not just the chat model.`)}),(0,P.jsx)(`div`,{className:`flex rounded-full bg-surface-2/80 p-0.5 text-[12px] font-medium`,children:[`today`,`total`].map(t=>(0,P.jsx)(`button`,{type:`button`,onClick:()=>a(t),className:e(`rounded-full px-2.5 py-1 transition`,i===t?`bg-surface shadow-sm`:`text-muted`),children:r(t===`today`?`Today`:`All time`)},t))})]}),l>0&&(0,P.jsx)(`div`,{className:`flex h-2.5 overflow-hidden rounded-full bg-surface-2`,children:s.map(t=>{let n=c.get(t);return!n||n.cost_cny<=0?null:(0,P.jsx)(`div`,{className:e(`h-full`,V[t]?.tone??`bg-fg/40`),style:{width:`${n.cost_cny/l*100}%`},title:r(V[t]?.label??t)},t)})}),(0,P.jsx)(`ul`,{className:`grid grid-cols-2 gap-2`,children:s.map(t=>{let n=c.get(t),i=V[t];return(0,P.jsxs)(`li`,{className:`rounded-2xl bg-surface-2/60 p-3`,children:[(0,P.jsxs)(`div`,{className:`flex items-center gap-1.5 text-[12.5px] text-muted`,children:[(0,P.jsx)(`span`,{className:e(`flex h-5 w-5 items-center justify-center rounded-md text-white`,i?.tone??`bg-fg/40`),children:i?.icon}),r(i?.label??t)]}),(0,P.jsxs)(`div`,{className:`mt-1.5 text-[17px] font-semibold tracking-tight`,children:[`¥`,(n?.cost_cny??0).toFixed(2)]}),(0,P.jsx)(`div`,{className:`text-[11.5px] text-muted`,children:n?t===`realtime`?r(`{n} answers · {tokens} tokens`,{n:n.requests,tokens:U(n.prompt_tokens+n.completion_tokens)}):t===`chat`?r(`{n} requests · {tokens} tokens`,{n:n.requests,tokens:U(n.prompt_tokens+n.completion_tokens)}):r(`{n} requests`,{n:n.requests}):r(`Nothing yet`)})]},t)})}),u.length>0&&(0,P.jsxs)(`div`,{children:[(0,P.jsx)(`div`,{className:`mb-1.5 text-[12px] font-medium text-muted`,children:r(`By model, all time`)}),(0,P.jsx)(`ul`,{className:`divide-y divide-border/60 rounded-2xl border border-border/60`,children:u.map(t=>(0,P.jsxs)(`li`,{className:`flex items-center gap-2 px-3 py-2 text-[12.5px]`,children:[(0,P.jsx)(`span`,{className:e(`h-2 w-2 shrink-0 rounded-full`,V[t.kind]?.tone??`bg-fg/40`)}),(0,P.jsx)(`span`,{className:`min-w-0 flex-1 truncate font-mono text-[12px]`,children:t.model}),(0,P.jsx)(`span`,{className:`text-muted`,children:U(t.prompt_tokens+t.completion_tokens)}),(0,P.jsxs)(`span`,{className:`w-16 text-right font-medium`,children:[`¥`,t.cost_cny.toFixed(2)]})]},`${t.model}-${t.kind}`))})]})]})}function U(e){return e>=1e6?`${(e/1e6).toFixed(1)}M`:e>=1e3?`${(e/1e3).toFixed(e>=1e5?0:1)}k`:String(e)}function W({account:t,onChanged:r}){let i=n(),{toast:a}=s(),o=!!t?.has_password,[c,d]=(0,N.useState)(!1),[f,p]=(0,N.useState)(``),[h,g]=(0,N.useState)(``),[_,v]=(0,N.useState)(``),[y,b]=(0,N.useState)(!1),[x,S]=(0,N.useState)(null),C=async(e=!1)=>{if(!(!e&&(h.length<8||h!==_))){b(!0),S(null);try{await u.cloudPassword(e?``:h,o?f:void 0),a(i(e?`Password removed.`:o?`Password changed.`:`Password set.`)),d(!1),p(``),g(``),v(``),r()}catch(e){S(i(e.message))}finally{b(!1)}}};return(0,P.jsxs)(I,{title:i(`Password`),children:[(0,P.jsxs)(`div`,{className:`flex items-center gap-3`,children:[(0,P.jsx)(`span`,{className:e(`flex h-9 w-9 items-center justify-center rounded-xl`,o?`bg-emerald-500/12 text-emerald-600 dark:text-emerald-300`:`bg-surface-2 text-muted`),children:(0,P.jsx)(A,{size:17})}),(0,P.jsxs)(`div`,{className:`min-w-0 flex-1 text-[13.5px]`,children:[(0,P.jsx)(`div`,{className:`font-medium`,children:i(o?`A password is set`:`No password yet`)}),(0,P.jsx)(`div`,{className:`text-[12.5px] text-muted`,children:i(o?`Sign in with it on a new device, or with a code as before.`:`Optional. With one, a new device can sign in without waiting for a code.`)})]}),!c&&(0,P.jsx)(`button`,{type:`button`,onClick:()=>d(!0),className:e(`flex items-center justify-center gap-1.5 rounded-2xl border border-border px-4 py-2.5 text-[14px] font-medium text-muted disabled:opacity-40`,`shrink-0 px-3 py-2 text-[13px]`),children:i(o?`Change`:`Set`)})]}),c&&(0,P.jsxs)(`form`,{className:`space-y-2.5`,onSubmit:e=>{e.preventDefault(),C()},children:[o&&(0,P.jsx)(`input`,{type:`password`,value:f,onChange:e=>p(e.target.value),placeholder:i(`Current password`),autoComplete:`current-password`,className:`w-full rounded-2xl bg-surface-2 px-3.5 py-2.5 text-[14.5px] outline-none focus:ring-2 focus:ring-accent/40`}),(0,P.jsx)(`input`,{type:`password`,value:h,onChange:e=>g(e.target.value),placeholder:i(`New password (8 characters or more)`),autoComplete:`new-password`,autoFocus:!0,className:`w-full rounded-2xl bg-surface-2 px-3.5 py-2.5 text-[14.5px] outline-none focus:ring-2 focus:ring-accent/40`}),(0,P.jsx)(`input`,{type:`password`,value:_,onChange:e=>v(e.target.value),placeholder:i(`Once more`),autoComplete:`new-password`,className:`w-full rounded-2xl bg-surface-2 px-3.5 py-2.5 text-[14.5px] outline-none focus:ring-2 focus:ring-accent/40`}),_&&h!==_&&(0,P.jsx)(`p`,{className:`text-[12px] text-rose-600 dark:text-rose-300`,children:i(`The two do not match.`)}),x&&(0,P.jsx)(`p`,{className:`rounded-2xl bg-rose-500/12 px-3 py-2 text-[12.5px] text-rose-700 dark:text-rose-300`,children:x}),(0,P.jsxs)(`div`,{className:`flex flex-wrap gap-2`,children:[(0,P.jsxs)(`button`,{type:`submit`,disabled:y||h.length<8||h!==_||o&&!f,className:e(`flex items-center justify-center gap-1.5 rounded-2xl bg-accent text-accent-fg px-4 py-2.5 text-[14px] font-medium disabled:opacity-40`,`flex-1`),children:[y?(0,P.jsx)(l,{size:15,className:`animate-spin`}):(0,P.jsx)(m,{size:15}),` `,i(o?`Change password`:`Set password`)]}),o&&(0,P.jsx)(`button`,{type:`button`,disabled:y||!f,onClick:()=>void C(!0),className:`flex items-center justify-center gap-1.5 rounded-2xl border border-border px-4 py-2.5 text-[14px] font-medium text-muted disabled:opacity-40`,children:i(`Remove`)}),(0,P.jsx)(`button`,{type:`button`,onClick:()=>d(!1),className:`flex items-center justify-center gap-1.5 rounded-2xl border border-border px-4 py-2.5 text-[14px] font-medium text-muted disabled:opacity-40`,children:i(`Cancel`)})]})]})]})}function G({sessions:e,loading:t,onChanged:r}){let a=n(),{toast:o}=s(),[d,f]=(0,N.useState)(null),p=async e=>{if(window.confirm(a(`Sign out {device}? It will need to sign in again.`,{device:e.device||e.prefix}))){f(e.prefix);try{await u.cloudRevokeSession(e.prefix),r()}catch(e){o(e.message)}finally{f(null)}}};return(0,P.jsx)(I,{title:a(`Signed in on`),children:e?(0,P.jsx)(`ul`,{className:`divide-y divide-border/60`,children:e.map(e=>(0,P.jsxs)(`li`,{className:`flex items-center gap-3 py-2.5`,children:[(0,P.jsx)(`span`,{className:`flex h-9 w-9 shrink-0 items-center justify-center rounded-xl bg-surface-2 text-fg/70`,children:(0,P.jsx)(S,{size:17})}),(0,P.jsxs)(`div`,{className:`min-w-0 flex-1`,children:[(0,P.jsxs)(`div`,{className:`flex items-center gap-2 text-[13.5px] font-medium`,children:[(0,P.jsx)(`span`,{className:`truncate`,children:e.device||a(`Unnamed device`)}),e.current&&(0,P.jsx)(`span`,{className:`rounded-full bg-accent/12 px-2 py-0.5 text-[10.5px] font-semibold text-accent`,children:a(`This one`)})]}),(0,P.jsxs)(`div`,{className:`truncate text-[12px] text-muted`,children:[e.via===`password`?a(`password`):a(`code`),` · `,a(`since {date}`,{date:new Date(e.created_at*1e3).toLocaleDateString(i())}),e.last_used_at?` · ${a(`used {when}`,{when:c(e.last_used_at)})}`:``]})]}),!e.current&&(0,P.jsx)(`button`,{type:`button`,disabled:d!==null,onClick:()=>void p(e),className:`rounded-full px-3 py-1.5 text-[12.5px] font-medium text-rose-600 hover:bg-rose-500/10 dark:text-rose-300`,children:d===e.prefix?(0,P.jsx)(l,{size:14,className:`animate-spin`}):a(`Sign out`)})]},e.prefix))}):(0,P.jsx)(`div`,{className:`flex justify-center py-3 text-muted`,children:t?(0,P.jsx)(l,{size:18,className:`animate-spin`}):null})})}var K={"account.created":`Account created`,"sign_in.code":`Signed in with a code`,"sign_in.password":`Signed in with the password`,"sign_in.failed":`A sign-in attempt failed`,sign_out:`Signed out`,"sign_out.all":`Signed out everywhere`,"password.set":`Password set`,"password.changed":`Password changed`,"password.cleared":`Password removed`,"budget.refused":`A request was refused: the allowance is used up`,"call.ended":`Call ended`,"upstream.error":`The model provider returned an error`,"credit.granted":`Allowance added`,"pool.set":`Allowance adjusted`,"invite.accepted":`Signed up with a friend's code`,"invite.used":`A friend signed up with your code`,"invite.unknown":`An invite code was not recognised`,"contribute.default":`Data controls: on for new accounts`,"contribute.on":`Data controls: help improve turned on`,"contribute.off":`Data controls: help improve turned off`,"contribute.deleted":`Data controls: kept conversations deleted`,"profile.put":`Agent's name and look saved`,"profile.clear":`Agent's name and look cleared`};function q({events:e}){let t=n(),[r,i]=(0,N.useState)(!1),a=r?e:e.slice(0,6);return(0,P.jsxs)(I,{title:t(`Recent activity`),children:[(0,P.jsx)(`ul`,{className:`space-y-2`,children:a.map((e,n)=>(0,P.jsxs)(`li`,{className:`flex gap-3 text-[12.5px]`,children:[(0,P.jsx)(`span`,{className:`w-[74px] shrink-0 text-muted`,children:c(e.ts)}),(0,P.jsxs)(`span`,{className:`min-w-0 flex-1`,children:[(0,P.jsx)(`span`,{className:`font-medium`,children:t(K[e.kind]??e.kind)}),e.detail&&(0,P.jsx)(`span`,{className:`ml-1.5 break-all text-muted`,children:e.detail})]})]},`${e.ts}-${n}`))}),e.length>6&&(0,P.jsx)(`button`,{type:`button`,onClick:()=>i(e=>!e),className:`text-[12.5px] font-medium text-accent`,children:r?t(`Show less`):t(`Show all {n}`,{n:e.length})})]})}function J({account:t,onDone:r}){let i=n(),{toast:a}=s(),[o,c]=(0,N.useState)(null),d=async e=>{let t=i(e===`here`?`Sign out of nanoMuse Cloud on this device? The hub and the Cloud model stop working here until you sign in again.`:e===`all`?`Sign out on every device, including this one?`:`Delete the account? The relay forgets your identifier, your devices and your usage. This cannot be undone.`);if(window.confirm(t)&&(e!==`delete`||window.confirm(i(`Really delete it?`)))){c(e);try{e===`here`?await u.cloudSignOut():e===`all`?await u.cloudSignOutAll(!0):await u.cloudDelete(),a(i(e===`delete`?`Account deleted.`:`Signed out.`)),r()}catch(e){a(e.message)}finally{c(null)}}};return(0,P.jsxs)(I,{tone:`danger`,children:[(0,P.jsxs)(`div`,{className:`flex flex-wrap gap-2`,children:[(0,P.jsxs)(`button`,{type:`button`,disabled:o!==null,onClick:()=>void d(`here`),className:e(h,`flex-1`),children:[o===`here`?(0,P.jsx)(l,{size:15,className:`animate-spin`}):(0,P.jsx)(E,{size:15}),` `,i(`Sign out`)]}),(0,P.jsxs)(`button`,{type:`button`,disabled:o!==null,onClick:()=>void d(`all`),className:e(h,`flex-1`),children:[o===`all`?(0,P.jsx)(l,{size:15,className:`animate-spin`}):(0,P.jsx)(S,{size:15}),` `,i(`Sign out everywhere`)]})]}),(0,P.jsxs)(`button`,{type:`button`,disabled:o!==null,onClick:()=>void d(`delete`),className:`flex w-full items-center justify-center gap-1.5 rounded-2xl py-2 text-[13px] font-medium text-rose-600 hover:bg-rose-500/10 dark:text-rose-300`,children:[o===`delete`?(0,P.jsx)(l,{size:15,className:`animate-spin`}):(0,P.jsx)(T,{size:15}),` `,i(`Delete the account`)]}),t?.is_model&&(0,P.jsx)(`p`,{className:`text-center text-[11.5px] text-muted`,children:i(`The Cloud model is in use; after signing out, pick another under Connections.`)})]})}export{F as AccountScreen}; \ No newline at end of file diff --git a/nanomuse/server/static/assets/AvatarPicker-oSjVM8L3.js b/nanomuse/server/static/assets/AvatarPicker-gR2knlot.js similarity index 97% rename from nanomuse/server/static/assets/AvatarPicker-oSjVM8L3.js rename to nanomuse/server/static/assets/AvatarPicker-gR2knlot.js index a709c2f4b..19d48a512 100644 --- a/nanomuse/server/static/assets/AvatarPicker-oSjVM8L3.js +++ b/nanomuse/server/static/assets/AvatarPicker-gR2knlot.js @@ -1 +1 @@ -import{E as e,K as t,a as n,b as r,c as i,s as a,u as o}from"./MuseHeader-Pw-NI98v.js";import{n as s}from"./external-link-Xj5fjR8v.js";import{W as c}from"./index-BjYzdKkG.js";var l=r(),u=[`✨`,`🌙`,`🪐`,`🌿`,`🔥`,`🌊`,`🦉`,`🦊`,`🐙`,`🎯`,`🧭`,`💎`,`🍀`,`🎈`,`🤖`,`🧠`],d=[`#0064d4`,`#7c3aed`,`#0891b2`,`#059669`,`#d97706`,`#dc2626`,`#db2777`,`#4b5563`],f=[{id:`muse`,label:`3D toy (Muse)`},{id:`flat`,label:`Flat`},{id:`clay`,label:`3D clay`},{id:`watercolor`,label:`Watercolour`},{id:`pixel`,label:`Pixel`},{id:`line`,label:`Line`},{id:`sticker`,label:`Sticker`}];function p({value:r,onChange:f,onStudio:p}){let m=t(),h=r.avatar===``,g=!h&&!i(r.avatar)?r.avatar:null,_=`ring-[2.5px] ring-accent ring-offset-2 ring-offset-bg`,v=`relative h-[72px] w-[72px] shrink-0 overflow-hidden rounded-full transition`;return(0,l.jsxs)(`div`,{className:`space-y-3`,children:[(0,l.jsxs)(`div`,{className:`flex flex-wrap gap-3`,children:[(0,l.jsx)(`button`,{type:`button`,"aria-label":m(`The dragon`),"aria-pressed":r.avatar===n,onClick:()=>f({...r,avatar:n}),className:e(v,`bg-[#f1efeb]`,r.avatar===`dragon`?_:`opacity-90 hover:opacity-100`),children:(0,l.jsx)(`img`,{src:a(r.avatar===`dragon`?`happy`:`idle`),alt:``,draggable:!1,className:`h-full w-full object-cover`})}),g&&(0,l.jsx)(`button`,{type:`button`,"aria-label":m(`The face drawn for you`),"aria-pressed":!0,className:e(v,`bg-surface-2`,_),children:(0,l.jsx)(`img`,{src:o(g,`happy`),alt:``,draggable:!1,className:`h-full w-full object-cover`})}),p&&(0,l.jsx)(`button`,{type:`button`,"aria-label":m(`Avatar studio`),onClick:p,className:e(v,`flex items-center justify-center border border-dashed border-border text-accent hover:bg-surface-2`),children:(0,l.jsx)(c,{size:22})}),(0,l.jsx)(`button`,{type:`button`,"aria-label":m(`An emoji instead`),"aria-pressed":h,onClick:()=>f({...r,avatar:``}),className:e(`flex h-[72px] w-[72px] shrink-0 items-center justify-center rounded-full text-[26px] transition`,h?_:`opacity-90 hover:opacity-100`),style:{background:`linear-gradient(135deg, ${r.color}, color-mix(in srgb, ${r.color} 60%, #ffffff))`},children:r.emoji})]}),h&&(0,l.jsxs)(l.Fragment,{children:[(0,l.jsx)(`div`,{className:`grid grid-cols-8 gap-1.5`,children:u.map(t=>(0,l.jsx)(`button`,{type:`button`,onClick:()=>f({...r,emoji:t}),className:e(`flex aspect-square items-center justify-center rounded-2xl bg-surface-2 text-[22px]`,r.emoji===t&&`ring-2 ring-accent`),children:t},t))}),(0,l.jsx)(`div`,{className:`flex gap-2`,children:d.map(e=>(0,l.jsx)(`button`,{type:`button`,"aria-label":e,onClick:()=>f({...r,color:e}),className:`flex h-8 w-8 items-center justify-center rounded-full text-white`,style:{background:e},children:r.color===e&&(0,l.jsx)(s,{size:16})},e))})]})]})}export{f as n,p as r,d as t}; \ No newline at end of file +import{E as e,K as t,a as n,b as r,c as i,s as a,u as o}from"./MuseHeader-Pw-NI98v.js";import{n as s}from"./external-link-Xj5fjR8v.js";import{W as c}from"./index-CIdGZ5PB.js";var l=r(),u=[`✨`,`🌙`,`🪐`,`🌿`,`🔥`,`🌊`,`🦉`,`🦊`,`🐙`,`🎯`,`🧭`,`💎`,`🍀`,`🎈`,`🤖`,`🧠`],d=[`#0064d4`,`#7c3aed`,`#0891b2`,`#059669`,`#d97706`,`#dc2626`,`#db2777`,`#4b5563`],f=[{id:`muse`,label:`3D toy (Muse)`},{id:`flat`,label:`Flat`},{id:`clay`,label:`3D clay`},{id:`watercolor`,label:`Watercolour`},{id:`pixel`,label:`Pixel`},{id:`line`,label:`Line`},{id:`sticker`,label:`Sticker`}];function p({value:r,onChange:f,onStudio:p}){let m=t(),h=r.avatar===``,g=!h&&!i(r.avatar)?r.avatar:null,_=`ring-[2.5px] ring-accent ring-offset-2 ring-offset-bg`,v=`relative h-[72px] w-[72px] shrink-0 overflow-hidden rounded-full transition`;return(0,l.jsxs)(`div`,{className:`space-y-3`,children:[(0,l.jsxs)(`div`,{className:`flex flex-wrap gap-3`,children:[(0,l.jsx)(`button`,{type:`button`,"aria-label":m(`The dragon`),"aria-pressed":r.avatar===n,onClick:()=>f({...r,avatar:n}),className:e(v,`bg-[#f1efeb]`,r.avatar===`dragon`?_:`opacity-90 hover:opacity-100`),children:(0,l.jsx)(`img`,{src:a(r.avatar===`dragon`?`happy`:`idle`),alt:``,draggable:!1,className:`h-full w-full object-cover`})}),g&&(0,l.jsx)(`button`,{type:`button`,"aria-label":m(`The face drawn for you`),"aria-pressed":!0,className:e(v,`bg-surface-2`,_),children:(0,l.jsx)(`img`,{src:o(g,`happy`),alt:``,draggable:!1,className:`h-full w-full object-cover`})}),p&&(0,l.jsx)(`button`,{type:`button`,"aria-label":m(`Avatar studio`),onClick:p,className:e(v,`flex items-center justify-center border border-dashed border-border text-accent hover:bg-surface-2`),children:(0,l.jsx)(c,{size:22})}),(0,l.jsx)(`button`,{type:`button`,"aria-label":m(`An emoji instead`),"aria-pressed":h,onClick:()=>f({...r,avatar:``}),className:e(`flex h-[72px] w-[72px] shrink-0 items-center justify-center rounded-full text-[26px] transition`,h?_:`opacity-90 hover:opacity-100`),style:{background:`linear-gradient(135deg, ${r.color}, color-mix(in srgb, ${r.color} 60%, #ffffff))`},children:r.emoji})]}),h&&(0,l.jsxs)(l.Fragment,{children:[(0,l.jsx)(`div`,{className:`grid grid-cols-8 gap-1.5`,children:u.map(t=>(0,l.jsx)(`button`,{type:`button`,onClick:()=>f({...r,emoji:t}),className:e(`flex aspect-square items-center justify-center rounded-2xl bg-surface-2 text-[22px]`,r.emoji===t&&`ring-2 ring-accent`),children:t},t))}),(0,l.jsx)(`div`,{className:`flex gap-2`,children:d.map(e=>(0,l.jsx)(`button`,{type:`button`,"aria-label":e,onClick:()=>f({...r,color:e}),className:`flex h-8 w-8 items-center justify-center rounded-full text-white`,style:{background:e},children:r.color===e&&(0,l.jsx)(s,{size:16})},e))})]})]})}export{f as n,p as r,d as t}; \ No newline at end of file diff --git a/nanomuse/server/static/assets/AvatarStudioScreen-C1Q0sV3j.js b/nanomuse/server/static/assets/AvatarStudioScreen-DD2X0R8P.js similarity index 99% rename from nanomuse/server/static/assets/AvatarStudioScreen-C1Q0sV3j.js rename to nanomuse/server/static/assets/AvatarStudioScreen-DD2X0R8P.js index 9d70cefbb..7a2e367df 100644 --- a/nanomuse/server/static/assets/AvatarStudioScreen-C1Q0sV3j.js +++ b/nanomuse/server/static/assets/AvatarStudioScreen-DD2X0R8P.js @@ -1 +1 @@ -import{E as e,K as t,L as n,Q as r,S as i,Y as a,a as o,b as s,c,f as l,l as u,o as d,q as f,r as p,s as m,u as h,x as g}from"./MuseHeader-Pw-NI98v.js";import{C as _,t as v,w as y}from"./StarNudge-DjXecvWj.js";import{n as b}from"./external-link-Xj5fjR8v.js";import{i as x,o as S}from"./Form-DwKuBk1V.js";import{t as ee}from"./refresh-cw-BKgIzslL.js";import{W as C,ht as te}from"./index-BjYzdKkG.js";import{t as ne}from"./BackBar-Dli0L0O_.js";import{n as w}from"./AvatarPicker-oSjVM8L3.js";var T=r(a(),1),E=s(),D=[`idle`,`working`,`waiting`,`happy`,`error`],O={idle:`Idle`,working:`Working`,waiting:`Waiting for you`,happy:`Done`,error:`Something went wrong`},re=4,k=`a round, custard-yellow baby dragon with small orange horns and folded little wings`;function A(){let{state:r,setTab:a,toast:s,draft:u,refreshSettings:d}=l(),m=t(),h=r.profile,O=h?.name??`nanoMuse`,[A,oe]=(0,T.useState)(null),[M,se]=(0,T.useState)(``),[N,ce]=(0,T.useState)(`muse`),[P,F]=(0,T.useState)(null),[I,L]=(0,T.useState)(null),[R,z]=(0,T.useState)(!1),[B,V]=(0,T.useState)(``),H=r.studio??A?.current??null,U=H?.stage??``,W=U===`drawing`,G=H?.candidates??[],K=(U===`drawing`||U===`choose`)&&G.length>0,le=()=>g.avatarView().then(oe,e=>s(e.message));(0,T.useEffect)(()=>{le()},[h?.avatar,r.settings?.llm.model,r.connectionsVersion]),(0,T.useEffect)(()=>{U!==`choose`&&F(null)},[U]);let q=async(e,t)=>{L(e),V(``);try{await t()}catch(e){V(e.message)}finally{L(null)}},ue=()=>q(`draw`,async()=>{let e=M.trim()||k,t=await g.avatarBegin(e,``,N);if(t.available===!1)throw Error(y(m,`image`,_(r.hub?.account),n()));t.cost?.cloud===!1&&t.session&&await g.avatarStart(t.session)}),de=()=>q(`reset`,async()=>{await g.updateSettings({profile:{avatar:o}}),await d(),s(m(`Back to the built-in look.`))}),J=A?.face??null,fe=!!h?.avatar&&!c(h.avatar),Y=H&&(U===`posing`||U===`animating`||U===`done`)&&H.face===h?.avatar,pe=Y?Object.keys(H.moods??{}).length:0,me=Y?Object.keys(H.clips??{}).length:0,X=Y?(H.errors??[]).filter(e=>!/clip/.test(e)).length:0,Z=H?.cost??{},Q=Z.clips?m(`{n} pictures and {c} clips`,{n:Z.pictures??8,c:Z.clips}):m(`{n} pictures`,{n:Z.pictures??8}),he=(()=>{if(Z.error)return m(`The cost could not be checked: {error}`,{error:Z.error});if(typeof Z.cny!=`number`)return m(`Checking the cost…`);if(Z.unlimited)return m(`About ¥{cny} for {what}; your account has no limit.`,{cny:Z.cny.toFixed(2),what:Q});let e=typeof Z.left_cny==`number`?Z.left_cny.toFixed(2):`?`;return Z.affordable===!1?m(`About ¥{cny} for {what}, more than the ¥{left} left in your allowance.`,{cny:Z.cny.toFixed(2),what:Q,left:e}):m(`About ¥{cny} for {what}; ¥{left} left in your allowance.`,{cny:Z.cny.toFixed(2),what:Q,left:e})})(),$=e=>w.find(t=>t.id===e)?.label,ge=A?.cloud?`nanoMuse Cloud`:ie(A?.host??``,m);return(0,E.jsxs)(`div`,{className:`flex h-full flex-col`,children:[(0,E.jsx)(ne,{title:m(`Avatar studio`),description:m(`Draw a look with your image model; it moves with what it is doing.`),actions:(0,E.jsxs)(`div`,{className:`relative`,children:[(0,E.jsx)(p,{small:!0,onClick:()=>z(e=>!e),label:m(`More`),expanded:R,children:(0,E.jsx)(te,{size:20})}),R&&(0,E.jsxs)(`div`,{className:`absolute right-0 z-20 mt-1 w-56 overflow-hidden rounded-2xl border border-border/70 bg-surface py-1 text-[14px] shadow-lg`,children:[(0,E.jsx)(j,{label:m(`Name & style`),onClick:()=>{z(!1),a(`you`)}}),(0,E.jsx)(j,{label:m(`Image model`),onClick:()=>{z(!1),a(`connections`)}}),fe&&(0,E.jsxs)(E.Fragment,{children:[(0,E.jsx)(j,{label:m(`Redraw the poses`),onClick:()=>{z(!1),q(`moods`,()=>g.avatarMoods())}}),(0,E.jsx)(j,{label:m(`Back to the built-in look`),danger:!0,onClick:()=>{z(!1),de()}})]})]})]})}),(0,E.jsxs)(`div`,{className:`flex-1 overflow-y-auto px-4 pb-8 space-y-5`,onClick:()=>R&&z(!1),children:[(0,E.jsxs)(`div`,{className:`flex flex-col items-center pt-2 text-center`,children:[(0,E.jsx)(ae,{avatar:h?.avatar,emoji:h?.emoji,color:h?.color,name:O}),J&&(0,E.jsx)(`div`,{className:`mt-0.5 max-w-sm text-[12.5px] text-muted`,children:[J.description,$(J.style)&&m($(J.style))].filter(Boolean).join(` · `)}),Y&&(0,E.jsxs)(`div`,{className:`mt-2.5 flex items-center gap-2 text-[13px] text-muted`,children:[U===`posing`&&(0,E.jsxs)(E.Fragment,{children:[(0,E.jsx)(f,{size:14,className:`animate-spin text-accent`}),(0,E.jsx)(`span`,{children:m(`Drawing the poses… {done}/{total}`,{done:pe,total:D.length})})]}),U===`animating`&&(0,E.jsxs)(E.Fragment,{children:[(0,E.jsx)(f,{size:14,className:`animate-spin text-accent`}),(0,E.jsx)(`span`,{children:m(`The new look is on; making the clips… {done}/{total}`,{done:me,total:re})})]}),U===`done`&&(0,E.jsxs)(E.Fragment,{children:[(0,E.jsx)(`span`,{children:X===0?m(`All five poses are in.`):m(`{done} of {total} poses are in; the rest show the main picture.`,{done:D.length-X,total:D.length})}),X>0&&(0,E.jsx)(`button`,{type:`button`,onClick:()=>void q(`moods`,()=>g.avatarMoods()),className:`font-medium text-accent`,children:m(`Retry`)})]})]})]}),U===`done`&&X===0&&(0,E.jsx)(v,{moment:`new_look`}),(0,E.jsxs)(`section`,{className:`rounded-3xl border border-border/70 bg-surface p-4 shadow-sm space-y-3`,children:[(0,E.jsxs)(`div`,{children:[(0,E.jsx)(`h2`,{className:`text-[17px] font-semibold`,children:m(`Describe a new look`)}),(0,E.jsx)(`p`,{className:`mt-0.5 text-[13px] leading-snug text-muted`,children:m(`One sentence is enough: what it is, what it wears, its air. Pick a style and your image model draws four to choose from.`)})]}),(0,E.jsx)(`textarea`,{value:M,onChange:e=>se(e.target.value),rows:2,maxLength:200,placeholder:m(k),className:`w-full resize-none rounded-2xl bg-surface-2 px-3.5 py-2.5 text-[14.5px] outline-none focus:ring-2 focus:ring-accent/40`}),(0,E.jsx)(`div`,{className:`flex flex-wrap gap-1.5`,children:w.map(t=>(0,E.jsx)(`button`,{type:`button`,onClick:()=>ce(t.id),className:e(`rounded-full px-3 py-1.5 text-[13px] font-medium transition`,N===t.id?`bg-fg text-bg`:`bg-surface-2 text-fg hover:bg-border/60`),children:m(t.label)},t.id))}),(0,E.jsxs)(`button`,{type:`button`,disabled:I!==null||W||A?.available===!1,onClick:()=>void ue(),className:e(x,`w-full rounded-full py-3`),children:[W||I===`draw`?(0,E.jsx)(f,{size:16,className:`animate-spin`}):(0,E.jsx)(C,{size:16}),m(W?`Drawing…`:K||U===`choose`?`Draw four more`:`Draw four`)]}),(0,E.jsxs)(`button`,{type:`button`,onClick:()=>a(`connections`),className:`flex w-full items-center justify-between gap-3 py-1 text-left text-[12.5px] text-muted`,children:[(0,E.jsx)(`span`,{className:`min-w-0 flex-1`,children:A===null?`…`:A.available?m(`Drawn by {provider} · {model}`,{provider:ge,model:A.image_model||`—`}):y(m,`image`,_(r.hub?.account),n())}),(0,E.jsx)(`span`,{className:`shrink-0 font-medium text-accent`,children:m(`Change model`)})]}),B&&(0,E.jsx)(`p`,{className:`text-[13px] text-rose-600 dark:text-rose-300`,children:B})]}),U===`estimate`&&H&&(0,E.jsxs)(`section`,{className:`rounded-3xl border border-accent/50 bg-surface p-4 shadow-sm space-y-3`,children:[(0,E.jsxs)(`div`,{children:[(0,E.jsx)(`h2`,{className:`text-[15px] font-semibold`,children:m(`A new look for {name}`,{name:O})}),(0,E.jsx)(`p`,{className:`mt-0.5 text-[13px] text-muted`,children:H.description})]}),(0,E.jsx)(`p`,{className:`text-[12.5px] text-muted`,children:he}),(0,E.jsxs)(`div`,{className:`flex gap-2`,children:[(0,E.jsxs)(`button`,{type:`button`,disabled:I!==null||typeof Z.cny!=`number`&&!Z.error,onClick:()=>void q(`start`,()=>g.avatarStart(H.session)),className:e(`flex items-center justify-center gap-1.5 rounded-2xl bg-accent text-accent-fg px-4 py-2.5 text-[14px] font-medium disabled:opacity-40`,`rounded-full`),children:[I===`start`?(0,E.jsx)(f,{size:14,className:`animate-spin`}):(0,E.jsx)(C,{size:14}),` `,m(`Draw`)]}),(0,E.jsxs)(`button`,{type:`button`,disabled:I!==null,onClick:()=>void q(`cancel`,()=>g.avatarCancel(H.session)),className:e(`flex items-center justify-center gap-1.5 rounded-2xl border border-border px-4 py-2.5 text-[14px] font-medium text-muted disabled:opacity-40`,`rounded-full`),children:[(0,E.jsx)(S,{size:14}),` `,m(`Not now`)]})]})]}),K&&H&&(0,E.jsxs)(`section`,{className:`space-y-3 px-1`,children:[(0,E.jsxs)(`div`,{children:[(0,E.jsx)(`h2`,{className:`text-[17px] font-semibold`,children:m(`Pick one`)}),(0,E.jsx)(`p`,{className:`mt-0.5 text-[13px] leading-snug text-muted`,children:m(`Draw four more any time; the old ones stay until you do.`)})]}),(0,E.jsx)(`div`,{className:`grid grid-cols-2 gap-3 wide:grid-cols-4`,children:G.map((t,n)=>(0,E.jsxs)(`button`,{type:`button`,disabled:!t||U!==`choose`,onClick:()=>F(e=>e===n?null:n),"aria-label":m(`Candidate {n}`,{n:n+1}),"aria-pressed":P===n,className:e(`relative aspect-square overflow-hidden rounded-[20px] bg-[#f1efeb] transition`,P===n?`ring-[3px] ring-accent`:t&&U===`choose`?`hover:ring-2 hover:ring-accent/60`:``),children:[t?(0,E.jsx)(`img`,{src:i(t),alt:``,draggable:!1,className:`h-full w-full object-cover`}):(0,E.jsx)(`span`,{className:`absolute inset-0 flex items-center justify-center text-muted`,children:W?(0,E.jsx)(f,{size:22,className:`animate-spin`}):(0,E.jsx)(S,{size:18,className:`opacity-50`})}),P===n&&(0,E.jsx)(`span`,{className:`absolute right-2 top-2 flex h-7 w-7 items-center justify-center rounded-full bg-accent text-accent-fg shadow`,children:(0,E.jsx)(b,{size:16})})]},n))}),H.errors&&H.errors.length>0&&U===`choose`&&(0,E.jsx)(`p`,{className:`text-[12.5px] text-rose-600 dark:text-rose-300`,children:m(H.errors[0])}),P!==null&&U===`choose`&&(0,E.jsxs)(`div`,{className:`space-y-1.5 pt-1`,children:[(0,E.jsxs)(`button`,{type:`button`,disabled:I!==null,onClick:()=>void q(`choose`,()=>g.avatarChoose(H.session,P)),className:e(`flex items-center justify-center gap-1.5 rounded-2xl bg-accent text-accent-fg px-4 py-2.5 text-[14px] font-medium disabled:opacity-40`,`w-full rounded-full py-3`),children:[I===`choose`?(0,E.jsx)(f,{size:16,className:`animate-spin`}):(0,E.jsx)(b,{size:16}),` `,m(`Use this one`)]}),(0,E.jsx)(`p`,{className:`text-center text-[12px] leading-snug text-muted`,children:m(`Next, its poses are drawn from it in the background: working, waiting for you, done, something wrong.`)})]}),U===`choose`&&(0,E.jsx)(`button`,{type:`button`,disabled:I!==null,onClick:()=>void q(`cancel`,()=>g.avatarCancel(H.session)),className:`w-full py-1 text-center text-[13px] text-muted`,children:m(`Keep the current look`)})]}),U===`failed`&&H&&(0,E.jsxs)(`section`,{className:`rounded-3xl border border-border/70 bg-surface p-4 shadow-sm space-y-2`,children:[(0,E.jsx)(`h2`,{className:`text-[15px] font-semibold`,children:m(`That did not work`)}),(0,E.jsx)(`p`,{className:`text-[13px] text-muted`,children:m(H.message||`Nothing came back.`)}),(0,E.jsxs)(`button`,{type:`button`,disabled:I!==null,onClick:()=>void q(`retry`,()=>g.avatarStart(H.session)),className:e(`flex items-center justify-center gap-1.5 rounded-2xl border border-border px-4 py-2.5 text-[14px] font-medium text-muted disabled:opacity-40`,`rounded-full`),children:[(0,E.jsx)(ee,{size:14}),` `,m(`Try again`)]})]}),(0,E.jsx)(`p`,{className:`px-1 text-[12px] leading-snug text-muted`,children:m(`The pictures stay in this computer's workspace under avatar/. Each new look asks your provider for eight pictures (four to choose from and four poses) and four short clips where there is a video model.`)}),(0,E.jsx)(`p`,{className:`px-1 text-[12px] leading-snug text-muted`,children:(0,E.jsx)(`button`,{type:`button`,onClick:()=>{u(m(`Change your avatar to `)),a(`chat`)},className:`font-medium text-accent`,children:m(`Or just say it in the chat: “change your avatar to a corgi”.`)})})]})]})}function ie(e,t){return e?/dashscope|aliyuncs/.test(e)?t(`Alibaba Cloud Bailian`):/openai\.com/.test(e)?`OpenAI`:/deepseek/.test(e)?`DeepSeek`:/moonshot/.test(e)?`Moonshot`:/bigmodel|zhipu/.test(e)?t(`Zhipu`):/siliconflow/.test(e)?`SiliconFlow`:/volces|ark/.test(e)?t(`Volcano Ark`):/openrouter/.test(e)?`OpenRouter`:/googleapis/.test(e)?`Gemini`:/x\.ai/.test(e)?`xAI`:/^(127\.0\.0\.1|localhost)/.test(e)?t(`this computer`):e:`—`}function j({label:t,onClick:n,danger:r=!1}){return(0,E.jsx)(`button`,{type:`button`,onClick:n,className:e(`block w-full px-4 py-2.5 text-left hover:bg-surface-2`,r?`text-rose-600 dark:text-rose-300`:``),children:t})}function ae({avatar:e,emoji:n,color:r,name:i}){let a=t(),[o,s]=(0,T.useState)(0),l=D[o%D.length],f=(0,T.useRef)(0);(0,T.useEffect)(()=>(f.current=window.setTimeout(()=>s(e=>(e+1)%D.length),l===`idle`?2600:2e3),()=>window.clearTimeout(f.current)),[o,l]);let p=c(e),g=!p&&e?e:null,_=p?m(l):g?h(g,l):``,v=p?d(l):g?u(g,l):null,[y,b]=(0,T.useState)(()=>new Set),x=v&&!y.has(v)?v:null;return(0,E.jsxs)(E.Fragment,{children:[(0,E.jsx)(`div`,{className:`avatar-pop h-[148px] w-[148px] overflow-hidden rounded-full`,style:_?{background:`#f1efeb`}:{background:`linear-gradient(135deg, ${r??`#0064d4`}, color-mix(in srgb, ${r??`#0064d4`} 60%, #ffffff))`},children:x?(0,E.jsx)(`video`,{src:x,poster:_,autoPlay:!0,loop:!0,muted:!0,playsInline:!0,disablePictureInPicture:!0,onError:()=>b(e=>new Set(e).add(x)),className:`h-full w-full object-cover`},x):_?(0,E.jsx)(`img`,{src:_,alt:``,draggable:!1,className:`h-full w-full object-cover`}):(0,E.jsx)(`span`,{className:`flex h-full w-full items-center justify-center text-[64px] leading-none`,children:n??`✨`})},e),(0,E.jsx)(`div`,{className:`mt-3 text-[20px] font-semibold tracking-tight`,children:i}),(0,E.jsx)(`div`,{className:`mt-1 text-[13px] text-muted`,children:a(O[l])})]})}export{A as AvatarStudioScreen}; \ No newline at end of file +import{E as e,K as t,L as n,Q as r,S as i,Y as a,a as o,b as s,c,f as l,l as u,o as d,q as f,r as p,s as m,u as h,x as g}from"./MuseHeader-Pw-NI98v.js";import{C as _,t as v,w as y}from"./StarNudge-DjXecvWj.js";import{n as b}from"./external-link-Xj5fjR8v.js";import{i as x,o as S}from"./Form-DwKuBk1V.js";import{t as ee}from"./refresh-cw-BKgIzslL.js";import{W as C,ht as te}from"./index-CIdGZ5PB.js";import{t as ne}from"./BackBar-Dl56jHZM.js";import{n as w}from"./AvatarPicker-gR2knlot.js";var T=r(a(),1),E=s(),D=[`idle`,`working`,`waiting`,`happy`,`error`],O={idle:`Idle`,working:`Working`,waiting:`Waiting for you`,happy:`Done`,error:`Something went wrong`},re=4,k=`a round, custard-yellow baby dragon with small orange horns and folded little wings`;function A(){let{state:r,setTab:a,toast:s,draft:u,refreshSettings:d}=l(),m=t(),h=r.profile,O=h?.name??`nanoMuse`,[A,oe]=(0,T.useState)(null),[M,se]=(0,T.useState)(``),[N,ce]=(0,T.useState)(`muse`),[P,F]=(0,T.useState)(null),[I,L]=(0,T.useState)(null),[R,z]=(0,T.useState)(!1),[B,V]=(0,T.useState)(``),H=r.studio??A?.current??null,U=H?.stage??``,W=U===`drawing`,G=H?.candidates??[],K=(U===`drawing`||U===`choose`)&&G.length>0,le=()=>g.avatarView().then(oe,e=>s(e.message));(0,T.useEffect)(()=>{le()},[h?.avatar,r.settings?.llm.model,r.connectionsVersion]),(0,T.useEffect)(()=>{U!==`choose`&&F(null)},[U]);let q=async(e,t)=>{L(e),V(``);try{await t()}catch(e){V(e.message)}finally{L(null)}},ue=()=>q(`draw`,async()=>{let e=M.trim()||k,t=await g.avatarBegin(e,``,N);if(t.available===!1)throw Error(y(m,`image`,_(r.hub?.account),n()));t.cost?.cloud===!1&&t.session&&await g.avatarStart(t.session)}),de=()=>q(`reset`,async()=>{await g.updateSettings({profile:{avatar:o}}),await d(),s(m(`Back to the built-in look.`))}),J=A?.face??null,fe=!!h?.avatar&&!c(h.avatar),Y=H&&(U===`posing`||U===`animating`||U===`done`)&&H.face===h?.avatar,pe=Y?Object.keys(H.moods??{}).length:0,me=Y?Object.keys(H.clips??{}).length:0,X=Y?(H.errors??[]).filter(e=>!/clip/.test(e)).length:0,Z=H?.cost??{},Q=Z.clips?m(`{n} pictures and {c} clips`,{n:Z.pictures??8,c:Z.clips}):m(`{n} pictures`,{n:Z.pictures??8}),he=(()=>{if(Z.error)return m(`The cost could not be checked: {error}`,{error:Z.error});if(typeof Z.cny!=`number`)return m(`Checking the cost…`);if(Z.unlimited)return m(`About ¥{cny} for {what}; your account has no limit.`,{cny:Z.cny.toFixed(2),what:Q});let e=typeof Z.left_cny==`number`?Z.left_cny.toFixed(2):`?`;return Z.affordable===!1?m(`About ¥{cny} for {what}, more than the ¥{left} left in your allowance.`,{cny:Z.cny.toFixed(2),what:Q,left:e}):m(`About ¥{cny} for {what}; ¥{left} left in your allowance.`,{cny:Z.cny.toFixed(2),what:Q,left:e})})(),$=e=>w.find(t=>t.id===e)?.label,ge=A?.cloud?`nanoMuse Cloud`:ie(A?.host??``,m);return(0,E.jsxs)(`div`,{className:`flex h-full flex-col`,children:[(0,E.jsx)(ne,{title:m(`Avatar studio`),description:m(`Draw a look with your image model; it moves with what it is doing.`),actions:(0,E.jsxs)(`div`,{className:`relative`,children:[(0,E.jsx)(p,{small:!0,onClick:()=>z(e=>!e),label:m(`More`),expanded:R,children:(0,E.jsx)(te,{size:20})}),R&&(0,E.jsxs)(`div`,{className:`absolute right-0 z-20 mt-1 w-56 overflow-hidden rounded-2xl border border-border/70 bg-surface py-1 text-[14px] shadow-lg`,children:[(0,E.jsx)(j,{label:m(`Name & style`),onClick:()=>{z(!1),a(`you`)}}),(0,E.jsx)(j,{label:m(`Image model`),onClick:()=>{z(!1),a(`connections`)}}),fe&&(0,E.jsxs)(E.Fragment,{children:[(0,E.jsx)(j,{label:m(`Redraw the poses`),onClick:()=>{z(!1),q(`moods`,()=>g.avatarMoods())}}),(0,E.jsx)(j,{label:m(`Back to the built-in look`),danger:!0,onClick:()=>{z(!1),de()}})]})]})]})}),(0,E.jsxs)(`div`,{className:`flex-1 overflow-y-auto px-4 pb-8 space-y-5`,onClick:()=>R&&z(!1),children:[(0,E.jsxs)(`div`,{className:`flex flex-col items-center pt-2 text-center`,children:[(0,E.jsx)(ae,{avatar:h?.avatar,emoji:h?.emoji,color:h?.color,name:O}),J&&(0,E.jsx)(`div`,{className:`mt-0.5 max-w-sm text-[12.5px] text-muted`,children:[J.description,$(J.style)&&m($(J.style))].filter(Boolean).join(` · `)}),Y&&(0,E.jsxs)(`div`,{className:`mt-2.5 flex items-center gap-2 text-[13px] text-muted`,children:[U===`posing`&&(0,E.jsxs)(E.Fragment,{children:[(0,E.jsx)(f,{size:14,className:`animate-spin text-accent`}),(0,E.jsx)(`span`,{children:m(`Drawing the poses… {done}/{total}`,{done:pe,total:D.length})})]}),U===`animating`&&(0,E.jsxs)(E.Fragment,{children:[(0,E.jsx)(f,{size:14,className:`animate-spin text-accent`}),(0,E.jsx)(`span`,{children:m(`The new look is on; making the clips… {done}/{total}`,{done:me,total:re})})]}),U===`done`&&(0,E.jsxs)(E.Fragment,{children:[(0,E.jsx)(`span`,{children:X===0?m(`All five poses are in.`):m(`{done} of {total} poses are in; the rest show the main picture.`,{done:D.length-X,total:D.length})}),X>0&&(0,E.jsx)(`button`,{type:`button`,onClick:()=>void q(`moods`,()=>g.avatarMoods()),className:`font-medium text-accent`,children:m(`Retry`)})]})]})]}),U===`done`&&X===0&&(0,E.jsx)(v,{moment:`new_look`}),(0,E.jsxs)(`section`,{className:`rounded-3xl border border-border/70 bg-surface p-4 shadow-sm space-y-3`,children:[(0,E.jsxs)(`div`,{children:[(0,E.jsx)(`h2`,{className:`text-[17px] font-semibold`,children:m(`Describe a new look`)}),(0,E.jsx)(`p`,{className:`mt-0.5 text-[13px] leading-snug text-muted`,children:m(`One sentence is enough: what it is, what it wears, its air. Pick a style and your image model draws four to choose from.`)})]}),(0,E.jsx)(`textarea`,{value:M,onChange:e=>se(e.target.value),rows:2,maxLength:200,placeholder:m(k),className:`w-full resize-none rounded-2xl bg-surface-2 px-3.5 py-2.5 text-[14.5px] outline-none focus:ring-2 focus:ring-accent/40`}),(0,E.jsx)(`div`,{className:`flex flex-wrap gap-1.5`,children:w.map(t=>(0,E.jsx)(`button`,{type:`button`,onClick:()=>ce(t.id),className:e(`rounded-full px-3 py-1.5 text-[13px] font-medium transition`,N===t.id?`bg-fg text-bg`:`bg-surface-2 text-fg hover:bg-border/60`),children:m(t.label)},t.id))}),(0,E.jsxs)(`button`,{type:`button`,disabled:I!==null||W||A?.available===!1,onClick:()=>void ue(),className:e(x,`w-full rounded-full py-3`),children:[W||I===`draw`?(0,E.jsx)(f,{size:16,className:`animate-spin`}):(0,E.jsx)(C,{size:16}),m(W?`Drawing…`:K||U===`choose`?`Draw four more`:`Draw four`)]}),(0,E.jsxs)(`button`,{type:`button`,onClick:()=>a(`connections`),className:`flex w-full items-center justify-between gap-3 py-1 text-left text-[12.5px] text-muted`,children:[(0,E.jsx)(`span`,{className:`min-w-0 flex-1`,children:A===null?`…`:A.available?m(`Drawn by {provider} · {model}`,{provider:ge,model:A.image_model||`—`}):y(m,`image`,_(r.hub?.account),n())}),(0,E.jsx)(`span`,{className:`shrink-0 font-medium text-accent`,children:m(`Change model`)})]}),B&&(0,E.jsx)(`p`,{className:`text-[13px] text-rose-600 dark:text-rose-300`,children:B})]}),U===`estimate`&&H&&(0,E.jsxs)(`section`,{className:`rounded-3xl border border-accent/50 bg-surface p-4 shadow-sm space-y-3`,children:[(0,E.jsxs)(`div`,{children:[(0,E.jsx)(`h2`,{className:`text-[15px] font-semibold`,children:m(`A new look for {name}`,{name:O})}),(0,E.jsx)(`p`,{className:`mt-0.5 text-[13px] text-muted`,children:H.description})]}),(0,E.jsx)(`p`,{className:`text-[12.5px] text-muted`,children:he}),(0,E.jsxs)(`div`,{className:`flex gap-2`,children:[(0,E.jsxs)(`button`,{type:`button`,disabled:I!==null||typeof Z.cny!=`number`&&!Z.error,onClick:()=>void q(`start`,()=>g.avatarStart(H.session)),className:e(`flex items-center justify-center gap-1.5 rounded-2xl bg-accent text-accent-fg px-4 py-2.5 text-[14px] font-medium disabled:opacity-40`,`rounded-full`),children:[I===`start`?(0,E.jsx)(f,{size:14,className:`animate-spin`}):(0,E.jsx)(C,{size:14}),` `,m(`Draw`)]}),(0,E.jsxs)(`button`,{type:`button`,disabled:I!==null,onClick:()=>void q(`cancel`,()=>g.avatarCancel(H.session)),className:e(`flex items-center justify-center gap-1.5 rounded-2xl border border-border px-4 py-2.5 text-[14px] font-medium text-muted disabled:opacity-40`,`rounded-full`),children:[(0,E.jsx)(S,{size:14}),` `,m(`Not now`)]})]})]}),K&&H&&(0,E.jsxs)(`section`,{className:`space-y-3 px-1`,children:[(0,E.jsxs)(`div`,{children:[(0,E.jsx)(`h2`,{className:`text-[17px] font-semibold`,children:m(`Pick one`)}),(0,E.jsx)(`p`,{className:`mt-0.5 text-[13px] leading-snug text-muted`,children:m(`Draw four more any time; the old ones stay until you do.`)})]}),(0,E.jsx)(`div`,{className:`grid grid-cols-2 gap-3 wide:grid-cols-4`,children:G.map((t,n)=>(0,E.jsxs)(`button`,{type:`button`,disabled:!t||U!==`choose`,onClick:()=>F(e=>e===n?null:n),"aria-label":m(`Candidate {n}`,{n:n+1}),"aria-pressed":P===n,className:e(`relative aspect-square overflow-hidden rounded-[20px] bg-[#f1efeb] transition`,P===n?`ring-[3px] ring-accent`:t&&U===`choose`?`hover:ring-2 hover:ring-accent/60`:``),children:[t?(0,E.jsx)(`img`,{src:i(t),alt:``,draggable:!1,className:`h-full w-full object-cover`}):(0,E.jsx)(`span`,{className:`absolute inset-0 flex items-center justify-center text-muted`,children:W?(0,E.jsx)(f,{size:22,className:`animate-spin`}):(0,E.jsx)(S,{size:18,className:`opacity-50`})}),P===n&&(0,E.jsx)(`span`,{className:`absolute right-2 top-2 flex h-7 w-7 items-center justify-center rounded-full bg-accent text-accent-fg shadow`,children:(0,E.jsx)(b,{size:16})})]},n))}),H.errors&&H.errors.length>0&&U===`choose`&&(0,E.jsx)(`p`,{className:`text-[12.5px] text-rose-600 dark:text-rose-300`,children:m(H.errors[0])}),P!==null&&U===`choose`&&(0,E.jsxs)(`div`,{className:`space-y-1.5 pt-1`,children:[(0,E.jsxs)(`button`,{type:`button`,disabled:I!==null,onClick:()=>void q(`choose`,()=>g.avatarChoose(H.session,P)),className:e(`flex items-center justify-center gap-1.5 rounded-2xl bg-accent text-accent-fg px-4 py-2.5 text-[14px] font-medium disabled:opacity-40`,`w-full rounded-full py-3`),children:[I===`choose`?(0,E.jsx)(f,{size:16,className:`animate-spin`}):(0,E.jsx)(b,{size:16}),` `,m(`Use this one`)]}),(0,E.jsx)(`p`,{className:`text-center text-[12px] leading-snug text-muted`,children:m(`Next, its poses are drawn from it in the background: working, waiting for you, done, something wrong.`)})]}),U===`choose`&&(0,E.jsx)(`button`,{type:`button`,disabled:I!==null,onClick:()=>void q(`cancel`,()=>g.avatarCancel(H.session)),className:`w-full py-1 text-center text-[13px] text-muted`,children:m(`Keep the current look`)})]}),U===`failed`&&H&&(0,E.jsxs)(`section`,{className:`rounded-3xl border border-border/70 bg-surface p-4 shadow-sm space-y-2`,children:[(0,E.jsx)(`h2`,{className:`text-[15px] font-semibold`,children:m(`That did not work`)}),(0,E.jsx)(`p`,{className:`text-[13px] text-muted`,children:m(H.message||`Nothing came back.`)}),(0,E.jsxs)(`button`,{type:`button`,disabled:I!==null,onClick:()=>void q(`retry`,()=>g.avatarStart(H.session)),className:e(`flex items-center justify-center gap-1.5 rounded-2xl border border-border px-4 py-2.5 text-[14px] font-medium text-muted disabled:opacity-40`,`rounded-full`),children:[(0,E.jsx)(ee,{size:14}),` `,m(`Try again`)]})]}),(0,E.jsx)(`p`,{className:`px-1 text-[12px] leading-snug text-muted`,children:m(`The pictures stay in this computer's workspace under avatar/. Each new look asks your provider for eight pictures (four to choose from and four poses) and four short clips where there is a video model.`)}),(0,E.jsx)(`p`,{className:`px-1 text-[12px] leading-snug text-muted`,children:(0,E.jsx)(`button`,{type:`button`,onClick:()=>{u(m(`Change your avatar to `)),a(`chat`)},className:`font-medium text-accent`,children:m(`Or just say it in the chat: “change your avatar to a corgi”.`)})})]})]})}function ie(e,t){return e?/dashscope|aliyuncs/.test(e)?t(`Alibaba Cloud Bailian`):/openai\.com/.test(e)?`OpenAI`:/deepseek/.test(e)?`DeepSeek`:/moonshot/.test(e)?`Moonshot`:/bigmodel|zhipu/.test(e)?t(`Zhipu`):/siliconflow/.test(e)?`SiliconFlow`:/volces|ark/.test(e)?t(`Volcano Ark`):/openrouter/.test(e)?`OpenRouter`:/googleapis/.test(e)?`Gemini`:/x\.ai/.test(e)?`xAI`:/^(127\.0\.0\.1|localhost)/.test(e)?t(`this computer`):e:`—`}function j({label:t,onClick:n,danger:r=!1}){return(0,E.jsx)(`button`,{type:`button`,onClick:n,className:e(`block w-full px-4 py-2.5 text-left hover:bg-surface-2`,r?`text-rose-600 dark:text-rose-300`:``),children:t})}function ae({avatar:e,emoji:n,color:r,name:i}){let a=t(),[o,s]=(0,T.useState)(0),l=D[o%D.length],f=(0,T.useRef)(0);(0,T.useEffect)(()=>(f.current=window.setTimeout(()=>s(e=>(e+1)%D.length),l===`idle`?2600:2e3),()=>window.clearTimeout(f.current)),[o,l]);let p=c(e),g=!p&&e?e:null,_=p?m(l):g?h(g,l):``,v=p?d(l):g?u(g,l):null,[y,b]=(0,T.useState)(()=>new Set),x=v&&!y.has(v)?v:null;return(0,E.jsxs)(E.Fragment,{children:[(0,E.jsx)(`div`,{className:`avatar-pop h-[148px] w-[148px] overflow-hidden rounded-full`,style:_?{background:`#f1efeb`}:{background:`linear-gradient(135deg, ${r??`#0064d4`}, color-mix(in srgb, ${r??`#0064d4`} 60%, #ffffff))`},children:x?(0,E.jsx)(`video`,{src:x,poster:_,autoPlay:!0,loop:!0,muted:!0,playsInline:!0,disablePictureInPicture:!0,onError:()=>b(e=>new Set(e).add(x)),className:`h-full w-full object-cover`},x):_?(0,E.jsx)(`img`,{src:_,alt:``,draggable:!1,className:`h-full w-full object-cover`}):(0,E.jsx)(`span`,{className:`flex h-full w-full items-center justify-center text-[64px] leading-none`,children:n??`✨`})},e),(0,E.jsx)(`div`,{className:`mt-3 text-[20px] font-semibold tracking-tight`,children:i}),(0,E.jsx)(`div`,{className:`mt-1 text-[13px] text-muted`,children:a(O[l])})]})}export{A as AvatarStudioScreen}; \ No newline at end of file diff --git a/nanomuse/server/static/assets/BackBar-Dli0L0O_.js b/nanomuse/server/static/assets/BackBar-Dl56jHZM.js similarity index 92% rename from nanomuse/server/static/assets/BackBar-Dli0L0O_.js rename to nanomuse/server/static/assets/BackBar-Dl56jHZM.js index 650184c79..b084e5e81 100644 --- a/nanomuse/server/static/assets/BackBar-Dli0L0O_.js +++ b/nanomuse/server/static/assets/BackBar-Dl56jHZM.js @@ -1 +1 @@ -import{K as e,b as t,f as n,r}from"./MuseHeader-Pw-NI98v.js";import{Dt as i}from"./index-BjYzdKkG.js";var a=t();function o({title:t,description:o,actions:s,onBack:c,backLabel:l}){let{setTab:u}=n(),d=e();return(0,a.jsxs)(`header`,{className:`safe-top shrink-0`,children:[(0,a.jsxs)(`div`,{className:`relative flex h-14 items-center justify-center px-3`,children:[(0,a.jsx)(`div`,{className:`absolute left-3 top-1/2 -translate-y-1/2`,children:(0,a.jsx)(r,{small:!0,onClick:c??(()=>u(`chat`)),label:l??d(`Back`),children:(0,a.jsx)(i,{size:20})})}),(0,a.jsx)(`h1`,{className:`max-w-[calc(100%-128px)] truncate text-[17px] font-semibold leading-[22px]`,children:t}),s&&(0,a.jsx)(`div`,{className:`absolute right-3 top-1/2 flex -translate-y-1/2 items-center gap-2`,children:s})]}),o&&(0,a.jsx)(`p`,{className:`px-5 pb-2 text-[13px] leading-[18px] text-muted`,children:o})]})}export{o as t}; \ No newline at end of file +import{K as e,b as t,f as n,r}from"./MuseHeader-Pw-NI98v.js";import{Dt as i}from"./index-CIdGZ5PB.js";var a=t();function o({title:t,description:o,actions:s,onBack:c,backLabel:l}){let{setTab:u}=n(),d=e();return(0,a.jsxs)(`header`,{className:`safe-top shrink-0`,children:[(0,a.jsxs)(`div`,{className:`relative flex h-14 items-center justify-center px-3`,children:[(0,a.jsx)(`div`,{className:`absolute left-3 top-1/2 -translate-y-1/2`,children:(0,a.jsx)(r,{small:!0,onClick:c??(()=>u(`chat`)),label:l??d(`Back`),children:(0,a.jsx)(i,{size:20})})}),(0,a.jsx)(`h1`,{className:`max-w-[calc(100%-128px)] truncate text-[17px] font-semibold leading-[22px]`,children:t}),s&&(0,a.jsx)(`div`,{className:`absolute right-3 top-1/2 flex -translate-y-1/2 items-center gap-2`,children:s})]}),o&&(0,a.jsx)(`p`,{className:`px-5 pb-2 text-[13px] leading-[18px] text-muted`,children:o})]})}export{o as t}; \ No newline at end of file diff --git a/nanomuse/server/static/assets/ChannelsScreen-Bt6eBqvc.js b/nanomuse/server/static/assets/ChannelsScreen-mBzj7BLf.js similarity index 99% rename from nanomuse/server/static/assets/ChannelsScreen-Bt6eBqvc.js rename to nanomuse/server/static/assets/ChannelsScreen-mBzj7BLf.js index eb8c6755e..c43a8d030 100644 --- a/nanomuse/server/static/assets/ChannelsScreen-Bt6eBqvc.js +++ b/nanomuse/server/static/assets/ChannelsScreen-mBzj7BLf.js @@ -1,2 +1,2 @@ -import{E as e,J as t,K as n,Q as r,Y as i,b as a,f as o,q as s,w as c}from"./MuseHeader-Pw-NI98v.js";import{n as l,t as u}from"./external-link-Xj5fjR8v.js";import{a as d,i as f,o as p,r as m}from"./Form-DwKuBk1V.js";import{t as h}from"./refresh-cw-BKgIzslL.js";import{C as g,V as _,Y as v,a as y,at as b,c as x,i as S,l as C,o as w,s as T}from"./index-BjYzdKkG.js";import{t as E}from"./BackBar-Dli0L0O_.js";var D=t(`qr-code`,[[`rect`,{width:`5`,height:`5`,x:`3`,y:`3`,rx:`1`,key:`1tu5fj`}],[`rect`,{width:`5`,height:`5`,x:`16`,y:`3`,rx:`1`,key:`1v8r4q`}],[`rect`,{width:`5`,height:`5`,x:`3`,y:`16`,rx:`1`,key:`1x03jg`}],[`path`,{d:`M21 16h-3a2 2 0 0 0-2 2v3`,key:`177gqh`}],[`path`,{d:`M21 21v.01`,key:`ents32`}],[`path`,{d:`M12 7v3a2 2 0 0 1-2 2H7`,key:`8crl2c`}],[`path`,{d:`M3 12h.01`,key:`nlz23k`}],[`path`,{d:`M12 3h.01`,key:`n36tog`}],[`path`,{d:`M12 16v.01`,key:`133mhm`}],[`path`,{d:`M16 12h1`,key:`1slzba`}],[`path`,{d:`M21 12v.01`,key:`1lwtk9`}],[`path`,{d:`M12 21v-1`,key:`1880an`}]]),O=r(i(),1),k=(e,t)=>({method:e,body:JSON.stringify(t)}),A=encodeURIComponent,j={view:()=>c(`/api/channels`),update:(e,t)=>c(`/api/channels/${A(e)}`,k(`PUT`,t)),reload:()=>c(`/api/channels/reload`,{method:`POST`}),test:(e,t=``)=>c(`/api/channels/${A(e)}/test`,k(`POST`,{chat_id:t})),approve:e=>c(`/api/channels/pairing/${A(e)}/approve`,{method:`POST`}),deny:e=>c(`/api/channels/pairing/${A(e)}/deny`,{method:`POST`}),setDeliver:(e,t,n)=>c(`/api/channels/${A(e)}/chats/${A(t)}`,k(`PUT`,{deliver:n})),removeChat:(e,t)=>c(`/api/channels/${A(e)}/chats/${A(t)}`,{method:`DELETE`}),loginBegin:(e,t)=>c(`/api/channels/${A(e)}/login`,k(`POST`,{domain:t})),loginPoll:(e,t)=>c(`/api/channels/${A(e)}/login/${A(t)}`),deliver:e=>c(`/api/channels/deliver`,k(`POST`,{text:e}))},M=a(),N={feishu:[`In the Feishu developer console create a custom app and add the Bot capability.`,`Permissions: im:message, im:message.p2p_msg:readonly, im:message.group_at_msg:readonly, im:resource.`,`Events & callbacks: subscription mode Long connection; add im.message.receive_v1; callback mode Long connection; add card.action.trigger.`,`Copy App ID and App Secret from Credentials & Basic Info, then publish a version.`],dingtalk:[`In the DingTalk developer console create an internal app and add the Robot capability.`,`Set the message receive mode to Stream.`,`Copy Client ID (AppKey) and Client Secret (AppSecret) from Credentials & Basic Info.`,`Add the robot send-message permission and publish the version.`],wecom:[`In the WeCom admin console open Intelligent robot and create a robot in API mode with a long connection.`,`Copy the Bot ID and Secret.`,`Add the robot to the chats where it should listen.`],telegram:[`In Telegram talk to @BotFather, send /newbot and copy the token.`,`Direct messages work at once. For a group, add the bot to it; with Group Privacy on it only hears @-mentions and replies.`,`If api.telegram.org is out of reach from this computer, set a proxy below.`]},P={telegram:(0,M.jsx)(v,{size:20})};function F(e,t){let n=t.status.state;return e(n===`off`?`Off`:n===`unconfigured`?`Needs settings`:n===`missing_sdk`?`Not installed`:n===`connecting`?`Connecting…`:n===`connected`?`Connected`:`Error`)}function I({state:t}){return(0,M.jsx)(`span`,{"aria-hidden":!0,className:e(`inline-block h-2 w-2 rounded-full`,t===`connected`?`bg-emerald-500`:t===`error`?`bg-red-500`:t===`connecting`?`bg-amber-400`:`bg-border`)})}function L(){let{toast:e}=o(),t=n(),[r,i]=(0,O.useState)(null),[a,c]=(0,O.useState)(null),l=async()=>{try{i(await j.view()),c(null)}catch(e){c(e.message||`Could not load.`)}};(0,O.useEffect)(()=>{l();let e=window.setInterval(()=>void l(),5e3),t=()=>void l();return window.addEventListener(`focus`,t),()=>{window.clearInterval(e),window.removeEventListener(`focus`,t)}},[]);let u=async(t,n)=>{try{i(await t()),n&&e(n)}catch(t){e(t.message)}};return(0,M.jsxs)(`div`,{className:`flex h-full flex-col`,children:[(0,M.jsx)(E,{title:t(`Chat apps`),description:t(`Talk to your Muse from the chat apps you already use. Nothing needs a public address: each app keeps a long connection open.`)}),(0,M.jsxs)(`div`,{className:`flex-1 overflow-y-auto pb-8`,children:[r===null&&a&&(0,M.jsx)(g,{message:a,onRetry:()=>void l()}),r===null&&!a&&(0,M.jsx)(`div`,{className:`flex justify-center py-10 text-muted`,children:(0,M.jsx)(s,{className:`animate-spin`,size:20})}),r&&r.pending.length>0&&(0,M.jsxs)(M.Fragment,{children:[(0,M.jsx)(x,{children:t(`Waiting for a yes`)}),(0,M.jsx)(y,{children:r.pending.map((e,t)=>(0,M.jsxs)(`div`,{children:[t>0&&(0,M.jsx)(w,{inset:16}),(0,M.jsx)(R,{p:e,label:r.channels.find(t=>t.name===e.channel)?.label??e.channel,onApprove:()=>u(()=>j.approve(e.code)),onDeny:()=>u(()=>j.deny(e.code))})]},e.code))})]}),r?.channels.map(e=>(0,M.jsx)(z,{c:e,run:u,reload:l},e.name)),r&&(0,M.jsx)(S,{children:t(`Each chat is one conversation of your Muse; its replies stream back as they are written.`)})]})]})}function R({p:t,label:r,onApprove:i,onDeny:a}){let o=n(),s=t.sender_name||t.sender_id;return(0,M.jsxs)(`div`,{className:`flex items-center gap-3 px-4 py-3`,children:[(0,M.jsxs)(`div`,{className:`min-w-0 flex-1`,children:[(0,M.jsx)(`p`,{className:`truncate text-[15px]`,children:o(`{name} wrote to the bot. Approve to let them talk to your Muse.`,{name:`${s} · ${r}`})}),(0,M.jsx)(`p`,{className:`text-[13px] text-muted`,children:o(`Code {code}`,{code:t.code})})]}),(0,M.jsxs)(`button`,{type:`button`,className:e(f,`px-3 py-2`),onClick:i,"aria-label":o(`Approve`),children:[(0,M.jsx)(l,{size:16}),` `,o(`Approve`)]}),(0,M.jsx)(`button`,{type:`button`,className:e(d,`px-3 py-2`),onClick:a,"aria-label":o(`Deny`),children:(0,M.jsx)(p,{size:16})})]})}function z({c:t,run:r,reload:i}){let a=n(),{toast:s}=o(),[c,l]=(0,O.useState)(!1),[d,f]=(0,O.useState)({}),[p,m]=(0,O.useState)([]),[g,v]=(0,O.useState)(null),[E,k]=(0,O.useState)(!1),[A,L]=(0,O.useState)(!1),[R,z]=(0,O.useState)(!1),[V,H]=(0,O.useState)(null),[U,W]=(0,O.useState)(``),[G,K]=(0,O.useState)(!1),q=(0,O.useRef)(null),J=Object.keys(d).length>0||g!==null,Y=g??t.allow_from.join(` +import{E as e,J as t,K as n,Q as r,Y as i,b as a,f as o,q as s,w as c}from"./MuseHeader-Pw-NI98v.js";import{n as l,t as u}from"./external-link-Xj5fjR8v.js";import{a as d,i as f,o as p,r as m}from"./Form-DwKuBk1V.js";import{t as h}from"./refresh-cw-BKgIzslL.js";import{C as g,V as _,Y as v,a as y,at as b,c as x,i as S,l as C,o as w,s as T}from"./index-CIdGZ5PB.js";import{t as E}from"./BackBar-Dl56jHZM.js";var D=t(`qr-code`,[[`rect`,{width:`5`,height:`5`,x:`3`,y:`3`,rx:`1`,key:`1tu5fj`}],[`rect`,{width:`5`,height:`5`,x:`16`,y:`3`,rx:`1`,key:`1v8r4q`}],[`rect`,{width:`5`,height:`5`,x:`3`,y:`16`,rx:`1`,key:`1x03jg`}],[`path`,{d:`M21 16h-3a2 2 0 0 0-2 2v3`,key:`177gqh`}],[`path`,{d:`M21 21v.01`,key:`ents32`}],[`path`,{d:`M12 7v3a2 2 0 0 1-2 2H7`,key:`8crl2c`}],[`path`,{d:`M3 12h.01`,key:`nlz23k`}],[`path`,{d:`M12 3h.01`,key:`n36tog`}],[`path`,{d:`M12 16v.01`,key:`133mhm`}],[`path`,{d:`M16 12h1`,key:`1slzba`}],[`path`,{d:`M21 12v.01`,key:`1lwtk9`}],[`path`,{d:`M12 21v-1`,key:`1880an`}]]),O=r(i(),1),k=(e,t)=>({method:e,body:JSON.stringify(t)}),A=encodeURIComponent,j={view:()=>c(`/api/channels`),update:(e,t)=>c(`/api/channels/${A(e)}`,k(`PUT`,t)),reload:()=>c(`/api/channels/reload`,{method:`POST`}),test:(e,t=``)=>c(`/api/channels/${A(e)}/test`,k(`POST`,{chat_id:t})),approve:e=>c(`/api/channels/pairing/${A(e)}/approve`,{method:`POST`}),deny:e=>c(`/api/channels/pairing/${A(e)}/deny`,{method:`POST`}),setDeliver:(e,t,n)=>c(`/api/channels/${A(e)}/chats/${A(t)}`,k(`PUT`,{deliver:n})),removeChat:(e,t)=>c(`/api/channels/${A(e)}/chats/${A(t)}`,{method:`DELETE`}),loginBegin:(e,t)=>c(`/api/channels/${A(e)}/login`,k(`POST`,{domain:t})),loginPoll:(e,t)=>c(`/api/channels/${A(e)}/login/${A(t)}`),deliver:e=>c(`/api/channels/deliver`,k(`POST`,{text:e}))},M=a(),N={feishu:[`In the Feishu developer console create a custom app and add the Bot capability.`,`Permissions: im:message, im:message.p2p_msg:readonly, im:message.group_at_msg:readonly, im:resource.`,`Events & callbacks: subscription mode Long connection; add im.message.receive_v1; callback mode Long connection; add card.action.trigger.`,`Copy App ID and App Secret from Credentials & Basic Info, then publish a version.`],dingtalk:[`In the DingTalk developer console create an internal app and add the Robot capability.`,`Set the message receive mode to Stream.`,`Copy Client ID (AppKey) and Client Secret (AppSecret) from Credentials & Basic Info.`,`Add the robot send-message permission and publish the version.`],wecom:[`In the WeCom admin console open Intelligent robot and create a robot in API mode with a long connection.`,`Copy the Bot ID and Secret.`,`Add the robot to the chats where it should listen.`],telegram:[`In Telegram talk to @BotFather, send /newbot and copy the token.`,`Direct messages work at once. For a group, add the bot to it; with Group Privacy on it only hears @-mentions and replies.`,`If api.telegram.org is out of reach from this computer, set a proxy below.`]},P={telegram:(0,M.jsx)(v,{size:20})};function F(e,t){let n=t.status.state;return e(n===`off`?`Off`:n===`unconfigured`?`Needs settings`:n===`missing_sdk`?`Not installed`:n===`connecting`?`Connecting…`:n===`connected`?`Connected`:`Error`)}function I({state:t}){return(0,M.jsx)(`span`,{"aria-hidden":!0,className:e(`inline-block h-2 w-2 rounded-full`,t===`connected`?`bg-emerald-500`:t===`error`?`bg-red-500`:t===`connecting`?`bg-amber-400`:`bg-border`)})}function L(){let{toast:e}=o(),t=n(),[r,i]=(0,O.useState)(null),[a,c]=(0,O.useState)(null),l=async()=>{try{i(await j.view()),c(null)}catch(e){c(e.message||`Could not load.`)}};(0,O.useEffect)(()=>{l();let e=window.setInterval(()=>void l(),5e3),t=()=>void l();return window.addEventListener(`focus`,t),()=>{window.clearInterval(e),window.removeEventListener(`focus`,t)}},[]);let u=async(t,n)=>{try{i(await t()),n&&e(n)}catch(t){e(t.message)}};return(0,M.jsxs)(`div`,{className:`flex h-full flex-col`,children:[(0,M.jsx)(E,{title:t(`Chat apps`),description:t(`Talk to your Muse from the chat apps you already use. Nothing needs a public address: each app keeps a long connection open.`)}),(0,M.jsxs)(`div`,{className:`flex-1 overflow-y-auto pb-8`,children:[r===null&&a&&(0,M.jsx)(g,{message:a,onRetry:()=>void l()}),r===null&&!a&&(0,M.jsx)(`div`,{className:`flex justify-center py-10 text-muted`,children:(0,M.jsx)(s,{className:`animate-spin`,size:20})}),r&&r.pending.length>0&&(0,M.jsxs)(M.Fragment,{children:[(0,M.jsx)(x,{children:t(`Waiting for a yes`)}),(0,M.jsx)(y,{children:r.pending.map((e,t)=>(0,M.jsxs)(`div`,{children:[t>0&&(0,M.jsx)(w,{inset:16}),(0,M.jsx)(R,{p:e,label:r.channels.find(t=>t.name===e.channel)?.label??e.channel,onApprove:()=>u(()=>j.approve(e.code)),onDeny:()=>u(()=>j.deny(e.code))})]},e.code))})]}),r?.channels.map(e=>(0,M.jsx)(z,{c:e,run:u,reload:l},e.name)),r&&(0,M.jsx)(S,{children:t(`Each chat is one conversation of your Muse; its replies stream back as they are written.`)})]})]})}function R({p:t,label:r,onApprove:i,onDeny:a}){let o=n(),s=t.sender_name||t.sender_id;return(0,M.jsxs)(`div`,{className:`flex items-center gap-3 px-4 py-3`,children:[(0,M.jsxs)(`div`,{className:`min-w-0 flex-1`,children:[(0,M.jsx)(`p`,{className:`truncate text-[15px]`,children:o(`{name} wrote to the bot. Approve to let them talk to your Muse.`,{name:`${s} · ${r}`})}),(0,M.jsx)(`p`,{className:`text-[13px] text-muted`,children:o(`Code {code}`,{code:t.code})})]}),(0,M.jsxs)(`button`,{type:`button`,className:e(f,`px-3 py-2`),onClick:i,"aria-label":o(`Approve`),children:[(0,M.jsx)(l,{size:16}),` `,o(`Approve`)]}),(0,M.jsx)(`button`,{type:`button`,className:e(d,`px-3 py-2`),onClick:a,"aria-label":o(`Deny`),children:(0,M.jsx)(p,{size:16})})]})}function z({c:t,run:r,reload:i}){let a=n(),{toast:s}=o(),[c,l]=(0,O.useState)(!1),[d,f]=(0,O.useState)({}),[p,m]=(0,O.useState)([]),[g,v]=(0,O.useState)(null),[E,k]=(0,O.useState)(!1),[A,L]=(0,O.useState)(!1),[R,z]=(0,O.useState)(!1),[V,H]=(0,O.useState)(null),[U,W]=(0,O.useState)(``),[G,K]=(0,O.useState)(!1),q=(0,O.useRef)(null),J=Object.keys(d).length>0||g!==null,Y=g??t.allow_from.join(` `),X=async()=>{k(!0);try{let e={},n={};for(let[e,r]of Object.entries(d))(t.fields.find(t=>t.key===e)?.kind!==`secret`||r!==``||p.includes(e))&&(n[e]=r);Object.keys(n).length&&(e.settings=n),g!==null&&(e.allow_from=g.split(/[\n,]/).map(e=>e.trim()).filter(Boolean)),await r(()=>j.update(t.name,e),a(`Saved.`)),f({}),m([]),v(null)}finally{k(!1)}},Z=async()=>{L(!0);try{let e=await j.test(t.name);s(e.detail)}catch(e){s(e.message)}finally{L(!1)}},Q=()=>{q.current!==null&&window.clearTimeout(q.current),q.current=null};(0,O.useEffect)(()=>Q,[]);let $=async()=>{W(``);try{let e=await j.loginBegin(t.name,G?`lark`:`feishu`);H(e);let n=Date.now(),r=async()=>{try{let r=await j.loginPoll(t.name,e.device_code);if(r.status===`succeeded`){H(null),W(a(`The bot was created and is connecting.`)),await i();return}if(r.status===`failed`||Date.now()-n>e.expires_in*1e3){H(null),W(a(`The login did not finish ({error}).`,{error:r.error??`expired`}));return}}catch(e){H(null),W(e.message);return}q.current=window.setTimeout(()=>void r(),Math.max(2,e.interval)*1e3)};q.current=window.setTimeout(()=>void r(),Math.max(2,e.interval)*1e3)}catch(e){s(e.message)}},ee=()=>{Q(),H(null)},te=t.fields.filter(e=>e.required&&(e.kind===`secret`?!e.has_value:!e.value)).map(e=>e.label);return(0,M.jsxs)(M.Fragment,{children:[(0,M.jsx)(x,{children:t.label}),(0,M.jsxs)(y,{children:[(0,M.jsx)(T,{icon:P[t.name]??(0,M.jsx)(b,{size:20}),label:t.label,value:F(a,t),trailing:(0,M.jsx)(I,{state:t.status.state}),onClick:()=>l(e=>!e)}),(0,M.jsx)(w,{}),(0,M.jsx)(C,{label:a(`Switched on`),checked:t.enabled,disabled:!t.sdk_available&&!t.enabled,onChange:e=>void r(()=>j.update(t.name,{enabled:e}))}),t.status.state===`error`&&t.status.detail&&(0,M.jsx)(`p`,{className:`px-4 pb-3 text-[13px] leading-[18px] text-red-600 dark:text-red-400`,children:t.status.detail}),t.status.state===`unconfigured`&&(0,M.jsxs)(`p`,{className:`px-4 pb-3 text-[13px] leading-[18px] text-muted`,children:[a(`Missing`),`: `,t.status.detail||te.join(`, `)]}),!t.sdk_available&&(0,M.jsxs)(`div`,{className:`px-4 pb-3 text-[13px] leading-[18px] text-muted`,children:[a(`Install on the computer running nanoMuse, then switch it on again:`),(0,M.jsx)(`code`,{className:`mt-1 block select-all rounded-lg bg-surface-2 px-2 py-1 text-[12.5px] text-fg`,children:t.install})]}),(c||t.enabled)&&(0,M.jsxs)(M.Fragment,{children:[(0,M.jsx)(w,{inset:16}),(0,M.jsxs)(`div`,{className:`space-y-3 px-4 py-3`,children:[t.fields.map(e=>(0,M.jsx)(B,{f:e,value:d[e.key],onChange:t=>{f(n=>({...n,[e.key]:t})),t!==``&&m(t=>t.filter(t=>t!==e.key))},onClear:()=>{f(t=>({...t,[e.key]:``})),m(t=>t.includes(e.key)?t:[...t,e.key])}},e.key)),(0,M.jsxs)(`label`,{className:`block`,children:[(0,M.jsx)(`span`,{className:`mb-1 block text-[13px] text-muted`,children:a(`In groups, reply`)}),(0,M.jsxs)(`select`,{className:`w-full rounded-2xl bg-surface-2 px-3.5 py-2.5 text-[14.5px] outline-none focus:ring-2 focus:ring-accent/40`,value:t.group_policy,onChange:e=>void r(()=>j.update(t.name,{group_policy:e.target.value})),children:[(0,M.jsx)(`option`,{value:`mention`,children:a(`only when @-mentioned`)}),(0,M.jsx)(`option`,{value:`open`,children:a(`to every message`)})]})]}),(0,M.jsxs)(`label`,{className:`block`,children:[(0,M.jsx)(`span`,{className:`mb-1 block text-[13px] text-muted`,children:a(`Always allowed (ids, one per line)`)}),(0,M.jsx)(`textarea`,{className:e(`w-full rounded-2xl bg-surface-2 px-3.5 py-2.5 text-[14.5px] outline-none focus:ring-2 focus:ring-accent/40`,`min-h-[56px] font-mono text-[13px]`),value:Y,onChange:e=>v(e.target.value),rows:2}),(0,M.jsx)(`span`,{className:`mt-1 block text-[12.5px] leading-[17px] text-muted`,children:a(`People listed here never need a pairing code. A lone * lets anyone in; do that only on a bot nobody else can reach.`)})]}),(0,M.jsxs)(`div`,{className:`flex flex-wrap gap-2`,children:[(0,M.jsx)(`button`,{type:`button`,className:`flex items-center justify-center gap-1.5 rounded-2xl bg-accent text-accent-fg px-4 py-2.5 text-[14px] font-medium disabled:opacity-40`,disabled:!J||E,onClick:()=>void X(),children:a(E?`Saving`:`Save`)}),(0,M.jsxs)(`button`,{type:`button`,className:`flex items-center justify-center gap-1.5 rounded-2xl border border-border px-4 py-2.5 text-[14px] font-medium text-muted disabled:opacity-40`,disabled:A||t.status.state!==`connected`,onClick:()=>void Z(),children:[(0,M.jsx)(h,{size:14,className:A?`animate-spin`:``}),` `,a(A?`Sending`:`Send a test message`)]}),t.name===`feishu`&&!V&&(0,M.jsxs)(`button`,{type:`button`,className:`flex items-center justify-center gap-1.5 rounded-2xl border border-border px-4 py-2.5 text-[14px] font-medium text-muted disabled:opacity-40`,onClick:()=>void $(),children:[(0,M.jsx)(D,{size:14}),` `,a(`Create the bot by QR code`)]}),(0,M.jsx)(`button`,{type:`button`,className:`flex items-center justify-center gap-1.5 rounded-2xl border border-border px-4 py-2.5 text-[14px] font-medium text-muted disabled:opacity-40`,onClick:()=>z(e=>!e),"aria-expanded":R,children:a(`Set up`)})]}),t.name===`feishu`&&!V&&(0,M.jsxs)(`label`,{className:`flex items-center gap-2 text-[13px] text-muted`,children:[(0,M.jsx)(`input`,{type:`checkbox`,checked:G,onChange:e=>K(e.target.checked)}),a(`Lark (international) instead of 飞书`)]}),V&&(0,M.jsxs)(`div`,{className:`rounded-2xl bg-surface-2 p-3 text-center`,children:[V.qr_png?(0,M.jsx)(`img`,{src:`data:image/png;base64,${V.qr_png}`,alt:`QR`,className:`mx-auto h-44 w-44 rounded-lg bg-white p-1`}):null,(0,M.jsx)(`p`,{className:`mt-2 text-[13px] text-muted`,children:a(`Scan with Feishu, confirm the new bot, and the App ID and Secret are saved for you.`)}),(0,M.jsx)(`p`,{className:`text-[13px] text-muted`,children:a(`Waiting for the scan…`)}),(0,M.jsxs)(`div`,{className:`mt-2 flex justify-center gap-2`,children:[(0,M.jsxs)(`a`,{href:V.url,target:`_blank`,rel:`noreferrer`,className:e(`flex items-center justify-center gap-1.5 rounded-2xl border border-border px-4 py-2.5 text-[14px] font-medium text-muted disabled:opacity-40`,`px-3 py-1.5`),children:[(0,M.jsx)(u,{size:14}),` `,a(`Open in Feishu`)]}),(0,M.jsx)(`button`,{type:`button`,className:e(`flex items-center justify-center gap-1.5 rounded-2xl border border-border px-4 py-2.5 text-[14px] font-medium text-muted disabled:opacity-40`,`px-3 py-1.5`),onClick:ee,children:a(`Cancel`)})]})]}),U&&(0,M.jsx)(`p`,{className:`text-[13px] text-muted`,children:U}),R&&(0,M.jsxs)(`div`,{className:`rounded-2xl bg-surface-2 p-3 text-[13.5px] leading-[19px]`,children:[(0,M.jsx)(`ol`,{className:`list-decimal space-y-1 pl-5`,children:(N[t.name]??[]).map(e=>(0,M.jsx)(`li`,{children:a(e)},e))}),(0,M.jsxs)(`p`,{className:`mt-2 text-muted`,children:[a(`Then write to the bot from the app. The first message gets a pairing code; approve it here or run`),` `,(0,M.jsx)(`code`,{className:`rounded bg-surface px-1`,children:`nanomuse channels approve `})]}),t.console_url&&(0,M.jsxs)(`a`,{href:t.console_url,target:`_blank`,rel:`noreferrer`,className:`mt-2 inline-flex items-center gap-1 text-accent underline-offset-2 hover:underline`,children:[(0,M.jsx)(u,{size:14}),` `,a(`Open the console`)]})]})]}),(0,M.jsx)(w,{inset:16}),(0,M.jsx)(`p`,{className:`px-4 pt-3 text-[13px] text-muted`,children:a(`Paired chats`)}),t.paired.length===0?(0,M.jsx)(`p`,{className:`px-4 pb-3 pt-1 text-[13px] leading-[18px] text-muted`,children:a(`Nobody yet. Write to the bot from the app; a pairing code comes back, approve it here.`)}):t.paired.map(e=>(0,M.jsxs)(`div`,{className:`flex items-center`,children:[(0,M.jsx)(`div`,{className:`min-w-0 flex-1`,children:(0,M.jsx)(C,{label:e.sender_name||e.sender_id,value:a(`Deliver here`),checked:e.deliver,onChange:n=>void r(()=>j.setDeliver(t.name,e.sender_id,n))})}),(0,M.jsx)(`button`,{type:`button`,className:`mr-3 rounded-full p-2 text-muted hover:bg-surface-2`,"aria-label":a(`Remove`),onClick:()=>{window.confirm(a(`Remove {name}? They will need a new pairing code.`,{name:e.sender_name||e.sender_id}))&&r(()=>j.removeChat(t.name,e.sender_id))},children:(0,M.jsx)(_,{size:16})})]},e.sender_id))]})]}),(c||t.enabled)&&t.paired.length>0&&(0,M.jsx)(S,{children:a(`Chats with “deliver here” on also get what the Muse does on its own: check-ins, reminders, the results of background work, and the questions it needs answered.`)})]})}function B({f:t,value:r,onChange:i,onClear:a}){let o=n();if(t.kind===`choice`)return(0,M.jsxs)(`label`,{className:`block`,children:[(0,M.jsx)(`span`,{className:`mb-1 block text-[13px] text-muted`,children:t.label}),(0,M.jsx)(`select`,{className:m,value:r??String(t.value??t.default),onChange:e=>i(e.target.value),children:t.choices.map(e=>(0,M.jsx)(`option`,{value:e,children:e},e))}),t.help&&(0,M.jsx)(`span`,{className:`mt-1 block text-[12.5px] text-muted`,children:t.help})]});let s=t.kind===`secret`;return(0,M.jsxs)(`label`,{className:`block`,children:[(0,M.jsxs)(`span`,{className:`mb-1 block text-[13px] text-muted`,children:[t.label,t.required?` *`:``]}),(0,M.jsxs)(`div`,{className:`flex gap-2`,children:[(0,M.jsx)(`input`,{type:s?`password`:`text`,autoComplete:`off`,className:m,value:r??(s?``:String(t.value??``)),placeholder:s&&t.has_value?o(`Set; leave blank to keep`):t.help,onChange:e=>i(e.target.value)}),s&&t.has_value&&(0,M.jsx)(`button`,{type:`button`,className:e(`flex items-center justify-center gap-1.5 rounded-2xl border border-border px-4 py-2.5 text-[14px] font-medium text-muted disabled:opacity-40`,`shrink-0 px-3`),onClick:a,title:o(`Clear the saved value`),"aria-label":o(`Clear the saved value`),children:(0,M.jsx)(p,{size:14})})]}),t.help&&!s&&(0,M.jsx)(`span`,{className:`mt-1 block text-[12.5px] text-muted`,children:t.help})]})}export{L as ChannelsScreen}; \ No newline at end of file diff --git a/nanomuse/server/static/assets/CloudCard-CdydxD3H.js b/nanomuse/server/static/assets/CloudCard-CtVHK0qc.js similarity index 97% rename from nanomuse/server/static/assets/CloudCard-CdydxD3H.js rename to nanomuse/server/static/assets/CloudCard-CtVHK0qc.js index fd11cb7bb..312716703 100644 --- a/nanomuse/server/static/assets/CloudCard-CdydxD3H.js +++ b/nanomuse/server/static/assets/CloudCard-CtVHK0qc.js @@ -1 +1 @@ -import{K as e,Q as t,Y as n,b as r,f as i,q as a,x as o}from"./MuseHeader-Pw-NI98v.js";import{a as s,t as c}from"./Form-DwKuBk1V.js";import{ct as l,l as u,t as d,vt as f}from"./index-BjYzdKkG.js";var p=t(n(),1),m=r();function h({account:t,onChange:n,compact:r=!1,useAsModel:h=!1}){let{toast:_}=i(),v=e(),[y,b]=(0,p.useState)(r||!t?.signed_in),[x,S]=(0,p.useState)(null),[C,w]=(0,p.useState)(null),T=!!t?.signed_in,E=async()=>{S(`model`),w(null);try{await o.cloudUseAsModel(),_(v(`The Cloud model is in use.`)),n()}catch(e){w(v(e.message))}finally{S(null)}},D=t?.models!==!1,O=async e=>{S(`switch`),w(null);try{await o.cloudModels(e),n()}catch(e){w(v(e.message))}finally{S(null)}},k=async()=>{if(window.confirm(v(`Sign out of nanoMuse Cloud on this device? The hub and the Cloud model stop working here until you sign in again.`))){S(`out`);try{await o.cloudSignOut(),n()}catch(e){_(e.message)}finally{S(null)}}},A=T?{text:v(`Signed in`),tone:`ok`}:{text:v(`Not signed in`),tone:`off`},j=T?t?.is_model?v(`{hint} · model and hub`,{hint:t.hint}):v(`{hint} · hub`,{hint:t?.hint??``}):v(`Free. One account for all your devices, and a model to start with.`);return(0,m.jsx)(c,{icon:(0,m.jsx)(f,{size:20}),title:v(`nanoMuse Cloud`),summary:j,status:A,open:y,onToggle:r?void 0:()=>b(e=>!e),children:T?(0,m.jsxs)(`div`,{className:`space-y-3`,children:[(0,m.jsx)(`p`,{className:`text-[13px] text-muted leading-relaxed`,children:v(`Signed in as {hint}. Your devices meet here; the Cloud model comes with a free allowance.`,{hint:t?.hint??``})}),(0,m.jsx)(`div`,{className:`-mx-4 border-y border-border/60`,children:(0,m.jsx)(u,{label:v(`Use nanoMuse Cloud models`),checked:D,disabled:x!==null,onChange:e=>void O(e)})}),(0,m.jsx)(`p`,{className:`text-[12.5px] text-muted leading-relaxed`,children:v(D?`nanoMuse Cloud is one of the sources for the chat, the hands, pictures and clips; what runs on it comes off your allowance.`:`Off: nothing runs on nanoMuse Cloud unless you choose it yourself. You stay signed in for sync and your devices.`)}),(0,m.jsxs)(`div`,{className:`flex flex-wrap gap-2`,children:[!t?.is_model&&(0,m.jsxs)(`button`,{type:`button`,disabled:x!==null,onClick:()=>void E(),className:`flex items-center justify-center gap-1.5 rounded-2xl bg-accent text-accent-fg px-4 py-2.5 text-[14px] font-medium disabled:opacity-40`,children:[x===`model`?(0,m.jsx)(a,{size:15,className:`animate-spin`}):null,` `,v(`Use the Cloud model`)]}),(0,m.jsxs)(`button`,{type:`button`,disabled:x!==null,onClick:()=>void k(),className:s,children:[(0,m.jsx)(l,{size:15}),` `,v(`Sign out`)]})]}),C&&(0,m.jsx)(g,{text:C})]}):(0,m.jsx)(d,{useAsModel:h,autoFocus:!1,onSignedIn:()=>{_(v(`Signed in to nanoMuse Cloud.`)),n()}})})}function g({text:e}){return(0,m.jsx)(`div`,{className:`rounded-2xl bg-rose-500/12 px-3 py-2 text-[12.5px] text-rose-700 dark:text-rose-300`,children:e})}export{h as t}; \ No newline at end of file +import{K as e,Q as t,Y as n,b as r,f as i,q as a,x as o}from"./MuseHeader-Pw-NI98v.js";import{a as s,t as c}from"./Form-DwKuBk1V.js";import{ct as l,l as u,t as d,vt as f}from"./index-CIdGZ5PB.js";var p=t(n(),1),m=r();function h({account:t,onChange:n,compact:r=!1,useAsModel:h=!1}){let{toast:_}=i(),v=e(),[y,b]=(0,p.useState)(r||!t?.signed_in),[x,S]=(0,p.useState)(null),[C,w]=(0,p.useState)(null),T=!!t?.signed_in,E=async()=>{S(`model`),w(null);try{await o.cloudUseAsModel(),_(v(`The Cloud model is in use.`)),n()}catch(e){w(v(e.message))}finally{S(null)}},D=t?.models!==!1,O=async e=>{S(`switch`),w(null);try{await o.cloudModels(e),n()}catch(e){w(v(e.message))}finally{S(null)}},k=async()=>{if(window.confirm(v(`Sign out of nanoMuse Cloud on this device? The hub and the Cloud model stop working here until you sign in again.`))){S(`out`);try{await o.cloudSignOut(),n()}catch(e){_(e.message)}finally{S(null)}}},A=T?{text:v(`Signed in`),tone:`ok`}:{text:v(`Not signed in`),tone:`off`},j=T?t?.is_model?v(`{hint} · model and hub`,{hint:t.hint}):v(`{hint} · hub`,{hint:t?.hint??``}):v(`Free. One account for all your devices, and a model to start with.`);return(0,m.jsx)(c,{icon:(0,m.jsx)(f,{size:20}),title:v(`nanoMuse Cloud`),summary:j,status:A,open:y,onToggle:r?void 0:()=>b(e=>!e),children:T?(0,m.jsxs)(`div`,{className:`space-y-3`,children:[(0,m.jsx)(`p`,{className:`text-[13px] text-muted leading-relaxed`,children:v(`Signed in as {hint}. Your devices meet here; the Cloud model comes with a free allowance.`,{hint:t?.hint??``})}),(0,m.jsx)(`div`,{className:`-mx-4 border-y border-border/60`,children:(0,m.jsx)(u,{label:v(`Use nanoMuse Cloud models`),checked:D,disabled:x!==null,onChange:e=>void O(e)})}),(0,m.jsx)(`p`,{className:`text-[12.5px] text-muted leading-relaxed`,children:v(D?`nanoMuse Cloud is one of the sources for the chat, the hands, pictures and clips; what runs on it comes off your allowance.`:`Off: nothing runs on nanoMuse Cloud unless you choose it yourself. You stay signed in for sync and your devices.`)}),(0,m.jsxs)(`div`,{className:`flex flex-wrap gap-2`,children:[!t?.is_model&&(0,m.jsxs)(`button`,{type:`button`,disabled:x!==null,onClick:()=>void E(),className:`flex items-center justify-center gap-1.5 rounded-2xl bg-accent text-accent-fg px-4 py-2.5 text-[14px] font-medium disabled:opacity-40`,children:[x===`model`?(0,m.jsx)(a,{size:15,className:`animate-spin`}):null,` `,v(`Use the Cloud model`)]}),(0,m.jsxs)(`button`,{type:`button`,disabled:x!==null,onClick:()=>void k(),className:s,children:[(0,m.jsx)(l,{size:15}),` `,v(`Sign out`)]})]}),C&&(0,m.jsx)(g,{text:C})]}):(0,m.jsx)(d,{useAsModel:h,autoFocus:!1,onSignedIn:()=>{_(v(`Signed in to nanoMuse Cloud.`)),n()}})})}function g({text:e}){return(0,m.jsx)(`div`,{className:`rounded-2xl bg-rose-500/12 px-3 py-2 text-[12.5px] text-rose-700 dark:text-rose-300`,children:e})}export{h as t}; \ No newline at end of file diff --git a/nanomuse/server/static/assets/CodingScreen-CTT5Jjn2.js b/nanomuse/server/static/assets/CodingScreen-C_tutsx0.js similarity index 99% rename from nanomuse/server/static/assets/CodingScreen-CTT5Jjn2.js rename to nanomuse/server/static/assets/CodingScreen-C_tutsx0.js index 0b4ec8c48..c7daae17b 100644 --- a/nanomuse/server/static/assets/CodingScreen-CTT5Jjn2.js +++ b/nanomuse/server/static/assets/CodingScreen-C_tutsx0.js @@ -1,3 +1,3 @@ -import{E as e,J as t,K as n,Q as r,Y as i,b as a,f as o,k as s,q as c,r as l,x as u}from"./MuseHeader-Pw-NI98v.js";import{a as d,i as f,r as p}from"./Form-DwKuBk1V.js";import{t as m}from"./refresh-cw-BKgIzslL.js";import{Ct as h,F as g,H as _,Tt as v,U as y,Z as b,bt as x,it as S,w as C,z as w}from"./index-BjYzdKkG.js";import{t as T}from"./BackBar-Dli0L0O_.js";var E=t(`folder-open`,[[`path`,{d:`m6 14 1.5-2.9A2 2 0 0 1 9.24 10H20a2 2 0 0 1 1.94 2.5l-1.54 6a2 2 0 0 1-1.95 1.5H4a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h3.9a2 2 0 0 1 1.69.9l.81 1.2a2 2 0 0 0 1.67.9H18a2 2 0 0 1 2 2v2`,key:`usdka0`}]]),D=r(i(),1),O=a(),k={cursor:{label:`Cursor`,tone:`from-slate-700 to-slate-900`,glyph:`C`},codex:{label:`Codex`,tone:`from-emerald-500 to-teal-700`,glyph:`X`},claude:{label:`Claude Code`,tone:`from-orange-400 to-amber-600`,glyph:`A`}};function A(){let{state:t,toast:r}=o(),i=n(),[a,d]=(0,D.useState)(``),[f,p]=(0,D.useState)(null),[h,g]=(0,D.useState)([]),[_,v]=(0,D.useState)(null),[C,w]=(0,D.useState)(``),[A,M]=(0,D.useState)(!1),[F,V]=(0,D.useState)(null),[H,U]=(0,D.useState)(null),[W,G]=(0,D.useState)(null),K=(0,D.useMemo)(()=>(t.hub?.devices??[]).filter(e=>!e.this&&e.online&&e.kind!==`web`&&(e.actions??[]).includes(`coding.sessions`)),[t.hub?.devices]),q=(0,D.useCallback)(async()=>{M(!0),V(null);try{let[e,t]=await Promise.all([u.coding(a),u.codingSessions({device:a,limit:40})]);p(e.agents),g(e.runs??[]),v(t.sessions)}catch(e){V(e.message),p([]),v([])}finally{M(!1)}},[a]);(0,D.useEffect)(()=>{q()},[q]);let J=Object.values(t.codingLive),Y=J.filter(e=>e.run.status!==`running`).length;(0,D.useEffect)(()=>{Y&&q()},[Y]);let X=(_??[]).filter(e=>(!C||e.agent===C)&&(e.messages>0||e.status===`running`)),Z=(f??[]).filter(e=>e.installed),Q=new Set(J.filter(e=>e.run.status===`running`&&(e.run.device??``)===(a?z(K,a):``)).map(e=>e.run.session_id||e.run.asked_session_id));return(0,O.jsxs)(`div`,{className:`flex h-full flex-col`,children:[(0,O.jsx)(T,{title:i(`Coding agents`),description:i(`Cursor, Codex and Claude Code: see what they are doing, and tell them things from anywhere.`),actions:(0,O.jsx)(l,{small:!0,onClick:()=>void q(),label:i(`Refresh`),children:(0,O.jsx)(m,{size:18,className:A?`animate-spin`:``})})}),(0,O.jsxs)(`div`,{className:`flex-1 overflow-y-auto px-4 pb-8 space-y-4`,children:[(K.length>0||a)&&(0,O.jsxs)(`div`,{className:`no-scrollbar -mx-4 flex gap-2 overflow-x-auto px-4`,children:[(0,O.jsx)(R,{active:!a,onClick:()=>d(``),icon:(0,O.jsx)(y,{size:14}),label:t.hub?.device?.name?i(`This one · {name}`,{name:t.hub.device.name}):i(`This computer`)}),K.map(e=>(0,O.jsx)(R,{active:a===e.id,onClick:()=>d(e.id),icon:(0,O.jsx)(S,{size:14}),label:e.name},e.id))]}),f&&(0,O.jsx)(`div`,{className:`grid grid-cols-3 gap-2`,children:f.map(t=>{let n=k[t.id];return(0,O.jsxs)(`button`,{type:`button`,disabled:!t.installed,onClick:()=>w(e=>e===t.id?``:t.id),className:e(`rounded-3xl border p-3 text-left transition`,C===t.id?`border-accent/40 bg-accent/5`:`border-border/70 bg-surface`,!t.installed&&`opacity-45`),children:[(0,O.jsxs)(`div`,{className:`flex items-center justify-between`,children:[(0,O.jsx)(I,{agent:t.id,size:30}),t.running>0&&(0,O.jsxs)(`span`,{className:`flex items-center gap-1 rounded-full bg-emerald-500/12 px-1.5 py-0.5 text-[10.5px] font-semibold text-emerald-700 dark:text-emerald-300`,children:[(0,O.jsx)(`span`,{className:`h-1.5 w-1.5 animate-pulse rounded-full bg-emerald-500`}),` `,t.running]})]}),(0,O.jsx)(`div`,{className:`mt-2 truncate text-[13.5px] font-semibold`,children:n?.label??t.name}),(0,O.jsx)(`div`,{className:`truncate text-[11.5px] text-muted`,children:t.installed?t.cli?t.version||i(`installed`):i(`chats only`):i(`not found`)})]},t.id)})}),F&&(0,O.jsx)(`div`,{className:`rounded-2xl bg-rose-500/12 px-3 py-2 text-[12.5px] text-rose-700 dark:text-rose-300`,children:F}),J.filter(e=>e.run.status===`running`).length>0&&(0,O.jsxs)(`section`,{className:`space-y-2`,children:[(0,O.jsx)(`h2`,{className:`px-1 text-[12px] font-semibold uppercase tracking-wide text-muted`,children:i(`Working now`)}),J.filter(e=>e.run.status===`running`).map(e=>(0,O.jsx)(N,{live:e,onOpen:()=>U({agent:e.run.agent,id:e.run.session_id||e.run.asked_session_id||``})},e.run.id))]}),(0,O.jsxs)(`section`,{className:`space-y-2`,children:[(0,O.jsxs)(`div`,{className:`flex items-center justify-between px-1`,children:[(0,O.jsx)(`h2`,{className:`text-[12px] font-semibold uppercase tracking-wide text-muted`,children:C?i(`{agent} chats`,{agent:k[C]?.label??C}):i(`Recent chats`)}),Z.some(e=>e.cli)&&(0,O.jsxs)(`button`,{type:`button`,onClick:()=>G(C&&Z.find(e=>e.id===C&&e.cli)?C:Z.find(e=>e.cli)?.id??null),className:`flex items-center gap-1 text-[12.5px] font-medium text-accent`,children:[(0,O.jsx)(b,{size:14}),` `,i(`New chat`)]})]}),_===null?(0,O.jsx)(`div`,{className:`flex justify-center py-10 text-muted`,children:(0,O.jsx)(c,{size:20,className:`animate-spin`})}):X.length===0?(0,O.jsx)(`div`,{className:`rounded-3xl border border-dashed border-border/80 px-4 py-8 text-center text-[13.5px] text-muted`,children:f&&f.every(e=>!e.installed)?i(`No coding agent found on this computer. Install Cursor, Codex or Claude Code and their chats appear here.`):i(`No chats yet.`)}):(0,O.jsx)(`ul`,{className:`divide-y divide-border/60 overflow-hidden rounded-3xl border border-border/70 bg-surface`,children:X.map(e=>(0,O.jsx)(`li`,{children:(0,O.jsxs)(`button`,{type:`button`,onClick:()=>U({agent:e.agent,id:e.id}),className:`flex w-full items-center gap-3 px-3.5 py-3 text-left hover:bg-surface-2/60 active:bg-surface-2`,children:[(0,O.jsx)(I,{agent:e.agent,size:34}),(0,O.jsxs)(`span`,{className:`min-w-0 flex-1`,children:[(0,O.jsxs)(`span`,{className:`flex items-center gap-2`,children:[(0,O.jsx)(`span`,{className:`truncate text-[14.5px] font-medium`,children:e.title||i(`Untitled chat`)}),(0,O.jsx)(L,{status:Q.has(e.id)?`running`:e.status})]}),(0,O.jsxs)(`span`,{className:`mt-0.5 flex items-center gap-1.5 truncate text-[12px] text-muted`,children:[e.workspace&&(0,O.jsxs)(`span`,{className:`flex min-w-0 items-center gap-1`,children:[(0,O.jsx)(E,{size:11}),` `,(0,O.jsx)(`span`,{className:`truncate`,children:B(e.workspace)})]}),(0,O.jsxs)(`span`,{children:[`· `,s(e.updated_at)]}),(0,O.jsxs)(`span`,{children:[`· `,i(`{n} messages`,{n:e.messages})]})]})]}),(0,O.jsx)(x,{size:16,className:`shrink-0 text-muted`})]})},`${e.agent}-${e.id}`))})]}),h.filter(e=>e.status!==`running`).length>0&&(0,O.jsxs)(`section`,{className:`space-y-2`,children:[(0,O.jsx)(`h2`,{className:`px-1 text-[12px] font-semibold uppercase tracking-wide text-muted`,children:i(`Sent through nanoMuse`)}),(0,O.jsx)(`ul`,{className:`divide-y divide-border/60 overflow-hidden rounded-3xl border border-border/70 bg-surface`,children:h.filter(e=>e.status!==`running`).slice(0,8).map(e=>(0,O.jsxs)(`li`,{className:`flex items-center gap-3 px-3.5 py-2.5`,children:[(0,O.jsx)(I,{agent:e.agent,size:28}),(0,O.jsxs)(`span`,{className:`min-w-0 flex-1`,children:[(0,O.jsx)(`span`,{className:`block truncate text-[13.5px]`,children:e.text}),(0,O.jsxs)(`span`,{className:`block truncate text-[11.5px] text-muted`,children:[e.status===`done`?i(`done`):e.status===`failed`?i(`failed`):i(`stopped`),` · `,s(e.started_at),e.tools?` · ${i(`{n} steps`,{n:e.tools})}`:``,e.error?` · ${e.error}`:``]})]}),e.session_id&&(0,O.jsx)(`button`,{type:`button`,onClick:()=>U({agent:e.agent,id:e.session_id}),className:`text-[12.5px] font-medium text-accent`,children:i(`Open`)})]},e.id))})]})]}),H&&(0,O.jsx)(j,{agent:H.agent,id:H.id,device:a,deviceLabel:a?z(K,a):``,onClose:()=>U(null)}),W&&(0,O.jsx)(P,{agent:W,agents:Z.filter(e=>e.cli),device:a,onClose:()=>G(null),onStarted:e=>{G(null),r(i(`Sent to {agent}.`,{agent:k[e.agent]?.label??e.agent}))}})]})}function j({agent:t,id:r,device:i,deviceLabel:a,onClose:s}){let{state:l,toast:d}=o(),f=n(),[m,h]=(0,D.useState)(null),[y,b]=(0,D.useState)(null),[x,S]=(0,D.useState)(``),[w,T]=(0,D.useState)(!1),E=(0,D.useRef)(null),A=(0,D.useCallback)(async()=>{try{h(await u.codingSession(t,r,i)),b(null)}catch(e){b(e.message)}},[t,r,i]);(0,D.useEffect)(()=>{A()},[A]);let j=Object.values(l.codingLive).filter(e=>e.run.agent===t&&(e.run.session_id===r||e.run.asked_session_id===r)),N=j.find(e=>e.run.status===`running`),P=j.filter(e=>e.run.status!==`running`).length;(0,D.useEffect)(()=>{P&&A()},[P]),(0,D.useEffect)(()=>{let e=E.current;e&&(e.scrollTop=e.scrollHeight)},[m?.transcript?.length,N?.events.length,N?.current.length]);let L=async()=>{let e=x.trim();if(e&&!w){T(!0);try{await u.codingSend({agent:t,text:e,session_id:r,workspace:m?.workspace??``,device:i}),S(``)}catch(e){d(e.message)}finally{T(!1)}}},R=k[t],z=m?.transcript??[],V=!!m||!!N,H=!!m&&!m.resumable&&!N;return(0,O.jsx)(C,{open:!0,onClose:s,title:(0,O.jsxs)(`span`,{className:`flex items-center gap-2.5`,children:[(0,O.jsx)(I,{agent:t,size:30}),(0,O.jsxs)(`span`,{className:`min-w-0`,children:[(0,O.jsx)(`span`,{className:`block truncate`,children:m?.title||R?.label||t}),(0,O.jsxs)(`span`,{className:`block truncate text-[12px] font-normal text-muted`,children:[a?`${a} · `:``,m?.workspace?B(m.workspace):R?.label,m?.source&&m.source!==`ide`&&m.source!==`cli`?` · ${m.source}`:``]})]})]}),footer:(0,O.jsxs)(O.Fragment,{children:[H&&(0,O.jsx)(`p`,{className:`mb-1.5 px-1 text-[11.5px] leading-snug text-muted`,children:f(`Made in the IDE: your message starts a new chat in the same workspace, with the last exchange quoted.`)}),(0,O.jsxs)(`form`,{className:`flex items-end gap-2`,onSubmit:e=>{e.preventDefault(),L()},children:[(0,O.jsx)(`textarea`,{value:x,onChange:e=>S(e.target.value),onKeyDown:e=>{e.key===`Enter`&&!e.shiftKey&&(e.preventDefault(),L())},rows:1,disabled:!V||!!N,placeholder:N?f(`{agent} is working…`,{agent:R?.label??t}):m?H?f(`Continue in a new chat…`):f(`Tell {agent}…`,{agent:R?.label??t}):`…`,className:e(p,`max-h-32 min-h-[44px] resize-none py-2.5`)}),N?(0,O.jsx)(`button`,{type:`button`,onClick:()=>void u.codingStop(N.run.id,i).catch(e=>d(e.message)),"aria-label":f(`Stop`),className:`flex h-11 w-11 shrink-0 items-center justify-center rounded-full bg-rose-500 text-white`,children:(0,O.jsx)(_,{size:16})}):(0,O.jsx)(`button`,{type:`submit`,disabled:!x.trim()||w||!V,"aria-label":f(`Send`),className:`flex h-11 w-11 shrink-0 items-center justify-center rounded-full bg-accent text-white disabled:opacity-40`,children:w?(0,O.jsx)(c,{size:16,className:`animate-spin`}):(0,O.jsx)(v,{size:18})})]})]}),children:(0,O.jsxs)(`div`,{ref:E,className:`space-y-2.5 py-1`,children:[y&&(0,O.jsx)(`div`,{className:`rounded-2xl bg-rose-500/12 px-3 py-2 text-[12.5px] text-rose-700 dark:text-rose-300`,children:y}),!m&&!y&&(0,O.jsx)(`div`,{className:`flex justify-center py-10 text-muted`,children:(0,O.jsx)(c,{size:20,className:`animate-spin`})}),z.map((e,n)=>(0,O.jsx)(F,{who:e.role===`user`?`you`:`agent`,agent:t,children:e.role===`user`?(0,O.jsx)(`span`,{className:`whitespace-pre-wrap`,children:e.text}):(0,O.jsx)(g,{text:e.text})},n)),j.filter(e=>!(e.run.status===`done`&&(e.run.resumed||!e.run.asked_session_id)&&z.some(t=>t.role===`user`&&t.text.trim()===e.run.text.trim()))).map(e=>(0,O.jsx)(M,{live:e,agent:t,hideFinishedText:z.length>0&&e.run.status===`done`},e.run.id)),m&&z.length===0&&j.length===0&&(0,O.jsx)(`p`,{className:`py-6 text-center text-[13px] text-muted`,children:f(`Nothing readable in this chat yet.`)})]})})}function M({live:e,agent:t,hideFinishedText:r}){let i=n(),{run:a,events:o,current:s}=e,l=o.filter(e=>e.kind===`tool`),u=k[t];return(0,O.jsxs)(O.Fragment,{children:[(0,O.jsx)(F,{who:`you`,agent:t,badge:i(`via nanoMuse`),children:(0,O.jsx)(`span`,{className:`whitespace-pre-wrap`,children:a.text})}),(l.length>0||a.status===`running`)&&(0,O.jsxs)(`div`,{className:`mx-1 rounded-2xl border border-border/60 bg-surface-2/40 px-3 py-2 text-[12.5px]`,children:[(0,O.jsxs)(`div`,{className:`flex items-center gap-1.5 font-medium text-fg/80`,children:[a.status===`running`?(0,O.jsx)(c,{size:13,className:`animate-spin text-accent`}):(0,O.jsx)(w,{size:13,className:`text-muted`}),a.status===`running`?i(`{agent} is working…`,{agent:u?.label??t}):i(`{n} steps`,{n:l.length}),a.device&&(0,O.jsxs)(`span`,{className:`ml-auto flex items-center gap-1 text-muted`,children:[(0,O.jsx)(S,{size:11}),` `,a.device]})]}),l.length>0&&(0,O.jsx)(`ul`,{className:`mt-1.5 max-h-28 space-y-0.5 overflow-y-auto font-mono text-[11.5px] text-muted`,children:l.slice(-12).map((e,t)=>(0,O.jsx)(`li`,{className:`truncate`,children:e.text},t))})]}),(s||a.output&&!r)&&(0,O.jsxs)(F,{who:`agent`,agent:t,children:[(0,O.jsx)(g,{text:a.status===`running`?(a.output?a.output+` +import{E as e,J as t,K as n,Q as r,Y as i,b as a,f as o,k as s,q as c,r as l,x as u}from"./MuseHeader-Pw-NI98v.js";import{a as d,i as f,r as p}from"./Form-DwKuBk1V.js";import{t as m}from"./refresh-cw-BKgIzslL.js";import{Ct as h,F as g,H as _,Tt as v,U as y,Z as b,bt as x,it as S,w as C,z as w}from"./index-CIdGZ5PB.js";import{t as T}from"./BackBar-Dl56jHZM.js";var E=t(`folder-open`,[[`path`,{d:`m6 14 1.5-2.9A2 2 0 0 1 9.24 10H20a2 2 0 0 1 1.94 2.5l-1.54 6a2 2 0 0 1-1.95 1.5H4a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h3.9a2 2 0 0 1 1.69.9l.81 1.2a2 2 0 0 0 1.67.9H18a2 2 0 0 1 2 2v2`,key:`usdka0`}]]),D=r(i(),1),O=a(),k={cursor:{label:`Cursor`,tone:`from-slate-700 to-slate-900`,glyph:`C`},codex:{label:`Codex`,tone:`from-emerald-500 to-teal-700`,glyph:`X`},claude:{label:`Claude Code`,tone:`from-orange-400 to-amber-600`,glyph:`A`}};function A(){let{state:t,toast:r}=o(),i=n(),[a,d]=(0,D.useState)(``),[f,p]=(0,D.useState)(null),[h,g]=(0,D.useState)([]),[_,v]=(0,D.useState)(null),[C,w]=(0,D.useState)(``),[A,M]=(0,D.useState)(!1),[F,V]=(0,D.useState)(null),[H,U]=(0,D.useState)(null),[W,G]=(0,D.useState)(null),K=(0,D.useMemo)(()=>(t.hub?.devices??[]).filter(e=>!e.this&&e.online&&e.kind!==`web`&&(e.actions??[]).includes(`coding.sessions`)),[t.hub?.devices]),q=(0,D.useCallback)(async()=>{M(!0),V(null);try{let[e,t]=await Promise.all([u.coding(a),u.codingSessions({device:a,limit:40})]);p(e.agents),g(e.runs??[]),v(t.sessions)}catch(e){V(e.message),p([]),v([])}finally{M(!1)}},[a]);(0,D.useEffect)(()=>{q()},[q]);let J=Object.values(t.codingLive),Y=J.filter(e=>e.run.status!==`running`).length;(0,D.useEffect)(()=>{Y&&q()},[Y]);let X=(_??[]).filter(e=>(!C||e.agent===C)&&(e.messages>0||e.status===`running`)),Z=(f??[]).filter(e=>e.installed),Q=new Set(J.filter(e=>e.run.status===`running`&&(e.run.device??``)===(a?z(K,a):``)).map(e=>e.run.session_id||e.run.asked_session_id));return(0,O.jsxs)(`div`,{className:`flex h-full flex-col`,children:[(0,O.jsx)(T,{title:i(`Coding agents`),description:i(`Cursor, Codex and Claude Code: see what they are doing, and tell them things from anywhere.`),actions:(0,O.jsx)(l,{small:!0,onClick:()=>void q(),label:i(`Refresh`),children:(0,O.jsx)(m,{size:18,className:A?`animate-spin`:``})})}),(0,O.jsxs)(`div`,{className:`flex-1 overflow-y-auto px-4 pb-8 space-y-4`,children:[(K.length>0||a)&&(0,O.jsxs)(`div`,{className:`no-scrollbar -mx-4 flex gap-2 overflow-x-auto px-4`,children:[(0,O.jsx)(R,{active:!a,onClick:()=>d(``),icon:(0,O.jsx)(y,{size:14}),label:t.hub?.device?.name?i(`This one · {name}`,{name:t.hub.device.name}):i(`This computer`)}),K.map(e=>(0,O.jsx)(R,{active:a===e.id,onClick:()=>d(e.id),icon:(0,O.jsx)(S,{size:14}),label:e.name},e.id))]}),f&&(0,O.jsx)(`div`,{className:`grid grid-cols-3 gap-2`,children:f.map(t=>{let n=k[t.id];return(0,O.jsxs)(`button`,{type:`button`,disabled:!t.installed,onClick:()=>w(e=>e===t.id?``:t.id),className:e(`rounded-3xl border p-3 text-left transition`,C===t.id?`border-accent/40 bg-accent/5`:`border-border/70 bg-surface`,!t.installed&&`opacity-45`),children:[(0,O.jsxs)(`div`,{className:`flex items-center justify-between`,children:[(0,O.jsx)(I,{agent:t.id,size:30}),t.running>0&&(0,O.jsxs)(`span`,{className:`flex items-center gap-1 rounded-full bg-emerald-500/12 px-1.5 py-0.5 text-[10.5px] font-semibold text-emerald-700 dark:text-emerald-300`,children:[(0,O.jsx)(`span`,{className:`h-1.5 w-1.5 animate-pulse rounded-full bg-emerald-500`}),` `,t.running]})]}),(0,O.jsx)(`div`,{className:`mt-2 truncate text-[13.5px] font-semibold`,children:n?.label??t.name}),(0,O.jsx)(`div`,{className:`truncate text-[11.5px] text-muted`,children:t.installed?t.cli?t.version||i(`installed`):i(`chats only`):i(`not found`)})]},t.id)})}),F&&(0,O.jsx)(`div`,{className:`rounded-2xl bg-rose-500/12 px-3 py-2 text-[12.5px] text-rose-700 dark:text-rose-300`,children:F}),J.filter(e=>e.run.status===`running`).length>0&&(0,O.jsxs)(`section`,{className:`space-y-2`,children:[(0,O.jsx)(`h2`,{className:`px-1 text-[12px] font-semibold uppercase tracking-wide text-muted`,children:i(`Working now`)}),J.filter(e=>e.run.status===`running`).map(e=>(0,O.jsx)(N,{live:e,onOpen:()=>U({agent:e.run.agent,id:e.run.session_id||e.run.asked_session_id||``})},e.run.id))]}),(0,O.jsxs)(`section`,{className:`space-y-2`,children:[(0,O.jsxs)(`div`,{className:`flex items-center justify-between px-1`,children:[(0,O.jsx)(`h2`,{className:`text-[12px] font-semibold uppercase tracking-wide text-muted`,children:C?i(`{agent} chats`,{agent:k[C]?.label??C}):i(`Recent chats`)}),Z.some(e=>e.cli)&&(0,O.jsxs)(`button`,{type:`button`,onClick:()=>G(C&&Z.find(e=>e.id===C&&e.cli)?C:Z.find(e=>e.cli)?.id??null),className:`flex items-center gap-1 text-[12.5px] font-medium text-accent`,children:[(0,O.jsx)(b,{size:14}),` `,i(`New chat`)]})]}),_===null?(0,O.jsx)(`div`,{className:`flex justify-center py-10 text-muted`,children:(0,O.jsx)(c,{size:20,className:`animate-spin`})}):X.length===0?(0,O.jsx)(`div`,{className:`rounded-3xl border border-dashed border-border/80 px-4 py-8 text-center text-[13.5px] text-muted`,children:f&&f.every(e=>!e.installed)?i(`No coding agent found on this computer. Install Cursor, Codex or Claude Code and their chats appear here.`):i(`No chats yet.`)}):(0,O.jsx)(`ul`,{className:`divide-y divide-border/60 overflow-hidden rounded-3xl border border-border/70 bg-surface`,children:X.map(e=>(0,O.jsx)(`li`,{children:(0,O.jsxs)(`button`,{type:`button`,onClick:()=>U({agent:e.agent,id:e.id}),className:`flex w-full items-center gap-3 px-3.5 py-3 text-left hover:bg-surface-2/60 active:bg-surface-2`,children:[(0,O.jsx)(I,{agent:e.agent,size:34}),(0,O.jsxs)(`span`,{className:`min-w-0 flex-1`,children:[(0,O.jsxs)(`span`,{className:`flex items-center gap-2`,children:[(0,O.jsx)(`span`,{className:`truncate text-[14.5px] font-medium`,children:e.title||i(`Untitled chat`)}),(0,O.jsx)(L,{status:Q.has(e.id)?`running`:e.status})]}),(0,O.jsxs)(`span`,{className:`mt-0.5 flex items-center gap-1.5 truncate text-[12px] text-muted`,children:[e.workspace&&(0,O.jsxs)(`span`,{className:`flex min-w-0 items-center gap-1`,children:[(0,O.jsx)(E,{size:11}),` `,(0,O.jsx)(`span`,{className:`truncate`,children:B(e.workspace)})]}),(0,O.jsxs)(`span`,{children:[`· `,s(e.updated_at)]}),(0,O.jsxs)(`span`,{children:[`· `,i(`{n} messages`,{n:e.messages})]})]})]}),(0,O.jsx)(x,{size:16,className:`shrink-0 text-muted`})]})},`${e.agent}-${e.id}`))})]}),h.filter(e=>e.status!==`running`).length>0&&(0,O.jsxs)(`section`,{className:`space-y-2`,children:[(0,O.jsx)(`h2`,{className:`px-1 text-[12px] font-semibold uppercase tracking-wide text-muted`,children:i(`Sent through nanoMuse`)}),(0,O.jsx)(`ul`,{className:`divide-y divide-border/60 overflow-hidden rounded-3xl border border-border/70 bg-surface`,children:h.filter(e=>e.status!==`running`).slice(0,8).map(e=>(0,O.jsxs)(`li`,{className:`flex items-center gap-3 px-3.5 py-2.5`,children:[(0,O.jsx)(I,{agent:e.agent,size:28}),(0,O.jsxs)(`span`,{className:`min-w-0 flex-1`,children:[(0,O.jsx)(`span`,{className:`block truncate text-[13.5px]`,children:e.text}),(0,O.jsxs)(`span`,{className:`block truncate text-[11.5px] text-muted`,children:[e.status===`done`?i(`done`):e.status===`failed`?i(`failed`):i(`stopped`),` · `,s(e.started_at),e.tools?` · ${i(`{n} steps`,{n:e.tools})}`:``,e.error?` · ${e.error}`:``]})]}),e.session_id&&(0,O.jsx)(`button`,{type:`button`,onClick:()=>U({agent:e.agent,id:e.session_id}),className:`text-[12.5px] font-medium text-accent`,children:i(`Open`)})]},e.id))})]})]}),H&&(0,O.jsx)(j,{agent:H.agent,id:H.id,device:a,deviceLabel:a?z(K,a):``,onClose:()=>U(null)}),W&&(0,O.jsx)(P,{agent:W,agents:Z.filter(e=>e.cli),device:a,onClose:()=>G(null),onStarted:e=>{G(null),r(i(`Sent to {agent}.`,{agent:k[e.agent]?.label??e.agent}))}})]})}function j({agent:t,id:r,device:i,deviceLabel:a,onClose:s}){let{state:l,toast:d}=o(),f=n(),[m,h]=(0,D.useState)(null),[y,b]=(0,D.useState)(null),[x,S]=(0,D.useState)(``),[w,T]=(0,D.useState)(!1),E=(0,D.useRef)(null),A=(0,D.useCallback)(async()=>{try{h(await u.codingSession(t,r,i)),b(null)}catch(e){b(e.message)}},[t,r,i]);(0,D.useEffect)(()=>{A()},[A]);let j=Object.values(l.codingLive).filter(e=>e.run.agent===t&&(e.run.session_id===r||e.run.asked_session_id===r)),N=j.find(e=>e.run.status===`running`),P=j.filter(e=>e.run.status!==`running`).length;(0,D.useEffect)(()=>{P&&A()},[P]),(0,D.useEffect)(()=>{let e=E.current;e&&(e.scrollTop=e.scrollHeight)},[m?.transcript?.length,N?.events.length,N?.current.length]);let L=async()=>{let e=x.trim();if(e&&!w){T(!0);try{await u.codingSend({agent:t,text:e,session_id:r,workspace:m?.workspace??``,device:i}),S(``)}catch(e){d(e.message)}finally{T(!1)}}},R=k[t],z=m?.transcript??[],V=!!m||!!N,H=!!m&&!m.resumable&&!N;return(0,O.jsx)(C,{open:!0,onClose:s,title:(0,O.jsxs)(`span`,{className:`flex items-center gap-2.5`,children:[(0,O.jsx)(I,{agent:t,size:30}),(0,O.jsxs)(`span`,{className:`min-w-0`,children:[(0,O.jsx)(`span`,{className:`block truncate`,children:m?.title||R?.label||t}),(0,O.jsxs)(`span`,{className:`block truncate text-[12px] font-normal text-muted`,children:[a?`${a} · `:``,m?.workspace?B(m.workspace):R?.label,m?.source&&m.source!==`ide`&&m.source!==`cli`?` · ${m.source}`:``]})]})]}),footer:(0,O.jsxs)(O.Fragment,{children:[H&&(0,O.jsx)(`p`,{className:`mb-1.5 px-1 text-[11.5px] leading-snug text-muted`,children:f(`Made in the IDE: your message starts a new chat in the same workspace, with the last exchange quoted.`)}),(0,O.jsxs)(`form`,{className:`flex items-end gap-2`,onSubmit:e=>{e.preventDefault(),L()},children:[(0,O.jsx)(`textarea`,{value:x,onChange:e=>S(e.target.value),onKeyDown:e=>{e.key===`Enter`&&!e.shiftKey&&(e.preventDefault(),L())},rows:1,disabled:!V||!!N,placeholder:N?f(`{agent} is working…`,{agent:R?.label??t}):m?H?f(`Continue in a new chat…`):f(`Tell {agent}…`,{agent:R?.label??t}):`…`,className:e(p,`max-h-32 min-h-[44px] resize-none py-2.5`)}),N?(0,O.jsx)(`button`,{type:`button`,onClick:()=>void u.codingStop(N.run.id,i).catch(e=>d(e.message)),"aria-label":f(`Stop`),className:`flex h-11 w-11 shrink-0 items-center justify-center rounded-full bg-rose-500 text-white`,children:(0,O.jsx)(_,{size:16})}):(0,O.jsx)(`button`,{type:`submit`,disabled:!x.trim()||w||!V,"aria-label":f(`Send`),className:`flex h-11 w-11 shrink-0 items-center justify-center rounded-full bg-accent text-white disabled:opacity-40`,children:w?(0,O.jsx)(c,{size:16,className:`animate-spin`}):(0,O.jsx)(v,{size:18})})]})]}),children:(0,O.jsxs)(`div`,{ref:E,className:`space-y-2.5 py-1`,children:[y&&(0,O.jsx)(`div`,{className:`rounded-2xl bg-rose-500/12 px-3 py-2 text-[12.5px] text-rose-700 dark:text-rose-300`,children:y}),!m&&!y&&(0,O.jsx)(`div`,{className:`flex justify-center py-10 text-muted`,children:(0,O.jsx)(c,{size:20,className:`animate-spin`})}),z.map((e,n)=>(0,O.jsx)(F,{who:e.role===`user`?`you`:`agent`,agent:t,children:e.role===`user`?(0,O.jsx)(`span`,{className:`whitespace-pre-wrap`,children:e.text}):(0,O.jsx)(g,{text:e.text})},n)),j.filter(e=>!(e.run.status===`done`&&(e.run.resumed||!e.run.asked_session_id)&&z.some(t=>t.role===`user`&&t.text.trim()===e.run.text.trim()))).map(e=>(0,O.jsx)(M,{live:e,agent:t,hideFinishedText:z.length>0&&e.run.status===`done`},e.run.id)),m&&z.length===0&&j.length===0&&(0,O.jsx)(`p`,{className:`py-6 text-center text-[13px] text-muted`,children:f(`Nothing readable in this chat yet.`)})]})})}function M({live:e,agent:t,hideFinishedText:r}){let i=n(),{run:a,events:o,current:s}=e,l=o.filter(e=>e.kind===`tool`),u=k[t];return(0,O.jsxs)(O.Fragment,{children:[(0,O.jsx)(F,{who:`you`,agent:t,badge:i(`via nanoMuse`),children:(0,O.jsx)(`span`,{className:`whitespace-pre-wrap`,children:a.text})}),(l.length>0||a.status===`running`)&&(0,O.jsxs)(`div`,{className:`mx-1 rounded-2xl border border-border/60 bg-surface-2/40 px-3 py-2 text-[12.5px]`,children:[(0,O.jsxs)(`div`,{className:`flex items-center gap-1.5 font-medium text-fg/80`,children:[a.status===`running`?(0,O.jsx)(c,{size:13,className:`animate-spin text-accent`}):(0,O.jsx)(w,{size:13,className:`text-muted`}),a.status===`running`?i(`{agent} is working…`,{agent:u?.label??t}):i(`{n} steps`,{n:l.length}),a.device&&(0,O.jsxs)(`span`,{className:`ml-auto flex items-center gap-1 text-muted`,children:[(0,O.jsx)(S,{size:11}),` `,a.device]})]}),l.length>0&&(0,O.jsx)(`ul`,{className:`mt-1.5 max-h-28 space-y-0.5 overflow-y-auto font-mono text-[11.5px] text-muted`,children:l.slice(-12).map((e,t)=>(0,O.jsx)(`li`,{className:`truncate`,children:e.text},t))})]}),(s||a.output&&!r)&&(0,O.jsxs)(F,{who:`agent`,agent:t,children:[(0,O.jsx)(g,{text:a.status===`running`?(a.output?a.output+` `:``)+s:a.output}),a.status===`running`&&(0,O.jsx)(`span`,{className:`ml-1 inline-block h-3.5 w-1 animate-pulse bg-accent align-middle`})]}),a.status===`failed`&&(0,O.jsx)(`div`,{className:`mx-1 rounded-2xl bg-rose-500/12 px-3 py-2 text-[12.5px] text-rose-700 dark:text-rose-300`,children:a.error||i(`failed`)}),a.status===`stopped`&&(0,O.jsx)(`div`,{className:`mx-1 text-center text-[12px] text-muted`,children:i(`stopped`)}),!a.resumed&&a.asked_session_id&&a.status!==`running`&&(0,O.jsx)(`div`,{className:`mx-1 text-center text-[12px] text-muted`,children:i(`Continued as a new chat: the agent could not reopen the old one.`)})]})}function N({live:e,onOpen:t}){let r=n(),{run:i,events:a,current:o}=e,s=[...a].reverse().find(e=>e.kind===`tool`);return(0,O.jsxs)(`button`,{type:`button`,onClick:t,className:`flex w-full items-center gap-3 rounded-3xl border border-accent/25 bg-accent/5 px-3.5 py-3 text-left`,children:[(0,O.jsx)(I,{agent:i.agent,size:34}),(0,O.jsxs)(`span`,{className:`min-w-0 flex-1`,children:[(0,O.jsx)(`span`,{className:`block truncate text-[14px] font-medium`,children:i.text}),(0,O.jsxs)(`span`,{className:`mt-0.5 flex items-center gap-1.5 truncate text-[12px] text-muted`,children:[(0,O.jsx)(c,{size:11,className:`animate-spin text-accent`}),(0,O.jsx)(`span`,{className:`truncate`,children:o.slice(-80)||s?.text||r(`starting…`)})]})]}),i.device&&(0,O.jsx)(S,{size:14,className:`shrink-0 text-muted`})]})}function P({agent:t,agents:r,device:i,onClose:a,onStarted:s}){let{toast:l}=o(),m=n(),[h,g]=(0,D.useState)(t),[_,y]=(0,D.useState)(``),[b,x]=(0,D.useState)(``),[S,w]=(0,D.useState)(!1),[T,E]=(0,D.useState)([]);(0,D.useEffect)(()=>{u.codingSessions({agent:h,device:i,limit:30}).then(e=>E(Array.from(new Set(e.sessions.map(e=>e.workspace).filter(Boolean))).slice(0,6))).catch(()=>E([]))},[h,i]);let A=async()=>{if(b.trim()&&!S){w(!0);try{s(await u.codingSend({agent:h,text:b.trim(),workspace:_.trim(),device:i}))}catch(e){l(e.message)}finally{w(!1)}}};return(0,O.jsx)(C,{open:!0,onClose:a,title:m(`New chat`),footer:(0,O.jsxs)(`button`,{type:`button`,disabled:!b.trim()||S,onClick:()=>void A(),className:e(f,`w-full py-3`),children:[S?(0,O.jsx)(c,{size:15,className:`animate-spin`}):(0,O.jsx)(v,{size:15}),` `,m(`Send to {agent}`,{agent:k[h]?.label??h})]}),children:(0,O.jsxs)(`div`,{className:`space-y-4 py-1`,children:[(0,O.jsx)(`div`,{className:`grid grid-cols-3 gap-1 rounded-2xl bg-surface-2/70 p-1 text-[13px] font-medium`,children:r.map(t=>(0,O.jsxs)(`button`,{type:`button`,onClick:()=>g(t.id),className:e(`flex items-center justify-center gap-1.5 rounded-xl px-2 py-2 transition`,h===t.id?`bg-surface text-fg shadow-sm`:`text-muted`),children:[(0,O.jsx)(I,{agent:t.id,size:18}),` `,k[t.id]?.label??t.name]},t.id))}),(0,O.jsxs)(`div`,{children:[(0,O.jsx)(`label`,{className:`text-[12px] text-muted`,children:m(`Project folder`)}),(0,O.jsx)(`input`,{value:_,onChange:e=>y(e.target.value),placeholder:`/home/you/project`,className:e(p,`mt-1 font-mono text-[13px]`)}),T.length>0&&(0,O.jsx)(`div`,{className:`mt-2 flex flex-wrap gap-1.5`,children:T.map(t=>(0,O.jsx)(`button`,{type:`button`,onClick:()=>y(t),className:e(`rounded-full border px-2.5 py-1 text-[12px]`,_===t?`border-accent/40 bg-accent/10 text-accent`:`border-border text-muted`),children:B(t)},t))})]}),(0,O.jsxs)(`div`,{children:[(0,O.jsx)(`label`,{className:`text-[12px] text-muted`,children:m(`What to do`)}),(0,O.jsx)(`textarea`,{value:b,onChange:e=>x(e.target.value),rows:4,autoFocus:!0,placeholder:m(`Add tests for the parser and run them`),className:e(p,`mt-1 resize-none`)})]}),(0,O.jsx)(`p`,{className:`text-[12px] text-muted`,children:m(`The agent runs on that computer with its own permissions; nanoMuse only carries the message and brings the answer back.`)}),(0,O.jsx)(`button`,{type:`button`,onClick:a,className:e(d,`w-full`),children:m(`Cancel`)})]})})}function F({who:t,agent:n,badge:r,children:i}){return(0,O.jsxs)(`div`,{className:e(`flex`,t===`you`?`justify-end`:`justify-start`),children:[t===`agent`&&(0,O.jsx)(I,{agent:n,size:24,className:`mr-2 mt-1 shrink-0`}),(0,O.jsxs)(`div`,{className:e(`max-w-[86%] rounded-3xl px-3.5 py-2 text-[14px] leading-relaxed`,t===`you`?`rounded-br-lg bg-bubble-user text-bubble-user-fg`:`rounded-bl-lg bg-surface-2`),children:[r&&(0,O.jsx)(`div`,{className:`mb-0.5 text-[10.5px] font-semibold uppercase tracking-wide text-fg/45`,children:r}),(0,O.jsx)(`div`,{className:`md break-words`,children:i})]})]})}function I({agent:t,size:n=28,className:r}){let i=k[t];return(0,O.jsx)(`span`,{className:e(`flex shrink-0 items-center justify-center rounded-xl bg-gradient-to-br font-bold text-white shadow-sm`,i?.tone??`from-slate-400 to-slate-600`,r),style:{width:n,height:n,fontSize:Math.round(n*.46)},"aria-hidden":!0,children:i?.glyph??(0,O.jsx)(h,{size:Math.round(n*.55)})})}function L({status:e}){let t=n();return e===`running`?(0,O.jsxs)(`span`,{className:`flex shrink-0 items-center gap-1 rounded-full bg-emerald-500/12 px-2 py-0.5 text-[10.5px] font-semibold text-emerald-700 dark:text-emerald-300`,children:[(0,O.jsx)(`span`,{className:`h-1.5 w-1.5 animate-pulse rounded-full bg-emerald-500`}),` `,t(`working`)]}):e===`active`?(0,O.jsx)(`span`,{className:`h-2 w-2 shrink-0 rounded-full bg-accent`,title:t(`active`)}):null}function R({active:t,onClick:n,icon:r,label:i}){return(0,O.jsxs)(`button`,{type:`button`,onClick:n,className:e(`flex shrink-0 items-center gap-1.5 rounded-full border px-3 py-1.5 text-[12.5px] font-medium transition`,t?`border-fg bg-fg text-bg`:`border-border bg-surface text-fg/75`),children:[r,` `,i]})}function z(e,t){return e.find(e=>e.id===t)?.name??t}function B(e){let t=e.replace(/[\\/]+$/,``).split(/[\\/]/);return t[t.length-1]||e}export{A as CodingScreen}; \ No newline at end of file diff --git a/nanomuse/server/static/assets/ConnectionsScreen-0U0bXAf7.js b/nanomuse/server/static/assets/ConnectionsScreen-CMt7GOff.js similarity index 99% rename from nanomuse/server/static/assets/ConnectionsScreen-0U0bXAf7.js rename to nanomuse/server/static/assets/ConnectionsScreen-CMt7GOff.js index 5de2928c2..5c97b83c3 100644 --- a/nanomuse/server/static/assets/ConnectionsScreen-0U0bXAf7.js +++ b/nanomuse/server/static/assets/ConnectionsScreen-CMt7GOff.js @@ -1 +1 @@ -import{A as e,E as t,J as n,K as r,L as i,Q as a,Y as o,b as s,f as c,q as l,x as u}from"./MuseHeader-Pw-NI98v.js";import{C as d,O as f,S as p,b as m,f as h,g,h as _,k as v,m as y,v as b,w as x,x as S}from"./StarNudge-DjXecvWj.js";import{n as C,t as w}from"./external-link-Xj5fjR8v.js";import{a as T,c as E,i as D,r as O,s as k,t as A}from"./Form-DwKuBk1V.js";import{t as j}from"./clapperboard-BokpXv9J.js";import{t as M}from"./image-crWy0a06.js";import{t as N}from"./plug-Bj_5EEV3.js";import{t as P}from"./refresh-cw-BKgIzslL.js";import{Ct as F,E as I,G as L,N as ee,P as te,T as R,V as z,X as B,Z as V,j as H,lt as U,pt as ne,st as re,ut as ie,xt as ae}from"./index-BjYzdKkG.js";import{t as oe}from"./BackBar-Dli0L0O_.js";import{t as se}from"./CloudCard-CdydxD3H.js";var ce=n(`brain-circuit`,[[`path`,{d:`M12 5a3 3 0 1 0-5.997.125 4 4 0 0 0-2.526 5.77 4 4 0 0 0 .556 6.588A4 4 0 1 0 12 18Z`,key:`l5xja`}],[`path`,{d:`M9 13a4.5 4.5 0 0 0 3-4`,key:`10igwf`}],[`path`,{d:`M6.003 5.125A3 3 0 0 0 6.401 6.5`,key:`105sqy`}],[`path`,{d:`M3.477 10.896a4 4 0 0 1 .585-.396`,key:`ql3yin`}],[`path`,{d:`M6 18a4 4 0 0 1-1.967-.516`,key:`2e4loj`}],[`path`,{d:`M12 13h4`,key:`1ku699`}],[`path`,{d:`M12 18h6a2 2 0 0 1 2 2v1`,key:`105ag5`}],[`path`,{d:`M12 8h8`,key:`1lhi5i`}],[`path`,{d:`M16 8V5a2 2 0 0 1 2-2`,key:`u6izg6`}],[`circle`,{cx:`16`,cy:`13`,r:`.5`,key:`ry7gng`}],[`circle`,{cx:`18`,cy:`3`,r:`.5`,key:`1aiba7`}],[`circle`,{cx:`20`,cy:`21`,r:`.5`,key:`yhc1fs`}],[`circle`,{cx:`20`,cy:`8`,r:`.5`,key:`1e43v0`}]]),W=n(`contact`,[[`path`,{d:`M16 2v2`,key:`scm5qe`}],[`path`,{d:`M7 22v-2a2 2 0 0 1 2-2h6a2 2 0 0 1 2 2v2`,key:`1waht3`}],[`path`,{d:`M8 2v2`,key:`pbkmx`}],[`circle`,{cx:`12`,cy:`11`,r:`3`,key:`itu57m`}],[`rect`,{x:`3`,y:`4`,width:`18`,height:`18`,rx:`2`,key:`12vinp`}]]),le=n(`eye-off`,[[`path`,{d:`M10.733 5.076a10.744 10.744 0 0 1 11.205 6.575 1 1 0 0 1 0 .696 10.747 10.747 0 0 1-1.444 2.49`,key:`ct8e1f`}],[`path`,{d:`M14.084 14.158a3 3 0 0 1-4.242-4.242`,key:`151rxh`}],[`path`,{d:`M17.479 17.499a10.75 10.75 0 0 1-15.417-5.151 1 1 0 0 1 0-.696 10.75 10.75 0 0 1 4.446-5.143`,key:`13bj9a`}],[`path`,{d:`m2 2 20 20`,key:`1ooewy`}]]),ue=n(`eye`,[[`path`,{d:`M2.062 12.348a1 1 0 0 1 0-.696 10.75 10.75 0 0 1 19.876 0 1 1 0 0 1 0 .696 10.75 10.75 0 0 1-19.876 0`,key:`1nclc0`}],[`circle`,{cx:`12`,cy:`12`,r:`3`,key:`1v7zrd`}]]),de=n(`unplug`,[[`path`,{d:`m19 5 3-3`,key:`yk6iyv`}],[`path`,{d:`m2 22 3-3`,key:`19mgm9`}],[`path`,{d:`M6.3 20.3a2.4 2.4 0 0 0 3.4 0L12 18l-6-6-2.3 2.3a2.4 2.4 0 0 0 0 3.4Z`,key:`goz73y`}],[`path`,{d:`M7.5 13.5 10 11`,key:`7xgeeb`}],[`path`,{d:`M10.5 16.5 13 14`,key:`10btkg`}],[`path`,{d:`m12 6 6 6 2.3-2.3a2.4 2.4 0 0 0 0-3.4l-2.6-2.6a2.4 2.4 0 0 0-3.4 0Z`,key:`1snsnr`}]]),fe=n(`upload`,[[`path`,{d:`M12 3v12`,key:`1x0j5s`}],[`path`,{d:`m17 8-5-5-5 5`,key:`7q97r8`}],[`path`,{d:`M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4`,key:`ih7n3h`}]]),G=a(o(),1);function pe(e,t){let n=t.trim().toLowerCase();return!n||e.id.toLowerCase().includes(n)||e.name.toLowerCase().includes(n)}function me(e,t){let n=e.default&&e.rows.some(t=>t.id===e.default)?e.default:e.rows.find(e=>e.recommended)?.id,r=t&&t.group===e.key?t.id:void 0,i=[];for(let t of[n,r]){if(!t||i.some(e=>e.id===t))continue;let n=e.rows.find(e=>e.id===t);n&&i.push(n)}return[...i,...e.rows.filter(e=>!i.includes(e))]}function he(e){return e.reduce((e,t)=>e+t.rows.length,0)}function ge(e){return he(e)>8}function _e(e,{current:t,query:n=``,expanded:r}={}){let i=n.trim().length>0,a=[];for(let o of e){let e=me(o,t);if(i){let t=e.filter(e=>pe(e,n));t.length&&a.push({key:o.key,label:o.label,rows:t,more:0});continue}e.length>8&&!r?.has(o.key)?a.push({key:o.key,label:o.label,rows:e.slice(0,8),more:e.length-8}):a.push({key:o.key,label:o.label,rows:e,more:0})}return a}var K=s(),q=`flex w-full items-center gap-2 rounded-xl px-3 py-2 text-left text-[14px] hover:bg-surface-2 focus:bg-surface-2 focus:outline-none`;function ve({label:e,text:n,heads:i=[],headValue:a,tail:o,groups:s,current:c,disabled:l,onHead:u,onPick:d,onTail:f,rowText:p}){let m=r(),[h,g]=(0,G.useState)(!1),[_,v]=(0,G.useState)(``),[y,b]=(0,G.useState)(()=>new Set),[x,S]=(0,G.useState)(!1),w=(0,G.useRef)(null),T=(0,G.useRef)(null),D=ge(s),k=(0,G.useCallback)((e=!1)=>{g(!1),v(``),b(new Set),S(e)},[]);(0,G.useEffect)(()=>{!h&&x&&(S(!1),w.current?.focus())},[h,x]),(0,G.useEffect)(()=>{if(!h)return;let e=e=>{let t=e.target;T.current?.contains(t)||w.current?.contains(t)||k()},t=e=>{e.key===`Escape`&&(e.stopPropagation(),k(!0))};return document.addEventListener(`pointerdown`,e,!0),document.addEventListener(`keydown`,t,!0),()=>{document.removeEventListener(`pointerdown`,e,!0),document.removeEventListener(`keydown`,t,!0)}},[h,k]),(0,G.useEffect)(()=>{h&&T.current&&(T.current.querySelector(`input`)??T.current.querySelector(`[aria-selected="true"]`)??T.current.querySelector(`[data-row]`))?.focus()},[h]);let A=e=>{if(e.key!==`ArrowDown`&&e.key!==`ArrowUp`)return;let t=[...e.currentTarget.closest(`[role="listbox"]`)?.querySelectorAll(`[data-row]`)??[]];if(!t.length)return;e.preventDefault();let n=t.indexOf(e.target);t[e.key===`ArrowDown`?n<0?0:Math.min(t.length-1,n+1):n<0?t.length-1:Math.max(0,n-1)]?.focus()},j=_e(s,{current:c,query:_,expanded:y}),M=_.trim().length>0,N=(e,n,r,i,a)=>(0,K.jsxs)(`button`,{type:`button`,role:`option`,"aria-selected":n,"data-row":``,title:a,onClick:i,onKeyDown:A,className:t(q,n&&`text-accent font-medium`),children:[(0,K.jsx)(`span`,{className:`min-w-0 flex-1 truncate`,children:r}),n&&(0,K.jsx)(C,{size:15,className:`shrink-0`})]},e);return(0,K.jsxs)(`div`,{className:`relative`,children:[(0,K.jsxs)(`button`,{ref:w,type:`button`,disabled:l,"aria-label":e,"aria-haspopup":`listbox`,"aria-expanded":h,title:n,onClick:()=>h?k():g(!0),className:t(O,`flex items-center gap-2 text-left text-fg disabled:opacity-50`),children:[(0,K.jsx)(`span`,{className:`min-w-0 flex-1 truncate`,children:n}),(0,K.jsx)(E,{size:16,className:`shrink-0 text-muted`})]}),h&&(0,K.jsxs)(`div`,{ref:T,role:`listbox`,"aria-label":e,className:`absolute left-0 right-0 top-full z-30 mt-1 flex max-h-[60vh] flex-col overflow-hidden rounded-2xl border border-border bg-surface p-1.5 shadow-xl`,children:[i.length>0&&(0,K.jsx)(`div`,{className:`mb-1 flex flex-col border-b border-border pb-1`,children:i.map(e=>N(`head:${e.value}`,a===e.value,e.label,()=>{u?.(e.value),k(!0)}))}),D&&(0,K.jsxs)(`label`,{className:`mb-1.5 flex items-center gap-2 rounded-xl bg-surface-2 px-3 py-2 text-muted focus-within:ring-2 focus-within:ring-accent/40`,children:[(0,K.jsx)(B,{size:15,className:`shrink-0`}),(0,K.jsx)(`input`,{type:`search`,value:_,onChange:e=>v(e.target.value),onKeyDown:A,placeholder:m(`Search models`),"aria-label":m(`Search models`),autoComplete:`off`,spellCheck:!1,className:`min-w-0 flex-1 bg-transparent text-[14px] text-fg outline-none placeholder:text-muted`})]}),(0,K.jsxs)(`div`,{className:`min-h-0 flex-1 overflow-y-auto`,children:[M&&j.length===0&&(0,K.jsx)(`div`,{className:`px-3 py-2.5 text-[13.5px] text-muted`,children:m(`No model matches`)}),j.map(e=>(0,K.jsxs)(`div`,{role:`group`,"aria-label":e.label,className:`[&+&]:mt-1.5`,children:[(0,K.jsx)(`div`,{className:`truncate px-3 pb-0.5 pt-1.5 text-[11px] font-semibold uppercase tracking-wide text-muted`,children:e.label}),e.rows.map(t=>N(`${e.key}:${t.id}`,c?.group===e.key&&c.id===t.id,p?p(t):t.name,()=>{d(e.key,t),k(!0)},t.id)),e.more>0&&(0,K.jsx)(`button`,{type:`button`,"data-row":``,onKeyDown:A,onClick:()=>b(t=>new Set([...t,e.key])),className:t(q,`text-[13px] text-accent`),children:m(`Show {n} more`,{n:e.more})})]},e.key))]}),o&&!M&&(0,K.jsx)(`div`,{className:`mt-1 border-t border-border pt-1`,children:N(`tail`,!1,o,()=>{f?.(),k(!0)})})]})]})}var ye=`nanomuse_cloud`,be=`{{vault:NANOMUSE_CLOUD_KEY}}`,xe=`custom`,J=[`openai`,`openai_responses`];function Y(e){try{return new URL(e).hostname.toLowerCase()}catch{return``}}function X(e,t,n=h){if(e&&!J.includes(e))return n.find(t=>t.id===e)??null;let r=Y(t);if(!r)return null;let i=e=>[e.base_url,e.base_url_global].map(e=>Y(e??``)).filter(Boolean);return n.find(e=>i(e).includes(r))||(n.find(e=>i(e).some(e=>{let t=e.indexOf(`.`);return t>0&&r.endsWith(e.slice(t))}))??null)}function Se(e,t,n=``,r=h){if(e===`nanomuse_cloud`)return`nanoMuse Cloud`;if(e===`chatgpt`)return`ChatGPT`;let i=r.find(t=>t.id===e);return i&&e!==`custom`?S(i,t):Y(n)||e}function Ce(e,t,n=h){if(!e.effective_provider)return``;let r=Se(e.effective_provider,t,e.base_url,n);return e.effective_model?`${r} · ${e.effective_model}`:r}function we(e,t,n,r=h){let i=e.effective_model??``;if(!i)return``;let a=(e,t)=>Se(X(e,t,r)?.id??(J.includes(e)?`custom`:e),n,t,r),o;return o=e.effective_source===`cloud`?`nanoMuse Cloud`:e.effective_source===`gui`&&(e.provider_id||e.base_url||!J.includes(e.provider||`openai`))?e.provider_id?Se(e.provider_id,n,e.base_url,r):a(e.provider,e.base_url):t.cloud?`nanoMuse Cloud`:a(t.provider,t.base_url),`${o} · ${i}`}function Te(e,t){let n=t.list??h,r=[];t.signedIn&&r.push({value:ye,label:`nanoMuse Cloud`,group:`cloud`,needsKey:!1,entry:null});let i=t.chat.cloud?null:X(t.chat.provider,t.chat.base_url,n);i&&i.capabilities.includes(e)&&r.push({value:i.id,label:S(i,t.locale),group:`chat`,needsKey:!1,entry:i});for(let a of p(t.region,e,n))a.id!==i?.id&&r.push({value:a.id,label:S(a,t.locale),group:`add`,needsKey:!0,entry:a});return r.push({value:xe,label:``,group:`add`,needsKey:!1,entry:null}),r}function Ee(e,t){return e.configured?t&&e.base_url&&Y(e.base_url)===Y(t)?ye:e.provider_id||`custom`:``}var De=`nanomuse_cloud`;function Oe(){let{state:e}=c(),[t,n]=(0,G.useState)(null),[i,a]=(0,G.useState)(null),o=e.profile?.name??`nanoMuse`,s=r(),d=(0,G.useCallback)(async()=>{try{n(await u.connections()),a(null)}catch(e){a(s(e.message))}},[s]);return(0,G.useEffect)(()=>{d()},[d,e.connectionsVersion]),(0,K.jsxs)(`div`,{className:`flex h-full flex-col`,children:[(0,K.jsx)(oe,{title:s(`Connections`),description:s(`What {name} can reach; keys stay in the vault on this machine.`,{name:o})}),(0,K.jsxs)(`div`,{className:`flex-1 overflow-y-auto px-4 pb-8 space-y-4`,children:[i&&(0,K.jsx)(`div`,{className:`rounded-2xl bg-rose-500/12 text-rose-700 dark:text-rose-300 p-3 text-[13.5px]`,children:i}),!t&&!i&&(0,K.jsx)(`div`,{className:`flex justify-center py-10 text-muted`,children:(0,K.jsx)(l,{className:`animate-spin`,size:20})}),t&&(0,K.jsxs)(K.Fragment,{children:[(0,K.jsx)(Z,{data:t,onChange:d}),t.image&&(0,K.jsx)(ke,{slot:`image`,data:t,onChange:d}),t.video&&(0,K.jsx)(ke,{slot:`video`,data:t,onChange:d}),(0,K.jsx)(se,{account:e.hub?.account??null,onChange:d}),t.embeddings.memory_enabled&&(0,K.jsx)(Ae,{data:t,onChange:d}),(0,K.jsx)(je,{data:t,onChange:d}),(0,K.jsx)(Ne,{data:t,onChange:d}),(0,K.jsx)(Fe,{data:t,onChange:d}),(0,K.jsx)(Ie,{data:t,onChange:d}),(0,K.jsx)(Q,{data:t,onChange:d}),(0,K.jsx)(Le,{data:t,onChange:d}),(0,K.jsx)(Re,{data:t,onChange:d}),(0,K.jsx)(ze,{data:t,onChange:d})]})]})]})}function Z({data:e,onChange:n,compact:a}){let{toast:o,state:s}=c(),p=r(),[m,g]=(0,G.useState)(!!a),j=e.providers,M=!!s.hub?.account?.any_model,P=Object.entries(j).find(([t,n])=>t!==`custom`&&n.base_url&&e.llm.base_url.startsWith(n.base_url)&&n.provider===e.llm.provider)?.[0]??Object.entries(j).find(([t,n])=>t!==`custom`&&n.base_url&&e.llm.base_url.startsWith(n.base_url))?.[0]??(e.llm.base_url?`custom`:`deepseek`),[I,L]=(0,G.useState)(P),[R,z]=(0,G.useState)(e.llm.model),[B,V]=(0,G.useState)(e.llm.base_url),[H,ne]=(0,G.useState)(``),[re,ie]=(0,G.useState)(!1),[ae,oe]=(0,G.useState)(!1),[se,ce]=(0,G.useState)(e.llm.key_source===`none`&&!!j[P]?.key_optional),[W,de]=(0,G.useState)(e.llm.tool_mode||`auto`),[fe,pe]=(0,G.useState)(e.llm.proxy??``),[me,he]=(0,G.useState)(!1),[ge,_e]=(0,G.useState)(!1),[q,ye]=(0,G.useState)(null),[be,xe]=(0,G.useState)(!1),[J,Y]=(0,G.useState)(e.gui?.model??``),[X,Se]=(0,G.useState)({list:j[P]?.models??[],image:[],video:[],menu:[],catalog:[],imageCatalog:[],videoCatalog:[],vision:[],gui:j[P]?.gui_models??[],source:`catalogue`}),[Ce,Te]=(0,G.useState)(!1),[Ee,Oe]=(0,G.useState)(!1);(0,G.useEffect)(()=>{z(e.llm.model),V(e.llm.base_url),de(e.llm.tool_mode||`auto`),pe(e.llm.proxy??``),he(!1),Y(e.gui?.model??``),L(P)},[e.llm,e.gui?.model]);let Z=j[I],ke=I===`custom`||!Z?.base_url?B:Z.base_url;(0,G.useEffect)(()=>{if(!m)return;let e=!0,t=setTimeout(()=>{Se(e=>({...e,source:`loading`})),u.llmModels({preset:I,base_url:ke,api_key:H||void 0}).then(t=>{e&&(Se({list:t.models,image:t.image_models??[],video:t.video_models??[],menu:t.menu??[],catalog:t.catalog??[],imageCatalog:t.image_catalog??[],videoCatalog:t.video_catalog??[],vision:t.vision??[],gui:t.gui??j[I]?.gui_models??[],source:t.source}),t.source===`live`&&t.models.length&&!Ce&&z(e=>t.models.includes(e)?e:t.models[0]))}).catch(()=>e&&Se({list:Z?.models??[],image:[],video:[],menu:[],catalog:[],imageCatalog:[],videoCatalog:[],vision:[],gui:Z?.gui_models??[],source:`catalogue`}))},H?600:150);return()=>{e=!1,clearTimeout(t)}},[m,I,ke,H]);let Ae=t=>{L(t);let n=j[t];n&&(n.base_url?V(n.base_url):j[I]?.base_url&&V(``),(!R||Object.values(j).some(e=>e.models?.includes(R)))&&n.models?.length&&!n.models.includes(R)&&z(n.models[0]),Se({list:n.models??[],image:[],video:[],menu:[],catalog:[],imageCatalog:[],videoCatalog:[],vision:[],gui:n.gui_models??[],source:`catalogue`}),(!e.gui?.model||Object.values(j).some(t=>t.gui_model===e.gui?.model))&&Y(n.cloud?``:n.gui_model??``),Oe(!1),Te(!1),ce(!1))};(0,G.useEffect)(()=>{let e=ee();e&&j[e]&&(g(!0),Ae(e))},[]);let je=!!Z?.no_key||se&&!!Z?.key_optional,Me=e.llm.cloud?{text:p(`Your account's model`),tone:`ok`}:e.llm.key_source===`none`&&!j[P]?.no_key&&!j[P]?.key_optional?{text:p(`No key yet`),tone:`warn`}:e.llm.key_source===`missing`?{text:p(`Key missing from vault`),tone:`warn`}:{text:e.llm.key_source===`vault`?p(`Key in vault`):e.llm.key_source===`config`?p(`Key from config`):p(`No key needed`),tone:`ok`},Ne=async()=>{_e(!0),ye(null);try{Z?.cloud?await u.cloudUseAsModel(R.trim()):await u.setLLM({provider:Z?.provider??`openai`,model:R.trim(),base_url:ke.trim(),tool_mode:W,api_key:H||(je?``:null),proxy:me&&e.llm.proxy!==void 0?fe.trim():null}),J.trim()!==(e.gui?.model??``)&&await u.setGui({model:J.trim()}),ne(``),b(),o(p(`Model saved`)),n(),a||g(!1)}catch(e){o(e.message)}finally{_e(!1)}},Pe=async()=>{xe(!0);try{ye(await u.testLLM())}catch(e){ye({ok:!1,error:e.message})}finally{xe(!1)}},Fe=[{id:`cloud`,title:p(`Your account`),ids:[]},{id:`openai`,title:p(`OpenAI-compatible · Chat Completions`),ids:[]},{id:`responses`,title:p(`Responses API`),ids:[]},{id:`local`,title:p(`Local or your own endpoint`),ids:[]}];for(let[e,t]of Object.entries(j))(Fe.find(e=>e.id===(t.group??`openai`))??Fe[0]).ids.push(e);for(let e of Fe)e.ids=v(e.ids,j,s.hub?.account);let Ie=I===`custom`||!Z?.base_url,Q=Z?.cloud?null:h.find(e=>e.id===y(I))??null,Le=d(s.hub?.account),Re=i(),ze=e=>!!Q&&!Q.user_capabilities&&!Q.capabilities.includes(e),Ve=j[De],Ge=Z?.cloud?X.gui[0]??Z.gui_model??``:Q&&!Q.user_capabilities?Q.capabilities.includes(`vision`)?Q.defaults.hands||R.trim():Ve?.gui_model??R.trim():R.trim(),Ke=!Z?.cloud&&ze(`vision`)&&!!Ve,qe=e.gui?we(e.gui,e.llm,Re):``,Je=Array.from(new Set([...Z?.cloud?X.gui:[],...Z?.gui_model?[Z.gui_model]:[],...X.list.filter(e=>X.vision.includes(e)||f(e)===!0)])).filter(Boolean),Ye=Z?.cloud?`nanoMuse Cloud`:Q?S(Q,Re):We(ke)||I,Xe=Z?.cloud?X.gui[0]??Z.gui_model??``:Q?.defaults.hands??Z?.gui_model??``,Ze=[{key:`hands`,label:Ye,rows:Je.map(e=>({id:e,name:e})),...Xe?{default:Xe}:{}}],Qe=Ie&&/^https?:\/\/[^/]+\/?$/.test(B.trim());return(0,K.jsxs)(A,{icon:(0,K.jsx)(F,{size:19}),title:p(`Chat model`),summary:e.llm.cloud?`nanoMuse Cloud · ${e.llm.model||`—`}`:`${e.llm.model||`—`}${e.llm.base_url?` · ${We(e.llm.base_url)}`:``}`,status:Me,open:m,onToggle:a?void 0:()=>g(!m),children:[(0,K.jsx)($,{label:p(`Provider`),children:(0,K.jsxs)(`div`,{className:`space-y-2.5`,children:[Fe.filter(e=>e.ids.length).map(e=>(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`div`,{className:`mb-1 text-[11px] uppercase tracking-wide text-muted`,children:e.title}),(0,K.jsx)(`div`,{className:`flex flex-wrap gap-1.5`,children:e.ids.map(e=>{let n=j[e];return(0,K.jsxs)(`button`,{type:`button`,onClick:()=>Ae(e),className:t(`rounded-2xl px-3 py-1.5 text-left border leading-tight`,I===e?`border-accent bg-accent/10 text-accent`:`border-border text-muted`),children:[(0,K.jsx)(`span`,{className:t(`block text-[13px]`,I===e&&`font-medium`),children:n.label}),n.subtitle&&(0,K.jsx)(`span`,{className:`block text-[10.5px] opacity-80`,children:p(n.subtitle)})]},e)})})]},e.id)),Q&&(0,K.jsxs)(`p`,{className:`text-[12px] text-muted`,children:[(0,K.jsx)(`span`,{className:`font-medium text-fg`,children:S(Q,Re)}),` · `,_(p,Q.capabilities),`. `,Re===`zh-CN`?Q.note_zh:Q.note]}),(0,K.jsxs)(`div`,{children:[(0,K.jsxs)(`button`,{type:`button`,onClick:()=>oe(!ae),className:`inline-flex items-center gap-1.5 text-[12.5px] text-accent`,children:[(0,K.jsx)(U,{size:13}),` `,p(`Or sign in with a ChatGPT plan`),` `,ae?(0,K.jsx)(k,{size:13}):(0,K.jsx)(E,{size:13})]}),ae&&(0,K.jsx)(`div`,{className:`mt-2`,children:(0,K.jsx)(te,{compact:!0,onChanged:()=>{n()}})})]})]})}),Ie&&(0,K.jsx)($,{label:p(`Base URL`),hint:p(Qe?`/v1 is added when the URL has no path.`:`The endpoint that serves /chat/completions, for example http://127.0.0.1:8000/v1.`),children:(0,K.jsx)(`input`,{value:B,onChange:e=>V(e.target.value),className:`w-full rounded-2xl bg-surface-2 px-3.5 py-2.5 text-[14.5px] outline-none focus:ring-2 focus:ring-accent/40`,placeholder:`https://host/v1`,inputMode:`url`,autoCapitalize:`off`})}),(0,K.jsxs)($,{label:p(`Chat model`),hint:Z?.cloud&&M&&X.catalog.length?p(`{n} models your account may use: the menu first, then everything else the provider lists under the Cloud key. Pick one; the ones beyond the menu are priced as the dearest menu model of their kind.`,{n:X.list.length}):Z?.cloud&&M?p(`Your account may name any model the provider has, not only these: type its id (a chat model here, a picture or clip model below) and it goes through as typed.`):X.source===`live`?p(`{n} models from the endpoint`,{n:X.list.length}):X.source===`loading`?p(`Asking the endpoint…`):X.list.length?p(`Could not list the endpoint's models; these are the usual ones.`):void 0,children:[Z?.cloud&&X.catalog.length>0&&!Ee&&(!R||X.list.includes(R))?(0,K.jsxs)(`select`,{value:R,onChange:e=>{if(e.target.value===Be){Oe(!0);return}z(e.target.value),Te(!0)},className:t(O,`text-fg`),children:[!R&&(0,K.jsx)(`option`,{value:``,children:p(`model name`)}),(0,K.jsx)(`optgroup`,{label:p(`Menu`),children:X.menu.map(e=>(0,K.jsx)(`option`,{value:e,children:X.vision.includes(e)?`${e} · ${p(`reads pictures`)}`:e},e))}),(0,K.jsx)(`optgroup`,{label:p(`More models on your account`),children:X.catalog.map(e=>(0,K.jsx)(`option`,{value:e,children:X.vision.includes(e)?`${e} · ${p(`reads pictures`)}`:e},e))}),(0,K.jsx)(`option`,{value:Be,children:p(`Type a model id…`)})]}):(0,K.jsxs)(K.Fragment,{children:[(0,K.jsx)(`input`,{list:`om-models`,value:R,onChange:e=>{z(e.target.value),Te(!0)},className:O,placeholder:p(`model name`),autoCapitalize:`off`,autoCorrect:`off`,autoFocus:Ee}),(0,K.jsx)(`datalist`,{id:`om-models`,children:X.list.map(e=>(0,K.jsx)(`option`,{value:e},e))}),Z?.cloud&&X.catalog.length>0&&(0,K.jsx)(`button`,{type:`button`,className:`mt-1.5 text-[12px] text-accent`,onClick:()=>{Oe(!1),X.list.includes(R)||z(X.menu[0]??X.list[0]??``)},children:p(`Pick from the list`)})]}),X.list.length>0&&(0,K.jsx)(`div`,{className:`mt-1.5 flex flex-wrap gap-1.5`,children:(X.menu.length?X.menu:X.list).slice(0,8).map(e=>(0,K.jsx)(`button`,{type:`button`,onClick:()=>z(e),className:t(`rounded-full px-2.5 py-1 text-[12px] border`,R===e?`border-accent bg-accent/10 text-accent font-medium`:`border-border text-muted`),children:e},e))})]}),(0,K.jsxs)($,{label:p(`Hands model`),hint:Z?.cloud?p(`The model that looks at screens when the hands run: the phone, this computer, a page the browser cannot read. Your account's hands model is {model}; the chat model above is a different pick.`,{model:Ge||`—`}):Ke?p(`The model that looks at screens when the hands run. This provider has no model that sees, so the hands use your account's, {model}, unless you pick one here.`,{model:Ge||`—`}):p(`The model that looks at screens when the hands run: a small, fast one that takes pictures, on the same endpoint and key. Default: this provider's own hands model.`),children:[(0,K.jsx)(ve,{label:p(`Hands model`),text:J?`${Ye} · ${J}`:p(`Automatic`),heads:[{value:``,label:p(`Automatic`)}],headValue:J?void 0:``,groups:Ze,current:J?{group:`hands`,id:J}:void 0,onHead:()=>Y(``),onPick:(e,t)=>Y(t.id)}),qe&&(0,K.jsx)(`p`,{className:`mt-1.5 text-[12px] text-muted`,children:p(`Currently {value}`,{value:qe})}),!Z?.cloud&&R.trim()&&!J&&f(R.trim())===!1&&(0,K.jsx)(`div`,{className:`mt-1.5 text-[12px] text-amber-700 dark:text-amber-300`,children:p(`{model} does not take pictures, so the hands would be blind with it. Pick a model that sees for them.`,{model:R.trim()})}),ze(`vision`)&&!Ke&&(0,K.jsxs)(`div`,{className:`mt-1.5 text-[12px] text-amber-700 dark:text-amber-300`,children:[x(p,`vision`,Le,Re),` `,(0,K.jsx)(He,{})]})]}),!Z?.no_key&&(0,K.jsxs)($,{label:p(`API key`),hint:se&&Z?.key_optional?p(`No key will be sent.`):e.llm.key_source===`vault`&&I===P?p(`A key is in the vault. Leave blank to keep it.`):p(`Stored encrypted in the vault as LLM_API_KEY.`),children:[(0,K.jsxs)(`div`,{className:`relative`,children:[(0,K.jsx)(`input`,{type:re?`text`:`password`,value:H,onChange:e=>ne(e.target.value),disabled:se&&!!Z?.key_optional,className:t(`w-full rounded-2xl bg-surface-2 px-3.5 py-2.5 text-[14.5px] outline-none focus:ring-2 focus:ring-accent/40`,`pr-10 disabled:opacity-50`),placeholder:e.llm.key_source===`vault`&&I===P?`••••••••`:Z?.key_hint||`sk-…`,autoComplete:`off`,autoCapitalize:`off`,spellCheck:!1}),(0,K.jsx)(`button`,{type:`button`,onClick:()=>ie(!re),"aria-label":p(re?`Hide key`:`Show key`),className:`absolute right-2 top-1/2 -translate-y-1/2 rounded-full p-1.5 text-muted`,children:re?(0,K.jsx)(le,{size:16}):(0,K.jsx)(ue,{size:16})})]}),(0,K.jsxs)(`div`,{className:`mt-1.5 flex items-center justify-between gap-2 text-[12px]`,children:[Z?.key_url?(0,K.jsxs)(`a`,{href:Z.key_url,target:`_blank`,rel:`noreferrer`,className:`inline-flex items-center gap-1 text-accent`,children:[p(`Get a key from {vendor}`,{vendor:Z.label}),` `,(0,K.jsx)(w,{size:12})]}):(0,K.jsx)(`span`,{}),Z?.key_optional&&(0,K.jsxs)(`label`,{className:`inline-flex items-center gap-1.5 text-muted`,children:[(0,K.jsx)(`input`,{type:`checkbox`,checked:se,onChange:e=>ce(e.target.checked),className:`accent-accent`}),` `,p(`No key`)]})]})]}),(0,K.jsx)($,{label:p(`Tool calling`),hint:p(`Auto uses the API's function calling and falls back to describing tools in the prompt when the endpoint rejects them. Prompt: for endpoints that silently ignore tools.`),children:(0,K.jsx)(`div`,{className:`flex gap-1.5`,children:[`auto`,`native`,`prompt`].map(e=>(0,K.jsx)(`button`,{type:`button`,onClick:()=>de(e),className:t(`rounded-full px-3 py-1.5 text-[13px] border`,W===e?`border-accent bg-accent/10 text-accent font-medium`:`border-border text-muted`),children:e},e))})}),!Z?.cloud&&e.llm.proxy!==void 0&&(0,K.jsx)($,{label:p(`Proxy (optional)`),hint:p(`Only this provider's requests go through it. nanoMuse Cloud never does.`),children:(0,K.jsx)(`input`,{className:`w-full rounded-2xl bg-surface-2 px-3.5 py-2.5 text-[14.5px] outline-none focus:ring-2 focus:ring-accent/40`,value:fe,onChange:e=>{pe(e.target.value),he(!0)},onFocus:()=>fe.includes(`••••`)&&!me&&pe(``),onBlur:()=>!me&&pe(e.llm.proxy??``),placeholder:`http://host:port / socks5://host:port`,autoComplete:`off`,spellCheck:!1})}),(0,K.jsxs)(`div`,{className:`flex gap-2 pt-1`,children:[(0,K.jsxs)(`button`,{type:`button`,disabled:ge||!R.trim()||Ie&&!B.trim(),onClick:()=>void Ne(),className:D,children:[ge?(0,K.jsx)(l,{size:16,className:`animate-spin`}):(0,K.jsx)(C,{size:16}),` `,p(`Save`)]}),(0,K.jsxs)(`button`,{type:`button`,disabled:be,onClick:()=>void Pe(),className:T,children:[be?(0,K.jsx)(l,{size:16,className:`animate-spin`}):(0,K.jsx)(N,{size:16}),` `,p(`Test`)]})]}),q&&(0,K.jsx)(Ue,{result:q,okText:p(`Replied "{reply}" in {ms} ms`,{reply:q.reply??``,ms:q.ms??0})})]})}function ke({slot:e,data:n,onChange:a}){let{toast:o,state:s}=c(),f=r(),p=n[e],h=e,v=s.hub?.account??null,y=!!v?.signed_in,T=d(v),E=i(),k=n.providers[De]?.base_url??``,N=Te(h,{signedIn:y,chat:{provider:n.llm.provider,base_url:n.llm.base_url,cloud:!!n.llm.cloud},region:T,locale:E}),P=Ee(p,k),[F,I]=(0,G.useState)(!1),[L,ee]=(0,G.useState)(P),[te,R]=(0,G.useState)(p.model),[z,B]=(0,G.useState)(p.base_url),[H,U]=(0,G.useState)(``),[ne,re]=(0,G.useState)(!1),[ie,ae]=(0,G.useState)(!1),[oe,se]=(0,G.useState)({list:[],more:[],source:`catalogue`});(0,G.useEffect)(()=>{ee(P),R(p.model),B(p.base_url),U(``)},[p]);let ce=N.find(e=>e.value===L)??null,W=ce?.entry??null,de=W?g(W,T):null,fe=L===`nanomuse_cloud`?k:L===`custom`?z.trim():de?.base_url??``,pe=P===L&&P!==``&&(p.key_source===`vault`||p.key_source===`config`),me=!!ce?.needsKey&&!H&&!pe,he=L===`nanomuse_cloud`?oe.list[0]??``:W?.defaults[e]??``;(0,G.useEffect)(()=>{if(!F||!L||L!==`nanomuse_cloud`&&!fe){se({list:[],more:[],source:`catalogue`});return}let t=!0,n=setTimeout(()=>{se(e=>({...e,source:`loading`})),u.llmModels(L===`nanomuse_cloud`?{preset:De}:{preset:W?m(W.id):``,base_url:fe,api_key:H||void 0}).then(n=>{if(!t)return;let r=(e===`image`?n.image_models:n.video_models)??[],i=(e===`image`?n.image_catalog:n.video_catalog)??[];se({list:r.filter(e=>!i.includes(e)),more:i,source:n.source})}).catch(()=>t&&se({list:[],more:[],source:`catalogue`}))},H?600:150);return()=>{t=!1,clearTimeout(n)}},[F,L,fe,H]);let ge=f(e===`image`?`Making pictures`:`Making clips`),_e=f(e===`image`?`Portraits of your Muse.`:`Short clips of your Muse.`),q=Ce(p,E),ve=x(f,h,T,E),ye=p.effective_provider?p.effective_source===`cloud`?{text:f(`Your account`),tone:`ok`}:p.effective_source===`chat`?{text:f(`The chat model's provider`),tone:`ok`}:{text:f(`Your key`),tone:`ok`}:{text:f(`Not set up`),tone:`warn`},xe=async()=>{ae(!0);try{L?L===`nanomuse_cloud`?await u.setMedia(e,{provider:`openai`,base_url:k,model:te.trim(),api_key:be}):L===`custom`?await u.setMedia(e,{provider:`openai`,base_url:z.trim(),model:te.trim(),api_key:H||null}):await u.setMedia(e,{provider:L,base_url:``,model:te.trim(),api_key:H||(ce?.group===`chat`?``:null)}):await u.setMedia(e,{provider:``,model:``,base_url:``,api_key:``}),U(``),b(),o(f(`Saved`)),a(),I(!1)}catch(e){o(e.message)}finally{ae(!1)}},J=e=>f(e===`cloud`?`Your account`:e===`chat`?`The chat model's provider`:`Add a provider`),Y=[`cloud`,`chat`,`add`].map(e=>({g:e,items:N.filter(t=>t.group===e)})).filter(e=>e.items.length),X=e===`image`?`IMAGE_API_KEY`:`VIDEO_API_KEY`;return(0,K.jsxs)(A,{icon:e===`image`?(0,K.jsx)(M,{size:19}):(0,K.jsx)(j,{size:19}),title:ge,summary:q||ve,status:ye,open:F,onToggle:()=>I(!F),children:[(0,K.jsx)(`p`,{className:`text-[12.5px] text-muted`,children:_e}),(0,K.jsxs)($,{label:f(`Provider`),hint:!q&&!L?ve:void 0,children:[(0,K.jsxs)(`select`,{value:L,onChange:e=>{ee(e.target.value),R(``),U(``)},className:t(O,`text-fg`),children:[(0,K.jsx)(`option`,{value:``,children:f(`Automatic`)}),Y.map(({g:e,items:t})=>(0,K.jsx)(`optgroup`,{label:J(e),children:t.map(e=>(0,K.jsx)(`option`,{value:e.value,children:e.value===`custom`?f(`Other OpenAI-compatible endpoint`):e.label},e.value))},e))]}),q&&(0,K.jsx)(`p`,{className:`mt-1.5 text-[12px] text-muted`,children:f(`Currently {value}`,{value:q})}),!q&&!L&&(0,K.jsxs)(`button`,{type:`button`,className:`mt-1.5 inline-flex items-center gap-1 text-[12.5px] text-accent`,onClick:()=>ee(N.find(e=>e.group===`add`)?.value??``),children:[(0,K.jsx)(V,{size:13}),` `,f(`Add a provider`)]}),W&&(0,K.jsxs)(`p`,{className:`mt-1.5 text-[12px] text-muted`,children:[(0,K.jsx)(`span`,{className:`font-medium text-fg`,children:S(W,E)}),` · `,_(f,W.capabilities),`. `,E===`zh-CN`?W.note_zh:W.note]})]}),L===`custom`&&(0,K.jsx)($,{label:f(`Base URL`),hint:f(`The endpoint that serves /images/generations, for example https://host/v1.`),children:(0,K.jsx)(`input`,{value:z,onChange:e=>B(e.target.value),className:`w-full rounded-2xl bg-surface-2 px-3.5 py-2.5 text-[14.5px] outline-none focus:ring-2 focus:ring-accent/40`,placeholder:`https://host/v1`,inputMode:`url`,autoCapitalize:`off`})}),L&&(0,K.jsx)(Ve,{label:f(e===`image`?`Picture model`:`Clip model`),provider:L===`nanomuse_cloud`?`nanoMuse Cloud`:L===`custom`?We(z)||f(`Other OpenAI-compatible endpoint`):ce?.label??L,value:te,options:oe.list,more:oe.more,onChange:R,other:L!==`nanomuse_cloud`||!!v?.any_model,placeholder:he||void 0}),L&&L!==`nanomuse_cloud`&&ce?.group!==`chat`&&(0,K.jsxs)($,{label:f(`API key`),hint:pe?f(`A key is in the vault. Leave blank to keep it.`):f(`Stored encrypted in the vault as {name}.`,{name:X}),children:[(0,K.jsxs)(`div`,{className:`relative`,children:[(0,K.jsx)(`input`,{type:ne?`text`:`password`,value:H,onChange:e=>U(e.target.value),className:t(`w-full rounded-2xl bg-surface-2 px-3.5 py-2.5 text-[14.5px] outline-none focus:ring-2 focus:ring-accent/40`,`pr-10`),placeholder:pe?`••••••••`:W?.key_hint||`sk-…`,autoComplete:`off`,autoCapitalize:`off`,spellCheck:!1}),(0,K.jsx)(`button`,{type:`button`,onClick:()=>re(!ne),"aria-label":f(ne?`Hide key`:`Show key`),className:`absolute right-2 top-1/2 -translate-y-1/2 rounded-full p-1.5 text-muted`,children:ne?(0,K.jsx)(le,{size:16}):(0,K.jsx)(ue,{size:16})})]}),de?.key_url&&(0,K.jsxs)(`a`,{href:de.key_url,target:`_blank`,rel:`noreferrer`,className:`mt-1.5 inline-flex items-center gap-1 text-[12px] text-accent`,children:[f(`Get a key from {vendor}`,{vendor:W?S(W,E):``}),` `,(0,K.jsx)(w,{size:12})]})]}),ce?.group===`chat`&&(0,K.jsx)(`p`,{className:`text-[12px] text-muted`,children:f(`Uses the chat model's key.`)}),(0,K.jsx)(`div`,{className:`flex gap-2 pt-1`,children:(0,K.jsxs)(`button`,{type:`button`,disabled:ie||me||L===`custom`&&!z.trim(),onClick:()=>void xe(),className:D,children:[ie?(0,K.jsx)(l,{size:16,className:`animate-spin`}):(0,K.jsx)(C,{size:16}),` `,f(`Save`)]})})]})}function Ae({data:e,onChange:n}){let{toast:i}=c(),a=r(),o=e.embeddings,[s,d]=(0,G.useState)(!1),[f,p]=(0,G.useState)(o.mode),[m,h]=(0,G.useState)(!!o.base_url),[g,_]=(0,G.useState)(o.base_url),[v,y]=(0,G.useState)(o.model),[b,x]=(0,G.useState)(``),[S,w]=(0,G.useState)(!1),[E,O]=(0,G.useState)(null),[k,j]=(0,G.useState)(!1);(0,G.useEffect)(()=>{p(o.mode),h(!!o.base_url),_(o.base_url),y(o.model)},[e.embeddings]);let M=o.mode===`off`?{text:a(`Off`),tone:`off`}:o.available===!0?{text:a(`On`),tone:`ok`}:o.available===!1?{text:o.mode===`on`?a(`Not reachable`):a(`By keyword`),tone:`warn`}:{text:a(`Not tried yet`),tone:`off`},P=o.mode===`off`?a(`Keyword recall only`):o.available===!0?a(`{model} · {n} of {total} memories indexed`,{model:o.model||o.default_model,n:o.indexed,total:o.total}):o.available===!1?o.reason:a(`{model} at {host}`,{model:o.model||o.default_model,host:We(o.effective_base_url)}),F=async()=>{w(!0),O(null);try{await u.setEmbeddings({mode:f,base_url:m?g.trim():``,model:v.trim(),api_key:m?b||void 0:``}),x(``),i(a(`Saved`)),n()}catch(e){i(e.message)}finally{w(!1)}},I=async()=>{j(!0);try{O(await u.testEmbeddings()),n()}catch(e){O({ok:!1,error:e.message})}finally{j(!1)}},L=e=>t(`rounded-full px-3 py-1.5 text-[13px] border`,e?`border-accent bg-accent/10 text-accent font-medium`:`border-border text-muted`);return(0,K.jsxs)(A,{icon:(0,K.jsx)(ce,{size:19}),title:a(`Recall by meaning`),summary:P,status:M,open:s,onToggle:()=>d(!s),children:[(0,K.jsx)(`p`,{className:`text-[12.5px] text-muted leading-snug`,children:a(`Memories are embedded once and a message finds the ones that mean the same thing, in any language: “写邮件给房东” finds “the landlord is Bob Li”. Keyword recall stays; the two are fused.`)}),(0,K.jsx)($,{label:a(`Mode`),hint:a(`Auto uses the model's endpoint when it has embeddings and falls back to keywords when it does not. On insists and warns. Off: keywords only.`),children:(0,K.jsx)(`div`,{className:`flex gap-1.5`,children:[`auto`,`on`,`off`].map(e=>(0,K.jsx)(`button`,{type:`button`,onClick:()=>p(e),className:L(f===e),children:a(e===`auto`?`Auto`:e===`on`?`On`:`Off`)},e))})}),f!==`off`&&(0,K.jsxs)(K.Fragment,{children:[(0,K.jsx)($,{label:a(`Endpoint`),hint:a(m?`Any OpenAI-compatible /embeddings: Ollama with an embedding model pulled, OpenAI, a gateway.`:`The model's endpoint and key. DeepSeek has no embeddings; pick another endpoint.`),children:(0,K.jsxs)(`div`,{className:`flex gap-1.5`,children:[(0,K.jsx)(`button`,{type:`button`,onClick:()=>h(!1),className:L(!m),children:a(`Same as the model`)}),(0,K.jsx)(`button`,{type:`button`,onClick:()=>{h(!0),g||_(`http://127.0.0.1:11434/v1`)},className:L(m),children:a(`Another endpoint`)})]})}),m&&(0,K.jsxs)(K.Fragment,{children:[(0,K.jsx)($,{label:a(`Base URL`),children:(0,K.jsx)(`input`,{value:g,onChange:e=>_(e.target.value),className:`w-full rounded-2xl bg-surface-2 px-3.5 py-2.5 text-[14.5px] outline-none focus:ring-2 focus:ring-accent/40`,placeholder:`http://127.0.0.1:11434/v1`,inputMode:`url`})}),(0,K.jsx)($,{label:a(`API key`),hint:o.key_source===`vault`?a(`A key is in the vault. Leave blank to keep it.`):a(`Stored encrypted in the vault as EMBEDDINGS_API_KEY. Ollama needs none.`),children:(0,K.jsx)(`input`,{type:`password`,value:b,onChange:e=>x(e.target.value),className:`w-full rounded-2xl bg-surface-2 px-3.5 py-2.5 text-[14.5px] outline-none focus:ring-2 focus:ring-accent/40`,placeholder:o.key_source===`vault`?`••••••••`:`sk-…`,autoComplete:`off`})})]}),(0,K.jsx)($,{label:a(`Embedding model`),hint:a(`Blank uses the endpoint's default: {model}. On Ollama: ollama pull qwen3-embedding:0.6b (reads Chinese and English).`,{model:o.default_model}),children:(0,K.jsx)(`input`,{value:v,onChange:e=>y(e.target.value),className:`w-full rounded-2xl bg-surface-2 px-3.5 py-2.5 text-[14.5px] outline-none focus:ring-2 focus:ring-accent/40`,placeholder:o.default_model,autoComplete:`off`})})]}),(0,K.jsxs)(`div`,{className:`flex gap-2 pt-1`,children:[(0,K.jsxs)(`button`,{type:`button`,disabled:S||m&&!/^https?:\/\//.test(g.trim()),onClick:()=>void F(),className:D,children:[S?(0,K.jsx)(l,{size:16,className:`animate-spin`}):(0,K.jsx)(C,{size:16}),` `,a(`Save`)]}),(0,K.jsxs)(`button`,{type:`button`,disabled:k||o.mode===`off`,onClick:()=>void I(),className:T,children:[k?(0,K.jsx)(l,{size:16,className:`animate-spin`}):(0,K.jsx)(N,{size:16}),` `,a(`Test`)]})]}),E&&(0,K.jsx)(Ue,{result:E,okText:a(`{model} · {dims} dims · {n} memories indexed · {ms} ms`,{model:E.model??``,dims:E.dims??0,n:E.indexed??0,ms:E.ms??0})})]})}function je({data:e,onChange:n}){let{toast:i}=c(),a=r(),o=e.search,[s,d]=(0,G.useState)(!1),[f,p]=(0,G.useState)(o.provider),[m,h]=(0,G.useState)(o.base_url),[g,_]=(0,G.useState)(``),[v,y]=(0,G.useState)(!1),[b,x]=(0,G.useState)(null),[S,w]=(0,G.useState)(!1);(0,G.useEffect)(()=>{p(o.provider),h(o.base_url)},[e.search]);let E=o.providers.find(e=>e.id===o.provider),O=o.providers.find(e=>e.id===f),k=!!O?.needs_key,j=o.configured?{text:a(`On`),tone:`ok`}:{text:a(`Not set up`),tone:`warn`},M=o.configured?o.provider===`searxng`?a(`{provider} at {host}`,{provider:E?.label??o.provider,host:We(o.base_url)}):E?.label??o.provider:a(`{provider} needs {what}; searches use DuckDuckGo until then`,{provider:E?.label??o.provider,what:E?.needs_key?a(`a key`):a(`an instance URL`)}),P=async()=>{y(!0),x(null);try{await u.setSearch({provider:f,base_url:f===`searxng`?m.trim():``,api_key:k?g||void 0:``}),_(``),i(a(`Saved`)),n()}catch(e){i(e.message)}finally{y(!1)}},F=async()=>{w(!0);try{x(await u.testSearch())}catch(e){x({ok:!1,error:e.message})}finally{w(!1)}},I=e=>t(`rounded-full px-3 py-1.5 text-[13px] border`,e?`border-accent bg-accent/10 text-accent font-medium`:`border-border text-muted`),L=f!==`searxng`||/^https?:\/\//.test(m.trim());return(0,K.jsxs)(A,{icon:(0,K.jsx)(B,{size:19}),title:a(`Web search`),summary:M,status:j,open:s,onToggle:()=>d(!s),children:[(0,K.jsx)(`p`,{className:`text-[12.5px] text-muted leading-snug`,children:a(`DuckDuckGo needs nothing, but it is scraped and rate-limits now and then. For searches that always work, use a provider with an API. Whichever you pick, a failed search falls back to DuckDuckGo with a note.`)}),(0,K.jsx)($,{label:a(`Provider`),children:(0,K.jsx)(`div`,{className:`flex flex-wrap gap-1.5`,children:o.providers.map(e=>(0,K.jsx)(`button`,{type:`button`,onClick:()=>p(e.id),className:I(f===e.id),children:e.label},e.id))})}),k&&(0,K.jsxs)($,{label:a(`API key`),hint:o.key_source===`vault`&&o.provider===f?a(`A key is in the vault. Leave blank to keep it.`):a(`Stored encrypted in the vault as SEARCH_API_KEY.`),children:[(0,K.jsx)(`input`,{type:`password`,value:g,onChange:e=>_(e.target.value),className:`w-full rounded-2xl bg-surface-2 px-3.5 py-2.5 text-[14.5px] outline-none focus:ring-2 focus:ring-accent/40`,placeholder:o.key_source===`vault`&&o.provider===f?`••••••••`:`…`,autoComplete:`off`}),O?.keys_url&&(0,K.jsx)(`a`,{href:O.keys_url,target:`_blank`,rel:`noreferrer`,className:`mt-1 inline-block text-[12px] text-accent`,children:a(`Get a key from {label}`,{label:O.label})})]}),f===`searxng`&&(0,K.jsx)($,{label:a(`Instance URL`),hint:a(`A SearXNG you run, with the JSON format enabled in its settings.`),children:(0,K.jsx)(`input`,{value:m,onChange:e=>h(e.target.value),className:`w-full rounded-2xl bg-surface-2 px-3.5 py-2.5 text-[14.5px] outline-none focus:ring-2 focus:ring-accent/40`,placeholder:`http://127.0.0.1:8080`,inputMode:`url`})}),(0,K.jsxs)(`div`,{className:`flex gap-2 pt-1`,children:[(0,K.jsxs)(`button`,{type:`button`,disabled:v||!L,onClick:()=>void P(),className:D,children:[v?(0,K.jsx)(l,{size:16,className:`animate-spin`}):(0,K.jsx)(C,{size:16}),` `,a(`Save`)]}),(0,K.jsxs)(`button`,{type:`button`,disabled:S,onClick:()=>void F(),className:T,children:[S?(0,K.jsx)(l,{size:16,className:`animate-spin`}):(0,K.jsx)(N,{size:16}),` `,a(`Test`)]})]}),b&&(0,K.jsx)(Ue,{result:b,okText:a(`{provider} · {n} results · {ms} ms`,{provider:b.provider??``,n:b.results??0,ms:b.ms??0})})]})}var Me=[{id:`gmail`,label:`Gmail`,imap:`imap.gmail.com`,smtp:`smtp.gmail.com`,port:587,starttls:!0},{id:`outlook`,label:`Outlook`,imap:`outlook.office365.com`,smtp:`smtp.office365.com`,port:587,starttls:!0},{id:`icloud`,label:`iCloud`,imap:`imap.mail.me.com`,smtp:`smtp.mail.me.com`,port:587,starttls:!0},{id:`qq`,label:`QQ`,imap:`imap.qq.com`,smtp:`smtp.qq.com`,port:587,starttls:!0},{id:`163`,label:`163`,imap:`imap.163.com`,smtp:`smtp.163.com`,port:465,starttls:!1},{id:`fastmail`,label:`Fastmail`,imap:`imap.fastmail.com`,smtp:`smtp.fastmail.com`,port:587,starttls:!0}];function Ne({data:e,onChange:n,compact:i}){let{toast:a}=c(),o=r(),s=e.email,[d,f]=(0,G.useState)(!!i),[p,m]=(0,G.useState)(s.address),[h,g]=(0,G.useState)(``),[_,v]=(0,G.useState)(s.imap_host),[y,b]=(0,G.useState)(s.imap_port),[x,S]=(0,G.useState)(s.smtp_host),[C,w]=(0,G.useState)(s.smtp_port),[T,E]=(0,G.useState)(s.smtp_starttls),[k,j]=(0,G.useState)(null),[M,P]=(0,G.useState)(null);(0,G.useEffect)(()=>{m(s.address),v(s.imap_host),b(s.imap_port),S(s.smtp_host),w(s.smtp_port),E(s.smtp_starttls)},[s]);let F=e=>{v(e.imap),b(993),S(e.smtp),w(e.port),E(e.starttls)},I=async()=>{j(`save`),P(null);try{await u.setEmail({enabled:!0,address:p.trim(),password:h||void 0,imap_host:_.trim(),imap_port:y,smtp_host:x.trim(),smtp_port:C,smtp_starttls:T}),g(``);let e=await u.testEmail();P(e),a(e.ok?o(`Email connected`):o(`Saved, but the test failed`)),n()}catch(e){a(e.message)}finally{j(null)}},L=async()=>{j(`off`);try{await u.disconnectEmail(),P(null),a(o(`Email disconnected`)),n()}catch(e){a(e.message)}finally{j(null)}},ee=s.enabled&&s.configured?{text:o(`Connected`),tone:`ok`}:s.enabled?{text:o(`Incomplete`),tone:`warn`}:{text:o(`Not connected`),tone:`off`};return(0,K.jsxs)(A,{icon:(0,K.jsx)(re,{size:19}),title:o(`Email`),summary:s.configured&&s.enabled?`${s.address} · ${o(`reads and sends`)}`:o(`Read your inbox, draft and send mail`),status:ee,open:d,onToggle:i?void 0:()=>f(!d),children:[(0,K.jsx)(`p`,{className:`text-[12.5px] text-muted -mt-1`,children:o(`Reading is a moderate action; sending always asks you first. Use an app password where your provider offers one.`)}),(0,K.jsx)($,{label:o(`Provider`),children:(0,K.jsx)(`div`,{className:`flex flex-wrap gap-1.5`,children:Me.map(e=>(0,K.jsx)(`button`,{type:`button`,onClick:()=>F(e),className:t(`rounded-full px-3 py-1.5 text-[13px] border`,_===e.imap?`border-accent bg-accent/10 text-accent font-medium`:`border-border text-muted`),children:e.label},e.id))})}),(0,K.jsx)($,{label:o(`Address`),children:(0,K.jsx)(`input`,{value:p,onChange:e=>m(e.target.value),className:O,placeholder:`you@example.com`,inputMode:`email`,autoComplete:`off`})}),(0,K.jsx)($,{label:o(`Password`),hint:s.password_set?o(`A password is in the vault. Leave blank to keep it.`):o(`Stored encrypted in the vault as EMAIL_PASSWORD.`),children:(0,K.jsx)(`input`,{type:`password`,value:h,onChange:e=>g(e.target.value),className:O,placeholder:s.password_set?`••••••••`:o(`app password`),autoComplete:`off`})}),(0,K.jsxs)(`div`,{className:`grid grid-cols-[1fr_84px] gap-2`,children:[(0,K.jsx)($,{label:o(`IMAP server`),children:(0,K.jsx)(`input`,{value:_,onChange:e=>v(e.target.value),className:O,placeholder:`imap.example.com`})}),(0,K.jsx)($,{label:o(`Port`),children:(0,K.jsx)(`input`,{type:`number`,value:y,onChange:e=>b(Number(e.target.value)),className:O})}),(0,K.jsx)($,{label:o(`SMTP server`),children:(0,K.jsx)(`input`,{value:x,onChange:e=>S(e.target.value),className:O,placeholder:`smtp.example.com`})}),(0,K.jsx)($,{label:o(`Port`),children:(0,K.jsx)(`input`,{type:`number`,value:C,onChange:e=>w(Number(e.target.value)),className:O})})]}),(0,K.jsxs)(`label`,{className:`flex items-center gap-2 text-[13.5px]`,children:[(0,K.jsx)(`input`,{type:`checkbox`,checked:T,onChange:e=>E(e.target.checked),className:`accent-[var(--om-accent)]`}),` `,o(`STARTTLS for SMTP (off for port 465)`)]}),(0,K.jsxs)(`div`,{className:`flex gap-2 pt-1`,children:[(0,K.jsxs)(`button`,{type:`button`,disabled:k!==null||!p.trim()||!_.trim()||!x.trim()||!h&&!s.password_set,onClick:()=>void I(),className:D,children:[k===`save`?(0,K.jsx)(l,{size:16,className:`animate-spin`}):(0,K.jsx)(N,{size:16}),` `,s.configured?o(`Save & test`):o(`Connect`)]}),s.enabled&&(0,K.jsxs)(`button`,{type:`button`,disabled:k!==null,onClick:()=>void L(),className:`flex items-center justify-center gap-1.5 rounded-2xl border border-border px-4 py-2.5 text-[14px] font-medium text-muted disabled:opacity-40`,children:[k===`off`?(0,K.jsx)(l,{size:16,className:`animate-spin`}):(0,K.jsx)(de,{size:16}),` `,o(`Disconnect`)]})]}),M&&(0,K.jsx)(Ue,{result:M,okText:o(`Signed in · {n} messages in the inbox`,{n:M.inbox??`?`})})]})}var Pe=[{id:`google`,label:`Google`,hint:`Settings → your calendar → Integrate calendar → Secret address in iCal format`},{id:`outlook`,label:`Outlook`,hint:`Settings → Calendar → Shared calendars → Publish a calendar → ICS link`},{id:`icloud`,label:`iCloud`,hint:`Share Calendar → Public Calendar → copy the webcal:// link`},{id:`fastmail`,label:`Fastmail`,hint:`Settings → Calendars → Export → Calendar URL`},{id:`file`,label:`.ics file`,hint:`A path on the machine where nanoMuse runs, for example ~/calendar.ics`}];function Fe({data:n,onChange:i,compact:a}){let{toast:o}=c(),s=r(),d=n.calendar,[f,p]=(0,G.useState)(!!a),[m,h]=(0,G.useState)(!1),[g,_]=(0,G.useState)(``),[v,y]=(0,G.useState)(``),[b,x]=(0,G.useState)(null),[S,w]=(0,G.useState)(d.day_start),[E,k]=(0,G.useState)(d.day_end),[j,M]=(0,G.useState)(null),[F,I]=(0,G.useState)(null);(0,G.useEffect)(()=>{w(d.day_start),k(d.day_end)},[d.day_start,d.day_end]);let L=async()=>{M(`add`),I(null);try{let e=await u.addCalendarFeed(g.trim(),v.trim());if(e.error)o(s(`Added, but it could not be read: {error}`,{error:e.error}));else{let t=e.feeds.find(e=>e.name===g.trim());o(`${s(`Calendar connected`)} · ${U(t?.events??0)}`),_(``),y(``),h(!1)}i()}catch(e){o(e.message)}finally{M(null)}},ee=async e=>{M(e);try{await u.removeCalendarFeed(e),i()}catch(e){o(e.message)}finally{M(null)}},te=async()=>{M(`hours`);try{await u.setCalendar({day_start:S,day_end:E}),o(s(`Saved`)),i()}catch(e){o(e.message)}finally{M(null)}},R=async()=>{M(`test`);try{I(await u.testCalendar()),i()}catch(e){o(e.message)}finally{M(null)}},B=d.feeds.reduce((e,t)=>e+t.events,0),H=d.feeds.filter(e=>e.error).length,U=e=>e===1?s(`1 event`):s(`{n} events`,{n:e}),ne=d.configured?H?{text:s(`{n} not reading`,{n:H}),tone:`warn`}:{text:s(`Connected`),tone:`ok`}:{text:s(`Not connected`),tone:`off`};return(0,K.jsxs)(A,{icon:(0,K.jsx)(ae,{size:19}),title:s(`Calendar`),summary:d.configured?d.feeds.length===1?`${d.feeds[0].name} · ${U(B)}`:`${s(`{n} calendars`,{n:d.feeds.length})} · ${U(B)}`:s(`Your agenda, free time, and events it can draft`),status:ne,open:f,onToggle:a?void 0:()=>p(!f),children:[(0,K.jsx)(`p`,{className:`text-[12.5px] text-muted -mt-1`,children:s(`Reads your calendar from its private .ics link; the link stays in the vault. It never changes your calendar; an event it proposes comes as a file you add with a tap.`)}),d.feeds.length>0&&(0,K.jsx)(`ul`,{className:`space-y-1.5`,children:d.feeds.map(n=>(0,K.jsxs)(`li`,{className:`flex items-center gap-2.5 rounded-2xl bg-surface-2/60 px-3 py-2`,children:[(0,K.jsx)(`span`,{className:t(`h-2 w-2 rounded-full`,n.error?`bg-rose-500`:n.fetched_at?`bg-emerald-500`:`bg-amber-500`)}),(0,K.jsxs)(`div`,{className:`min-w-0 flex-1`,children:[(0,K.jsx)(`div`,{className:`text-[13.5px] font-medium truncate`,children:n.name}),(0,K.jsxs)(`div`,{className:`text-[11.5px] text-muted truncate`,children:[n.error?n.error:n.fetched_at?`${U(n.events)} · ${s(`read {when}`,{when:e(n.fetched_at)})}`:s(`not read yet`),!n.from_app&&` · ${s(`from config.toml`)}`]})]}),n.from_app&&(0,K.jsx)(`button`,{type:`button`,"aria-label":s(`Remove`),disabled:j===n.name,onClick:()=>void ee(n.name),className:`p-1.5 rounded-full text-muted hover:bg-surface-2`,children:j===n.name?(0,K.jsx)(l,{size:15,className:`animate-spin`}):(0,K.jsx)(z,{size:15})})]},n.name))}),m?(0,K.jsxs)(`div`,{className:`space-y-2.5 rounded-2xl border border-border/70 p-3`,children:[(0,K.jsxs)($,{label:s(`Where is the link?`),children:[(0,K.jsx)(`div`,{className:`flex flex-wrap gap-1.5`,children:Pe.map(e=>(0,K.jsx)(`button`,{type:`button`,onClick:()=>x(b===e.id?null:e.id),className:t(`rounded-full px-3 py-1.5 text-[13px] border`,b===e.id?`border-accent bg-accent/10 text-accent font-medium`:`border-border text-muted`),children:s(e.label)},e.id))}),b&&(0,K.jsx)(`div`,{className:`mt-1.5 text-[11.5px] text-muted leading-snug`,children:s(Pe.find(e=>e.id===b).hint)})]}),(0,K.jsx)($,{label:s(`Name`),children:(0,K.jsx)(`input`,{value:g,onChange:e=>_(e.target.value),className:O,placeholder:s(`Work`)})}),(0,K.jsx)($,{label:s(`Private .ics link or file path`),hint:s(`Stored encrypted in the vault as CALENDAR_{name}.`,{name:g.trim().toUpperCase().replace(/[^A-Z0-9]+/g,`_`).replace(/^_+|_+$/g,``)||`NAME`})+` `+s(`nanoMuse fetches whatever address you put here, from this machine; only paste links you trust.`),children:(0,K.jsx)(`input`,{value:v,onChange:e=>y(e.target.value),className:O,placeholder:`https://calendar.google.com/calendar/ical/…/basic.ics`,inputMode:`url`,autoComplete:`off`})}),(0,K.jsxs)(`div`,{className:`flex gap-2`,children:[(0,K.jsxs)(`button`,{type:`button`,disabled:j===`add`||!g.trim()||!v.trim(),onClick:()=>void L(),className:D,children:[j===`add`?(0,K.jsx)(l,{size:16,className:`animate-spin`}):(0,K.jsx)(N,{size:16}),` `,s(`Connect`)]}),(0,K.jsx)(`button`,{type:`button`,onClick:()=>h(!1),className:T,children:s(`Cancel`)})]})]}):(0,K.jsxs)(`button`,{type:`button`,onClick:()=>h(!0),className:T,children:[(0,K.jsx)(V,{size:16}),` `,s(`Add a calendar`)]}),d.configured&&(0,K.jsxs)(K.Fragment,{children:[(0,K.jsx)($,{label:s(`Working hours`),hint:s(`Free time is looked for inside these hours.`),children:(0,K.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,K.jsx)(`input`,{type:`time`,value:S,onChange:e=>w(e.target.value),className:t(`w-full rounded-2xl bg-surface-2 px-3.5 py-2.5 text-[14.5px] outline-none focus:ring-2 focus:ring-accent/40`,`w-auto`)}),(0,K.jsx)(`span`,{className:`text-muted`,children:`–`}),(0,K.jsx)(`input`,{type:`time`,value:E,onChange:e=>k(e.target.value),className:t(`w-full rounded-2xl bg-surface-2 px-3.5 py-2.5 text-[14.5px] outline-none focus:ring-2 focus:ring-accent/40`,`w-auto`)}),(S!==d.day_start||E!==d.day_end)&&(0,K.jsx)(`button`,{type:`button`,disabled:j===`hours`,onClick:()=>void te(),className:t(`flex items-center justify-center gap-1.5 rounded-2xl bg-accent text-accent-fg px-4 py-2.5 text-[14px] font-medium disabled:opacity-40`,`px-3`),"aria-label":s(`Save`),children:j===`hours`?(0,K.jsx)(l,{size:16,className:`animate-spin`}):(0,K.jsx)(C,{size:16})})]})}),(0,K.jsxs)(`button`,{type:`button`,disabled:j===`test`,onClick:()=>void R(),className:`flex items-center justify-center gap-1.5 rounded-2xl border border-border px-4 py-2.5 text-[14px] font-medium text-muted disabled:opacity-40`,children:[j===`test`?(0,K.jsx)(l,{size:16,className:`animate-spin`}):(0,K.jsx)(P,{size:16}),` `,s(`Read again`)]}),F&&(0,K.jsx)(Ue,{result:F,okText:d.feeds.length===1?U(F.events??0):`${U(F.events??0)} · ${s(`{n} calendars`,{n:d.feeds.length})}`})]})]})}function Ie({data:n,onChange:i,compact:a}){let{toast:o}=c(),s=r(),d=n.contacts,[f,p]=(0,G.useState)(!!a),[m,h]=(0,G.useState)(!1),[g,_]=(0,G.useState)(``),[v,y]=(0,G.useState)(``),[b,x]=(0,G.useState)(null),[S,C]=(0,G.useState)(null),[w,E]=(0,G.useState)(``),[k,j]=(0,G.useState)(null),M=(0,G.useRef)(null),F=e=>e===1?s(`1 person`):s(`{n} people`,{n:e}),I=(e,t)=>{if(e.error)o(s(`Added, but it could not be read: {error}`,{error:e.error}));else{let n=e.sources.find(e=>e.name===t);o(`${s(`Address book connected`)} · ${F(n?.contacts??0)}`),_(``),y(``),h(!1)}i()},L=async()=>{x(`add`),C(null);try{I(await u.addContactsSource(g.trim(),v.trim()),g.trim())}catch(e){o(e.message)}finally{x(null)}},ee=async e=>{x(`upload`),C(null);try{let t=(g.trim()||e.name.replace(/\.vcf$/i,``)||`Imported`).slice(0,40);I(await u.importContacts(t,await e.text()),t)}catch(e){o(e.message)}finally{x(null),M.current&&(M.current.value=``)}},te=async e=>{x(e);try{await u.removeContactsSource(e),i()}catch(e){o(e.message)}finally{x(null)}},R=async()=>{x(`test`);try{C(await u.testContacts()),i()}catch(e){o(e.message)}finally{x(null)}};(0,G.useEffect)(()=>{if(!w.trim()){j(null);return}let e=setTimeout(()=>{u.contacts(w.trim(),5).then(e=>j(e.people)).catch(()=>j([]))},250);return()=>clearTimeout(e)},[w]);let H=d.sources.filter(e=>e.error).length,U=d.enabled?d.configured?H?{text:s(`{n} not reading`,{n:H}),tone:`warn`}:{text:s(`Connected`),tone:`ok`}:{text:s(`Not connected`),tone:`off`}:{text:s(`Off`),tone:`off`};return(0,K.jsxs)(A,{icon:(0,K.jsx)(W,{size:19}),title:s(`Contacts`),summary:d.configured?d.sources.length===0?`${F(d.count)} · ${s(`told to it in chat`)}`:`${F(d.count)} · ${d.sources.length===1?d.sources[0].name:s(`{n} address books`,{n:d.sources.length})}`:s(`Who is who, so it never guesses an address`),status:U,open:f,onToggle:a?void 0:()=>p(!f),children:[(0,K.jsx)(`p`,{className:`text-[12.5px] text-muted -mt-1`,children:s(`Import a .vcf export from Google Contacts, iCloud, Outlook or your phone, or paste a link to one. People you mention in chat go into its own book. It looks people up before writing to them and warns when an address is unknown.`)}),(d.sources.length>0||d.own>0)&&(0,K.jsxs)(`ul`,{className:`space-y-1.5`,children:[d.own>0&&(0,K.jsxs)(`li`,{className:`flex items-center gap-2.5 rounded-2xl bg-surface-2/60 px-3 py-2`,children:[(0,K.jsx)(`span`,{className:`h-2 w-2 rounded-full bg-emerald-500`}),(0,K.jsxs)(`div`,{className:`min-w-0 flex-1`,children:[(0,K.jsx)(`div`,{className:`text-[13.5px] font-medium truncate`,children:s(`My contacts`)}),(0,K.jsx)(`div`,{className:`text-[11.5px] text-muted truncate`,children:`${F(d.own)} · ${s(`added in chat`)}`})]})]}),d.sources.map(n=>(0,K.jsxs)(`li`,{className:`flex items-center gap-2.5 rounded-2xl bg-surface-2/60 px-3 py-2`,children:[(0,K.jsx)(`span`,{className:t(`h-2 w-2 rounded-full`,n.error?`bg-rose-500`:n.fetched_at?`bg-emerald-500`:`bg-amber-500`)}),(0,K.jsxs)(`div`,{className:`min-w-0 flex-1`,children:[(0,K.jsx)(`div`,{className:`text-[13.5px] font-medium truncate`,children:n.name}),(0,K.jsxs)(`div`,{className:`text-[11.5px] text-muted truncate`,children:[n.error?n.error:n.fetched_at?`${F(n.contacts)} · ${s(`read {when}`,{when:e(n.fetched_at)})}`:s(`not read yet`),!n.from_app&&` · ${s(`from config.toml`)}`]})]}),n.from_app&&(0,K.jsx)(`button`,{type:`button`,"aria-label":s(`Remove`),disabled:b===n.name,onClick:()=>void te(n.name),className:`p-1.5 rounded-full text-muted hover:bg-surface-2`,children:b===n.name?(0,K.jsx)(l,{size:15,className:`animate-spin`}):(0,K.jsx)(z,{size:15})})]},n.name))]}),m?(0,K.jsxs)(`div`,{className:`space-y-2.5 rounded-2xl border border-border/70 p-3`,children:[(0,K.jsx)($,{label:s(`Name`),children:(0,K.jsx)(`input`,{value:g,onChange:e=>_(e.target.value),className:O,placeholder:s(`iPhone`)})}),(0,K.jsxs)($,{label:s(`A .vcf file from your phone or computer`),hint:s(`Google Contacts: Export → vCard. iPhone: Contacts → select all → Share → Save to Files. Outlook: People → Manage → Export.`),children:[(0,K.jsx)(`input`,{ref:M,type:`file`,accept:`.vcf,text/vcard,text/x-vcard`,className:`hidden`,onChange:e=>e.target.files?.[0]&&void ee(e.target.files[0])}),(0,K.jsxs)(`button`,{type:`button`,disabled:b===`upload`,onClick:()=>M.current?.click(),className:T,children:[b===`upload`?(0,K.jsx)(l,{size:16,className:`animate-spin`}):(0,K.jsx)(fe,{size:16}),` `,s(`Choose a .vcf file`)]})]}),(0,K.jsx)($,{label:s(`Or a link / path to one`),hint:s(`A link is stored encrypted in the vault as CONTACTS_{name}.`,{name:g.trim().toUpperCase().replace(/[^A-Z0-9]+/g,`_`).replace(/^_+|_+$/g,``)||`NAME`})+` `+s(`nanoMuse fetches whatever address you put here, from this machine; only paste links you trust.`),children:(0,K.jsx)(`input`,{value:v,onChange:e=>y(e.target.value),className:O,placeholder:`https://… /contacts.vcf`,inputMode:`url`,autoComplete:`off`})}),(0,K.jsxs)(`div`,{className:`flex gap-2`,children:[(0,K.jsxs)(`button`,{type:`button`,disabled:b===`add`||!g.trim()||!v.trim(),onClick:()=>void L(),className:D,children:[b===`add`?(0,K.jsx)(l,{size:16,className:`animate-spin`}):(0,K.jsx)(N,{size:16}),` `,s(`Connect`)]}),(0,K.jsx)(`button`,{type:`button`,onClick:()=>h(!1),className:T,children:s(`Cancel`)})]})]}):(0,K.jsxs)(`button`,{type:`button`,onClick:()=>h(!0),className:T,children:[(0,K.jsx)(V,{size:16}),` `,s(`Add an address book`)]}),d.configured&&(0,K.jsxs)(K.Fragment,{children:[(0,K.jsxs)(`div`,{className:`relative`,children:[(0,K.jsx)(B,{size:15,className:`absolute left-3 top-1/2 -translate-y-1/2 text-muted`}),(0,K.jsx)(`input`,{value:w,onChange:e=>E(e.target.value),className:t(`w-full rounded-2xl bg-surface-2 px-3.5 py-2.5 text-[14.5px] outline-none focus:ring-2 focus:ring-accent/40`,`pl-9`),placeholder:s(`Find someone, as the agent would`),autoComplete:`off`})]}),k!==null&&(0,K.jsxs)(`ul`,{className:`space-y-1`,children:[k.length===0&&(0,K.jsx)(`li`,{className:`text-[12.5px] text-muted px-1`,children:s(`No one matches.`)}),k.map(e=>(0,K.jsxs)(`li`,{className:`rounded-2xl bg-surface-2/60 px-3 py-2`,children:[(0,K.jsxs)(`div`,{className:`text-[13.5px] font-medium`,children:[e.name,e.org&&(0,K.jsxs)(`span`,{className:`text-muted font-normal`,children:[` · `,e.org]})]}),(0,K.jsx)(`div`,{className:`text-[12px] text-muted break-words`,children:[...e.emails,...e.phones].join(` · `)})]},e.id))]}),d.sources.length>0&&(0,K.jsxs)(`button`,{type:`button`,disabled:b===`test`,onClick:()=>void R(),className:`flex items-center justify-center gap-1.5 rounded-2xl border border-border px-4 py-2.5 text-[14px] font-medium text-muted disabled:opacity-40`,children:[b===`test`?(0,K.jsx)(l,{size:16,className:`animate-spin`}):(0,K.jsx)(P,{size:16}),` `,s(`Read again`)]}),S&&(0,K.jsx)(Ue,{result:S,okText:F(S.contacts??0)})]})]})}function Q({data:e,onChange:n}){let{toast:i}=c(),a=r(),o=e.browser,[s,l]=(0,G.useState)(!1),d=async()=>{l(!0);try{await u.setBrowser(!o.enabled),n()}catch(e){i(e.message)}finally{l(!1)}};return(0,K.jsx)(A,{icon:(0,K.jsx)(ne,{size:19}),title:a(`Browser`),summary:o.available?a(`Open pages, click, fill forms, screenshot`):a(`Playwright is not installed on the server`),status:o.enabled&&o.available?{text:a(`On`),tone:`ok`}:o.enabled?{text:a(`Unavailable`),tone:`warn`}:{text:a(`Off`),tone:`off`},open:!1,trailing:(0,K.jsx)(`button`,{type:`button`,role:`switch`,"aria-checked":o.enabled,disabled:s,onClick:()=>void d(),className:t(`relative h-7 w-12 shrink-0 rounded-full transition`,o.enabled?`bg-accent`:`bg-surface-2 border border-border`),children:(0,K.jsx)(`span`,{className:t(`absolute top-0.5 h-6 w-6 rounded-full bg-white shadow transition`,o.enabled?`left-[22px]`:`left-0.5`)})}),children:!o.available&&(0,K.jsxs)(`p`,{className:`text-[12.5px] text-muted`,children:[a(`Install it where the server runs:`),` `,(0,K.jsx)(`code`,{className:`rounded bg-surface-2 px-1`,children:`pip install "nanomuse[browser]" && playwright install chromium`})]})})}function Le({data:e,onChange:n}){let{toast:i}=c(),a=r(),o=e.gui,[s,d]=(0,G.useState)(!1),[f,p]=(0,G.useState)(!1),[m,h]=(0,G.useState)(o.model),[g,_]=(0,G.useState)(o.base_url),[v,y]=(0,G.useState)(``),[b,x]=(0,G.useState)(null);(0,G.useEffect)(()=>{h(o.model),_(o.base_url)},[o.model,o.base_url]);let S=async()=>{p(!0);try{await u.setGui({enabled:!o.enabled}),n()}catch(e){i(e.message)}finally{p(!1)}},w=async()=>{p(!0),x(null);try{await u.setGui({model:m.trim(),base_url:g.trim(),...v?{api_key:v.trim()}:{}}),y(``),n(),x(await u.testGui())}catch(e){i(e.message)}finally{p(!1)}},T=o.phone,[E,k]=(0,G.useState)(R),j=(0,G.useRef)(E);(0,G.useEffect)(()=>{if(!s)return;let e=()=>{let e=R();e!==j.current&&(j.current=e,k(e),setTimeout(n,400))};return e(),document.addEventListener(`visibilitychange`,e),window.addEventListener(`focus`,e),()=>{document.removeEventListener(`visibilitychange`,e),window.removeEventListener(`focus`,e)}},[s,n]);let M=T.connected?a(`{name} is connected`,{name:T.device?.name??a(`A phone`)}):o.enabled?a(`No phone connected. Open the app on the phone`):a(`Tap, type and swipe in the apps on your phone`);return(0,K.jsxs)(A,{icon:(0,K.jsx)(L,{size:19}),title:a(`Phone`),summary:M,status:o.enabled&&T.connected?{text:a(`On`),tone:`ok`}:o.enabled?{text:a(`Waiting`),tone:`warn`}:{text:a(`Off`),tone:`off`},open:s,onToggle:()=>d(e=>!e),children:[(0,K.jsxs)(`div`,{className:`flex items-center justify-between gap-3`,children:[(0,K.jsxs)(`div`,{className:`text-[13px] leading-snug`,children:[(0,K.jsx)(`div`,{className:`font-medium`,children:a(`Operate the phone`)}),(0,K.jsx)(`div`,{className:`text-[12px] text-muted`,children:a(`When on, the agent can read the screen and act in the apps on the connected phone: 12306, WeChat, Alipay… It asks before paying, sending or deleting.`)})]}),(0,K.jsx)(`button`,{type:`button`,role:`switch`,"aria-checked":o.enabled,disabled:f,onClick:()=>void S(),className:t(`relative h-7 w-12 shrink-0 rounded-full transition`,o.enabled?`bg-accent`:`bg-surface-2 border border-border`),children:(0,K.jsx)(`span`,{className:t(`absolute top-0.5 h-6 w-6 rounded-full bg-white shadow transition`,o.enabled?`left-[22px]`:`left-0.5`)})})]}),E!==null&&(0,K.jsxs)(`div`,{className:`rounded-2xl bg-surface-2 px-3 py-2.5 text-[12.5px] leading-snug space-y-1.5`,children:[(0,K.jsxs)(`div`,{className:`flex items-center justify-between gap-3`,children:[(0,K.jsx)(`span`,{className:`font-medium`,children:a(`This phone`)}),(0,K.jsx)(`span`,{className:t(`rounded-full px-2 py-0.5 text-[11px] font-medium`,E===`on`&&`bg-emerald-500/12 text-emerald-700 dark:text-emerald-300`,E===`off`&&`bg-amber-500/15 text-amber-700 dark:text-amber-300`,E===`unsupported`&&`bg-surface text-muted`),children:a(E===`on`?`Ready`:E===`off`?`Not yet`:`Not on this Android`)})]}),E===`unsupported`&&(0,K.jsx)(`div`,{className:`text-muted`,children:a(`Operating the screen needs Android 11 or newer; this phone can still be used for everything else.`)}),E===`off`&&(0,K.jsxs)(K.Fragment,{children:[(0,K.jsx)(`div`,{className:`text-muted`,children:a(`Turn on the nanoMuse accessibility service; that is how it sees the screen and taps for you, only while a task runs, with a Stop button on screen.`)}),(0,K.jsxs)(`div`,{className:`flex flex-wrap gap-2 pt-0.5`,children:[(0,K.jsx)(`button`,{type:`button`,onClick:()=>I()?.openAccessibilitySettings?.(),className:`rounded-full bg-accent px-3 py-1.5 text-[12.5px] font-medium text-white`,children:a(`Open Accessibility settings`)}),(0,K.jsx)(`button`,{type:`button`,onClick:()=>I()?.openAppSettings?.(),className:`rounded-full border border-border px-3 py-1.5 text-[12.5px]`,children:a(`App settings`)})]}),(0,K.jsx)(`div`,{className:`text-muted`,children:a(`Greyed out with “Restricted setting”? Android 13+ does that for apps installed from a download: in App settings tap ⋮ → Allow restricted settings, then come back.`)})]}),E===`on`&&(0,K.jsx)(`div`,{className:`text-muted`,children:a(`Android may switch the service off after an update or a battery clean-up; if the phone stops answering, come back here.`)})]}),T.connected&&T.device&&(0,K.jsxs)(`div`,{className:`rounded-2xl bg-surface-2 px-3 py-2 text-[12.5px] text-muted`,children:[a(`{name} ({platform}), {n} apps`,{name:T.device.name,platform:T.device.platform,n:String(T.device.apps)}),T.last_screen&&(0,K.jsxs)(K.Fragment,{children:[` `,`·`,` `,a(`last seen in {app}`,{app:T.last_screen.app_name||T.last_screen.app})]})]}),(0,K.jsx)(`div`,{className:`text-[12px] text-muted leading-snug`,children:a(`The operator's model looks at screens step by step: a small, fast model that takes pictures. The Hands model row under Chat model picks one on the same endpoint and key; the fields here are for a different endpoint. Empty = {model}.`,{model:o.default_model||a(`the chat model`)})}),(0,K.jsx)($,{label:a(`Model`),children:(0,K.jsx)(`input`,{value:m,onChange:e=>h(e.target.value),placeholder:o.default_model||a(`same as the chat model`),className:O})}),(0,K.jsx)($,{label:a(`Base URL`),children:(0,K.jsx)(`input`,{value:g,onChange:e=>_(e.target.value),placeholder:a(`same as the chat model`),className:O})}),(0,K.jsx)($,{label:a(`API key`),hint:o.key_source===`vault`?a(`A key is in the vault; leave empty to keep it.`):o.key_source===`config`?a(`Set in config.toml.`):a(`Leave empty to use the main model's key.`),children:(0,K.jsx)(`input`,{type:`password`,value:v,onChange:e=>y(e.target.value),placeholder:`sk-…`,className:O,autoComplete:`off`})}),(0,K.jsxs)(`button`,{type:`button`,disabled:f,onClick:()=>void w(),className:D,children:[f?(0,K.jsx)(l,{size:16,className:`animate-spin`}):(0,K.jsx)(C,{size:16}),a(`Save and test`)]}),b&&(0,K.jsx)(Ue,{result:b,okText:a(`The operator's model answers.`)})]})}function Re({data:e,onChange:n}){let{toast:i}=c(),a=r(),[o,s]=(0,G.useState)(!1),[d,f]=(0,G.useState)(!1),[p,m]=(0,G.useState)(``),[h,g]=(0,G.useState)(``),[_,v]=(0,G.useState)(``),[y,b]=(0,G.useState)(`moderate`),[x,S]=(0,G.useState)(null),C=async()=>{S(`add`);try{let e=h.trim().split(/\s+/).filter(Boolean);await u.addMCP({name:p.trim(),command:e[0]??null,args:e.slice(1),url:_.trim()||null,risk:y}),m(``),g(``),v(``),f(!1),i(a(`Server connected`)),n()}catch(e){i(e.message)}finally{S(null)}},w=async e=>{S(e);try{await u.removeMCP(e),n()}catch(e){i(e.message)}finally{S(null)}},E=e.mcp.filter(e=>e.connected).length,k=(e.shared??[]).filter(e=>e.enabled&&!e.here),j=e=>{m(e.id),v(e.url),g(``),f(!0),s(!0)};return(0,K.jsxs)(A,{icon:(0,K.jsx)(N,{size:19}),title:a(`MCP servers`),summary:e.mcp.length?a(`{n} of {total} connected · {tools} tools`,{n:E,total:e.mcp.length,tools:e.mcp.reduce((e,t)=>e+t.tools,0)}):a(`Add tools from any Model Context Protocol server`),status:e.mcp.length?{text:a(`{n} on`,{n:E}),tone:E?`ok`:`warn`}:{text:a(`None`),tone:`off`},open:o,onToggle:()=>s(!o),children:[e.mcp.length>0&&(0,K.jsx)(`ul`,{className:`space-y-1.5`,children:e.mcp.map(e=>(0,K.jsxs)(`li`,{className:`flex items-center gap-2.5 rounded-2xl bg-surface-2/60 px-3 py-2`,children:[(0,K.jsx)(`span`,{className:t(`h-2 w-2 rounded-full`,e.connected?`bg-emerald-500`:`bg-rose-500`)}),(0,K.jsxs)(`div`,{className:`min-w-0 flex-1`,children:[(0,K.jsx)(`div`,{className:`text-[13.5px] font-medium truncate`,children:e.builtin?a(`This phone`):e.name}),(0,K.jsxs)(`div`,{className:`text-[11.5px] text-muted truncate`,children:[e.builtin?a(`clipboard, notifications, calendar, contacts, location, alarms, photos`):e.url??[e.command,...e.args].join(` `),` ·`,` `,a(`{n} tools`,{n:e.tools}),` · `,a(e.risk),!e.from_app&&!e.builtin&&` · ${a(`from config.toml`)}`]})]}),e.from_app&&(0,K.jsx)(`button`,{type:`button`,"aria-label":a(`Remove`),disabled:x===e.name,onClick:()=>void w(e.name),className:`p-1.5 rounded-full text-muted hover:bg-surface-2`,children:x===e.name?(0,K.jsx)(l,{size:15,className:`animate-spin`}):(0,K.jsx)(z,{size:15})})]},e.name))}),k.length>0&&(0,K.jsx)(`ul`,{className:`space-y-1.5`,children:k.map(e=>(0,K.jsxs)(`li`,{className:`flex items-center gap-2.5 rounded-2xl border border-dashed border-border/70 px-3 py-2`,children:[(0,K.jsx)(`span`,{className:`h-2 w-2 rounded-full bg-border`}),(0,K.jsxs)(`div`,{className:`min-w-0 flex-1`,children:[(0,K.jsx)(`div`,{className:`text-[13.5px] font-medium truncate`,children:e.label||e.id}),(0,K.jsxs)(`div`,{className:`text-[11.5px] text-muted truncate`,children:[a(`Connected on {device}; sign in here to use it on this device`,{device:e.device||e.device_id}),e.url?` · ${e.url}`:``]})]}),e.url&&(0,K.jsx)(`button`,{type:`button`,onClick:()=>j(e),className:t(`flex items-center justify-center gap-1.5 rounded-2xl border border-border px-4 py-2.5 text-[14px] font-medium text-muted disabled:opacity-40`,`py-1.5 text-[12.5px]`),children:a(`Sign in here`)})]},`${e.device_id}:${e.id}`))}),d?(0,K.jsxs)(`div`,{className:`space-y-2.5 rounded-2xl border border-border/70 p-3`,children:[(0,K.jsx)($,{label:a(`Name`),children:(0,K.jsx)(`input`,{value:p,onChange:e=>m(e.target.value),className:O,placeholder:`filesystem`})}),(0,K.jsx)($,{label:a(`Command`),hint:a(`Run locally over stdio, for example: npx -y @modelcontextprotocol/server-filesystem ./workspace`),children:(0,K.jsx)(`input`,{value:h,onChange:e=>g(e.target.value),className:O,placeholder:`npx -y @modelcontextprotocol/server-…`})}),(0,K.jsx)($,{label:a(`or URL`),hint:a(`A remote server over Streamable HTTP.`),children:(0,K.jsx)(`input`,{value:_,onChange:e=>v(e.target.value),className:O,placeholder:`https://host/mcp`,inputMode:`url`})}),(0,K.jsx)($,{label:a(`Risk of its tools`),hint:a(`Decides when the Sentinel asks you before a call.`),children:(0,K.jsx)(`div`,{className:`flex gap-1.5`,children:[`safe`,`moderate`,`high`].map(e=>(0,K.jsx)(`button`,{type:`button`,onClick:()=>b(e),className:t(`rounded-full px-3 py-1.5 text-[13px] border`,y===e?`border-accent bg-accent/10 text-accent font-medium`:`border-border text-muted`),children:a(e)},e))})}),(0,K.jsxs)(`div`,{className:`flex gap-2`,children:[(0,K.jsxs)(`button`,{type:`button`,disabled:x===`add`||!p.trim()||!(h.trim()||_.trim()),onClick:()=>void C(),className:D,children:[x===`add`?(0,K.jsx)(l,{size:16,className:`animate-spin`}):(0,K.jsx)(N,{size:16}),` `,a(`Connect`)]}),(0,K.jsx)(`button`,{type:`button`,onClick:()=>f(!1),className:T,children:a(`Cancel`)})]})]}):(0,K.jsxs)(`button`,{type:`button`,onClick:()=>f(!0),className:T,children:[(0,K.jsx)(V,{size:16}),` `,a(`Add a server`)]})]})}function ze({data:e,onChange:n}){let{toast:i}=c(),a=r(),[o,s]=(0,G.useState)(!1),[d,f]=(0,G.useState)(``),[p,m]=(0,G.useState)(``),[h,g]=(0,G.useState)(null),_=async()=>{g(`add`);try{await u.vaultSet(d.trim(),p),f(``),m(``),i(a(`Stored in the vault`)),n()}catch(e){i(e.message)}finally{g(null)}},v=async e=>{g(e);try{await u.vaultDelete(e),n()}catch(e){i(e.message)}finally{g(null)}};return(0,K.jsxs)(A,{icon:(0,K.jsx)(ie,{size:19}),title:a(`Vault`),summary:e.vault.length?a(`{n} secrets · encrypted on your machine`,{n:e.vault.length}):a(`Encrypted secrets the model never sees`),status:{text:`${e.vault.length}`,tone:`off`},open:o,onToggle:()=>s(!o),children:[(0,K.jsxs)(`p`,{className:`text-[12.5px] text-muted -mt-1`,children:[a(`Refer to a secret as`),` `,(0,K.jsx)(`code`,{className:`rounded bg-surface-2 px-1`,children:`{{vault:NAME}}`}),` `,a(`in a tool call or config: the value is filled in after the Sentinel approves and is redacted from everything the model reads.`)]}),e.vault.length>0&&(0,K.jsx)(`ul`,{className:`flex flex-wrap gap-1.5`,children:e.vault.map(e=>(0,K.jsxs)(`li`,{className:`flex items-center gap-1 rounded-full bg-surface-2 pl-3 pr-1 py-1 text-[12.5px] font-mono`,children:[e,(0,K.jsx)(`button`,{type:`button`,"aria-label":a(`Delete {name}`,{name:e}),disabled:h===e,onClick:()=>void v(e),className:`p-1 rounded-full text-muted hover:text-rose-500`,children:h===e?(0,K.jsx)(l,{size:13,className:`animate-spin`}):(0,K.jsx)(z,{size:13})})]},e))}),(0,K.jsxs)(`div`,{className:`grid grid-cols-[1fr_1fr_auto] gap-2 items-end`,children:[(0,K.jsx)($,{label:a(`Name`),children:(0,K.jsx)(`input`,{value:d,onChange:e=>f(e.target.value.toUpperCase().replace(/[^A-Z0-9_.-]/g,`_`)),className:t(O,`font-mono`),placeholder:`GITHUB_TOKEN`})}),(0,K.jsx)($,{label:a(`Value`),children:(0,K.jsx)(`input`,{type:`password`,value:p,onChange:e=>m(e.target.value),className:O,placeholder:a(`secret`),autoComplete:`off`})}),(0,K.jsx)(`button`,{type:`button`,disabled:h===`add`||!d||!p,onClick:()=>void _(),className:t(D,`px-3`),"aria-label":a(`Store`),children:h===`add`?(0,K.jsx)(l,{size:16,className:`animate-spin`}):(0,K.jsx)(V,{size:16})})]})]})}var Be=`\0other`;function Ve({label:e,provider:n,value:i,options:a,more:o=[],onChange:s,other:c=!0,placeholder:l}){let u=r(),d=a.includes(i)||o.includes(i),[f,p]=(0,G.useState)(!1),m=l?u(`Automatic · {model}`,{model:l}):u(`Automatic`),h=e=>e.map(e=>({id:e,name:e})),g=o.length?[{key:`menu`,label:u(`Menu`),rows:h(a),...l?{default:l}:{}},{key:`more`,label:u(`More models on your account`),rows:h(o)}]:[{key:`list`,label:n,rows:h(a),...l?{default:l}:{}}],_=i&&d?{group:a.includes(i)?g[0].key:`more`,id:i}:void 0;return(0,K.jsxs)(`div`,{className:`block text-[12.5px] text-muted`,children:[(0,K.jsx)(`span`,{className:`block mb-1`,children:e}),(a.length||o.length)&&(d||!i)&&!f?(0,K.jsx)(ve,{label:e,text:i?`${n} · ${i}`:m,heads:[{value:``,label:m}],headValue:i?void 0:``,groups:g,current:_,onHead:()=>s(``),onPick:(e,t)=>s(t.id),tail:c?u(`Other model…`):void 0,onTail:()=>{p(!0),s(``)}}):(0,K.jsx)(`input`,{value:i,onChange:e=>s(e.target.value),placeholder:m,"aria-label":e,className:t(O,`text-fg`),spellCheck:!1})]})}function He(){let e=r();return(0,K.jsxs)(`a`,{href:H,target:`_blank`,rel:`noopener noreferrer`,className:`inline-flex items-center gap-0.5 text-accent`,children:[e(`How`),` `,(0,K.jsx)(w,{size:11})]})}function $({label:e,hint:t,children:n}){return(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`label`,{className:`text-[12px] text-muted`,children:e}),(0,K.jsx)(`div`,{className:`mt-1`,children:n}),t&&(0,K.jsx)(`div`,{className:`mt-1 text-[11.5px] text-muted leading-snug`,children:t})]})}function Ue({result:e,okText:n}){let i=r(),[a,o]=(0,G.useState)(!1),s=!e.ok&&e.detail&&e.detail!==e.error?e.detail:null;return(0,K.jsxs)(`div`,{className:t(`rounded-2xl px-3 py-2 text-[12.5px]`,e.ok?`bg-emerald-500/12 text-emerald-700 dark:text-emerald-300`:`bg-rose-500/12 text-rose-700 dark:text-rose-300`),children:[e.ok?n:i(e.error??`The model provider did not answer.`),s&&(0,K.jsxs)(K.Fragment,{children:[` `,(0,K.jsx)(`button`,{type:`button`,onClick:()=>o(e=>!e),className:`underline decoration-dotted underline-offset-2 opacity-70 hover:opacity-100`,children:i(a?`Hide details`:`Details`)}),a&&(0,K.jsx)(`div`,{className:`mt-1.5 break-all font-mono text-[11px] opacity-80`,children:s})]})]})}function We(e){try{return new URL(e).host}catch{return e}}export{Fe as CalendarCard,Oe as ConnectionsScreen,Ie as ContactsCard,Ne as EmailCard,Z as ModelCard}; \ No newline at end of file +import{A as e,E as t,J as n,K as r,L as i,Q as a,Y as o,b as s,f as c,q as l,x as u}from"./MuseHeader-Pw-NI98v.js";import{C as d,O as f,S as p,b as m,f as h,g,h as _,k as v,m as y,v as b,w as x,x as S}from"./StarNudge-DjXecvWj.js";import{n as C,t as w}from"./external-link-Xj5fjR8v.js";import{a as T,c as E,i as D,r as O,s as k,t as A}from"./Form-DwKuBk1V.js";import{t as j}from"./clapperboard-BokpXv9J.js";import{t as M}from"./image-crWy0a06.js";import{t as N}from"./plug-Bj_5EEV3.js";import{t as P}from"./refresh-cw-BKgIzslL.js";import{Ct as F,E as I,G as L,N as ee,P as te,T as R,V as z,X as B,Z as V,j as H,lt as U,pt as ne,st as re,ut as ie,xt as ae}from"./index-CIdGZ5PB.js";import{t as oe}from"./BackBar-Dl56jHZM.js";import{t as se}from"./CloudCard-CtVHK0qc.js";var ce=n(`brain-circuit`,[[`path`,{d:`M12 5a3 3 0 1 0-5.997.125 4 4 0 0 0-2.526 5.77 4 4 0 0 0 .556 6.588A4 4 0 1 0 12 18Z`,key:`l5xja`}],[`path`,{d:`M9 13a4.5 4.5 0 0 0 3-4`,key:`10igwf`}],[`path`,{d:`M6.003 5.125A3 3 0 0 0 6.401 6.5`,key:`105sqy`}],[`path`,{d:`M3.477 10.896a4 4 0 0 1 .585-.396`,key:`ql3yin`}],[`path`,{d:`M6 18a4 4 0 0 1-1.967-.516`,key:`2e4loj`}],[`path`,{d:`M12 13h4`,key:`1ku699`}],[`path`,{d:`M12 18h6a2 2 0 0 1 2 2v1`,key:`105ag5`}],[`path`,{d:`M12 8h8`,key:`1lhi5i`}],[`path`,{d:`M16 8V5a2 2 0 0 1 2-2`,key:`u6izg6`}],[`circle`,{cx:`16`,cy:`13`,r:`.5`,key:`ry7gng`}],[`circle`,{cx:`18`,cy:`3`,r:`.5`,key:`1aiba7`}],[`circle`,{cx:`20`,cy:`21`,r:`.5`,key:`yhc1fs`}],[`circle`,{cx:`20`,cy:`8`,r:`.5`,key:`1e43v0`}]]),W=n(`contact`,[[`path`,{d:`M16 2v2`,key:`scm5qe`}],[`path`,{d:`M7 22v-2a2 2 0 0 1 2-2h6a2 2 0 0 1 2 2v2`,key:`1waht3`}],[`path`,{d:`M8 2v2`,key:`pbkmx`}],[`circle`,{cx:`12`,cy:`11`,r:`3`,key:`itu57m`}],[`rect`,{x:`3`,y:`4`,width:`18`,height:`18`,rx:`2`,key:`12vinp`}]]),le=n(`eye-off`,[[`path`,{d:`M10.733 5.076a10.744 10.744 0 0 1 11.205 6.575 1 1 0 0 1 0 .696 10.747 10.747 0 0 1-1.444 2.49`,key:`ct8e1f`}],[`path`,{d:`M14.084 14.158a3 3 0 0 1-4.242-4.242`,key:`151rxh`}],[`path`,{d:`M17.479 17.499a10.75 10.75 0 0 1-15.417-5.151 1 1 0 0 1 0-.696 10.75 10.75 0 0 1 4.446-5.143`,key:`13bj9a`}],[`path`,{d:`m2 2 20 20`,key:`1ooewy`}]]),ue=n(`eye`,[[`path`,{d:`M2.062 12.348a1 1 0 0 1 0-.696 10.75 10.75 0 0 1 19.876 0 1 1 0 0 1 0 .696 10.75 10.75 0 0 1-19.876 0`,key:`1nclc0`}],[`circle`,{cx:`12`,cy:`12`,r:`3`,key:`1v7zrd`}]]),de=n(`unplug`,[[`path`,{d:`m19 5 3-3`,key:`yk6iyv`}],[`path`,{d:`m2 22 3-3`,key:`19mgm9`}],[`path`,{d:`M6.3 20.3a2.4 2.4 0 0 0 3.4 0L12 18l-6-6-2.3 2.3a2.4 2.4 0 0 0 0 3.4Z`,key:`goz73y`}],[`path`,{d:`M7.5 13.5 10 11`,key:`7xgeeb`}],[`path`,{d:`M10.5 16.5 13 14`,key:`10btkg`}],[`path`,{d:`m12 6 6 6 2.3-2.3a2.4 2.4 0 0 0 0-3.4l-2.6-2.6a2.4 2.4 0 0 0-3.4 0Z`,key:`1snsnr`}]]),fe=n(`upload`,[[`path`,{d:`M12 3v12`,key:`1x0j5s`}],[`path`,{d:`m17 8-5-5-5 5`,key:`7q97r8`}],[`path`,{d:`M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4`,key:`ih7n3h`}]]),G=a(o(),1);function pe(e,t){let n=t.trim().toLowerCase();return!n||e.id.toLowerCase().includes(n)||e.name.toLowerCase().includes(n)}function me(e,t){let n=e.default&&e.rows.some(t=>t.id===e.default)?e.default:e.rows.find(e=>e.recommended)?.id,r=t&&t.group===e.key?t.id:void 0,i=[];for(let t of[n,r]){if(!t||i.some(e=>e.id===t))continue;let n=e.rows.find(e=>e.id===t);n&&i.push(n)}return[...i,...e.rows.filter(e=>!i.includes(e))]}function he(e){return e.reduce((e,t)=>e+t.rows.length,0)}function ge(e){return he(e)>8}function _e(e,{current:t,query:n=``,expanded:r}={}){let i=n.trim().length>0,a=[];for(let o of e){let e=me(o,t);if(i){let t=e.filter(e=>pe(e,n));t.length&&a.push({key:o.key,label:o.label,rows:t,more:0});continue}e.length>8&&!r?.has(o.key)?a.push({key:o.key,label:o.label,rows:e.slice(0,8),more:e.length-8}):a.push({key:o.key,label:o.label,rows:e,more:0})}return a}var K=s(),q=`flex w-full items-center gap-2 rounded-xl px-3 py-2 text-left text-[14px] hover:bg-surface-2 focus:bg-surface-2 focus:outline-none`;function ve({label:e,text:n,heads:i=[],headValue:a,tail:o,groups:s,current:c,disabled:l,onHead:u,onPick:d,onTail:f,rowText:p}){let m=r(),[h,g]=(0,G.useState)(!1),[_,v]=(0,G.useState)(``),[y,b]=(0,G.useState)(()=>new Set),[x,S]=(0,G.useState)(!1),w=(0,G.useRef)(null),T=(0,G.useRef)(null),D=ge(s),k=(0,G.useCallback)((e=!1)=>{g(!1),v(``),b(new Set),S(e)},[]);(0,G.useEffect)(()=>{!h&&x&&(S(!1),w.current?.focus())},[h,x]),(0,G.useEffect)(()=>{if(!h)return;let e=e=>{let t=e.target;T.current?.contains(t)||w.current?.contains(t)||k()},t=e=>{e.key===`Escape`&&(e.stopPropagation(),k(!0))};return document.addEventListener(`pointerdown`,e,!0),document.addEventListener(`keydown`,t,!0),()=>{document.removeEventListener(`pointerdown`,e,!0),document.removeEventListener(`keydown`,t,!0)}},[h,k]),(0,G.useEffect)(()=>{h&&T.current&&(T.current.querySelector(`input`)??T.current.querySelector(`[aria-selected="true"]`)??T.current.querySelector(`[data-row]`))?.focus()},[h]);let A=e=>{if(e.key!==`ArrowDown`&&e.key!==`ArrowUp`)return;let t=[...e.currentTarget.closest(`[role="listbox"]`)?.querySelectorAll(`[data-row]`)??[]];if(!t.length)return;e.preventDefault();let n=t.indexOf(e.target);t[e.key===`ArrowDown`?n<0?0:Math.min(t.length-1,n+1):n<0?t.length-1:Math.max(0,n-1)]?.focus()},j=_e(s,{current:c,query:_,expanded:y}),M=_.trim().length>0,N=(e,n,r,i,a)=>(0,K.jsxs)(`button`,{type:`button`,role:`option`,"aria-selected":n,"data-row":``,title:a,onClick:i,onKeyDown:A,className:t(q,n&&`text-accent font-medium`),children:[(0,K.jsx)(`span`,{className:`min-w-0 flex-1 truncate`,children:r}),n&&(0,K.jsx)(C,{size:15,className:`shrink-0`})]},e);return(0,K.jsxs)(`div`,{className:`relative`,children:[(0,K.jsxs)(`button`,{ref:w,type:`button`,disabled:l,"aria-label":e,"aria-haspopup":`listbox`,"aria-expanded":h,title:n,onClick:()=>h?k():g(!0),className:t(O,`flex items-center gap-2 text-left text-fg disabled:opacity-50`),children:[(0,K.jsx)(`span`,{className:`min-w-0 flex-1 truncate`,children:n}),(0,K.jsx)(E,{size:16,className:`shrink-0 text-muted`})]}),h&&(0,K.jsxs)(`div`,{ref:T,role:`listbox`,"aria-label":e,className:`absolute left-0 right-0 top-full z-30 mt-1 flex max-h-[60vh] flex-col overflow-hidden rounded-2xl border border-border bg-surface p-1.5 shadow-xl`,children:[i.length>0&&(0,K.jsx)(`div`,{className:`mb-1 flex flex-col border-b border-border pb-1`,children:i.map(e=>N(`head:${e.value}`,a===e.value,e.label,()=>{u?.(e.value),k(!0)}))}),D&&(0,K.jsxs)(`label`,{className:`mb-1.5 flex items-center gap-2 rounded-xl bg-surface-2 px-3 py-2 text-muted focus-within:ring-2 focus-within:ring-accent/40`,children:[(0,K.jsx)(B,{size:15,className:`shrink-0`}),(0,K.jsx)(`input`,{type:`search`,value:_,onChange:e=>v(e.target.value),onKeyDown:A,placeholder:m(`Search models`),"aria-label":m(`Search models`),autoComplete:`off`,spellCheck:!1,className:`min-w-0 flex-1 bg-transparent text-[14px] text-fg outline-none placeholder:text-muted`})]}),(0,K.jsxs)(`div`,{className:`min-h-0 flex-1 overflow-y-auto`,children:[M&&j.length===0&&(0,K.jsx)(`div`,{className:`px-3 py-2.5 text-[13.5px] text-muted`,children:m(`No model matches`)}),j.map(e=>(0,K.jsxs)(`div`,{role:`group`,"aria-label":e.label,className:`[&+&]:mt-1.5`,children:[(0,K.jsx)(`div`,{className:`truncate px-3 pb-0.5 pt-1.5 text-[11px] font-semibold uppercase tracking-wide text-muted`,children:e.label}),e.rows.map(t=>N(`${e.key}:${t.id}`,c?.group===e.key&&c.id===t.id,p?p(t):t.name,()=>{d(e.key,t),k(!0)},t.id)),e.more>0&&(0,K.jsx)(`button`,{type:`button`,"data-row":``,onKeyDown:A,onClick:()=>b(t=>new Set([...t,e.key])),className:t(q,`text-[13px] text-accent`),children:m(`Show {n} more`,{n:e.more})})]},e.key))]}),o&&!M&&(0,K.jsx)(`div`,{className:`mt-1 border-t border-border pt-1`,children:N(`tail`,!1,o,()=>{f?.(),k(!0)})})]})]})}var ye=`nanomuse_cloud`,be=`{{vault:NANOMUSE_CLOUD_KEY}}`,xe=`custom`,J=[`openai`,`openai_responses`];function Y(e){try{return new URL(e).hostname.toLowerCase()}catch{return``}}function X(e,t,n=h){if(e&&!J.includes(e))return n.find(t=>t.id===e)??null;let r=Y(t);if(!r)return null;let i=e=>[e.base_url,e.base_url_global].map(e=>Y(e??``)).filter(Boolean);return n.find(e=>i(e).includes(r))||(n.find(e=>i(e).some(e=>{let t=e.indexOf(`.`);return t>0&&r.endsWith(e.slice(t))}))??null)}function Se(e,t,n=``,r=h){if(e===`nanomuse_cloud`)return`nanoMuse Cloud`;if(e===`chatgpt`)return`ChatGPT`;let i=r.find(t=>t.id===e);return i&&e!==`custom`?S(i,t):Y(n)||e}function Ce(e,t,n=h){if(!e.effective_provider)return``;let r=Se(e.effective_provider,t,e.base_url,n);return e.effective_model?`${r} · ${e.effective_model}`:r}function we(e,t,n,r=h){let i=e.effective_model??``;if(!i)return``;let a=(e,t)=>Se(X(e,t,r)?.id??(J.includes(e)?`custom`:e),n,t,r),o;return o=e.effective_source===`cloud`?`nanoMuse Cloud`:e.effective_source===`gui`&&(e.provider_id||e.base_url||!J.includes(e.provider||`openai`))?e.provider_id?Se(e.provider_id,n,e.base_url,r):a(e.provider,e.base_url):t.cloud?`nanoMuse Cloud`:a(t.provider,t.base_url),`${o} · ${i}`}function Te(e,t){let n=t.list??h,r=[];t.signedIn&&r.push({value:ye,label:`nanoMuse Cloud`,group:`cloud`,needsKey:!1,entry:null});let i=t.chat.cloud?null:X(t.chat.provider,t.chat.base_url,n);i&&i.capabilities.includes(e)&&r.push({value:i.id,label:S(i,t.locale),group:`chat`,needsKey:!1,entry:i});for(let a of p(t.region,e,n))a.id!==i?.id&&r.push({value:a.id,label:S(a,t.locale),group:`add`,needsKey:!0,entry:a});return r.push({value:xe,label:``,group:`add`,needsKey:!1,entry:null}),r}function Ee(e,t){return e.configured?t&&e.base_url&&Y(e.base_url)===Y(t)?ye:e.provider_id||`custom`:``}var De=`nanomuse_cloud`;function Oe(){let{state:e}=c(),[t,n]=(0,G.useState)(null),[i,a]=(0,G.useState)(null),o=e.profile?.name??`nanoMuse`,s=r(),d=(0,G.useCallback)(async()=>{try{n(await u.connections()),a(null)}catch(e){a(s(e.message))}},[s]);return(0,G.useEffect)(()=>{d()},[d,e.connectionsVersion]),(0,K.jsxs)(`div`,{className:`flex h-full flex-col`,children:[(0,K.jsx)(oe,{title:s(`Connections`),description:s(`What {name} can reach; keys stay in the vault on this machine.`,{name:o})}),(0,K.jsxs)(`div`,{className:`flex-1 overflow-y-auto px-4 pb-8 space-y-4`,children:[i&&(0,K.jsx)(`div`,{className:`rounded-2xl bg-rose-500/12 text-rose-700 dark:text-rose-300 p-3 text-[13.5px]`,children:i}),!t&&!i&&(0,K.jsx)(`div`,{className:`flex justify-center py-10 text-muted`,children:(0,K.jsx)(l,{className:`animate-spin`,size:20})}),t&&(0,K.jsxs)(K.Fragment,{children:[(0,K.jsx)(Z,{data:t,onChange:d}),t.image&&(0,K.jsx)(ke,{slot:`image`,data:t,onChange:d}),t.video&&(0,K.jsx)(ke,{slot:`video`,data:t,onChange:d}),(0,K.jsx)(se,{account:e.hub?.account??null,onChange:d}),t.embeddings.memory_enabled&&(0,K.jsx)(Ae,{data:t,onChange:d}),(0,K.jsx)(je,{data:t,onChange:d}),(0,K.jsx)(Ne,{data:t,onChange:d}),(0,K.jsx)(Fe,{data:t,onChange:d}),(0,K.jsx)(Ie,{data:t,onChange:d}),(0,K.jsx)(Q,{data:t,onChange:d}),(0,K.jsx)(Le,{data:t,onChange:d}),(0,K.jsx)(Re,{data:t,onChange:d}),(0,K.jsx)(ze,{data:t,onChange:d})]})]})]})}function Z({data:e,onChange:n,compact:a}){let{toast:o,state:s}=c(),p=r(),[m,g]=(0,G.useState)(!!a),j=e.providers,M=!!s.hub?.account?.any_model,P=Object.entries(j).find(([t,n])=>t!==`custom`&&n.base_url&&e.llm.base_url.startsWith(n.base_url)&&n.provider===e.llm.provider)?.[0]??Object.entries(j).find(([t,n])=>t!==`custom`&&n.base_url&&e.llm.base_url.startsWith(n.base_url))?.[0]??(e.llm.base_url?`custom`:`deepseek`),[I,L]=(0,G.useState)(P),[R,z]=(0,G.useState)(e.llm.model),[B,V]=(0,G.useState)(e.llm.base_url),[H,ne]=(0,G.useState)(``),[re,ie]=(0,G.useState)(!1),[ae,oe]=(0,G.useState)(!1),[se,ce]=(0,G.useState)(e.llm.key_source===`none`&&!!j[P]?.key_optional),[W,de]=(0,G.useState)(e.llm.tool_mode||`auto`),[fe,pe]=(0,G.useState)(e.llm.proxy??``),[me,he]=(0,G.useState)(!1),[ge,_e]=(0,G.useState)(!1),[q,ye]=(0,G.useState)(null),[be,xe]=(0,G.useState)(!1),[J,Y]=(0,G.useState)(e.gui?.model??``),[X,Se]=(0,G.useState)({list:j[P]?.models??[],image:[],video:[],menu:[],catalog:[],imageCatalog:[],videoCatalog:[],vision:[],gui:j[P]?.gui_models??[],source:`catalogue`}),[Ce,Te]=(0,G.useState)(!1),[Ee,Oe]=(0,G.useState)(!1);(0,G.useEffect)(()=>{z(e.llm.model),V(e.llm.base_url),de(e.llm.tool_mode||`auto`),pe(e.llm.proxy??``),he(!1),Y(e.gui?.model??``),L(P)},[e.llm,e.gui?.model]);let Z=j[I],ke=I===`custom`||!Z?.base_url?B:Z.base_url;(0,G.useEffect)(()=>{if(!m)return;let e=!0,t=setTimeout(()=>{Se(e=>({...e,source:`loading`})),u.llmModels({preset:I,base_url:ke,api_key:H||void 0}).then(t=>{e&&(Se({list:t.models,image:t.image_models??[],video:t.video_models??[],menu:t.menu??[],catalog:t.catalog??[],imageCatalog:t.image_catalog??[],videoCatalog:t.video_catalog??[],vision:t.vision??[],gui:t.gui??j[I]?.gui_models??[],source:t.source}),t.source===`live`&&t.models.length&&!Ce&&z(e=>t.models.includes(e)?e:t.models[0]))}).catch(()=>e&&Se({list:Z?.models??[],image:[],video:[],menu:[],catalog:[],imageCatalog:[],videoCatalog:[],vision:[],gui:Z?.gui_models??[],source:`catalogue`}))},H?600:150);return()=>{e=!1,clearTimeout(t)}},[m,I,ke,H]);let Ae=t=>{L(t);let n=j[t];n&&(n.base_url?V(n.base_url):j[I]?.base_url&&V(``),(!R||Object.values(j).some(e=>e.models?.includes(R)))&&n.models?.length&&!n.models.includes(R)&&z(n.models[0]),Se({list:n.models??[],image:[],video:[],menu:[],catalog:[],imageCatalog:[],videoCatalog:[],vision:[],gui:n.gui_models??[],source:`catalogue`}),(!e.gui?.model||Object.values(j).some(t=>t.gui_model===e.gui?.model))&&Y(n.cloud?``:n.gui_model??``),Oe(!1),Te(!1),ce(!1))};(0,G.useEffect)(()=>{let e=ee();e&&j[e]&&(g(!0),Ae(e))},[]);let je=!!Z?.no_key||se&&!!Z?.key_optional,Me=e.llm.cloud?{text:p(`Your account's model`),tone:`ok`}:e.llm.key_source===`none`&&!j[P]?.no_key&&!j[P]?.key_optional?{text:p(`No key yet`),tone:`warn`}:e.llm.key_source===`missing`?{text:p(`Key missing from vault`),tone:`warn`}:{text:e.llm.key_source===`vault`?p(`Key in vault`):e.llm.key_source===`config`?p(`Key from config`):p(`No key needed`),tone:`ok`},Ne=async()=>{_e(!0),ye(null);try{Z?.cloud?await u.cloudUseAsModel(R.trim()):await u.setLLM({provider:Z?.provider??`openai`,model:R.trim(),base_url:ke.trim(),tool_mode:W,api_key:H||(je?``:null),proxy:me&&e.llm.proxy!==void 0?fe.trim():null}),J.trim()!==(e.gui?.model??``)&&await u.setGui({model:J.trim()}),ne(``),b(),o(p(`Model saved`)),n(),a||g(!1)}catch(e){o(e.message)}finally{_e(!1)}},Pe=async()=>{xe(!0);try{ye(await u.testLLM())}catch(e){ye({ok:!1,error:e.message})}finally{xe(!1)}},Fe=[{id:`cloud`,title:p(`Your account`),ids:[]},{id:`openai`,title:p(`OpenAI-compatible · Chat Completions`),ids:[]},{id:`responses`,title:p(`Responses API`),ids:[]},{id:`local`,title:p(`Local or your own endpoint`),ids:[]}];for(let[e,t]of Object.entries(j))(Fe.find(e=>e.id===(t.group??`openai`))??Fe[0]).ids.push(e);for(let e of Fe)e.ids=v(e.ids,j,s.hub?.account);let Ie=I===`custom`||!Z?.base_url,Q=Z?.cloud?null:h.find(e=>e.id===y(I))??null,Le=d(s.hub?.account),Re=i(),ze=e=>!!Q&&!Q.user_capabilities&&!Q.capabilities.includes(e),Ve=j[De],Ge=Z?.cloud?X.gui[0]??Z.gui_model??``:Q&&!Q.user_capabilities?Q.capabilities.includes(`vision`)?Q.defaults.hands||R.trim():Ve?.gui_model??R.trim():R.trim(),Ke=!Z?.cloud&&ze(`vision`)&&!!Ve,qe=e.gui?we(e.gui,e.llm,Re):``,Je=Array.from(new Set([...Z?.cloud?X.gui:[],...Z?.gui_model?[Z.gui_model]:[],...X.list.filter(e=>X.vision.includes(e)||f(e)===!0)])).filter(Boolean),Ye=Z?.cloud?`nanoMuse Cloud`:Q?S(Q,Re):We(ke)||I,Xe=Z?.cloud?X.gui[0]??Z.gui_model??``:Q?.defaults.hands??Z?.gui_model??``,Ze=[{key:`hands`,label:Ye,rows:Je.map(e=>({id:e,name:e})),...Xe?{default:Xe}:{}}],Qe=Ie&&/^https?:\/\/[^/]+\/?$/.test(B.trim());return(0,K.jsxs)(A,{icon:(0,K.jsx)(F,{size:19}),title:p(`Chat model`),summary:e.llm.cloud?`nanoMuse Cloud · ${e.llm.model||`—`}`:`${e.llm.model||`—`}${e.llm.base_url?` · ${We(e.llm.base_url)}`:``}`,status:Me,open:m,onToggle:a?void 0:()=>g(!m),children:[(0,K.jsx)($,{label:p(`Provider`),children:(0,K.jsxs)(`div`,{className:`space-y-2.5`,children:[Fe.filter(e=>e.ids.length).map(e=>(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`div`,{className:`mb-1 text-[11px] uppercase tracking-wide text-muted`,children:e.title}),(0,K.jsx)(`div`,{className:`flex flex-wrap gap-1.5`,children:e.ids.map(e=>{let n=j[e];return(0,K.jsxs)(`button`,{type:`button`,onClick:()=>Ae(e),className:t(`rounded-2xl px-3 py-1.5 text-left border leading-tight`,I===e?`border-accent bg-accent/10 text-accent`:`border-border text-muted`),children:[(0,K.jsx)(`span`,{className:t(`block text-[13px]`,I===e&&`font-medium`),children:n.label}),n.subtitle&&(0,K.jsx)(`span`,{className:`block text-[10.5px] opacity-80`,children:p(n.subtitle)})]},e)})})]},e.id)),Q&&(0,K.jsxs)(`p`,{className:`text-[12px] text-muted`,children:[(0,K.jsx)(`span`,{className:`font-medium text-fg`,children:S(Q,Re)}),` · `,_(p,Q.capabilities),`. `,Re===`zh-CN`?Q.note_zh:Q.note]}),(0,K.jsxs)(`div`,{children:[(0,K.jsxs)(`button`,{type:`button`,onClick:()=>oe(!ae),className:`inline-flex items-center gap-1.5 text-[12.5px] text-accent`,children:[(0,K.jsx)(U,{size:13}),` `,p(`Or sign in with a ChatGPT plan`),` `,ae?(0,K.jsx)(k,{size:13}):(0,K.jsx)(E,{size:13})]}),ae&&(0,K.jsx)(`div`,{className:`mt-2`,children:(0,K.jsx)(te,{compact:!0,onChanged:()=>{n()}})})]})]})}),Ie&&(0,K.jsx)($,{label:p(`Base URL`),hint:p(Qe?`/v1 is added when the URL has no path.`:`The endpoint that serves /chat/completions, for example http://127.0.0.1:8000/v1.`),children:(0,K.jsx)(`input`,{value:B,onChange:e=>V(e.target.value),className:`w-full rounded-2xl bg-surface-2 px-3.5 py-2.5 text-[14.5px] outline-none focus:ring-2 focus:ring-accent/40`,placeholder:`https://host/v1`,inputMode:`url`,autoCapitalize:`off`})}),(0,K.jsxs)($,{label:p(`Chat model`),hint:Z?.cloud&&M&&X.catalog.length?p(`{n} models your account may use: the menu first, then everything else the provider lists under the Cloud key. Pick one; the ones beyond the menu are priced as the dearest menu model of their kind.`,{n:X.list.length}):Z?.cloud&&M?p(`Your account may name any model the provider has, not only these: type its id (a chat model here, a picture or clip model below) and it goes through as typed.`):X.source===`live`?p(`{n} models from the endpoint`,{n:X.list.length}):X.source===`loading`?p(`Asking the endpoint…`):X.list.length?p(`Could not list the endpoint's models; these are the usual ones.`):void 0,children:[Z?.cloud&&X.catalog.length>0&&!Ee&&(!R||X.list.includes(R))?(0,K.jsxs)(`select`,{value:R,onChange:e=>{if(e.target.value===Be){Oe(!0);return}z(e.target.value),Te(!0)},className:t(O,`text-fg`),children:[!R&&(0,K.jsx)(`option`,{value:``,children:p(`model name`)}),(0,K.jsx)(`optgroup`,{label:p(`Menu`),children:X.menu.map(e=>(0,K.jsx)(`option`,{value:e,children:X.vision.includes(e)?`${e} · ${p(`reads pictures`)}`:e},e))}),(0,K.jsx)(`optgroup`,{label:p(`More models on your account`),children:X.catalog.map(e=>(0,K.jsx)(`option`,{value:e,children:X.vision.includes(e)?`${e} · ${p(`reads pictures`)}`:e},e))}),(0,K.jsx)(`option`,{value:Be,children:p(`Type a model id…`)})]}):(0,K.jsxs)(K.Fragment,{children:[(0,K.jsx)(`input`,{list:`om-models`,value:R,onChange:e=>{z(e.target.value),Te(!0)},className:O,placeholder:p(`model name`),autoCapitalize:`off`,autoCorrect:`off`,autoFocus:Ee}),(0,K.jsx)(`datalist`,{id:`om-models`,children:X.list.map(e=>(0,K.jsx)(`option`,{value:e},e))}),Z?.cloud&&X.catalog.length>0&&(0,K.jsx)(`button`,{type:`button`,className:`mt-1.5 text-[12px] text-accent`,onClick:()=>{Oe(!1),X.list.includes(R)||z(X.menu[0]??X.list[0]??``)},children:p(`Pick from the list`)})]}),X.list.length>0&&(0,K.jsx)(`div`,{className:`mt-1.5 flex flex-wrap gap-1.5`,children:(X.menu.length?X.menu:X.list).slice(0,8).map(e=>(0,K.jsx)(`button`,{type:`button`,onClick:()=>z(e),className:t(`rounded-full px-2.5 py-1 text-[12px] border`,R===e?`border-accent bg-accent/10 text-accent font-medium`:`border-border text-muted`),children:e},e))})]}),(0,K.jsxs)($,{label:p(`Hands model`),hint:Z?.cloud?p(`The model that looks at screens when the hands run: the phone, this computer, a page the browser cannot read. Your account's hands model is {model}; the chat model above is a different pick.`,{model:Ge||`—`}):Ke?p(`The model that looks at screens when the hands run. This provider has no model that sees, so the hands use your account's, {model}, unless you pick one here.`,{model:Ge||`—`}):p(`The model that looks at screens when the hands run: a small, fast one that takes pictures, on the same endpoint and key. Default: this provider's own hands model.`),children:[(0,K.jsx)(ve,{label:p(`Hands model`),text:J?`${Ye} · ${J}`:p(`Automatic`),heads:[{value:``,label:p(`Automatic`)}],headValue:J?void 0:``,groups:Ze,current:J?{group:`hands`,id:J}:void 0,onHead:()=>Y(``),onPick:(e,t)=>Y(t.id)}),qe&&(0,K.jsx)(`p`,{className:`mt-1.5 text-[12px] text-muted`,children:p(`Currently {value}`,{value:qe})}),!Z?.cloud&&R.trim()&&!J&&f(R.trim())===!1&&(0,K.jsx)(`div`,{className:`mt-1.5 text-[12px] text-amber-700 dark:text-amber-300`,children:p(`{model} does not take pictures, so the hands would be blind with it. Pick a model that sees for them.`,{model:R.trim()})}),ze(`vision`)&&!Ke&&(0,K.jsxs)(`div`,{className:`mt-1.5 text-[12px] text-amber-700 dark:text-amber-300`,children:[x(p,`vision`,Le,Re),` `,(0,K.jsx)(He,{})]})]}),!Z?.no_key&&(0,K.jsxs)($,{label:p(`API key`),hint:se&&Z?.key_optional?p(`No key will be sent.`):e.llm.key_source===`vault`&&I===P?p(`A key is in the vault. Leave blank to keep it.`):p(`Stored encrypted in the vault as LLM_API_KEY.`),children:[(0,K.jsxs)(`div`,{className:`relative`,children:[(0,K.jsx)(`input`,{type:re?`text`:`password`,value:H,onChange:e=>ne(e.target.value),disabled:se&&!!Z?.key_optional,className:t(`w-full rounded-2xl bg-surface-2 px-3.5 py-2.5 text-[14.5px] outline-none focus:ring-2 focus:ring-accent/40`,`pr-10 disabled:opacity-50`),placeholder:e.llm.key_source===`vault`&&I===P?`••••••••`:Z?.key_hint||`sk-…`,autoComplete:`off`,autoCapitalize:`off`,spellCheck:!1}),(0,K.jsx)(`button`,{type:`button`,onClick:()=>ie(!re),"aria-label":p(re?`Hide key`:`Show key`),className:`absolute right-2 top-1/2 -translate-y-1/2 rounded-full p-1.5 text-muted`,children:re?(0,K.jsx)(le,{size:16}):(0,K.jsx)(ue,{size:16})})]}),(0,K.jsxs)(`div`,{className:`mt-1.5 flex items-center justify-between gap-2 text-[12px]`,children:[Z?.key_url?(0,K.jsxs)(`a`,{href:Z.key_url,target:`_blank`,rel:`noreferrer`,className:`inline-flex items-center gap-1 text-accent`,children:[p(`Get a key from {vendor}`,{vendor:Z.label}),` `,(0,K.jsx)(w,{size:12})]}):(0,K.jsx)(`span`,{}),Z?.key_optional&&(0,K.jsxs)(`label`,{className:`inline-flex items-center gap-1.5 text-muted`,children:[(0,K.jsx)(`input`,{type:`checkbox`,checked:se,onChange:e=>ce(e.target.checked),className:`accent-accent`}),` `,p(`No key`)]})]})]}),(0,K.jsx)($,{label:p(`Tool calling`),hint:p(`Auto uses the API's function calling and falls back to describing tools in the prompt when the endpoint rejects them. Prompt: for endpoints that silently ignore tools.`),children:(0,K.jsx)(`div`,{className:`flex gap-1.5`,children:[`auto`,`native`,`prompt`].map(e=>(0,K.jsx)(`button`,{type:`button`,onClick:()=>de(e),className:t(`rounded-full px-3 py-1.5 text-[13px] border`,W===e?`border-accent bg-accent/10 text-accent font-medium`:`border-border text-muted`),children:e},e))})}),!Z?.cloud&&e.llm.proxy!==void 0&&(0,K.jsx)($,{label:p(`Proxy (optional)`),hint:p(`Only this provider's requests go through it. nanoMuse Cloud never does.`),children:(0,K.jsx)(`input`,{className:`w-full rounded-2xl bg-surface-2 px-3.5 py-2.5 text-[14.5px] outline-none focus:ring-2 focus:ring-accent/40`,value:fe,onChange:e=>{pe(e.target.value),he(!0)},onFocus:()=>fe.includes(`••••`)&&!me&&pe(``),onBlur:()=>!me&&pe(e.llm.proxy??``),placeholder:`http://host:port / socks5://host:port`,autoComplete:`off`,spellCheck:!1})}),(0,K.jsxs)(`div`,{className:`flex gap-2 pt-1`,children:[(0,K.jsxs)(`button`,{type:`button`,disabled:ge||!R.trim()||Ie&&!B.trim(),onClick:()=>void Ne(),className:D,children:[ge?(0,K.jsx)(l,{size:16,className:`animate-spin`}):(0,K.jsx)(C,{size:16}),` `,p(`Save`)]}),(0,K.jsxs)(`button`,{type:`button`,disabled:be,onClick:()=>void Pe(),className:T,children:[be?(0,K.jsx)(l,{size:16,className:`animate-spin`}):(0,K.jsx)(N,{size:16}),` `,p(`Test`)]})]}),q&&(0,K.jsx)(Ue,{result:q,okText:p(`Replied "{reply}" in {ms} ms`,{reply:q.reply??``,ms:q.ms??0})})]})}function ke({slot:e,data:n,onChange:a}){let{toast:o,state:s}=c(),f=r(),p=n[e],h=e,v=s.hub?.account??null,y=!!v?.signed_in,T=d(v),E=i(),k=n.providers[De]?.base_url??``,N=Te(h,{signedIn:y,chat:{provider:n.llm.provider,base_url:n.llm.base_url,cloud:!!n.llm.cloud},region:T,locale:E}),P=Ee(p,k),[F,I]=(0,G.useState)(!1),[L,ee]=(0,G.useState)(P),[te,R]=(0,G.useState)(p.model),[z,B]=(0,G.useState)(p.base_url),[H,U]=(0,G.useState)(``),[ne,re]=(0,G.useState)(!1),[ie,ae]=(0,G.useState)(!1),[oe,se]=(0,G.useState)({list:[],more:[],source:`catalogue`});(0,G.useEffect)(()=>{ee(P),R(p.model),B(p.base_url),U(``)},[p]);let ce=N.find(e=>e.value===L)??null,W=ce?.entry??null,de=W?g(W,T):null,fe=L===`nanomuse_cloud`?k:L===`custom`?z.trim():de?.base_url??``,pe=P===L&&P!==``&&(p.key_source===`vault`||p.key_source===`config`),me=!!ce?.needsKey&&!H&&!pe,he=L===`nanomuse_cloud`?oe.list[0]??``:W?.defaults[e]??``;(0,G.useEffect)(()=>{if(!F||!L||L!==`nanomuse_cloud`&&!fe){se({list:[],more:[],source:`catalogue`});return}let t=!0,n=setTimeout(()=>{se(e=>({...e,source:`loading`})),u.llmModels(L===`nanomuse_cloud`?{preset:De}:{preset:W?m(W.id):``,base_url:fe,api_key:H||void 0}).then(n=>{if(!t)return;let r=(e===`image`?n.image_models:n.video_models)??[],i=(e===`image`?n.image_catalog:n.video_catalog)??[];se({list:r.filter(e=>!i.includes(e)),more:i,source:n.source})}).catch(()=>t&&se({list:[],more:[],source:`catalogue`}))},H?600:150);return()=>{t=!1,clearTimeout(n)}},[F,L,fe,H]);let ge=f(e===`image`?`Making pictures`:`Making clips`),_e=f(e===`image`?`Portraits of your Muse.`:`Short clips of your Muse.`),q=Ce(p,E),ve=x(f,h,T,E),ye=p.effective_provider?p.effective_source===`cloud`?{text:f(`Your account`),tone:`ok`}:p.effective_source===`chat`?{text:f(`The chat model's provider`),tone:`ok`}:{text:f(`Your key`),tone:`ok`}:{text:f(`Not set up`),tone:`warn`},xe=async()=>{ae(!0);try{L?L===`nanomuse_cloud`?await u.setMedia(e,{provider:`openai`,base_url:k,model:te.trim(),api_key:be}):L===`custom`?await u.setMedia(e,{provider:`openai`,base_url:z.trim(),model:te.trim(),api_key:H||null}):await u.setMedia(e,{provider:L,base_url:``,model:te.trim(),api_key:H||(ce?.group===`chat`?``:null)}):await u.setMedia(e,{provider:``,model:``,base_url:``,api_key:``}),U(``),b(),o(f(`Saved`)),a(),I(!1)}catch(e){o(e.message)}finally{ae(!1)}},J=e=>f(e===`cloud`?`Your account`:e===`chat`?`The chat model's provider`:`Add a provider`),Y=[`cloud`,`chat`,`add`].map(e=>({g:e,items:N.filter(t=>t.group===e)})).filter(e=>e.items.length),X=e===`image`?`IMAGE_API_KEY`:`VIDEO_API_KEY`;return(0,K.jsxs)(A,{icon:e===`image`?(0,K.jsx)(M,{size:19}):(0,K.jsx)(j,{size:19}),title:ge,summary:q||ve,status:ye,open:F,onToggle:()=>I(!F),children:[(0,K.jsx)(`p`,{className:`text-[12.5px] text-muted`,children:_e}),(0,K.jsxs)($,{label:f(`Provider`),hint:!q&&!L?ve:void 0,children:[(0,K.jsxs)(`select`,{value:L,onChange:e=>{ee(e.target.value),R(``),U(``)},className:t(O,`text-fg`),children:[(0,K.jsx)(`option`,{value:``,children:f(`Automatic`)}),Y.map(({g:e,items:t})=>(0,K.jsx)(`optgroup`,{label:J(e),children:t.map(e=>(0,K.jsx)(`option`,{value:e.value,children:e.value===`custom`?f(`Other OpenAI-compatible endpoint`):e.label},e.value))},e))]}),q&&(0,K.jsx)(`p`,{className:`mt-1.5 text-[12px] text-muted`,children:f(`Currently {value}`,{value:q})}),!q&&!L&&(0,K.jsxs)(`button`,{type:`button`,className:`mt-1.5 inline-flex items-center gap-1 text-[12.5px] text-accent`,onClick:()=>ee(N.find(e=>e.group===`add`)?.value??``),children:[(0,K.jsx)(V,{size:13}),` `,f(`Add a provider`)]}),W&&(0,K.jsxs)(`p`,{className:`mt-1.5 text-[12px] text-muted`,children:[(0,K.jsx)(`span`,{className:`font-medium text-fg`,children:S(W,E)}),` · `,_(f,W.capabilities),`. `,E===`zh-CN`?W.note_zh:W.note]})]}),L===`custom`&&(0,K.jsx)($,{label:f(`Base URL`),hint:f(`The endpoint that serves /images/generations, for example https://host/v1.`),children:(0,K.jsx)(`input`,{value:z,onChange:e=>B(e.target.value),className:`w-full rounded-2xl bg-surface-2 px-3.5 py-2.5 text-[14.5px] outline-none focus:ring-2 focus:ring-accent/40`,placeholder:`https://host/v1`,inputMode:`url`,autoCapitalize:`off`})}),L&&(0,K.jsx)(Ve,{label:f(e===`image`?`Picture model`:`Clip model`),provider:L===`nanomuse_cloud`?`nanoMuse Cloud`:L===`custom`?We(z)||f(`Other OpenAI-compatible endpoint`):ce?.label??L,value:te,options:oe.list,more:oe.more,onChange:R,other:L!==`nanomuse_cloud`||!!v?.any_model,placeholder:he||void 0}),L&&L!==`nanomuse_cloud`&&ce?.group!==`chat`&&(0,K.jsxs)($,{label:f(`API key`),hint:pe?f(`A key is in the vault. Leave blank to keep it.`):f(`Stored encrypted in the vault as {name}.`,{name:X}),children:[(0,K.jsxs)(`div`,{className:`relative`,children:[(0,K.jsx)(`input`,{type:ne?`text`:`password`,value:H,onChange:e=>U(e.target.value),className:t(`w-full rounded-2xl bg-surface-2 px-3.5 py-2.5 text-[14.5px] outline-none focus:ring-2 focus:ring-accent/40`,`pr-10`),placeholder:pe?`••••••••`:W?.key_hint||`sk-…`,autoComplete:`off`,autoCapitalize:`off`,spellCheck:!1}),(0,K.jsx)(`button`,{type:`button`,onClick:()=>re(!ne),"aria-label":f(ne?`Hide key`:`Show key`),className:`absolute right-2 top-1/2 -translate-y-1/2 rounded-full p-1.5 text-muted`,children:ne?(0,K.jsx)(le,{size:16}):(0,K.jsx)(ue,{size:16})})]}),de?.key_url&&(0,K.jsxs)(`a`,{href:de.key_url,target:`_blank`,rel:`noreferrer`,className:`mt-1.5 inline-flex items-center gap-1 text-[12px] text-accent`,children:[f(`Get a key from {vendor}`,{vendor:W?S(W,E):``}),` `,(0,K.jsx)(w,{size:12})]})]}),ce?.group===`chat`&&(0,K.jsx)(`p`,{className:`text-[12px] text-muted`,children:f(`Uses the chat model's key.`)}),(0,K.jsx)(`div`,{className:`flex gap-2 pt-1`,children:(0,K.jsxs)(`button`,{type:`button`,disabled:ie||me||L===`custom`&&!z.trim(),onClick:()=>void xe(),className:D,children:[ie?(0,K.jsx)(l,{size:16,className:`animate-spin`}):(0,K.jsx)(C,{size:16}),` `,f(`Save`)]})})]})}function Ae({data:e,onChange:n}){let{toast:i}=c(),a=r(),o=e.embeddings,[s,d]=(0,G.useState)(!1),[f,p]=(0,G.useState)(o.mode),[m,h]=(0,G.useState)(!!o.base_url),[g,_]=(0,G.useState)(o.base_url),[v,y]=(0,G.useState)(o.model),[b,x]=(0,G.useState)(``),[S,w]=(0,G.useState)(!1),[E,O]=(0,G.useState)(null),[k,j]=(0,G.useState)(!1);(0,G.useEffect)(()=>{p(o.mode),h(!!o.base_url),_(o.base_url),y(o.model)},[e.embeddings]);let M=o.mode===`off`?{text:a(`Off`),tone:`off`}:o.available===!0?{text:a(`On`),tone:`ok`}:o.available===!1?{text:o.mode===`on`?a(`Not reachable`):a(`By keyword`),tone:`warn`}:{text:a(`Not tried yet`),tone:`off`},P=o.mode===`off`?a(`Keyword recall only`):o.available===!0?a(`{model} · {n} of {total} memories indexed`,{model:o.model||o.default_model,n:o.indexed,total:o.total}):o.available===!1?o.reason:a(`{model} at {host}`,{model:o.model||o.default_model,host:We(o.effective_base_url)}),F=async()=>{w(!0),O(null);try{await u.setEmbeddings({mode:f,base_url:m?g.trim():``,model:v.trim(),api_key:m?b||void 0:``}),x(``),i(a(`Saved`)),n()}catch(e){i(e.message)}finally{w(!1)}},I=async()=>{j(!0);try{O(await u.testEmbeddings()),n()}catch(e){O({ok:!1,error:e.message})}finally{j(!1)}},L=e=>t(`rounded-full px-3 py-1.5 text-[13px] border`,e?`border-accent bg-accent/10 text-accent font-medium`:`border-border text-muted`);return(0,K.jsxs)(A,{icon:(0,K.jsx)(ce,{size:19}),title:a(`Recall by meaning`),summary:P,status:M,open:s,onToggle:()=>d(!s),children:[(0,K.jsx)(`p`,{className:`text-[12.5px] text-muted leading-snug`,children:a(`Memories are embedded once and a message finds the ones that mean the same thing, in any language: “写邮件给房东” finds “the landlord is Bob Li”. Keyword recall stays; the two are fused.`)}),(0,K.jsx)($,{label:a(`Mode`),hint:a(`Auto uses the model's endpoint when it has embeddings and falls back to keywords when it does not. On insists and warns. Off: keywords only.`),children:(0,K.jsx)(`div`,{className:`flex gap-1.5`,children:[`auto`,`on`,`off`].map(e=>(0,K.jsx)(`button`,{type:`button`,onClick:()=>p(e),className:L(f===e),children:a(e===`auto`?`Auto`:e===`on`?`On`:`Off`)},e))})}),f!==`off`&&(0,K.jsxs)(K.Fragment,{children:[(0,K.jsx)($,{label:a(`Endpoint`),hint:a(m?`Any OpenAI-compatible /embeddings: Ollama with an embedding model pulled, OpenAI, a gateway.`:`The model's endpoint and key. DeepSeek has no embeddings; pick another endpoint.`),children:(0,K.jsxs)(`div`,{className:`flex gap-1.5`,children:[(0,K.jsx)(`button`,{type:`button`,onClick:()=>h(!1),className:L(!m),children:a(`Same as the model`)}),(0,K.jsx)(`button`,{type:`button`,onClick:()=>{h(!0),g||_(`http://127.0.0.1:11434/v1`)},className:L(m),children:a(`Another endpoint`)})]})}),m&&(0,K.jsxs)(K.Fragment,{children:[(0,K.jsx)($,{label:a(`Base URL`),children:(0,K.jsx)(`input`,{value:g,onChange:e=>_(e.target.value),className:`w-full rounded-2xl bg-surface-2 px-3.5 py-2.5 text-[14.5px] outline-none focus:ring-2 focus:ring-accent/40`,placeholder:`http://127.0.0.1:11434/v1`,inputMode:`url`})}),(0,K.jsx)($,{label:a(`API key`),hint:o.key_source===`vault`?a(`A key is in the vault. Leave blank to keep it.`):a(`Stored encrypted in the vault as EMBEDDINGS_API_KEY. Ollama needs none.`),children:(0,K.jsx)(`input`,{type:`password`,value:b,onChange:e=>x(e.target.value),className:`w-full rounded-2xl bg-surface-2 px-3.5 py-2.5 text-[14.5px] outline-none focus:ring-2 focus:ring-accent/40`,placeholder:o.key_source===`vault`?`••••••••`:`sk-…`,autoComplete:`off`})})]}),(0,K.jsx)($,{label:a(`Embedding model`),hint:a(`Blank uses the endpoint's default: {model}. On Ollama: ollama pull qwen3-embedding:0.6b (reads Chinese and English).`,{model:o.default_model}),children:(0,K.jsx)(`input`,{value:v,onChange:e=>y(e.target.value),className:`w-full rounded-2xl bg-surface-2 px-3.5 py-2.5 text-[14.5px] outline-none focus:ring-2 focus:ring-accent/40`,placeholder:o.default_model,autoComplete:`off`})})]}),(0,K.jsxs)(`div`,{className:`flex gap-2 pt-1`,children:[(0,K.jsxs)(`button`,{type:`button`,disabled:S||m&&!/^https?:\/\//.test(g.trim()),onClick:()=>void F(),className:D,children:[S?(0,K.jsx)(l,{size:16,className:`animate-spin`}):(0,K.jsx)(C,{size:16}),` `,a(`Save`)]}),(0,K.jsxs)(`button`,{type:`button`,disabled:k||o.mode===`off`,onClick:()=>void I(),className:T,children:[k?(0,K.jsx)(l,{size:16,className:`animate-spin`}):(0,K.jsx)(N,{size:16}),` `,a(`Test`)]})]}),E&&(0,K.jsx)(Ue,{result:E,okText:a(`{model} · {dims} dims · {n} memories indexed · {ms} ms`,{model:E.model??``,dims:E.dims??0,n:E.indexed??0,ms:E.ms??0})})]})}function je({data:e,onChange:n}){let{toast:i}=c(),a=r(),o=e.search,[s,d]=(0,G.useState)(!1),[f,p]=(0,G.useState)(o.provider),[m,h]=(0,G.useState)(o.base_url),[g,_]=(0,G.useState)(``),[v,y]=(0,G.useState)(!1),[b,x]=(0,G.useState)(null),[S,w]=(0,G.useState)(!1);(0,G.useEffect)(()=>{p(o.provider),h(o.base_url)},[e.search]);let E=o.providers.find(e=>e.id===o.provider),O=o.providers.find(e=>e.id===f),k=!!O?.needs_key,j=o.configured?{text:a(`On`),tone:`ok`}:{text:a(`Not set up`),tone:`warn`},M=o.configured?o.provider===`searxng`?a(`{provider} at {host}`,{provider:E?.label??o.provider,host:We(o.base_url)}):E?.label??o.provider:a(`{provider} needs {what}; searches use DuckDuckGo until then`,{provider:E?.label??o.provider,what:E?.needs_key?a(`a key`):a(`an instance URL`)}),P=async()=>{y(!0),x(null);try{await u.setSearch({provider:f,base_url:f===`searxng`?m.trim():``,api_key:k?g||void 0:``}),_(``),i(a(`Saved`)),n()}catch(e){i(e.message)}finally{y(!1)}},F=async()=>{w(!0);try{x(await u.testSearch())}catch(e){x({ok:!1,error:e.message})}finally{w(!1)}},I=e=>t(`rounded-full px-3 py-1.5 text-[13px] border`,e?`border-accent bg-accent/10 text-accent font-medium`:`border-border text-muted`),L=f!==`searxng`||/^https?:\/\//.test(m.trim());return(0,K.jsxs)(A,{icon:(0,K.jsx)(B,{size:19}),title:a(`Web search`),summary:M,status:j,open:s,onToggle:()=>d(!s),children:[(0,K.jsx)(`p`,{className:`text-[12.5px] text-muted leading-snug`,children:a(`DuckDuckGo needs nothing, but it is scraped and rate-limits now and then. For searches that always work, use a provider with an API. Whichever you pick, a failed search falls back to DuckDuckGo with a note.`)}),(0,K.jsx)($,{label:a(`Provider`),children:(0,K.jsx)(`div`,{className:`flex flex-wrap gap-1.5`,children:o.providers.map(e=>(0,K.jsx)(`button`,{type:`button`,onClick:()=>p(e.id),className:I(f===e.id),children:e.label},e.id))})}),k&&(0,K.jsxs)($,{label:a(`API key`),hint:o.key_source===`vault`&&o.provider===f?a(`A key is in the vault. Leave blank to keep it.`):a(`Stored encrypted in the vault as SEARCH_API_KEY.`),children:[(0,K.jsx)(`input`,{type:`password`,value:g,onChange:e=>_(e.target.value),className:`w-full rounded-2xl bg-surface-2 px-3.5 py-2.5 text-[14.5px] outline-none focus:ring-2 focus:ring-accent/40`,placeholder:o.key_source===`vault`&&o.provider===f?`••••••••`:`…`,autoComplete:`off`}),O?.keys_url&&(0,K.jsx)(`a`,{href:O.keys_url,target:`_blank`,rel:`noreferrer`,className:`mt-1 inline-block text-[12px] text-accent`,children:a(`Get a key from {label}`,{label:O.label})})]}),f===`searxng`&&(0,K.jsx)($,{label:a(`Instance URL`),hint:a(`A SearXNG you run, with the JSON format enabled in its settings.`),children:(0,K.jsx)(`input`,{value:m,onChange:e=>h(e.target.value),className:`w-full rounded-2xl bg-surface-2 px-3.5 py-2.5 text-[14.5px] outline-none focus:ring-2 focus:ring-accent/40`,placeholder:`http://127.0.0.1:8080`,inputMode:`url`})}),(0,K.jsxs)(`div`,{className:`flex gap-2 pt-1`,children:[(0,K.jsxs)(`button`,{type:`button`,disabled:v||!L,onClick:()=>void P(),className:D,children:[v?(0,K.jsx)(l,{size:16,className:`animate-spin`}):(0,K.jsx)(C,{size:16}),` `,a(`Save`)]}),(0,K.jsxs)(`button`,{type:`button`,disabled:S,onClick:()=>void F(),className:T,children:[S?(0,K.jsx)(l,{size:16,className:`animate-spin`}):(0,K.jsx)(N,{size:16}),` `,a(`Test`)]})]}),b&&(0,K.jsx)(Ue,{result:b,okText:a(`{provider} · {n} results · {ms} ms`,{provider:b.provider??``,n:b.results??0,ms:b.ms??0})})]})}var Me=[{id:`gmail`,label:`Gmail`,imap:`imap.gmail.com`,smtp:`smtp.gmail.com`,port:587,starttls:!0},{id:`outlook`,label:`Outlook`,imap:`outlook.office365.com`,smtp:`smtp.office365.com`,port:587,starttls:!0},{id:`icloud`,label:`iCloud`,imap:`imap.mail.me.com`,smtp:`smtp.mail.me.com`,port:587,starttls:!0},{id:`qq`,label:`QQ`,imap:`imap.qq.com`,smtp:`smtp.qq.com`,port:587,starttls:!0},{id:`163`,label:`163`,imap:`imap.163.com`,smtp:`smtp.163.com`,port:465,starttls:!1},{id:`fastmail`,label:`Fastmail`,imap:`imap.fastmail.com`,smtp:`smtp.fastmail.com`,port:587,starttls:!0}];function Ne({data:e,onChange:n,compact:i}){let{toast:a}=c(),o=r(),s=e.email,[d,f]=(0,G.useState)(!!i),[p,m]=(0,G.useState)(s.address),[h,g]=(0,G.useState)(``),[_,v]=(0,G.useState)(s.imap_host),[y,b]=(0,G.useState)(s.imap_port),[x,S]=(0,G.useState)(s.smtp_host),[C,w]=(0,G.useState)(s.smtp_port),[T,E]=(0,G.useState)(s.smtp_starttls),[k,j]=(0,G.useState)(null),[M,P]=(0,G.useState)(null);(0,G.useEffect)(()=>{m(s.address),v(s.imap_host),b(s.imap_port),S(s.smtp_host),w(s.smtp_port),E(s.smtp_starttls)},[s]);let F=e=>{v(e.imap),b(993),S(e.smtp),w(e.port),E(e.starttls)},I=async()=>{j(`save`),P(null);try{await u.setEmail({enabled:!0,address:p.trim(),password:h||void 0,imap_host:_.trim(),imap_port:y,smtp_host:x.trim(),smtp_port:C,smtp_starttls:T}),g(``);let e=await u.testEmail();P(e),a(e.ok?o(`Email connected`):o(`Saved, but the test failed`)),n()}catch(e){a(e.message)}finally{j(null)}},L=async()=>{j(`off`);try{await u.disconnectEmail(),P(null),a(o(`Email disconnected`)),n()}catch(e){a(e.message)}finally{j(null)}},ee=s.enabled&&s.configured?{text:o(`Connected`),tone:`ok`}:s.enabled?{text:o(`Incomplete`),tone:`warn`}:{text:o(`Not connected`),tone:`off`};return(0,K.jsxs)(A,{icon:(0,K.jsx)(re,{size:19}),title:o(`Email`),summary:s.configured&&s.enabled?`${s.address} · ${o(`reads and sends`)}`:o(`Read your inbox, draft and send mail`),status:ee,open:d,onToggle:i?void 0:()=>f(!d),children:[(0,K.jsx)(`p`,{className:`text-[12.5px] text-muted -mt-1`,children:o(`Reading is a moderate action; sending always asks you first. Use an app password where your provider offers one.`)}),(0,K.jsx)($,{label:o(`Provider`),children:(0,K.jsx)(`div`,{className:`flex flex-wrap gap-1.5`,children:Me.map(e=>(0,K.jsx)(`button`,{type:`button`,onClick:()=>F(e),className:t(`rounded-full px-3 py-1.5 text-[13px] border`,_===e.imap?`border-accent bg-accent/10 text-accent font-medium`:`border-border text-muted`),children:e.label},e.id))})}),(0,K.jsx)($,{label:o(`Address`),children:(0,K.jsx)(`input`,{value:p,onChange:e=>m(e.target.value),className:O,placeholder:`you@example.com`,inputMode:`email`,autoComplete:`off`})}),(0,K.jsx)($,{label:o(`Password`),hint:s.password_set?o(`A password is in the vault. Leave blank to keep it.`):o(`Stored encrypted in the vault as EMAIL_PASSWORD.`),children:(0,K.jsx)(`input`,{type:`password`,value:h,onChange:e=>g(e.target.value),className:O,placeholder:s.password_set?`••••••••`:o(`app password`),autoComplete:`off`})}),(0,K.jsxs)(`div`,{className:`grid grid-cols-[1fr_84px] gap-2`,children:[(0,K.jsx)($,{label:o(`IMAP server`),children:(0,K.jsx)(`input`,{value:_,onChange:e=>v(e.target.value),className:O,placeholder:`imap.example.com`})}),(0,K.jsx)($,{label:o(`Port`),children:(0,K.jsx)(`input`,{type:`number`,value:y,onChange:e=>b(Number(e.target.value)),className:O})}),(0,K.jsx)($,{label:o(`SMTP server`),children:(0,K.jsx)(`input`,{value:x,onChange:e=>S(e.target.value),className:O,placeholder:`smtp.example.com`})}),(0,K.jsx)($,{label:o(`Port`),children:(0,K.jsx)(`input`,{type:`number`,value:C,onChange:e=>w(Number(e.target.value)),className:O})})]}),(0,K.jsxs)(`label`,{className:`flex items-center gap-2 text-[13.5px]`,children:[(0,K.jsx)(`input`,{type:`checkbox`,checked:T,onChange:e=>E(e.target.checked),className:`accent-[var(--om-accent)]`}),` `,o(`STARTTLS for SMTP (off for port 465)`)]}),(0,K.jsxs)(`div`,{className:`flex gap-2 pt-1`,children:[(0,K.jsxs)(`button`,{type:`button`,disabled:k!==null||!p.trim()||!_.trim()||!x.trim()||!h&&!s.password_set,onClick:()=>void I(),className:D,children:[k===`save`?(0,K.jsx)(l,{size:16,className:`animate-spin`}):(0,K.jsx)(N,{size:16}),` `,s.configured?o(`Save & test`):o(`Connect`)]}),s.enabled&&(0,K.jsxs)(`button`,{type:`button`,disabled:k!==null,onClick:()=>void L(),className:`flex items-center justify-center gap-1.5 rounded-2xl border border-border px-4 py-2.5 text-[14px] font-medium text-muted disabled:opacity-40`,children:[k===`off`?(0,K.jsx)(l,{size:16,className:`animate-spin`}):(0,K.jsx)(de,{size:16}),` `,o(`Disconnect`)]})]}),M&&(0,K.jsx)(Ue,{result:M,okText:o(`Signed in · {n} messages in the inbox`,{n:M.inbox??`?`})})]})}var Pe=[{id:`google`,label:`Google`,hint:`Settings → your calendar → Integrate calendar → Secret address in iCal format`},{id:`outlook`,label:`Outlook`,hint:`Settings → Calendar → Shared calendars → Publish a calendar → ICS link`},{id:`icloud`,label:`iCloud`,hint:`Share Calendar → Public Calendar → copy the webcal:// link`},{id:`fastmail`,label:`Fastmail`,hint:`Settings → Calendars → Export → Calendar URL`},{id:`file`,label:`.ics file`,hint:`A path on the machine where nanoMuse runs, for example ~/calendar.ics`}];function Fe({data:n,onChange:i,compact:a}){let{toast:o}=c(),s=r(),d=n.calendar,[f,p]=(0,G.useState)(!!a),[m,h]=(0,G.useState)(!1),[g,_]=(0,G.useState)(``),[v,y]=(0,G.useState)(``),[b,x]=(0,G.useState)(null),[S,w]=(0,G.useState)(d.day_start),[E,k]=(0,G.useState)(d.day_end),[j,M]=(0,G.useState)(null),[F,I]=(0,G.useState)(null);(0,G.useEffect)(()=>{w(d.day_start),k(d.day_end)},[d.day_start,d.day_end]);let L=async()=>{M(`add`),I(null);try{let e=await u.addCalendarFeed(g.trim(),v.trim());if(e.error)o(s(`Added, but it could not be read: {error}`,{error:e.error}));else{let t=e.feeds.find(e=>e.name===g.trim());o(`${s(`Calendar connected`)} · ${U(t?.events??0)}`),_(``),y(``),h(!1)}i()}catch(e){o(e.message)}finally{M(null)}},ee=async e=>{M(e);try{await u.removeCalendarFeed(e),i()}catch(e){o(e.message)}finally{M(null)}},te=async()=>{M(`hours`);try{await u.setCalendar({day_start:S,day_end:E}),o(s(`Saved`)),i()}catch(e){o(e.message)}finally{M(null)}},R=async()=>{M(`test`);try{I(await u.testCalendar()),i()}catch(e){o(e.message)}finally{M(null)}},B=d.feeds.reduce((e,t)=>e+t.events,0),H=d.feeds.filter(e=>e.error).length,U=e=>e===1?s(`1 event`):s(`{n} events`,{n:e}),ne=d.configured?H?{text:s(`{n} not reading`,{n:H}),tone:`warn`}:{text:s(`Connected`),tone:`ok`}:{text:s(`Not connected`),tone:`off`};return(0,K.jsxs)(A,{icon:(0,K.jsx)(ae,{size:19}),title:s(`Calendar`),summary:d.configured?d.feeds.length===1?`${d.feeds[0].name} · ${U(B)}`:`${s(`{n} calendars`,{n:d.feeds.length})} · ${U(B)}`:s(`Your agenda, free time, and events it can draft`),status:ne,open:f,onToggle:a?void 0:()=>p(!f),children:[(0,K.jsx)(`p`,{className:`text-[12.5px] text-muted -mt-1`,children:s(`Reads your calendar from its private .ics link; the link stays in the vault. It never changes your calendar; an event it proposes comes as a file you add with a tap.`)}),d.feeds.length>0&&(0,K.jsx)(`ul`,{className:`space-y-1.5`,children:d.feeds.map(n=>(0,K.jsxs)(`li`,{className:`flex items-center gap-2.5 rounded-2xl bg-surface-2/60 px-3 py-2`,children:[(0,K.jsx)(`span`,{className:t(`h-2 w-2 rounded-full`,n.error?`bg-rose-500`:n.fetched_at?`bg-emerald-500`:`bg-amber-500`)}),(0,K.jsxs)(`div`,{className:`min-w-0 flex-1`,children:[(0,K.jsx)(`div`,{className:`text-[13.5px] font-medium truncate`,children:n.name}),(0,K.jsxs)(`div`,{className:`text-[11.5px] text-muted truncate`,children:[n.error?n.error:n.fetched_at?`${U(n.events)} · ${s(`read {when}`,{when:e(n.fetched_at)})}`:s(`not read yet`),!n.from_app&&` · ${s(`from config.toml`)}`]})]}),n.from_app&&(0,K.jsx)(`button`,{type:`button`,"aria-label":s(`Remove`),disabled:j===n.name,onClick:()=>void ee(n.name),className:`p-1.5 rounded-full text-muted hover:bg-surface-2`,children:j===n.name?(0,K.jsx)(l,{size:15,className:`animate-spin`}):(0,K.jsx)(z,{size:15})})]},n.name))}),m?(0,K.jsxs)(`div`,{className:`space-y-2.5 rounded-2xl border border-border/70 p-3`,children:[(0,K.jsxs)($,{label:s(`Where is the link?`),children:[(0,K.jsx)(`div`,{className:`flex flex-wrap gap-1.5`,children:Pe.map(e=>(0,K.jsx)(`button`,{type:`button`,onClick:()=>x(b===e.id?null:e.id),className:t(`rounded-full px-3 py-1.5 text-[13px] border`,b===e.id?`border-accent bg-accent/10 text-accent font-medium`:`border-border text-muted`),children:s(e.label)},e.id))}),b&&(0,K.jsx)(`div`,{className:`mt-1.5 text-[11.5px] text-muted leading-snug`,children:s(Pe.find(e=>e.id===b).hint)})]}),(0,K.jsx)($,{label:s(`Name`),children:(0,K.jsx)(`input`,{value:g,onChange:e=>_(e.target.value),className:O,placeholder:s(`Work`)})}),(0,K.jsx)($,{label:s(`Private .ics link or file path`),hint:s(`Stored encrypted in the vault as CALENDAR_{name}.`,{name:g.trim().toUpperCase().replace(/[^A-Z0-9]+/g,`_`).replace(/^_+|_+$/g,``)||`NAME`})+` `+s(`nanoMuse fetches whatever address you put here, from this machine; only paste links you trust.`),children:(0,K.jsx)(`input`,{value:v,onChange:e=>y(e.target.value),className:O,placeholder:`https://calendar.google.com/calendar/ical/…/basic.ics`,inputMode:`url`,autoComplete:`off`})}),(0,K.jsxs)(`div`,{className:`flex gap-2`,children:[(0,K.jsxs)(`button`,{type:`button`,disabled:j===`add`||!g.trim()||!v.trim(),onClick:()=>void L(),className:D,children:[j===`add`?(0,K.jsx)(l,{size:16,className:`animate-spin`}):(0,K.jsx)(N,{size:16}),` `,s(`Connect`)]}),(0,K.jsx)(`button`,{type:`button`,onClick:()=>h(!1),className:T,children:s(`Cancel`)})]})]}):(0,K.jsxs)(`button`,{type:`button`,onClick:()=>h(!0),className:T,children:[(0,K.jsx)(V,{size:16}),` `,s(`Add a calendar`)]}),d.configured&&(0,K.jsxs)(K.Fragment,{children:[(0,K.jsx)($,{label:s(`Working hours`),hint:s(`Free time is looked for inside these hours.`),children:(0,K.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,K.jsx)(`input`,{type:`time`,value:S,onChange:e=>w(e.target.value),className:t(`w-full rounded-2xl bg-surface-2 px-3.5 py-2.5 text-[14.5px] outline-none focus:ring-2 focus:ring-accent/40`,`w-auto`)}),(0,K.jsx)(`span`,{className:`text-muted`,children:`–`}),(0,K.jsx)(`input`,{type:`time`,value:E,onChange:e=>k(e.target.value),className:t(`w-full rounded-2xl bg-surface-2 px-3.5 py-2.5 text-[14.5px] outline-none focus:ring-2 focus:ring-accent/40`,`w-auto`)}),(S!==d.day_start||E!==d.day_end)&&(0,K.jsx)(`button`,{type:`button`,disabled:j===`hours`,onClick:()=>void te(),className:t(`flex items-center justify-center gap-1.5 rounded-2xl bg-accent text-accent-fg px-4 py-2.5 text-[14px] font-medium disabled:opacity-40`,`px-3`),"aria-label":s(`Save`),children:j===`hours`?(0,K.jsx)(l,{size:16,className:`animate-spin`}):(0,K.jsx)(C,{size:16})})]})}),(0,K.jsxs)(`button`,{type:`button`,disabled:j===`test`,onClick:()=>void R(),className:`flex items-center justify-center gap-1.5 rounded-2xl border border-border px-4 py-2.5 text-[14px] font-medium text-muted disabled:opacity-40`,children:[j===`test`?(0,K.jsx)(l,{size:16,className:`animate-spin`}):(0,K.jsx)(P,{size:16}),` `,s(`Read again`)]}),F&&(0,K.jsx)(Ue,{result:F,okText:d.feeds.length===1?U(F.events??0):`${U(F.events??0)} · ${s(`{n} calendars`,{n:d.feeds.length})}`})]})]})}function Ie({data:n,onChange:i,compact:a}){let{toast:o}=c(),s=r(),d=n.contacts,[f,p]=(0,G.useState)(!!a),[m,h]=(0,G.useState)(!1),[g,_]=(0,G.useState)(``),[v,y]=(0,G.useState)(``),[b,x]=(0,G.useState)(null),[S,C]=(0,G.useState)(null),[w,E]=(0,G.useState)(``),[k,j]=(0,G.useState)(null),M=(0,G.useRef)(null),F=e=>e===1?s(`1 person`):s(`{n} people`,{n:e}),I=(e,t)=>{if(e.error)o(s(`Added, but it could not be read: {error}`,{error:e.error}));else{let n=e.sources.find(e=>e.name===t);o(`${s(`Address book connected`)} · ${F(n?.contacts??0)}`),_(``),y(``),h(!1)}i()},L=async()=>{x(`add`),C(null);try{I(await u.addContactsSource(g.trim(),v.trim()),g.trim())}catch(e){o(e.message)}finally{x(null)}},ee=async e=>{x(`upload`),C(null);try{let t=(g.trim()||e.name.replace(/\.vcf$/i,``)||`Imported`).slice(0,40);I(await u.importContacts(t,await e.text()),t)}catch(e){o(e.message)}finally{x(null),M.current&&(M.current.value=``)}},te=async e=>{x(e);try{await u.removeContactsSource(e),i()}catch(e){o(e.message)}finally{x(null)}},R=async()=>{x(`test`);try{C(await u.testContacts()),i()}catch(e){o(e.message)}finally{x(null)}};(0,G.useEffect)(()=>{if(!w.trim()){j(null);return}let e=setTimeout(()=>{u.contacts(w.trim(),5).then(e=>j(e.people)).catch(()=>j([]))},250);return()=>clearTimeout(e)},[w]);let H=d.sources.filter(e=>e.error).length,U=d.enabled?d.configured?H?{text:s(`{n} not reading`,{n:H}),tone:`warn`}:{text:s(`Connected`),tone:`ok`}:{text:s(`Not connected`),tone:`off`}:{text:s(`Off`),tone:`off`};return(0,K.jsxs)(A,{icon:(0,K.jsx)(W,{size:19}),title:s(`Contacts`),summary:d.configured?d.sources.length===0?`${F(d.count)} · ${s(`told to it in chat`)}`:`${F(d.count)} · ${d.sources.length===1?d.sources[0].name:s(`{n} address books`,{n:d.sources.length})}`:s(`Who is who, so it never guesses an address`),status:U,open:f,onToggle:a?void 0:()=>p(!f),children:[(0,K.jsx)(`p`,{className:`text-[12.5px] text-muted -mt-1`,children:s(`Import a .vcf export from Google Contacts, iCloud, Outlook or your phone, or paste a link to one. People you mention in chat go into its own book. It looks people up before writing to them and warns when an address is unknown.`)}),(d.sources.length>0||d.own>0)&&(0,K.jsxs)(`ul`,{className:`space-y-1.5`,children:[d.own>0&&(0,K.jsxs)(`li`,{className:`flex items-center gap-2.5 rounded-2xl bg-surface-2/60 px-3 py-2`,children:[(0,K.jsx)(`span`,{className:`h-2 w-2 rounded-full bg-emerald-500`}),(0,K.jsxs)(`div`,{className:`min-w-0 flex-1`,children:[(0,K.jsx)(`div`,{className:`text-[13.5px] font-medium truncate`,children:s(`My contacts`)}),(0,K.jsx)(`div`,{className:`text-[11.5px] text-muted truncate`,children:`${F(d.own)} · ${s(`added in chat`)}`})]})]}),d.sources.map(n=>(0,K.jsxs)(`li`,{className:`flex items-center gap-2.5 rounded-2xl bg-surface-2/60 px-3 py-2`,children:[(0,K.jsx)(`span`,{className:t(`h-2 w-2 rounded-full`,n.error?`bg-rose-500`:n.fetched_at?`bg-emerald-500`:`bg-amber-500`)}),(0,K.jsxs)(`div`,{className:`min-w-0 flex-1`,children:[(0,K.jsx)(`div`,{className:`text-[13.5px] font-medium truncate`,children:n.name}),(0,K.jsxs)(`div`,{className:`text-[11.5px] text-muted truncate`,children:[n.error?n.error:n.fetched_at?`${F(n.contacts)} · ${s(`read {when}`,{when:e(n.fetched_at)})}`:s(`not read yet`),!n.from_app&&` · ${s(`from config.toml`)}`]})]}),n.from_app&&(0,K.jsx)(`button`,{type:`button`,"aria-label":s(`Remove`),disabled:b===n.name,onClick:()=>void te(n.name),className:`p-1.5 rounded-full text-muted hover:bg-surface-2`,children:b===n.name?(0,K.jsx)(l,{size:15,className:`animate-spin`}):(0,K.jsx)(z,{size:15})})]},n.name))]}),m?(0,K.jsxs)(`div`,{className:`space-y-2.5 rounded-2xl border border-border/70 p-3`,children:[(0,K.jsx)($,{label:s(`Name`),children:(0,K.jsx)(`input`,{value:g,onChange:e=>_(e.target.value),className:O,placeholder:s(`iPhone`)})}),(0,K.jsxs)($,{label:s(`A .vcf file from your phone or computer`),hint:s(`Google Contacts: Export → vCard. iPhone: Contacts → select all → Share → Save to Files. Outlook: People → Manage → Export.`),children:[(0,K.jsx)(`input`,{ref:M,type:`file`,accept:`.vcf,text/vcard,text/x-vcard`,className:`hidden`,onChange:e=>e.target.files?.[0]&&void ee(e.target.files[0])}),(0,K.jsxs)(`button`,{type:`button`,disabled:b===`upload`,onClick:()=>M.current?.click(),className:T,children:[b===`upload`?(0,K.jsx)(l,{size:16,className:`animate-spin`}):(0,K.jsx)(fe,{size:16}),` `,s(`Choose a .vcf file`)]})]}),(0,K.jsx)($,{label:s(`Or a link / path to one`),hint:s(`A link is stored encrypted in the vault as CONTACTS_{name}.`,{name:g.trim().toUpperCase().replace(/[^A-Z0-9]+/g,`_`).replace(/^_+|_+$/g,``)||`NAME`})+` `+s(`nanoMuse fetches whatever address you put here, from this machine; only paste links you trust.`),children:(0,K.jsx)(`input`,{value:v,onChange:e=>y(e.target.value),className:O,placeholder:`https://… /contacts.vcf`,inputMode:`url`,autoComplete:`off`})}),(0,K.jsxs)(`div`,{className:`flex gap-2`,children:[(0,K.jsxs)(`button`,{type:`button`,disabled:b===`add`||!g.trim()||!v.trim(),onClick:()=>void L(),className:D,children:[b===`add`?(0,K.jsx)(l,{size:16,className:`animate-spin`}):(0,K.jsx)(N,{size:16}),` `,s(`Connect`)]}),(0,K.jsx)(`button`,{type:`button`,onClick:()=>h(!1),className:T,children:s(`Cancel`)})]})]}):(0,K.jsxs)(`button`,{type:`button`,onClick:()=>h(!0),className:T,children:[(0,K.jsx)(V,{size:16}),` `,s(`Add an address book`)]}),d.configured&&(0,K.jsxs)(K.Fragment,{children:[(0,K.jsxs)(`div`,{className:`relative`,children:[(0,K.jsx)(B,{size:15,className:`absolute left-3 top-1/2 -translate-y-1/2 text-muted`}),(0,K.jsx)(`input`,{value:w,onChange:e=>E(e.target.value),className:t(`w-full rounded-2xl bg-surface-2 px-3.5 py-2.5 text-[14.5px] outline-none focus:ring-2 focus:ring-accent/40`,`pl-9`),placeholder:s(`Find someone, as the agent would`),autoComplete:`off`})]}),k!==null&&(0,K.jsxs)(`ul`,{className:`space-y-1`,children:[k.length===0&&(0,K.jsx)(`li`,{className:`text-[12.5px] text-muted px-1`,children:s(`No one matches.`)}),k.map(e=>(0,K.jsxs)(`li`,{className:`rounded-2xl bg-surface-2/60 px-3 py-2`,children:[(0,K.jsxs)(`div`,{className:`text-[13.5px] font-medium`,children:[e.name,e.org&&(0,K.jsxs)(`span`,{className:`text-muted font-normal`,children:[` · `,e.org]})]}),(0,K.jsx)(`div`,{className:`text-[12px] text-muted break-words`,children:[...e.emails,...e.phones].join(` · `)})]},e.id))]}),d.sources.length>0&&(0,K.jsxs)(`button`,{type:`button`,disabled:b===`test`,onClick:()=>void R(),className:`flex items-center justify-center gap-1.5 rounded-2xl border border-border px-4 py-2.5 text-[14px] font-medium text-muted disabled:opacity-40`,children:[b===`test`?(0,K.jsx)(l,{size:16,className:`animate-spin`}):(0,K.jsx)(P,{size:16}),` `,s(`Read again`)]}),S&&(0,K.jsx)(Ue,{result:S,okText:F(S.contacts??0)})]})]})}function Q({data:e,onChange:n}){let{toast:i}=c(),a=r(),o=e.browser,[s,l]=(0,G.useState)(!1),d=async()=>{l(!0);try{await u.setBrowser(!o.enabled),n()}catch(e){i(e.message)}finally{l(!1)}};return(0,K.jsx)(A,{icon:(0,K.jsx)(ne,{size:19}),title:a(`Browser`),summary:o.available?a(`Open pages, click, fill forms, screenshot`):a(`Playwright is not installed on the server`),status:o.enabled&&o.available?{text:a(`On`),tone:`ok`}:o.enabled?{text:a(`Unavailable`),tone:`warn`}:{text:a(`Off`),tone:`off`},open:!1,trailing:(0,K.jsx)(`button`,{type:`button`,role:`switch`,"aria-checked":o.enabled,disabled:s,onClick:()=>void d(),className:t(`relative h-7 w-12 shrink-0 rounded-full transition`,o.enabled?`bg-accent`:`bg-surface-2 border border-border`),children:(0,K.jsx)(`span`,{className:t(`absolute top-0.5 h-6 w-6 rounded-full bg-white shadow transition`,o.enabled?`left-[22px]`:`left-0.5`)})}),children:!o.available&&(0,K.jsxs)(`p`,{className:`text-[12.5px] text-muted`,children:[a(`Install it where the server runs:`),` `,(0,K.jsx)(`code`,{className:`rounded bg-surface-2 px-1`,children:`pip install "nanomuse[browser]" && playwright install chromium`})]})})}function Le({data:e,onChange:n}){let{toast:i}=c(),a=r(),o=e.gui,[s,d]=(0,G.useState)(!1),[f,p]=(0,G.useState)(!1),[m,h]=(0,G.useState)(o.model),[g,_]=(0,G.useState)(o.base_url),[v,y]=(0,G.useState)(``),[b,x]=(0,G.useState)(null);(0,G.useEffect)(()=>{h(o.model),_(o.base_url)},[o.model,o.base_url]);let S=async()=>{p(!0);try{await u.setGui({enabled:!o.enabled}),n()}catch(e){i(e.message)}finally{p(!1)}},w=async()=>{p(!0),x(null);try{await u.setGui({model:m.trim(),base_url:g.trim(),...v?{api_key:v.trim()}:{}}),y(``),n(),x(await u.testGui())}catch(e){i(e.message)}finally{p(!1)}},T=o.phone,[E,k]=(0,G.useState)(R),j=(0,G.useRef)(E);(0,G.useEffect)(()=>{if(!s)return;let e=()=>{let e=R();e!==j.current&&(j.current=e,k(e),setTimeout(n,400))};return e(),document.addEventListener(`visibilitychange`,e),window.addEventListener(`focus`,e),()=>{document.removeEventListener(`visibilitychange`,e),window.removeEventListener(`focus`,e)}},[s,n]);let M=T.connected?a(`{name} is connected`,{name:T.device?.name??a(`A phone`)}):o.enabled?a(`No phone connected. Open the app on the phone`):a(`Tap, type and swipe in the apps on your phone`);return(0,K.jsxs)(A,{icon:(0,K.jsx)(L,{size:19}),title:a(`Phone`),summary:M,status:o.enabled&&T.connected?{text:a(`On`),tone:`ok`}:o.enabled?{text:a(`Waiting`),tone:`warn`}:{text:a(`Off`),tone:`off`},open:s,onToggle:()=>d(e=>!e),children:[(0,K.jsxs)(`div`,{className:`flex items-center justify-between gap-3`,children:[(0,K.jsxs)(`div`,{className:`text-[13px] leading-snug`,children:[(0,K.jsx)(`div`,{className:`font-medium`,children:a(`Operate the phone`)}),(0,K.jsx)(`div`,{className:`text-[12px] text-muted`,children:a(`When on, the agent can read the screen and act in the apps on the connected phone: 12306, WeChat, Alipay… It asks before paying, sending or deleting.`)})]}),(0,K.jsx)(`button`,{type:`button`,role:`switch`,"aria-checked":o.enabled,disabled:f,onClick:()=>void S(),className:t(`relative h-7 w-12 shrink-0 rounded-full transition`,o.enabled?`bg-accent`:`bg-surface-2 border border-border`),children:(0,K.jsx)(`span`,{className:t(`absolute top-0.5 h-6 w-6 rounded-full bg-white shadow transition`,o.enabled?`left-[22px]`:`left-0.5`)})})]}),E!==null&&(0,K.jsxs)(`div`,{className:`rounded-2xl bg-surface-2 px-3 py-2.5 text-[12.5px] leading-snug space-y-1.5`,children:[(0,K.jsxs)(`div`,{className:`flex items-center justify-between gap-3`,children:[(0,K.jsx)(`span`,{className:`font-medium`,children:a(`This phone`)}),(0,K.jsx)(`span`,{className:t(`rounded-full px-2 py-0.5 text-[11px] font-medium`,E===`on`&&`bg-emerald-500/12 text-emerald-700 dark:text-emerald-300`,E===`off`&&`bg-amber-500/15 text-amber-700 dark:text-amber-300`,E===`unsupported`&&`bg-surface text-muted`),children:a(E===`on`?`Ready`:E===`off`?`Not yet`:`Not on this Android`)})]}),E===`unsupported`&&(0,K.jsx)(`div`,{className:`text-muted`,children:a(`Operating the screen needs Android 11 or newer; this phone can still be used for everything else.`)}),E===`off`&&(0,K.jsxs)(K.Fragment,{children:[(0,K.jsx)(`div`,{className:`text-muted`,children:a(`Turn on the nanoMuse accessibility service; that is how it sees the screen and taps for you, only while a task runs, with a Stop button on screen.`)}),(0,K.jsxs)(`div`,{className:`flex flex-wrap gap-2 pt-0.5`,children:[(0,K.jsx)(`button`,{type:`button`,onClick:()=>I()?.openAccessibilitySettings?.(),className:`rounded-full bg-accent px-3 py-1.5 text-[12.5px] font-medium text-white`,children:a(`Open Accessibility settings`)}),(0,K.jsx)(`button`,{type:`button`,onClick:()=>I()?.openAppSettings?.(),className:`rounded-full border border-border px-3 py-1.5 text-[12.5px]`,children:a(`App settings`)})]}),(0,K.jsx)(`div`,{className:`text-muted`,children:a(`Greyed out with “Restricted setting”? Android 13+ does that for apps installed from a download: in App settings tap ⋮ → Allow restricted settings, then come back.`)})]}),E===`on`&&(0,K.jsx)(`div`,{className:`text-muted`,children:a(`Android may switch the service off after an update or a battery clean-up; if the phone stops answering, come back here.`)})]}),T.connected&&T.device&&(0,K.jsxs)(`div`,{className:`rounded-2xl bg-surface-2 px-3 py-2 text-[12.5px] text-muted`,children:[a(`{name} ({platform}), {n} apps`,{name:T.device.name,platform:T.device.platform,n:String(T.device.apps)}),T.last_screen&&(0,K.jsxs)(K.Fragment,{children:[` `,`·`,` `,a(`last seen in {app}`,{app:T.last_screen.app_name||T.last_screen.app})]})]}),(0,K.jsx)(`div`,{className:`text-[12px] text-muted leading-snug`,children:a(`The operator's model looks at screens step by step: a small, fast model that takes pictures. The Hands model row under Chat model picks one on the same endpoint and key; the fields here are for a different endpoint. Empty = {model}.`,{model:o.default_model||a(`the chat model`)})}),(0,K.jsx)($,{label:a(`Model`),children:(0,K.jsx)(`input`,{value:m,onChange:e=>h(e.target.value),placeholder:o.default_model||a(`same as the chat model`),className:O})}),(0,K.jsx)($,{label:a(`Base URL`),children:(0,K.jsx)(`input`,{value:g,onChange:e=>_(e.target.value),placeholder:a(`same as the chat model`),className:O})}),(0,K.jsx)($,{label:a(`API key`),hint:o.key_source===`vault`?a(`A key is in the vault; leave empty to keep it.`):o.key_source===`config`?a(`Set in config.toml.`):a(`Leave empty to use the main model's key.`),children:(0,K.jsx)(`input`,{type:`password`,value:v,onChange:e=>y(e.target.value),placeholder:`sk-…`,className:O,autoComplete:`off`})}),(0,K.jsxs)(`button`,{type:`button`,disabled:f,onClick:()=>void w(),className:D,children:[f?(0,K.jsx)(l,{size:16,className:`animate-spin`}):(0,K.jsx)(C,{size:16}),a(`Save and test`)]}),b&&(0,K.jsx)(Ue,{result:b,okText:a(`The operator's model answers.`)})]})}function Re({data:e,onChange:n}){let{toast:i}=c(),a=r(),[o,s]=(0,G.useState)(!1),[d,f]=(0,G.useState)(!1),[p,m]=(0,G.useState)(``),[h,g]=(0,G.useState)(``),[_,v]=(0,G.useState)(``),[y,b]=(0,G.useState)(`moderate`),[x,S]=(0,G.useState)(null),C=async()=>{S(`add`);try{let e=h.trim().split(/\s+/).filter(Boolean);await u.addMCP({name:p.trim(),command:e[0]??null,args:e.slice(1),url:_.trim()||null,risk:y}),m(``),g(``),v(``),f(!1),i(a(`Server connected`)),n()}catch(e){i(e.message)}finally{S(null)}},w=async e=>{S(e);try{await u.removeMCP(e),n()}catch(e){i(e.message)}finally{S(null)}},E=e.mcp.filter(e=>e.connected).length,k=(e.shared??[]).filter(e=>e.enabled&&!e.here),j=e=>{m(e.id),v(e.url),g(``),f(!0),s(!0)};return(0,K.jsxs)(A,{icon:(0,K.jsx)(N,{size:19}),title:a(`MCP servers`),summary:e.mcp.length?a(`{n} of {total} connected · {tools} tools`,{n:E,total:e.mcp.length,tools:e.mcp.reduce((e,t)=>e+t.tools,0)}):a(`Add tools from any Model Context Protocol server`),status:e.mcp.length?{text:a(`{n} on`,{n:E}),tone:E?`ok`:`warn`}:{text:a(`None`),tone:`off`},open:o,onToggle:()=>s(!o),children:[e.mcp.length>0&&(0,K.jsx)(`ul`,{className:`space-y-1.5`,children:e.mcp.map(e=>(0,K.jsxs)(`li`,{className:`flex items-center gap-2.5 rounded-2xl bg-surface-2/60 px-3 py-2`,children:[(0,K.jsx)(`span`,{className:t(`h-2 w-2 rounded-full`,e.connected?`bg-emerald-500`:`bg-rose-500`)}),(0,K.jsxs)(`div`,{className:`min-w-0 flex-1`,children:[(0,K.jsx)(`div`,{className:`text-[13.5px] font-medium truncate`,children:e.builtin?a(`This phone`):e.name}),(0,K.jsxs)(`div`,{className:`text-[11.5px] text-muted truncate`,children:[e.builtin?a(`clipboard, notifications, calendar, contacts, location, alarms, photos`):e.url??[e.command,...e.args].join(` `),` ·`,` `,a(`{n} tools`,{n:e.tools}),` · `,a(e.risk),!e.from_app&&!e.builtin&&` · ${a(`from config.toml`)}`]})]}),e.from_app&&(0,K.jsx)(`button`,{type:`button`,"aria-label":a(`Remove`),disabled:x===e.name,onClick:()=>void w(e.name),className:`p-1.5 rounded-full text-muted hover:bg-surface-2`,children:x===e.name?(0,K.jsx)(l,{size:15,className:`animate-spin`}):(0,K.jsx)(z,{size:15})})]},e.name))}),k.length>0&&(0,K.jsx)(`ul`,{className:`space-y-1.5`,children:k.map(e=>(0,K.jsxs)(`li`,{className:`flex items-center gap-2.5 rounded-2xl border border-dashed border-border/70 px-3 py-2`,children:[(0,K.jsx)(`span`,{className:`h-2 w-2 rounded-full bg-border`}),(0,K.jsxs)(`div`,{className:`min-w-0 flex-1`,children:[(0,K.jsx)(`div`,{className:`text-[13.5px] font-medium truncate`,children:e.label||e.id}),(0,K.jsxs)(`div`,{className:`text-[11.5px] text-muted truncate`,children:[a(`Connected on {device}; sign in here to use it on this device`,{device:e.device||e.device_id}),e.url?` · ${e.url}`:``]})]}),e.url&&(0,K.jsx)(`button`,{type:`button`,onClick:()=>j(e),className:t(`flex items-center justify-center gap-1.5 rounded-2xl border border-border px-4 py-2.5 text-[14px] font-medium text-muted disabled:opacity-40`,`py-1.5 text-[12.5px]`),children:a(`Sign in here`)})]},`${e.device_id}:${e.id}`))}),d?(0,K.jsxs)(`div`,{className:`space-y-2.5 rounded-2xl border border-border/70 p-3`,children:[(0,K.jsx)($,{label:a(`Name`),children:(0,K.jsx)(`input`,{value:p,onChange:e=>m(e.target.value),className:O,placeholder:`filesystem`})}),(0,K.jsx)($,{label:a(`Command`),hint:a(`Run locally over stdio, for example: npx -y @modelcontextprotocol/server-filesystem ./workspace`),children:(0,K.jsx)(`input`,{value:h,onChange:e=>g(e.target.value),className:O,placeholder:`npx -y @modelcontextprotocol/server-…`})}),(0,K.jsx)($,{label:a(`or URL`),hint:a(`A remote server over Streamable HTTP.`),children:(0,K.jsx)(`input`,{value:_,onChange:e=>v(e.target.value),className:O,placeholder:`https://host/mcp`,inputMode:`url`})}),(0,K.jsx)($,{label:a(`Risk of its tools`),hint:a(`Decides when the Sentinel asks you before a call.`),children:(0,K.jsx)(`div`,{className:`flex gap-1.5`,children:[`safe`,`moderate`,`high`].map(e=>(0,K.jsx)(`button`,{type:`button`,onClick:()=>b(e),className:t(`rounded-full px-3 py-1.5 text-[13px] border`,y===e?`border-accent bg-accent/10 text-accent font-medium`:`border-border text-muted`),children:a(e)},e))})}),(0,K.jsxs)(`div`,{className:`flex gap-2`,children:[(0,K.jsxs)(`button`,{type:`button`,disabled:x===`add`||!p.trim()||!(h.trim()||_.trim()),onClick:()=>void C(),className:D,children:[x===`add`?(0,K.jsx)(l,{size:16,className:`animate-spin`}):(0,K.jsx)(N,{size:16}),` `,a(`Connect`)]}),(0,K.jsx)(`button`,{type:`button`,onClick:()=>f(!1),className:T,children:a(`Cancel`)})]})]}):(0,K.jsxs)(`button`,{type:`button`,onClick:()=>f(!0),className:T,children:[(0,K.jsx)(V,{size:16}),` `,a(`Add a server`)]})]})}function ze({data:e,onChange:n}){let{toast:i}=c(),a=r(),[o,s]=(0,G.useState)(!1),[d,f]=(0,G.useState)(``),[p,m]=(0,G.useState)(``),[h,g]=(0,G.useState)(null),_=async()=>{g(`add`);try{await u.vaultSet(d.trim(),p),f(``),m(``),i(a(`Stored in the vault`)),n()}catch(e){i(e.message)}finally{g(null)}},v=async e=>{g(e);try{await u.vaultDelete(e),n()}catch(e){i(e.message)}finally{g(null)}};return(0,K.jsxs)(A,{icon:(0,K.jsx)(ie,{size:19}),title:a(`Vault`),summary:e.vault.length?a(`{n} secrets · encrypted on your machine`,{n:e.vault.length}):a(`Encrypted secrets the model never sees`),status:{text:`${e.vault.length}`,tone:`off`},open:o,onToggle:()=>s(!o),children:[(0,K.jsxs)(`p`,{className:`text-[12.5px] text-muted -mt-1`,children:[a(`Refer to a secret as`),` `,(0,K.jsx)(`code`,{className:`rounded bg-surface-2 px-1`,children:`{{vault:NAME}}`}),` `,a(`in a tool call or config: the value is filled in after the Sentinel approves and is redacted from everything the model reads.`)]}),e.vault.length>0&&(0,K.jsx)(`ul`,{className:`flex flex-wrap gap-1.5`,children:e.vault.map(e=>(0,K.jsxs)(`li`,{className:`flex items-center gap-1 rounded-full bg-surface-2 pl-3 pr-1 py-1 text-[12.5px] font-mono`,children:[e,(0,K.jsx)(`button`,{type:`button`,"aria-label":a(`Delete {name}`,{name:e}),disabled:h===e,onClick:()=>void v(e),className:`p-1 rounded-full text-muted hover:text-rose-500`,children:h===e?(0,K.jsx)(l,{size:13,className:`animate-spin`}):(0,K.jsx)(z,{size:13})})]},e))}),(0,K.jsxs)(`div`,{className:`grid grid-cols-[1fr_1fr_auto] gap-2 items-end`,children:[(0,K.jsx)($,{label:a(`Name`),children:(0,K.jsx)(`input`,{value:d,onChange:e=>f(e.target.value.toUpperCase().replace(/[^A-Z0-9_.-]/g,`_`)),className:t(O,`font-mono`),placeholder:`GITHUB_TOKEN`})}),(0,K.jsx)($,{label:a(`Value`),children:(0,K.jsx)(`input`,{type:`password`,value:p,onChange:e=>m(e.target.value),className:O,placeholder:a(`secret`),autoComplete:`off`})}),(0,K.jsx)(`button`,{type:`button`,disabled:h===`add`||!d||!p,onClick:()=>void _(),className:t(D,`px-3`),"aria-label":a(`Store`),children:h===`add`?(0,K.jsx)(l,{size:16,className:`animate-spin`}):(0,K.jsx)(V,{size:16})})]})]})}var Be=`\0other`;function Ve({label:e,provider:n,value:i,options:a,more:o=[],onChange:s,other:c=!0,placeholder:l}){let u=r(),d=a.includes(i)||o.includes(i),[f,p]=(0,G.useState)(!1),m=l?u(`Automatic · {model}`,{model:l}):u(`Automatic`),h=e=>e.map(e=>({id:e,name:e})),g=o.length?[{key:`menu`,label:u(`Menu`),rows:h(a),...l?{default:l}:{}},{key:`more`,label:u(`More models on your account`),rows:h(o)}]:[{key:`list`,label:n,rows:h(a),...l?{default:l}:{}}],_=i&&d?{group:a.includes(i)?g[0].key:`more`,id:i}:void 0;return(0,K.jsxs)(`div`,{className:`block text-[12.5px] text-muted`,children:[(0,K.jsx)(`span`,{className:`block mb-1`,children:e}),(a.length||o.length)&&(d||!i)&&!f?(0,K.jsx)(ve,{label:e,text:i?`${n} · ${i}`:m,heads:[{value:``,label:m}],headValue:i?void 0:``,groups:g,current:_,onHead:()=>s(``),onPick:(e,t)=>s(t.id),tail:c?u(`Other model…`):void 0,onTail:()=>{p(!0),s(``)}}):(0,K.jsx)(`input`,{value:i,onChange:e=>s(e.target.value),placeholder:m,"aria-label":e,className:t(O,`text-fg`),spellCheck:!1})]})}function He(){let e=r();return(0,K.jsxs)(`a`,{href:H,target:`_blank`,rel:`noopener noreferrer`,className:`inline-flex items-center gap-0.5 text-accent`,children:[e(`How`),` `,(0,K.jsx)(w,{size:11})]})}function $({label:e,hint:t,children:n}){return(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`label`,{className:`text-[12px] text-muted`,children:e}),(0,K.jsx)(`div`,{className:`mt-1`,children:n}),t&&(0,K.jsx)(`div`,{className:`mt-1 text-[11.5px] text-muted leading-snug`,children:t})]})}function Ue({result:e,okText:n}){let i=r(),[a,o]=(0,G.useState)(!1),s=!e.ok&&e.detail&&e.detail!==e.error?e.detail:null;return(0,K.jsxs)(`div`,{className:t(`rounded-2xl px-3 py-2 text-[12.5px]`,e.ok?`bg-emerald-500/12 text-emerald-700 dark:text-emerald-300`:`bg-rose-500/12 text-rose-700 dark:text-rose-300`),children:[e.ok?n:i(e.error??`The model provider did not answer.`),s&&(0,K.jsxs)(K.Fragment,{children:[` `,(0,K.jsx)(`button`,{type:`button`,onClick:()=>o(e=>!e),className:`underline decoration-dotted underline-offset-2 opacity-70 hover:opacity-100`,children:i(a?`Hide details`:`Details`)}),a&&(0,K.jsx)(`div`,{className:`mt-1.5 break-all font-mono text-[11px] opacity-80`,children:s})]})]})}function We(e){try{return new URL(e).host}catch{return e}}export{Fe as CalendarCard,Oe as ConnectionsScreen,Ie as ContactsCard,Ne as EmailCard,Z as ModelCard}; \ No newline at end of file diff --git a/nanomuse/server/static/assets/DevicesScreen-P67eLmyB.js b/nanomuse/server/static/assets/DevicesScreen-g6FUY327.js similarity index 99% rename from nanomuse/server/static/assets/DevicesScreen-P67eLmyB.js rename to nanomuse/server/static/assets/DevicesScreen-g6FUY327.js index 999d0d3b3..64daca63e 100644 --- a/nanomuse/server/static/assets/DevicesScreen-P67eLmyB.js +++ b/nanomuse/server/static/assets/DevicesScreen-g6FUY327.js @@ -1 +1 @@ -import{A as e,E as t,J as n,K as r,Q as i,Y as a,b as o,f as s,x as c}from"./MuseHeader-Pw-NI98v.js";import{n as l}from"./external-link-Xj5fjR8v.js";import{o as u}from"./Form-DwKuBk1V.js";import{t as d}from"./refresh-cw-BKgIzslL.js";import{G as f,H as p,a as m,at as h,et as g,ft as _,ht as v,i as y,l as b,o as x,pt as S,s as C}from"./index-BjYzdKkG.js";import{t as w}from"./BackBar-Dli0L0O_.js";import{t as T}from"./CloudCard-CdydxD3H.js";var E=n(`laptop`,[[`path`,{d:`M18 5a2 2 0 0 1 2 2v8.526a2 2 0 0 0 .212.897l1.068 2.127a1 1 0 0 1-.9 1.45H3.62a1 1 0 0 1-.9-1.45l1.068-2.127A2 2 0 0 0 4 15.526V7a2 2 0 0 1 2-2z`,key:`1pdavp`}],[`path`,{d:`M20.054 15.987H3.946`,key:`14rxg9`}]]),D=n(`wifi`,[[`path`,{d:`M12 20h.01`,key:`zekei9`}],[`path`,{d:`M2 8.82a15 15 0 0 1 20 0`,key:`dnpr2z`}],[`path`,{d:`M5 12.859a10 10 0 0 1 14 0`,key:`1x1e6c`}],[`path`,{d:`M8.5 16.429a5 5 0 0 1 7 0`,key:`1bycff`}]]),O=i(a(),1),k=o(),A=`https://nanomuse.cn/dl/`;function j(){let{state:e,dispatch:n,openThread:i,setTab:a,toast:o}=s(),l=r(),u=e.hub,f=e.hands,[p,m]=(0,O.useState)(!1),h=async()=>{try{let[e,t]=await Promise.all([c.hub(),c.hands()]);n({type:`ws`,msg:{kind:`hub`,hub:e}}),n({type:`ws`,msg:{kind:`hands_state`,hands:t}})}catch{}};(0,O.useEffect)(()=>{h()},[]);let g=async()=>{m(!0),await h(),m(!1)},_=async e=>{try{let t=await c.askDevice(e.id);n({type:`ws`,msg:{kind:`thread`,thread:t.thread}}),i(t.thread.id),a(`chat`)}catch(e){o(e.message)}},v=e=>{window.confirm(l(`Forget {name}? It can join again by signing in.`,{name:e.name}))&&c.forgetDevice(e.id).then(e=>n({type:`ws`,msg:{kind:`hub`,hub:e}})).catch(e=>o(e.message))},y=(u?.devices??[]).filter(e=>!e.this&&e.kind!==`web`),b=!!u?.account.signed_in,x=u?.state===`connected`,S=y.length+(u&&x?1:0),C=y.filter(e=>e.online).length+(u&&x?1:0);return(0,k.jsxs)(`div`,{className:`flex h-full flex-col`,children:[(0,k.jsx)(w,{title:l(`Devices`),actions:(0,k.jsx)(`button`,{type:`button`,onClick:()=>void g(),"aria-label":l(`Refresh`),title:l(`Refresh`),className:`flex h-9 w-9 items-center justify-center rounded-full text-muted hover:bg-surface-2 hover:text-fg`,children:(0,k.jsx)(d,{size:17,className:t(p&&`animate-spin`)})})}),(0,k.jsxs)(`div`,{className:`@container flex-1 overflow-y-auto pb-8`,children:[(0,k.jsxs)(`div`,{className:`px-5 pb-4 pt-1`,children:[(0,k.jsx)(`p`,{className:`text-[14px] leading-[20px] text-muted`,children:l(`Every device signed in to your account is a Muse of its own, on the same conversations. Type @ and a device's name in the chat to hand it work; a computer lends its hands.`)}),u&&b&&S>0&&(0,k.jsxs)(`p`,{className:`mt-1.5 text-[12.5px] font-medium uppercase tracking-wide text-muted/80`,children:[S===1?l(`1 device`):l(`{n} devices`,{n:S}),` · `,l(`{n} online`,{n:C})]})]}),(0,k.jsx)(`div`,{className:`px-4 pb-3`,children:(0,k.jsx)(T,{account:u?.account??null,onChange:()=>void h()})}),u&&(0,k.jsxs)(`div`,{className:`px-4`,children:[(0,k.jsx)(M,{children:l(`This device`)}),(0,k.jsx)(H,{hub:u,hands:f??void 0,onChange:()=>void h()})]}),(0,k.jsxs)(`div`,{className:`px-4 pt-4`,children:[(0,k.jsx)(M,{children:l(`Other devices`)}),y.length===0?(0,k.jsx)(G,{hub:u??void 0,signedIn:b}):(0,k.jsx)(`div`,{className:`grid grid-cols-1 gap-3 @2xl:grid-cols-2`,children:y.map(e=>(0,k.jsx)(U,{device:e,onAsk:()=>void _(e),onForget:()=>v(e)},e.id))}),(0,k.jsx)(`p`,{className:`px-1 pt-3 text-[12.5px] leading-[18px] text-muted`,children:l(`A chat addressed to a device runs there; you see every step here and answer its approvals.`)})]}),f&&!f.reason?.includes(`phone`)&&(0,k.jsxs)(`div`,{className:`pt-4`,children:[(0,k.jsx)(`div`,{className:`px-4`,children:(0,k.jsx)(M,{children:l(`Hands`)})}),(0,k.jsx)(K,{hands:f,onChange:()=>void h()})]})]})]})}function M({children:e}){return(0,k.jsx)(`p`,{className:`px-1 pb-2 text-[12.5px] font-medium uppercase tracking-wide text-muted/80`,children:e})}function N({children:e}){return(0,k.jsx)(`p`,{className:`px-4 pb-3 text-[12.5px] leading-[18px] text-muted`,children:e})}function P({children:e,className:n}){return(0,k.jsx)(`div`,{className:t(`relative rounded-2xl border border-border/70 bg-surface p-4`,n),children:e})}function F({kind:e,online:n}){return(0,k.jsx)(`span`,{className:t(`flex h-11 w-11 shrink-0 items-center justify-center rounded-xl`,n?`bg-accent/10 text-accent`:`bg-surface-2 text-muted`),"aria-hidden":!0,children:q(e,22)})}function I({online:e}){return(0,k.jsx)(`span`,{"aria-hidden":!0,className:t(`inline-block h-2 w-2 shrink-0 rounded-full`,e?`bg-[#2fb344]`:`bg-muted/35`)})}function L(e){if(e==null||e===``)return``;let t=typeof e==`number`?e:/^\d+(\.\d+)?$/.test(e)?Number(e):NaN;return Number.isFinite(t)?new Date(t*1e3).toISOString():String(e)}function R(t,n){let r=L(t.last_seen),i=e(r);return t.online?r&&Date.now()-new Date(r).getTime()<12e4?`${n(`Online`)} · ${n(`just now`)}`:n(`Online`):i?n(`Last seen {when}`,{when:i}):n(`Offline`)}function z(e,t,n=[]){let r=new Set(e??[]),i=[...n];return r.has(`task`)&&i.push(t(`Tasks`)),r.has(`shell`)&&i.push(t(`Commands`)),(r.has(`files`)||r.has(`file.get`)||r.has(`file.put`))&&i.push(t(`Files`)),r.has(`screen`)&&i.push(t(`Screenshot`)),r.has(`open`)&&i.push(t(`Open links`)),[...r].some(e=>e.startsWith(`coding.`))&&i.push(t(`Coding agents`)),r.has(`notify`)&&i.push(t(`Notifications`)),i}function B({items:e}){return e.length===0?null:(0,k.jsx)(`div`,{className:`flex flex-wrap gap-1.5`,children:e.map(e=>(0,k.jsx)(`span`,{className:`rounded-full bg-surface-2 px-2.5 py-1 text-[12px] font-medium text-fg/80`,children:e},e))})}function V(e){return[e.os||``,e.version||``].filter(Boolean).join(` · `)}function H({hub:e,hands:t,onChange:n}){let{dispatch:i,toast:a}=s(),o=r(),[d,f]=(0,O.useState)(!1),[p,m]=(0,O.useState)(e.device.name),[h,_]=(0,O.useState)(!1),v=e.account.signed_in,y=e.state===`connected`,S=e.devices.find(e=>e.this),C=async e=>{_(!0);try{let t=await c.updateHub(e);i({type:`ws`,msg:{kind:`hub`,hub:t}}),n()}catch(e){a(e.message)}finally{_(!1)}},w=v?e.enabled?y?o(`Online`):e.state===`refused`?o(`Refused`):o(`Connecting…`):o(`Off`):o(`Signed out`),T=z(e.device.actions,o,t?.enabled&&t.available?[o(`Hands`)]:[]);return(0,k.jsxs)(P,{children:[(0,k.jsxs)(`div`,{className:`flex items-start gap-3.5`,children:[(0,k.jsx)(F,{kind:e.device.kind,online:y}),(0,k.jsxs)(`div`,{className:`min-w-0 flex-1`,children:[d?(0,k.jsxs)(`form`,{className:`flex items-center gap-2`,onSubmit:e=>{e.preventDefault(),p.trim()&&C({name:p.trim()}).then(()=>f(!1))},children:[(0,k.jsx)(`input`,{value:p,onChange:e=>m(e.target.value),maxLength:60,autoFocus:!0,"aria-label":o(`This device's name`),placeholder:o(`A name your other devices will see`),className:`h-9 min-w-0 flex-1 rounded-xl bg-surface-2 px-3 text-[15px] outline-none focus:ring-2 focus:ring-accent/40`}),(0,k.jsx)(`button`,{type:`submit`,disabled:h||!p.trim(),"aria-label":o(`Save`),className:`flex h-9 w-9 items-center justify-center rounded-full bg-accent text-accent-fg disabled:opacity-40`,children:(0,k.jsx)(l,{size:16})}),(0,k.jsx)(`button`,{type:`button`,onClick:()=>f(!1),"aria-label":o(`Cancel`),className:`flex h-9 w-9 items-center justify-center rounded-full bg-surface-2 text-muted`,children:(0,k.jsx)(u,{size:16})})]}):(0,k.jsxs)(`div`,{className:`flex items-center gap-1.5`,children:[(0,k.jsx)(`span`,{className:`truncate text-[16px] font-semibold leading-[22px]`,children:e.device.name}),(0,k.jsx)(`button`,{type:`button`,onClick:()=>{m(e.device.name),f(!0)},"aria-label":o(`Rename this device`),title:o(`Rename this device`),className:`flex h-7 w-7 shrink-0 items-center justify-center rounded-full text-muted hover:bg-surface-2 hover:text-fg`,children:(0,k.jsx)(g,{size:13})})]}),(0,k.jsxs)(`p`,{className:`mt-0.5 flex items-center gap-1.5 text-[13px] leading-[18px] text-muted`,children:[(0,k.jsx)(I,{online:y}),(0,k.jsx)(`span`,{className:`truncate`,children:[w,V(S??{})].filter(Boolean).join(` · `)})]}),T.length>0&&(0,k.jsx)(`div`,{className:`mt-3`,children:(0,k.jsx)(B,{items:T})})]})]}),(0,k.jsxs)(`div`,{className:`-mx-4 -mb-2 mt-4 border-t border-border/60`,children:[(0,k.jsx)(b,{label:o(`Join the hub`),checked:e.enabled&&v,disabled:!v||h,onChange:e=>void C({enabled:e})}),(0,k.jsx)(N,{children:o(v?`Reachable by your other devices while this runs.`:`Sign in first.`)}),(0,k.jsx)(x,{inset:16}),(0,k.jsx)(b,{label:o(`My other devices may operate it`),checked:e.remote_control,disabled:h,onChange:e=>void C({remote_control:e})}),(0,k.jsx)(N,{children:o(`They can run commands, read files and see its screen here; each step still goes through the Sentinel.`)})]}),(e.state===`refused`||e.state===`disconnected`)&&e.detail&&(0,k.jsx)(`div`,{className:`mt-3 rounded-xl bg-amber-500/12 px-3 py-2 text-[12.5px] text-amber-700 dark:text-amber-300`,children:e.detail})]})}function U({device:e,onAsk:t,onForget:n}){let i=r(),a=z(e.actions,i),o=e.online&&(e.actions??[]).includes(`task`);return(0,k.jsxs)(P,{className:`flex flex-col gap-3`,children:[(0,k.jsxs)(`div`,{className:`flex items-start gap-3.5`,children:[(0,k.jsx)(F,{kind:e.kind,online:e.online}),(0,k.jsxs)(`div`,{className:`min-w-0 flex-1`,children:[(0,k.jsx)(`p`,{className:`truncate text-[16px] font-semibold leading-[22px]`,children:e.name}),(0,k.jsxs)(`p`,{className:`mt-0.5 flex items-center gap-1.5 text-[13px] leading-[18px] text-muted`,children:[(0,k.jsx)(I,{online:e.online}),(0,k.jsx)(`span`,{className:`truncate`,children:[R(e,i),V(e)].filter(Boolean).join(` · `)})]})]}),(0,k.jsx)(W,{label:i(`More about {name}`,{name:e.name}),items:[{label:i(`Forget this device`),onClick:n,danger:!0}]})]}),(0,k.jsx)(B,{items:a}),o&&(0,k.jsx)(`p`,{className:`text-[12.5px] leading-[18px] text-muted`,children:i(`Type @{name} in the chat to hand it work.`,{name:e.name})}),e.online&&(0,k.jsxs)(`button`,{type:`button`,onClick:t,className:`flex h-9 w-fit items-center gap-1.5 rounded-full bg-accent/10 px-3.5 text-[13.5px] font-medium text-accent hover:bg-accent/15`,children:[(0,k.jsx)(h,{size:14}),` `,i(`Ask`)]})]})}function W({label:e,items:n}){let[r,i]=(0,O.useState)(!1),a=(0,O.useRef)(null);return(0,O.useEffect)(()=>{if(!r)return;let e=e=>{a.current?.contains(e.target)||i(!1)},t=e=>{e.key===`Escape`&&i(!1)};return window.addEventListener(`pointerdown`,e),window.addEventListener(`keydown`,t),()=>{window.removeEventListener(`pointerdown`,e),window.removeEventListener(`keydown`,t)}},[r]),(0,k.jsxs)(`div`,{ref:a,className:`relative -mr-1.5 -mt-1`,children:[(0,k.jsx)(`button`,{type:`button`,onClick:()=>i(e=>!e),"aria-label":e,"aria-haspopup":`menu`,"aria-expanded":r,className:`flex h-8 w-8 items-center justify-center rounded-full text-muted hover:bg-surface-2 hover:text-fg`,children:(0,k.jsx)(v,{size:18})}),r&&(0,k.jsx)(`ul`,{role:`menu`,className:`absolute right-0 top-9 z-30 min-w-[180px] overflow-hidden rounded-2xl border border-border bg-surface py-1 shadow-xl`,children:n.map(e=>(0,k.jsx)(`li`,{children:(0,k.jsx)(`button`,{type:`button`,role:`menuitem`,onClick:()=>{i(!1),e.onClick()},className:t(`w-full px-4 py-2.5 text-left text-[14px] hover:bg-surface-2`,e.danger&&`text-red-600 dark:text-red-400`),children:e.label})},e.label))})]})}function G({hub:e,signedIn:t}){let n=r(),i=t&&e?.state===`connected`;return(0,k.jsxs)(P,{className:`flex flex-col gap-3`,children:[(0,k.jsxs)(`div`,{className:`flex items-start gap-3.5`,children:[(0,k.jsx)(`span`,{className:`flex h-11 w-11 shrink-0 items-center justify-center rounded-xl bg-surface-2 text-muted`,"aria-hidden":!0,children:(0,k.jsx)(f,{size:22})}),(0,k.jsxs)(`div`,{className:`min-w-0 flex-1`,children:[(0,k.jsx)(`p`,{className:`text-[15px] font-semibold leading-[20px]`,children:n(i?`Add a device`:`No other device yet`)}),(0,k.jsx)(`p`,{className:`mt-1 text-[13px] leading-[18px] text-muted`,children:t?i?e?.account.hint?n(`Install nanoMuse on your phone, Mac or PC and sign in as {hint}; it appears here on its own.`,{hint:e.account.hint}):n(`Install nanoMuse on your phone, Mac or PC and sign in with the same account; it appears here on its own.`):J(e?.state??``,n):n(`Sign in above to see them.`)})]})]}),i&&(0,k.jsx)(`a`,{href:A,target:`_blank`,rel:`noopener noreferrer`,className:`flex h-9 w-fit items-center gap-1.5 rounded-full bg-accent/10 px-3.5 text-[13.5px] font-medium text-accent hover:bg-accent/15`,children:n(`Get the apps`)})]})}function K({hands:e,onChange:n}){let{dispatch:i,toast:a,state:o}=s(),l=r(),[u,d]=(0,O.useState)(!1),f=o.profile?.name??`nanoMuse`,h=async e=>{d(!0);try{let t=await c.setHands(e);i({type:`ws`,msg:{kind:`hands_state`,hands:t}}),n()}catch(e){a(e.message)}finally{d(!1)}},g=e.task_active?l(`Working`):e.enabled?e.available?l(`On`):l(`Unavailable`):l(`Off`);return(0,k.jsxs)(k.Fragment,{children:[(0,k.jsxs)(m,{className:`border border-border/70`,children:[(0,k.jsx)(b,{icon:(0,k.jsx)(_,{size:22}),label:l(`Hands on this computer`),value:g,checked:e.enabled,disabled:u,onChange:e=>void h({enabled:e})}),(0,k.jsx)(y,{className:`pb-3 pt-0`,children:e.task_active?e.task_text||l(`On the screen now`):e.available?l(`It looks at a screenshot and clicks by position; paying, sending and deleting ask you first.`):e.reason||l(`Nothing can drive this screen yet.`)}),(0,k.jsx)(x,{inset:16}),(0,k.jsxs)(`div`,{className:`flex items-center gap-2 px-4 py-3 text-[13px] text-muted`,children:[(0,k.jsxs)(`span`,{children:[l(`Driver`),`:`]}),[`auto`,`desktop`,`pyautogui`,`xdotool`].map(n=>(0,k.jsx)(`button`,{type:`button`,disabled:u,onClick:()=>void h({backend:n}),className:t(`rounded-full px-2.5 py-1`,(e.backend??`auto`)===n||n===`auto`&&!e.backend?`bg-fg text-bg`:`bg-surface-2 text-fg`),children:n},n))]}),(e.device?.platform===`darwin`||e.window?.available)&&(0,k.jsxs)(k.Fragment,{children:[(0,k.jsx)(x,{inset:16}),(0,k.jsxs)(`div`,{className:`flex flex-wrap items-center gap-2 px-4 py-3 text-[13px] text-muted`,children:[(0,k.jsxs)(`span`,{children:[l(`Where`),`:`]}),[`auto`,`window`,`screen`].map(n=>(0,k.jsx)(`button`,{type:`button`,disabled:u,onClick:()=>void h({mode:n}),className:t(`rounded-full px-2.5 py-1`,(e.mode??`auto`)===n?`bg-fg text-bg`:`bg-surface-2 text-fg`),children:l(n===`auto`?`Auto`:n===`window`?`One window`:`Whole screen`)},n))]}),(0,k.jsx)(y,{className:`pb-3 pt-0`,children:e.window?.active&&e.window.app?l(`Working in {app}'s window; the mouse stays yours.`,{app:e.window.app}):e.window?.reason&&(e.mode??`auto`)!==`screen`?l(`On the whole screen for now: {reason}`,{reason:e.window.reason}):l(`One window: the hands work inside the app they were given, send clicks and keys to it alone and leave your mouse alone. Whole screen: the system mouse, like other platforms. Auto picks one window as soon as an app is named.`)})]}),e.task_active&&(0,k.jsxs)(k.Fragment,{children:[(0,k.jsx)(x,{inset:16}),(0,k.jsx)(C,{icon:(0,k.jsx)(p,{size:18,fill:`currentColor`}),label:l(`Stop the hands`),onClick:()=>void c.stopHands().catch(e=>a(e.message)),chevron:!1})]})]}),e.enabled&&e.device?.platform===`darwin`&&(0,k.jsx)(y,{children:l(`On a Mac, allow nanoMuse under System Settings → Privacy & Security → Accessibility and Screen Recording when macOS asks; without them clicks do nothing and the screenshot is black. The first action in each app asks you once ("Let {name} use Safari?") and the answer is kept under Permissions.`,{name:f})})]})}function q(e,t=18){switch(e){case`phone`:return(0,k.jsx)(f,{size:t});case`computer`:return(0,k.jsx)(E,{size:t});case`web`:return(0,k.jsx)(S,{size:t});default:return(0,k.jsx)(D,{size:t})}}function J(e,t){switch(e){case`connected`:return t(`On the hub`);case`connecting`:case`disconnected`:return t(`Connecting to the hub…`);case`refused`:return t(`The hub refused this device. Sign in again.`);case`signed_out`:return t(`Not signed in.`);case`off`:case`stopped`:return t(`The hub is off on this device.`);default:return e}}export{j as DevicesScreen}; \ No newline at end of file +import{A as e,E as t,J as n,K as r,Q as i,Y as a,b as o,f as s,x as c}from"./MuseHeader-Pw-NI98v.js";import{n as l}from"./external-link-Xj5fjR8v.js";import{o as u}from"./Form-DwKuBk1V.js";import{t as d}from"./refresh-cw-BKgIzslL.js";import{G as f,H as p,a as m,at as h,et as g,ft as _,ht as v,i as y,l as b,o as x,pt as S,s as C}from"./index-CIdGZ5PB.js";import{t as w}from"./BackBar-Dl56jHZM.js";import{t as T}from"./CloudCard-CtVHK0qc.js";var E=n(`laptop`,[[`path`,{d:`M18 5a2 2 0 0 1 2 2v8.526a2 2 0 0 0 .212.897l1.068 2.127a1 1 0 0 1-.9 1.45H3.62a1 1 0 0 1-.9-1.45l1.068-2.127A2 2 0 0 0 4 15.526V7a2 2 0 0 1 2-2z`,key:`1pdavp`}],[`path`,{d:`M20.054 15.987H3.946`,key:`14rxg9`}]]),D=n(`wifi`,[[`path`,{d:`M12 20h.01`,key:`zekei9`}],[`path`,{d:`M2 8.82a15 15 0 0 1 20 0`,key:`dnpr2z`}],[`path`,{d:`M5 12.859a10 10 0 0 1 14 0`,key:`1x1e6c`}],[`path`,{d:`M8.5 16.429a5 5 0 0 1 7 0`,key:`1bycff`}]]),O=i(a(),1),k=o(),A=`https://nanomuse.cn/dl/`;function j(){let{state:e,dispatch:n,openThread:i,setTab:a,toast:o}=s(),l=r(),u=e.hub,f=e.hands,[p,m]=(0,O.useState)(!1),h=async()=>{try{let[e,t]=await Promise.all([c.hub(),c.hands()]);n({type:`ws`,msg:{kind:`hub`,hub:e}}),n({type:`ws`,msg:{kind:`hands_state`,hands:t}})}catch{}};(0,O.useEffect)(()=>{h()},[]);let g=async()=>{m(!0),await h(),m(!1)},_=async e=>{try{let t=await c.askDevice(e.id);n({type:`ws`,msg:{kind:`thread`,thread:t.thread}}),i(t.thread.id),a(`chat`)}catch(e){o(e.message)}},v=e=>{window.confirm(l(`Forget {name}? It can join again by signing in.`,{name:e.name}))&&c.forgetDevice(e.id).then(e=>n({type:`ws`,msg:{kind:`hub`,hub:e}})).catch(e=>o(e.message))},y=(u?.devices??[]).filter(e=>!e.this&&e.kind!==`web`),b=!!u?.account.signed_in,x=u?.state===`connected`,S=y.length+(u&&x?1:0),C=y.filter(e=>e.online).length+(u&&x?1:0);return(0,k.jsxs)(`div`,{className:`flex h-full flex-col`,children:[(0,k.jsx)(w,{title:l(`Devices`),actions:(0,k.jsx)(`button`,{type:`button`,onClick:()=>void g(),"aria-label":l(`Refresh`),title:l(`Refresh`),className:`flex h-9 w-9 items-center justify-center rounded-full text-muted hover:bg-surface-2 hover:text-fg`,children:(0,k.jsx)(d,{size:17,className:t(p&&`animate-spin`)})})}),(0,k.jsxs)(`div`,{className:`@container flex-1 overflow-y-auto pb-8`,children:[(0,k.jsxs)(`div`,{className:`px-5 pb-4 pt-1`,children:[(0,k.jsx)(`p`,{className:`text-[14px] leading-[20px] text-muted`,children:l(`Every device signed in to your account is a Muse of its own, on the same conversations. Type @ and a device's name in the chat to hand it work; a computer lends its hands.`)}),u&&b&&S>0&&(0,k.jsxs)(`p`,{className:`mt-1.5 text-[12.5px] font-medium uppercase tracking-wide text-muted/80`,children:[S===1?l(`1 device`):l(`{n} devices`,{n:S}),` · `,l(`{n} online`,{n:C})]})]}),(0,k.jsx)(`div`,{className:`px-4 pb-3`,children:(0,k.jsx)(T,{account:u?.account??null,onChange:()=>void h()})}),u&&(0,k.jsxs)(`div`,{className:`px-4`,children:[(0,k.jsx)(M,{children:l(`This device`)}),(0,k.jsx)(H,{hub:u,hands:f??void 0,onChange:()=>void h()})]}),(0,k.jsxs)(`div`,{className:`px-4 pt-4`,children:[(0,k.jsx)(M,{children:l(`Other devices`)}),y.length===0?(0,k.jsx)(G,{hub:u??void 0,signedIn:b}):(0,k.jsx)(`div`,{className:`grid grid-cols-1 gap-3 @2xl:grid-cols-2`,children:y.map(e=>(0,k.jsx)(U,{device:e,onAsk:()=>void _(e),onForget:()=>v(e)},e.id))}),(0,k.jsx)(`p`,{className:`px-1 pt-3 text-[12.5px] leading-[18px] text-muted`,children:l(`A chat addressed to a device runs there; you see every step here and answer its approvals.`)})]}),f&&!f.reason?.includes(`phone`)&&(0,k.jsxs)(`div`,{className:`pt-4`,children:[(0,k.jsx)(`div`,{className:`px-4`,children:(0,k.jsx)(M,{children:l(`Hands`)})}),(0,k.jsx)(K,{hands:f,onChange:()=>void h()})]})]})]})}function M({children:e}){return(0,k.jsx)(`p`,{className:`px-1 pb-2 text-[12.5px] font-medium uppercase tracking-wide text-muted/80`,children:e})}function N({children:e}){return(0,k.jsx)(`p`,{className:`px-4 pb-3 text-[12.5px] leading-[18px] text-muted`,children:e})}function P({children:e,className:n}){return(0,k.jsx)(`div`,{className:t(`relative rounded-2xl border border-border/70 bg-surface p-4`,n),children:e})}function F({kind:e,online:n}){return(0,k.jsx)(`span`,{className:t(`flex h-11 w-11 shrink-0 items-center justify-center rounded-xl`,n?`bg-accent/10 text-accent`:`bg-surface-2 text-muted`),"aria-hidden":!0,children:q(e,22)})}function I({online:e}){return(0,k.jsx)(`span`,{"aria-hidden":!0,className:t(`inline-block h-2 w-2 shrink-0 rounded-full`,e?`bg-[#2fb344]`:`bg-muted/35`)})}function L(e){if(e==null||e===``)return``;let t=typeof e==`number`?e:/^\d+(\.\d+)?$/.test(e)?Number(e):NaN;return Number.isFinite(t)?new Date(t*1e3).toISOString():String(e)}function R(t,n){let r=L(t.last_seen),i=e(r);return t.online?r&&Date.now()-new Date(r).getTime()<12e4?`${n(`Online`)} · ${n(`just now`)}`:n(`Online`):i?n(`Last seen {when}`,{when:i}):n(`Offline`)}function z(e,t,n=[]){let r=new Set(e??[]),i=[...n];return r.has(`task`)&&i.push(t(`Tasks`)),r.has(`shell`)&&i.push(t(`Commands`)),(r.has(`files`)||r.has(`file.get`)||r.has(`file.put`))&&i.push(t(`Files`)),r.has(`screen`)&&i.push(t(`Screenshot`)),r.has(`open`)&&i.push(t(`Open links`)),[...r].some(e=>e.startsWith(`coding.`))&&i.push(t(`Coding agents`)),r.has(`notify`)&&i.push(t(`Notifications`)),i}function B({items:e}){return e.length===0?null:(0,k.jsx)(`div`,{className:`flex flex-wrap gap-1.5`,children:e.map(e=>(0,k.jsx)(`span`,{className:`rounded-full bg-surface-2 px-2.5 py-1 text-[12px] font-medium text-fg/80`,children:e},e))})}function V(e){return[e.os||``,e.version||``].filter(Boolean).join(` · `)}function H({hub:e,hands:t,onChange:n}){let{dispatch:i,toast:a}=s(),o=r(),[d,f]=(0,O.useState)(!1),[p,m]=(0,O.useState)(e.device.name),[h,_]=(0,O.useState)(!1),v=e.account.signed_in,y=e.state===`connected`,S=e.devices.find(e=>e.this),C=async e=>{_(!0);try{let t=await c.updateHub(e);i({type:`ws`,msg:{kind:`hub`,hub:t}}),n()}catch(e){a(e.message)}finally{_(!1)}},w=v?e.enabled?y?o(`Online`):e.state===`refused`?o(`Refused`):o(`Connecting…`):o(`Off`):o(`Signed out`),T=z(e.device.actions,o,t?.enabled&&t.available?[o(`Hands`)]:[]);return(0,k.jsxs)(P,{children:[(0,k.jsxs)(`div`,{className:`flex items-start gap-3.5`,children:[(0,k.jsx)(F,{kind:e.device.kind,online:y}),(0,k.jsxs)(`div`,{className:`min-w-0 flex-1`,children:[d?(0,k.jsxs)(`form`,{className:`flex items-center gap-2`,onSubmit:e=>{e.preventDefault(),p.trim()&&C({name:p.trim()}).then(()=>f(!1))},children:[(0,k.jsx)(`input`,{value:p,onChange:e=>m(e.target.value),maxLength:60,autoFocus:!0,"aria-label":o(`This device's name`),placeholder:o(`A name your other devices will see`),className:`h-9 min-w-0 flex-1 rounded-xl bg-surface-2 px-3 text-[15px] outline-none focus:ring-2 focus:ring-accent/40`}),(0,k.jsx)(`button`,{type:`submit`,disabled:h||!p.trim(),"aria-label":o(`Save`),className:`flex h-9 w-9 items-center justify-center rounded-full bg-accent text-accent-fg disabled:opacity-40`,children:(0,k.jsx)(l,{size:16})}),(0,k.jsx)(`button`,{type:`button`,onClick:()=>f(!1),"aria-label":o(`Cancel`),className:`flex h-9 w-9 items-center justify-center rounded-full bg-surface-2 text-muted`,children:(0,k.jsx)(u,{size:16})})]}):(0,k.jsxs)(`div`,{className:`flex items-center gap-1.5`,children:[(0,k.jsx)(`span`,{className:`truncate text-[16px] font-semibold leading-[22px]`,children:e.device.name}),(0,k.jsx)(`button`,{type:`button`,onClick:()=>{m(e.device.name),f(!0)},"aria-label":o(`Rename this device`),title:o(`Rename this device`),className:`flex h-7 w-7 shrink-0 items-center justify-center rounded-full text-muted hover:bg-surface-2 hover:text-fg`,children:(0,k.jsx)(g,{size:13})})]}),(0,k.jsxs)(`p`,{className:`mt-0.5 flex items-center gap-1.5 text-[13px] leading-[18px] text-muted`,children:[(0,k.jsx)(I,{online:y}),(0,k.jsx)(`span`,{className:`truncate`,children:[w,V(S??{})].filter(Boolean).join(` · `)})]}),T.length>0&&(0,k.jsx)(`div`,{className:`mt-3`,children:(0,k.jsx)(B,{items:T})})]})]}),(0,k.jsxs)(`div`,{className:`-mx-4 -mb-2 mt-4 border-t border-border/60`,children:[(0,k.jsx)(b,{label:o(`Join the hub`),checked:e.enabled&&v,disabled:!v||h,onChange:e=>void C({enabled:e})}),(0,k.jsx)(N,{children:o(v?`Reachable by your other devices while this runs.`:`Sign in first.`)}),(0,k.jsx)(x,{inset:16}),(0,k.jsx)(b,{label:o(`My other devices may operate it`),checked:e.remote_control,disabled:h,onChange:e=>void C({remote_control:e})}),(0,k.jsx)(N,{children:o(`They can run commands, read files and see its screen here; each step still goes through the Sentinel.`)})]}),(e.state===`refused`||e.state===`disconnected`)&&e.detail&&(0,k.jsx)(`div`,{className:`mt-3 rounded-xl bg-amber-500/12 px-3 py-2 text-[12.5px] text-amber-700 dark:text-amber-300`,children:e.detail})]})}function U({device:e,onAsk:t,onForget:n}){let i=r(),a=z(e.actions,i),o=e.online&&(e.actions??[]).includes(`task`);return(0,k.jsxs)(P,{className:`flex flex-col gap-3`,children:[(0,k.jsxs)(`div`,{className:`flex items-start gap-3.5`,children:[(0,k.jsx)(F,{kind:e.kind,online:e.online}),(0,k.jsxs)(`div`,{className:`min-w-0 flex-1`,children:[(0,k.jsx)(`p`,{className:`truncate text-[16px] font-semibold leading-[22px]`,children:e.name}),(0,k.jsxs)(`p`,{className:`mt-0.5 flex items-center gap-1.5 text-[13px] leading-[18px] text-muted`,children:[(0,k.jsx)(I,{online:e.online}),(0,k.jsx)(`span`,{className:`truncate`,children:[R(e,i),V(e)].filter(Boolean).join(` · `)})]})]}),(0,k.jsx)(W,{label:i(`More about {name}`,{name:e.name}),items:[{label:i(`Forget this device`),onClick:n,danger:!0}]})]}),(0,k.jsx)(B,{items:a}),o&&(0,k.jsx)(`p`,{className:`text-[12.5px] leading-[18px] text-muted`,children:i(`Type @{name} in the chat to hand it work.`,{name:e.name})}),e.online&&(0,k.jsxs)(`button`,{type:`button`,onClick:t,className:`flex h-9 w-fit items-center gap-1.5 rounded-full bg-accent/10 px-3.5 text-[13.5px] font-medium text-accent hover:bg-accent/15`,children:[(0,k.jsx)(h,{size:14}),` `,i(`Ask`)]})]})}function W({label:e,items:n}){let[r,i]=(0,O.useState)(!1),a=(0,O.useRef)(null);return(0,O.useEffect)(()=>{if(!r)return;let e=e=>{a.current?.contains(e.target)||i(!1)},t=e=>{e.key===`Escape`&&i(!1)};return window.addEventListener(`pointerdown`,e),window.addEventListener(`keydown`,t),()=>{window.removeEventListener(`pointerdown`,e),window.removeEventListener(`keydown`,t)}},[r]),(0,k.jsxs)(`div`,{ref:a,className:`relative -mr-1.5 -mt-1`,children:[(0,k.jsx)(`button`,{type:`button`,onClick:()=>i(e=>!e),"aria-label":e,"aria-haspopup":`menu`,"aria-expanded":r,className:`flex h-8 w-8 items-center justify-center rounded-full text-muted hover:bg-surface-2 hover:text-fg`,children:(0,k.jsx)(v,{size:18})}),r&&(0,k.jsx)(`ul`,{role:`menu`,className:`absolute right-0 top-9 z-30 min-w-[180px] overflow-hidden rounded-2xl border border-border bg-surface py-1 shadow-xl`,children:n.map(e=>(0,k.jsx)(`li`,{children:(0,k.jsx)(`button`,{type:`button`,role:`menuitem`,onClick:()=>{i(!1),e.onClick()},className:t(`w-full px-4 py-2.5 text-left text-[14px] hover:bg-surface-2`,e.danger&&`text-red-600 dark:text-red-400`),children:e.label})},e.label))})]})}function G({hub:e,signedIn:t}){let n=r(),i=t&&e?.state===`connected`;return(0,k.jsxs)(P,{className:`flex flex-col gap-3`,children:[(0,k.jsxs)(`div`,{className:`flex items-start gap-3.5`,children:[(0,k.jsx)(`span`,{className:`flex h-11 w-11 shrink-0 items-center justify-center rounded-xl bg-surface-2 text-muted`,"aria-hidden":!0,children:(0,k.jsx)(f,{size:22})}),(0,k.jsxs)(`div`,{className:`min-w-0 flex-1`,children:[(0,k.jsx)(`p`,{className:`text-[15px] font-semibold leading-[20px]`,children:n(i?`Add a device`:`No other device yet`)}),(0,k.jsx)(`p`,{className:`mt-1 text-[13px] leading-[18px] text-muted`,children:t?i?e?.account.hint?n(`Install nanoMuse on your phone, Mac or PC and sign in as {hint}; it appears here on its own.`,{hint:e.account.hint}):n(`Install nanoMuse on your phone, Mac or PC and sign in with the same account; it appears here on its own.`):J(e?.state??``,n):n(`Sign in above to see them.`)})]})]}),i&&(0,k.jsx)(`a`,{href:A,target:`_blank`,rel:`noopener noreferrer`,className:`flex h-9 w-fit items-center gap-1.5 rounded-full bg-accent/10 px-3.5 text-[13.5px] font-medium text-accent hover:bg-accent/15`,children:n(`Get the apps`)})]})}function K({hands:e,onChange:n}){let{dispatch:i,toast:a,state:o}=s(),l=r(),[u,d]=(0,O.useState)(!1),f=o.profile?.name??`nanoMuse`,h=async e=>{d(!0);try{let t=await c.setHands(e);i({type:`ws`,msg:{kind:`hands_state`,hands:t}}),n()}catch(e){a(e.message)}finally{d(!1)}},g=e.task_active?l(`Working`):e.enabled?e.available?l(`On`):l(`Unavailable`):l(`Off`);return(0,k.jsxs)(k.Fragment,{children:[(0,k.jsxs)(m,{className:`border border-border/70`,children:[(0,k.jsx)(b,{icon:(0,k.jsx)(_,{size:22}),label:l(`Hands on this computer`),value:g,checked:e.enabled,disabled:u,onChange:e=>void h({enabled:e})}),(0,k.jsx)(y,{className:`pb-3 pt-0`,children:e.task_active?e.task_text||l(`On the screen now`):e.available?l(`It looks at a screenshot and clicks by position; paying, sending and deleting ask you first.`):e.reason||l(`Nothing can drive this screen yet.`)}),(0,k.jsx)(x,{inset:16}),(0,k.jsxs)(`div`,{className:`flex items-center gap-2 px-4 py-3 text-[13px] text-muted`,children:[(0,k.jsxs)(`span`,{children:[l(`Driver`),`:`]}),[`auto`,`desktop`,`pyautogui`,`xdotool`].map(n=>(0,k.jsx)(`button`,{type:`button`,disabled:u,onClick:()=>void h({backend:n}),className:t(`rounded-full px-2.5 py-1`,(e.backend??`auto`)===n||n===`auto`&&!e.backend?`bg-fg text-bg`:`bg-surface-2 text-fg`),children:n},n))]}),(e.device?.platform===`darwin`||e.window?.available)&&(0,k.jsxs)(k.Fragment,{children:[(0,k.jsx)(x,{inset:16}),(0,k.jsxs)(`div`,{className:`flex flex-wrap items-center gap-2 px-4 py-3 text-[13px] text-muted`,children:[(0,k.jsxs)(`span`,{children:[l(`Where`),`:`]}),[`auto`,`window`,`screen`].map(n=>(0,k.jsx)(`button`,{type:`button`,disabled:u,onClick:()=>void h({mode:n}),className:t(`rounded-full px-2.5 py-1`,(e.mode??`auto`)===n?`bg-fg text-bg`:`bg-surface-2 text-fg`),children:l(n===`auto`?`Auto`:n===`window`?`One window`:`Whole screen`)},n))]}),(0,k.jsx)(y,{className:`pb-3 pt-0`,children:e.window?.active&&e.window.app?l(`Working in {app}'s window; the mouse stays yours.`,{app:e.window.app}):e.window?.reason&&(e.mode??`auto`)!==`screen`?l(`On the whole screen for now: {reason}`,{reason:e.window.reason}):l(`One window: the hands work inside the app they were given, send clicks and keys to it alone and leave your mouse alone. Whole screen: the system mouse, like other platforms. Auto picks one window as soon as an app is named.`)})]}),e.task_active&&(0,k.jsxs)(k.Fragment,{children:[(0,k.jsx)(x,{inset:16}),(0,k.jsx)(C,{icon:(0,k.jsx)(p,{size:18,fill:`currentColor`}),label:l(`Stop the hands`),onClick:()=>void c.stopHands().catch(e=>a(e.message)),chevron:!1})]})]}),e.enabled&&e.device?.platform===`darwin`&&(0,k.jsx)(y,{children:l(`On a Mac, allow nanoMuse under System Settings → Privacy & Security → Accessibility and Screen Recording when macOS asks; without them clicks do nothing and the screenshot is black. The first action in each app asks you once ("Let {name} use Safari?") and the answer is kept under Permissions.`,{name:f})})]})}function q(e,t=18){switch(e){case`phone`:return(0,k.jsx)(f,{size:t});case`computer`:return(0,k.jsx)(E,{size:t});case`web`:return(0,k.jsx)(S,{size:t});default:return(0,k.jsx)(D,{size:t})}}function J(e,t){switch(e){case`connected`:return t(`On the hub`);case`connecting`:case`disconnected`:return t(`Connecting to the hub…`);case`refused`:return t(`The hub refused this device. Sign in again.`);case`signed_out`:return t(`Not signed in.`);case`off`:case`stopped`:return t(`The hub is off on this device.`);default:return e}}export{j as DevicesScreen}; \ No newline at end of file diff --git a/nanomuse/server/static/assets/GoalsScreen-BGb02qG6.js b/nanomuse/server/static/assets/GoalsScreen-Dp2fRaLA.js similarity index 99% rename from nanomuse/server/static/assets/GoalsScreen-BGb02qG6.js rename to nanomuse/server/static/assets/GoalsScreen-Dp2fRaLA.js index 6773bc051..2973d5d55 100644 --- a/nanomuse/server/static/assets/GoalsScreen-BGb02qG6.js +++ b/nanomuse/server/static/assets/GoalsScreen-Dp2fRaLA.js @@ -1,2 +1,2 @@ -import{A as e,E as t,J as n,K as r,N as i,Q as a,Y as o,b as s,f as c,r as l,x as u}from"./MuseHeader-Pw-NI98v.js";import{t as d}from"./StarNudge-DjXecvWj.js";import{H as f,Q as p,S as m,V as h,W as g,Z as _,_ as v,b as y,f as b,g as x,h as S,m as C,ot as w,p as T,v as E,w as D,wt as O,x as k,xt as A,y as j}from"./index-BjYzdKkG.js";var M=n(`bell-ring`,[[`path`,{d:`M10.268 21a2 2 0 0 0 3.464 0`,key:`vwvbt9`}],[`path`,{d:`M22 8c0-2.3-.8-4.3-2-6`,key:`5bb3ad`}],[`path`,{d:`M3.262 15.326A1 1 0 0 0 4 17h16a1 1 0 0 0 .74-1.673C19.41 13.956 18 12.499 18 8A6 6 0 0 0 6 8c0 4.499-1.411 5.956-2.738 7.326`,key:`11g9vi`}],[`path`,{d:`M4 2C2.8 3.7 2 5.7 2 8`,key:`tap9e0`}]]),N=n(`circle-check`,[[`circle`,{cx:`12`,cy:`12`,r:`10`,key:`1mglay`}],[`path`,{d:`m9 12 2 2 4-4`,key:`dzmm74`}]]),P=n(`circle-dashed`,[[`path`,{d:`M10.1 2.182a10 10 0 0 1 3.8 0`,key:`5ilxe3`}],[`path`,{d:`M13.9 21.818a10 10 0 0 1-3.8 0`,key:`11zvb9`}],[`path`,{d:`M17.609 3.721a10 10 0 0 1 2.69 2.7`,key:`1iw5b2`}],[`path`,{d:`M2.182 13.9a10 10 0 0 1 0-3.8`,key:`c0bmvh`}],[`path`,{d:`M20.279 17.609a10 10 0 0 1-2.7 2.69`,key:`1ruxm7`}],[`path`,{d:`M21.818 10.1a10 10 0 0 1 0 3.8`,key:`qkgqxc`}],[`path`,{d:`M3.721 6.391a10 10 0 0 1 2.7-2.69`,key:`1mcia2`}],[`path`,{d:`M6.391 20.279a10 10 0 0 1-2.69-2.7`,key:`1fvljs`}]]),F=n(`circle-slash`,[[`circle`,{cx:`12`,cy:`12`,r:`10`,key:`1mglay`}],[`line`,{x1:`9`,x2:`15`,y1:`15`,y2:`9`,key:`1dfufj`}]]),I=n(`circle`,[[`circle`,{cx:`12`,cy:`12`,r:`10`,key:`1mglay`}]]),L=n(`ellipsis-vertical`,[[`circle`,{cx:`12`,cy:`12`,r:`1`,key:`41hilf`}],[`circle`,{cx:`12`,cy:`5`,r:`1`,key:`gxeob9`}],[`circle`,{cx:`12`,cy:`19`,r:`1`,key:`lyex9k`}]]),R=n(`octagon-alert`,[[`path`,{d:`M12 16h.01`,key:`1drbdi`}],[`path`,{d:`M12 8v4`,key:`1got3b`}],[`path`,{d:`M15.312 2a2 2 0 0 1 1.414.586l4.688 4.688A2 2 0 0 1 22 8.688v6.624a2 2 0 0 1-.586 1.414l-4.688 4.688a2 2 0 0 1-1.414.586H8.688a2 2 0 0 1-1.414-.586l-4.688-4.688A2 2 0 0 1 2 15.312V8.688a2 2 0 0 1 .586-1.414l4.688-4.688A2 2 0 0 1 8.688 2z`,key:`1fd625`}]]),z=n(`pause`,[[`rect`,{x:`14`,y:`3`,width:`5`,height:`18`,rx:`1`,key:`kaeet6`}],[`rect`,{x:`5`,y:`3`,width:`5`,height:`18`,rx:`1`,key:`1wsw3u`}]]),B=n(`square-check`,[[`rect`,{width:`18`,height:`18`,x:`3`,y:`3`,rx:`2`,key:`afitv7`}],[`path`,{d:`m9 12 2 2 4-4`,key:`dzmm74`}]]),V=a(o(),1),H=s(),U={pending:e=>(0,H.jsx)(I,{...e}),in_progress:e=>(0,H.jsx)(P,{...e,className:t(e.className,`text-accent`)}),done:e=>(0,H.jsx)(N,{...e,className:t(e.className,`text-emerald-500`)}),blocked:e=>(0,H.jsx)(R,{...e,className:t(e.className,`text-rose-500`)}),skipped:e=>(0,H.jsx)(F,{...e,className:t(e.className,`text-muted`)})},W={pending:`done`,in_progress:`done`,done:`pending`,blocked:`pending`,skipped:`pending`};function G(){let{state:e,refreshGoals:t,send:n,openThread:i,toast:a}=c(),[o,s]=(0,V.useState)(null),[f,p]=(0,V.useState)(!1),[m,h]=(0,V.useState)(null),[g,v]=(0,V.useState)(!1),y=(0,V.useRef)(null),x=e.profile?.name??`nanoMuse`,S=r();(0,V.useEffect)(()=>{t()},[t]);let T=e.goals.filter(e=>e.proposal&&e.status!==`cancelled`),E=[...e.goals.filter(e=>e.status===`active`),...e.goals.filter(e=>e.status===`paused`)],O=e.goals.filter(e=>e.status===`done`||e.status===`cancelled`),k=e.goals.find(e=>e.id===o)??null,A=async e=>{try{await u.advanceGoal(e.id),a(S(`{name} is working on “{title}” in the main chat`,{name:x,title:e.title})),i(`main`)}catch(e){a(e.message)}},[j,M]=(0,V.useState)(!1),N=async e=>{try{let n=e.status!==`done`;await u.patchGoal(e.id,{status:n?`done`:`active`}),n&&M(!0),t()}catch(e){a(e.message)}},P=e=>{h(null),n(`main`,S(`I'd like to create a {category} goal. Ask me a few short questions, one at a time (what exactly I want, why and by when, how often to check in), then create it with concrete steps using the goals tool.`,{category:S(e.label)})).catch(e=>a(e.message||S(`Could not send`))),i(`main`)};return(0,H.jsxs)(`div`,{className:`flex h-full flex-col`,children:[(0,H.jsx)(b,{title:S(`Goals`),children:(0,H.jsx)(l,{small:!0,onClick:()=>p(!0),label:S(`New goal`),children:(0,H.jsx)(_,{size:22})})}),(0,H.jsxs)(`div`,{className:`flex-1 overflow-y-auto pb-6`,children:[T.length>0&&(0,H.jsxs)(`section`,{className:`px-4 pb-2`,children:[(0,H.jsx)(`div`,{className:`px-1 mb-2 text-[12px] font-semibold uppercase tracking-wide text-muted`,children:S(`{name} suggests`,{name:x})}),(0,H.jsx)(`div`,{className:`space-y-2.5`,children:T.map(e=>(0,H.jsx)(Y,{goal:e,onChanged:t,onOpen:()=>s(e.id)},e.id))})]}),(0,H.jsx)(d,{moment:`goal_done`,due:j,className:`mx-4 mb-3`}),(0,H.jsx)(K,{label:S(`Tracking`),dot:!0,onAdd:()=>y.current?.scrollIntoView({behavior:`smooth`,block:`start`})}),E.length===0?(0,H.jsx)(`p`,{className:`px-5 pb-3 text-[13px] text-muted`,children:S(`Nothing tracked yet`)}):E.map(e=>(0,H.jsx)(J,{goal:e,onOpen:()=>s(e.id),onToggle:()=>void N(e)},e.id)),O.length>0&&(0,H.jsxs)(H.Fragment,{children:[(0,H.jsx)(`div`,{className:`h-1.5`}),(0,H.jsx)(K,{label:S(`Finished`)}),(g?O:O.slice(0,2)).map(e=>(0,H.jsx)(J,{goal:e,onOpen:()=>s(e.id),onToggle:()=>void N(e)},e.id)),!g&&O.length>2&&(0,H.jsx)(`button`,{type:`button`,onClick:()=>v(!0),className:`px-5 py-2 text-[13.5px] font-medium text-accent`,children:S(`Show {n} more`,{n:O.length-2})})]}),(0,H.jsxs)(`div`,{ref:y,className:`mt-2.5 border-t border-border/70 px-5 pt-3.5 pb-1.5`,children:[(0,H.jsx)(`h3`,{className:`text-[17px] font-semibold`,children:S(`Create a goal`)}),(0,H.jsx)(`p`,{className:`mt-1 text-[13px] leading-[18px] text-muted`,children:S(`Pick a category and tell me the goal you have in mind. I'll shape a plan with you and keep improving it as you go.`)})]}),C.map(e=>(0,H.jsxs)(`button`,{type:`button`,onClick:()=>h(e),className:`flex h-[50px] w-full items-center gap-3.5 pl-5 pr-2 text-left active:bg-surface-2/70`,children:[(0,H.jsx)(`span`,{className:`text-fg`,children:e.icon({size:22})}),(0,H.jsx)(`span`,{className:`flex-1 text-[15px] font-medium`,children:S(e.label)}),(0,H.jsx)(`span`,{className:`flex h-10 w-10 items-center justify-center text-muted`,children:(0,H.jsx)(_,{size:22})})]},e.id))]}),(0,H.jsx)(Q,{goal:k,onClose:()=>s(null),onAdvance:A,onChanged:t}),(0,H.jsx)($,{open:f,onClose:()=>p(!1),onCreated:()=>{p(!1),t()}}),(0,H.jsx)(D,{open:m!==null,onClose:()=>h(null),children:m&&(0,H.jsxs)(`div`,{className:`px-1 pb-2`,children:[(0,H.jsx)(`h3`,{className:`text-[20px] font-bold`,children:S(`Create a {category} goal`,{category:S(m.label)})}),(0,H.jsx)(`p`,{className:`mt-3.5 text-[15px] leading-[22px]`,children:S(`First, we'll shape the goal together in the chat. I'll ask a few questions so I understand exactly what you're after.`)}),(0,H.jsx)(`p`,{className:`mt-3.5 text-[15px] leading-[22px]`,children:S(`Once it's set, I'll track your progress here.`)}),(0,H.jsxs)(`button`,{type:`button`,onClick:()=>P(m),className:`mt-6 flex h-[50px] w-full items-center justify-center gap-2 rounded-full bg-accent text-[16px] font-semibold text-accent-fg`,children:[(0,H.jsx)(w,{size:18}),` `,S(`Start`)]})]})})]})}function K({label:e,dot:n=!1,onAdd:r}){return(0,H.jsxs)(`div`,{className:`flex items-center pl-5 pr-2 pt-1`,children:[n&&(0,H.jsx)(`span`,{className:`mr-2.5 h-2 w-2 rounded-full bg-emerald-500`}),(0,H.jsx)(`span`,{className:t(`flex-1 text-[15px] font-semibold`,n&&`text-emerald-600 dark:text-emerald-400`),children:e}),r?(0,H.jsx)(`button`,{type:`button`,onClick:r,"aria-label":e,className:`flex h-10 w-10 items-center justify-center text-muted`,children:(0,H.jsx)(_,{size:22})}):(0,H.jsx)(`span`,{className:`h-10`})]})}function q({id:e,size:n=`sm`}){let i=r(),a=x(e);return a?(0,H.jsxs)(`span`,{className:t(`inline-flex items-center gap-1 rounded-full font-medium`,a.tone,n===`sm`?`px-2 py-0.5 text-[11.5px]`:`px-2.5 py-1 text-[12.5px]`),children:[a.icon({size:n===`sm`?11:13}),` `,i(a.label)]}):null}function J({goal:n,onOpen:i,onToggle:a}){let o=r(),s=n.status===`done`,c=n.progress.total?Math.round(n.progress.done/n.progress.total*100):0,l=E(n.due,n.overdue),u=n.next_step?o(`Next: {step}`,{step:n.next_step}):n.description||``,d=n.status===`paused`?o(`Paused`):n.status===`cancelled`?o(`Cancelled`):s?o(`Done`):n.check_in?v(n.check_in):o(`Updated {when}`,{when:e(n.updated_at)});return(0,H.jsxs)(`div`,{className:`flex items-start pl-[18px] pr-1 pt-2 pb-2.5`,children:[(0,H.jsx)(`button`,{type:`button`,onClick:a,"aria-label":o(s?`Mark as not done`:`Mark as done`),className:`mt-0.5 flex h-7 w-7 shrink-0 items-center justify-center text-muted`,children:s?(0,H.jsx)(B,{size:22}):(0,H.jsx)(f,{size:22})}),(0,H.jsxs)(`button`,{type:`button`,onClick:i,className:`ml-2.5 min-w-0 flex-1 pt-[3px] text-left`,children:[(0,H.jsx)(`span`,{className:t(`line-clamp-2 block text-[15px] font-semibold leading-snug`,s&&`text-muted`),children:n.title}),u&&(0,H.jsx)(`span`,{className:`mt-0.5 line-clamp-2 block text-[13px] leading-[18px] text-muted`,children:u}),(0,H.jsxs)(`span`,{className:`mt-0.5 flex items-center gap-2 text-[12px] text-muted/80`,children:[(0,H.jsxs)(`span`,{className:`truncate`,children:[d,l&&n.status===`active`?` · ${l}`:``]}),c>0&&!s&&(0,H.jsxs)(`span`,{className:`shrink-0 font-medium text-emerald-600 dark:text-emerald-400`,children:[c,`%`]})]})]}),(0,H.jsx)(`button`,{type:`button`,onClick:i,"aria-label":o(`More`),className:`flex h-10 w-10 shrink-0 items-center justify-center text-muted`,children:(0,H.jsx)(L,{size:20})})]})}function Y({goal:e,onChanged:t,onOpen:n}){let{toast:i,state:a}=c(),[o,s]=(0,V.useState)(!1),l=a.profile?.name??`nanoMuse`,d=r(),f=e.proposal;if(!f)return null;let p=async n=>{s(!0);try{n?await u.acceptProposal(e.id):await u.dismissProposal(e.id),i(d(n?`Plan updated`:`Kept your plan`)),t()}catch(e){i(e.message)}finally{s(!1)}},m=e.steps.filter(e=>e.status===`done`||e.status===`skipped`).length;return(0,H.jsxs)(`div`,{className:`rounded-3xl border border-accent/30 bg-accent/5 px-4 py-3.5`,children:[(0,H.jsxs)(`button`,{type:`button`,onClick:n,className:`w-full text-left`,children:[(0,H.jsxs)(`div`,{className:`flex items-center gap-2 text-[12px] font-semibold uppercase tracking-wide text-accent`,children:[(0,H.jsx)(g,{size:13}),` `,d(`Adjust the plan for “{title}”?`,{title:e.title})]}),(0,H.jsx)(`p`,{className:`mt-1.5 text-[14px] leading-snug`,children:f.reason}),(0,H.jsxs)(`div`,{className:`mt-2 text-[12px] text-muted`,children:[m>0&&(0,H.jsxs)(`span`,{children:[m===1?d(`Keeps the 1 step already done.`):d(`Keeps the {n} steps already done.`,{n:m}),` `]}),d(`New remaining steps:`)]}),(0,H.jsx)(`ol`,{className:`mt-1 space-y-0.5 text-[13.5px] list-decimal pl-5`,children:f.steps.map((e,t)=>(0,H.jsx)(`li`,{children:e},t))})]}),(0,H.jsxs)(`div`,{className:`mt-3 flex gap-2`,children:[(0,H.jsx)(`button`,{type:`button`,disabled:o,onClick:()=>void p(!1),className:`flex-1 rounded-2xl border border-border py-2 text-[13.5px] font-medium disabled:opacity-50`,children:d(`Keep my plan`)}),(0,H.jsx)(`button`,{type:`button`,disabled:o,onClick:()=>void p(!0),className:`flex-1 rounded-2xl bg-accent text-accent-fg py-2 text-[13.5px] font-medium disabled:opacity-50`,children:d(`Use {name}'s plan`,{name:l})})]})]})}function X({value:e,onChange:n}){let i=r();return(0,H.jsx)(`div`,{className:`flex flex-wrap gap-1.5`,children:C.map(r=>(0,H.jsxs)(`button`,{type:`button`,onClick:()=>n(e===r.id?``:r.id),className:t(`inline-flex items-center gap-1 rounded-full px-2.5 py-1 text-[12.5px] font-medium transition border`,e===r.id?t(r.tone,`border-transparent ring-2 ring-accent/40`):`border-border text-muted`),children:[r.icon({size:12}),` `,i(r.label)]},r.id))})}function Z({value:e,onChange:n}){let i=r(),{cadence:a,anchor:o,time:s}=k(e),c=(e,t,r)=>n(j(e,t,r));return(0,H.jsxs)(`div`,{className:`space-y-2`,children:[(0,H.jsx)(`div`,{className:`flex flex-wrap gap-1.5`,children:T.map(e=>(0,H.jsx)(`button`,{type:`button`,onClick:()=>c(e.id,e.id===`weekly`?o||`mon`:e.id===`monthly`?o||`1`:``,s),className:t(`rounded-full px-2.5 py-1 text-[12.5px] font-medium border transition`,a===e.id?`bg-accent text-accent-fg border-transparent`:`border-border text-muted`),children:i(e.label)},e.id))}),a&&(0,H.jsxs)(`div`,{className:`flex items-center gap-2 text-[13.5px]`,children:[a===`weekly`&&(0,H.jsx)(`select`,{value:o||`mon`,onChange:e=>c(a,e.target.value,s),className:`rounded-xl bg-surface-2 px-2.5 py-1.5 outline-none`,children:S.map(e=>(0,H.jsx)(`option`,{value:e,children:m(e)},e))}),a===`monthly`&&(0,H.jsx)(`select`,{value:o||`1`,onChange:e=>c(a,e.target.value,s),className:`rounded-xl bg-surface-2 px-2.5 py-1.5 outline-none`,children:Array.from({length:28},(e,t)=>String(t+1)).map(e=>(0,H.jsx)(`option`,{value:e,children:y(Number(e))},e))}),(0,H.jsx)(`span`,{className:`text-muted`,children:i(`at`)}),(0,H.jsx)(`input`,{type:`time`,value:s,onChange:e=>c(a,o,e.target.value||`09:00`),className:`rounded-xl bg-surface-2 px-2.5 py-1.5 outline-none`})]})]})}function Q({goal:n,onClose:a,onAdvance:o,onChanged:s}){let{toast:l,send:d,openThread:f,state:m}=c(),[g,y]=(0,V.useState)(``),[b,x]=(0,V.useState)(!1),S=m.profile?.name??`nanoMuse`,C=r(),w=async e=>{if(n)try{await u.patchGoal(n.id,e),s()}catch(e){l(e.message)}},T=async()=>{if(n&&g.trim())try{await u.addStep(n.id,g.trim()),y(``),s()}catch(e){l(e.message)}},k=async()=>{if(n)try{await u.checkInGoal(n.id),l(C(`{name} will check in with you in the main chat`,{name:S})),f(`main`),a()}catch(e){l(e.message)}},j=async()=>{if(n&&window.confirm(C(`Delete “{title}”?`,{title:n.title})))try{await u.deleteGoal(n.id),s(),a()}catch(e){l(e.message)}},N=n?E(n.due,n.overdue):``;return(0,H.jsx)(D,{open:!!n,onClose:a,title:n?.title,footer:n&&(0,H.jsxs)(`div`,{className:`flex gap-2`,children:[n.status===`active`?(0,H.jsxs)(`button`,{type:`button`,onClick:()=>void w({status:`paused`}),className:`flex-1 rounded-2xl border border-border py-2.5 font-medium flex items-center justify-center gap-1.5`,children:[(0,H.jsx)(z,{size:16}),` `,C(`Pause`)]}):n.status===`paused`?(0,H.jsxs)(`button`,{type:`button`,onClick:()=>void w({status:`active`}),className:`flex-1 rounded-2xl border border-border py-2.5 font-medium flex items-center justify-center gap-1.5`,children:[(0,H.jsx)(p,{size:16}),` `,C(`Resume`)]}):null,n.status===`active`&&(0,H.jsxs)(`button`,{type:`button`,onClick:()=>o(n),className:`flex-1 rounded-2xl bg-accent text-accent-fg py-2.5 font-medium flex items-center justify-center gap-1.5`,children:[(0,H.jsx)(p,{size:16}),` `,C(`Work on it now`)]}),(0,H.jsx)(`button`,{type:`button`,onClick:()=>void j(),"aria-label":C(`Delete goal`),className:`rounded-2xl border border-border px-3 text-muted hover:text-rose-500`,children:(0,H.jsx)(h,{size:18})})]}),children:n&&(0,H.jsxs)(`div`,{className:`space-y-4`,children:[n.proposal&&(0,H.jsx)(Y,{goal:n,onChanged:s,onOpen:()=>void 0}),n.description&&(0,H.jsx)(`p`,{className:`text-[14px] text-muted leading-snug`,children:n.description}),(0,H.jsx)(`div`,{className:`rounded-2xl bg-surface-2/60 px-3.5 py-3`,children:b?(0,H.jsxs)(`div`,{className:`space-y-3`,children:[(0,H.jsxs)(`div`,{children:[(0,H.jsx)(`div`,{className:`text-[12px] font-semibold uppercase tracking-wide text-muted mb-1.5`,children:C(`Area of life`)}),(0,H.jsx)(X,{value:n.category,onChange:e=>void w({category:e})})]}),(0,H.jsxs)(`div`,{children:[(0,H.jsx)(`div`,{className:`text-[12px] font-semibold uppercase tracking-wide text-muted mb-1.5`,children:C(`Target date`)}),(0,H.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,H.jsx)(`input`,{type:`date`,value:n.due,onChange:e=>void w({due:e.target.value}),className:`rounded-xl bg-surface px-2.5 py-1.5 text-[13.5px] outline-none`}),n.due&&(0,H.jsx)(`button`,{type:`button`,onClick:()=>void w({due:``}),className:`text-[12.5px] text-muted`,children:C(`Clear`)})]})]}),(0,H.jsxs)(`div`,{children:[(0,H.jsx)(`div`,{className:`text-[12px] font-semibold uppercase tracking-wide text-muted mb-1.5`,children:C(`Reminders from {name}`,{name:S})}),(0,H.jsx)(Z,{value:n.check_in,onChange:e=>void w({check_in:e})})]}),(0,H.jsx)(`button`,{type:`button`,onClick:()=>x(!1),className:`text-[12.5px] text-accent font-medium`,children:C(`Done`)})]}):(0,H.jsxs)(`button`,{type:`button`,onClick:()=>x(!0),className:`w-full text-left`,children:[(0,H.jsxs)(`div`,{className:`flex flex-wrap items-center gap-1.5 text-[12.5px]`,children:[n.category?(0,H.jsx)(q,{id:n.category,size:`md`}):(0,H.jsx)(`span`,{className:`rounded-full border border-dashed border-border px-2.5 py-1 text-muted`,children:C(`No category`)}),(0,H.jsxs)(`span`,{className:t(`inline-flex items-center gap-1 rounded-full px-2.5 py-1`,n.overdue?`bg-rose-500/12 text-rose-600 dark:text-rose-300 font-medium`:`bg-surface text-muted`),children:[(0,H.jsx)(A,{size:13}),` `,N||C(`No target date`)]}),(0,H.jsxs)(`span`,{className:`inline-flex items-center gap-1 rounded-full bg-surface px-2.5 py-1 text-muted`,children:[(0,H.jsx)(O,{size:13}),` `,n.check_in?v(n.check_in):C(`No reminders`)]})]}),n.next_check_in&&n.status===`active`&&(0,H.jsxs)(`div`,{className:`mt-1.5 text-[12px] text-muted`,children:[C(`Next check-in {when}`,{when:e(n.next_check_in)}),` · `,i(n.next_check_in)]}),(0,H.jsx)(`div`,{className:`mt-1.5 text-[12px] text-accent font-medium`,children:C(`Edit`)})]})}),(0,H.jsxs)(`div`,{children:[(0,H.jsxs)(`div`,{className:`text-[12px] font-semibold uppercase tracking-wide text-muted mb-2`,children:[C(`Plan`),` · `,n.progress.done,`/`,n.progress.total]}),(0,H.jsx)(`ul`,{className:`space-y-1`,children:n.steps.map(e=>{let n=U[e.status];return(0,H.jsxs)(`li`,{className:`flex items-start gap-2.5 rounded-2xl px-2 py-1.5 hover:bg-surface-2/60`,children:[(0,H.jsx)(`button`,{type:`button`,"aria-label":C(`Mark step {n} {status}`,{n:e.idx,status:C(W[e.status])}),onClick:()=>void w({step_index:e.idx,step_status:W[e.status]}),className:`mt-0.5 text-muted`,children:(0,H.jsx)(n,{size:20})}),(0,H.jsxs)(`div`,{className:`flex-1 min-w-0`,children:[(0,H.jsxs)(`div`,{className:t(`text-[14.5px] leading-snug`,(e.status===`done`||e.status===`skipped`)&&`line-through text-muted`),children:[e.idx,`. `,e.title]}),e.note&&(0,H.jsx)(`div`,{className:`text-[12.5px] text-muted mt-0.5 whitespace-pre-wrap`,children:e.note})]})]},e.idx)})}),(0,H.jsxs)(`div`,{className:`mt-2 flex gap-2`,children:[(0,H.jsx)(`input`,{value:g,onChange:e=>y(e.target.value),onKeyDown:e=>e.key===`Enter`&&void T(),placeholder:C(`Add a step`),className:`flex-1 rounded-2xl bg-surface-2 px-3.5 py-2 text-[14px] outline-none focus:ring-2 focus:ring-accent/40`}),(0,H.jsx)(`button`,{type:`button`,onClick:()=>void T(),className:`rounded-2xl bg-surface-2 px-3 text-accent`,"aria-label":C(`Add step`),children:(0,H.jsx)(_,{size:18})})]})]}),n.notes&&(0,H.jsxs)(`div`,{children:[(0,H.jsx)(`div`,{className:`text-[12px] font-semibold uppercase tracking-wide text-muted mb-1.5`,children:C(`Notes from {name}`,{name:S})}),(0,H.jsx)(`pre`,{className:`whitespace-pre-wrap break-words text-[13px] leading-snug text-muted font-sans`,children:n.notes})]}),(0,H.jsxs)(`div`,{className:`flex flex-wrap gap-x-4 gap-y-1.5`,children:[(0,H.jsx)(`button`,{type:`button`,onClick:()=>{d(`main`,C(`About my goal “{title}” ({id}): what's the status, and what should we do next?`,{title:n.title,id:n.id})).catch(e=>l(e.message||C(`Could not send`))),f(`main`),a()},className:`text-[13.5px] text-accent font-medium`,children:C(`Discuss this goal in chat →`)}),n.status===`active`&&(0,H.jsxs)(`button`,{type:`button`,onClick:()=>void k(),className:`text-[13.5px] text-accent font-medium inline-flex items-center gap-1`,children:[(0,H.jsx)(M,{size:14}),` `,C(`Check in with me now`)]})]})]})})}function $({open:e,onClose:t,onCreated:n}){let{toast:i,send:a,openThread:o,state:s}=c(),[l,d]=(0,V.useState)(``),[f,p]=(0,V.useState)(``),[m,h]=(0,V.useState)(``),[_,v]=(0,V.useState)(``),[y,b]=(0,V.useState)(``),[x,S]=(0,V.useState)(``),[C,w]=(0,V.useState)(!1),T=s.profile?.name??`nanoMuse`,E=r(),O=()=>{d(``),p(``),h(``),v(``),b(``),S(``)},k=async()=>{if(l.trim()){w(!0);try{await u.createGoal({title:l.trim(),description:f.trim(),steps:m.split(` +import{A as e,E as t,J as n,K as r,N as i,Q as a,Y as o,b as s,f as c,r as l,x as u}from"./MuseHeader-Pw-NI98v.js";import{t as d}from"./StarNudge-DjXecvWj.js";import{H as f,Q as p,S as m,V as h,W as g,Z as _,_ as v,b as y,f as b,g as x,h as S,m as C,ot as w,p as T,v as E,w as D,wt as O,x as k,xt as A,y as j}from"./index-CIdGZ5PB.js";var M=n(`bell-ring`,[[`path`,{d:`M10.268 21a2 2 0 0 0 3.464 0`,key:`vwvbt9`}],[`path`,{d:`M22 8c0-2.3-.8-4.3-2-6`,key:`5bb3ad`}],[`path`,{d:`M3.262 15.326A1 1 0 0 0 4 17h16a1 1 0 0 0 .74-1.673C19.41 13.956 18 12.499 18 8A6 6 0 0 0 6 8c0 4.499-1.411 5.956-2.738 7.326`,key:`11g9vi`}],[`path`,{d:`M4 2C2.8 3.7 2 5.7 2 8`,key:`tap9e0`}]]),N=n(`circle-check`,[[`circle`,{cx:`12`,cy:`12`,r:`10`,key:`1mglay`}],[`path`,{d:`m9 12 2 2 4-4`,key:`dzmm74`}]]),P=n(`circle-dashed`,[[`path`,{d:`M10.1 2.182a10 10 0 0 1 3.8 0`,key:`5ilxe3`}],[`path`,{d:`M13.9 21.818a10 10 0 0 1-3.8 0`,key:`11zvb9`}],[`path`,{d:`M17.609 3.721a10 10 0 0 1 2.69 2.7`,key:`1iw5b2`}],[`path`,{d:`M2.182 13.9a10 10 0 0 1 0-3.8`,key:`c0bmvh`}],[`path`,{d:`M20.279 17.609a10 10 0 0 1-2.7 2.69`,key:`1ruxm7`}],[`path`,{d:`M21.818 10.1a10 10 0 0 1 0 3.8`,key:`qkgqxc`}],[`path`,{d:`M3.721 6.391a10 10 0 0 1 2.7-2.69`,key:`1mcia2`}],[`path`,{d:`M6.391 20.279a10 10 0 0 1-2.69-2.7`,key:`1fvljs`}]]),F=n(`circle-slash`,[[`circle`,{cx:`12`,cy:`12`,r:`10`,key:`1mglay`}],[`line`,{x1:`9`,x2:`15`,y1:`15`,y2:`9`,key:`1dfufj`}]]),I=n(`circle`,[[`circle`,{cx:`12`,cy:`12`,r:`10`,key:`1mglay`}]]),L=n(`ellipsis-vertical`,[[`circle`,{cx:`12`,cy:`12`,r:`1`,key:`41hilf`}],[`circle`,{cx:`12`,cy:`5`,r:`1`,key:`gxeob9`}],[`circle`,{cx:`12`,cy:`19`,r:`1`,key:`lyex9k`}]]),R=n(`octagon-alert`,[[`path`,{d:`M12 16h.01`,key:`1drbdi`}],[`path`,{d:`M12 8v4`,key:`1got3b`}],[`path`,{d:`M15.312 2a2 2 0 0 1 1.414.586l4.688 4.688A2 2 0 0 1 22 8.688v6.624a2 2 0 0 1-.586 1.414l-4.688 4.688a2 2 0 0 1-1.414.586H8.688a2 2 0 0 1-1.414-.586l-4.688-4.688A2 2 0 0 1 2 15.312V8.688a2 2 0 0 1 .586-1.414l4.688-4.688A2 2 0 0 1 8.688 2z`,key:`1fd625`}]]),z=n(`pause`,[[`rect`,{x:`14`,y:`3`,width:`5`,height:`18`,rx:`1`,key:`kaeet6`}],[`rect`,{x:`5`,y:`3`,width:`5`,height:`18`,rx:`1`,key:`1wsw3u`}]]),B=n(`square-check`,[[`rect`,{width:`18`,height:`18`,x:`3`,y:`3`,rx:`2`,key:`afitv7`}],[`path`,{d:`m9 12 2 2 4-4`,key:`dzmm74`}]]),V=a(o(),1),H=s(),U={pending:e=>(0,H.jsx)(I,{...e}),in_progress:e=>(0,H.jsx)(P,{...e,className:t(e.className,`text-accent`)}),done:e=>(0,H.jsx)(N,{...e,className:t(e.className,`text-emerald-500`)}),blocked:e=>(0,H.jsx)(R,{...e,className:t(e.className,`text-rose-500`)}),skipped:e=>(0,H.jsx)(F,{...e,className:t(e.className,`text-muted`)})},W={pending:`done`,in_progress:`done`,done:`pending`,blocked:`pending`,skipped:`pending`};function G(){let{state:e,refreshGoals:t,send:n,openThread:i,toast:a}=c(),[o,s]=(0,V.useState)(null),[f,p]=(0,V.useState)(!1),[m,h]=(0,V.useState)(null),[g,v]=(0,V.useState)(!1),y=(0,V.useRef)(null),x=e.profile?.name??`nanoMuse`,S=r();(0,V.useEffect)(()=>{t()},[t]);let T=e.goals.filter(e=>e.proposal&&e.status!==`cancelled`),E=[...e.goals.filter(e=>e.status===`active`),...e.goals.filter(e=>e.status===`paused`)],O=e.goals.filter(e=>e.status===`done`||e.status===`cancelled`),k=e.goals.find(e=>e.id===o)??null,A=async e=>{try{await u.advanceGoal(e.id),a(S(`{name} is working on “{title}” in the main chat`,{name:x,title:e.title})),i(`main`)}catch(e){a(e.message)}},[j,M]=(0,V.useState)(!1),N=async e=>{try{let n=e.status!==`done`;await u.patchGoal(e.id,{status:n?`done`:`active`}),n&&M(!0),t()}catch(e){a(e.message)}},P=e=>{h(null),n(`main`,S(`I'd like to create a {category} goal. Ask me a few short questions, one at a time (what exactly I want, why and by when, how often to check in), then create it with concrete steps using the goals tool.`,{category:S(e.label)})).catch(e=>a(e.message||S(`Could not send`))),i(`main`)};return(0,H.jsxs)(`div`,{className:`flex h-full flex-col`,children:[(0,H.jsx)(b,{title:S(`Goals`),children:(0,H.jsx)(l,{small:!0,onClick:()=>p(!0),label:S(`New goal`),children:(0,H.jsx)(_,{size:22})})}),(0,H.jsxs)(`div`,{className:`flex-1 overflow-y-auto pb-6`,children:[T.length>0&&(0,H.jsxs)(`section`,{className:`px-4 pb-2`,children:[(0,H.jsx)(`div`,{className:`px-1 mb-2 text-[12px] font-semibold uppercase tracking-wide text-muted`,children:S(`{name} suggests`,{name:x})}),(0,H.jsx)(`div`,{className:`space-y-2.5`,children:T.map(e=>(0,H.jsx)(Y,{goal:e,onChanged:t,onOpen:()=>s(e.id)},e.id))})]}),(0,H.jsx)(d,{moment:`goal_done`,due:j,className:`mx-4 mb-3`}),(0,H.jsx)(K,{label:S(`Tracking`),dot:!0,onAdd:()=>y.current?.scrollIntoView({behavior:`smooth`,block:`start`})}),E.length===0?(0,H.jsx)(`p`,{className:`px-5 pb-3 text-[13px] text-muted`,children:S(`Nothing tracked yet`)}):E.map(e=>(0,H.jsx)(J,{goal:e,onOpen:()=>s(e.id),onToggle:()=>void N(e)},e.id)),O.length>0&&(0,H.jsxs)(H.Fragment,{children:[(0,H.jsx)(`div`,{className:`h-1.5`}),(0,H.jsx)(K,{label:S(`Finished`)}),(g?O:O.slice(0,2)).map(e=>(0,H.jsx)(J,{goal:e,onOpen:()=>s(e.id),onToggle:()=>void N(e)},e.id)),!g&&O.length>2&&(0,H.jsx)(`button`,{type:`button`,onClick:()=>v(!0),className:`px-5 py-2 text-[13.5px] font-medium text-accent`,children:S(`Show {n} more`,{n:O.length-2})})]}),(0,H.jsxs)(`div`,{ref:y,className:`mt-2.5 border-t border-border/70 px-5 pt-3.5 pb-1.5`,children:[(0,H.jsx)(`h3`,{className:`text-[17px] font-semibold`,children:S(`Create a goal`)}),(0,H.jsx)(`p`,{className:`mt-1 text-[13px] leading-[18px] text-muted`,children:S(`Pick a category and tell me the goal you have in mind. I'll shape a plan with you and keep improving it as you go.`)})]}),C.map(e=>(0,H.jsxs)(`button`,{type:`button`,onClick:()=>h(e),className:`flex h-[50px] w-full items-center gap-3.5 pl-5 pr-2 text-left active:bg-surface-2/70`,children:[(0,H.jsx)(`span`,{className:`text-fg`,children:e.icon({size:22})}),(0,H.jsx)(`span`,{className:`flex-1 text-[15px] font-medium`,children:S(e.label)}),(0,H.jsx)(`span`,{className:`flex h-10 w-10 items-center justify-center text-muted`,children:(0,H.jsx)(_,{size:22})})]},e.id))]}),(0,H.jsx)(Q,{goal:k,onClose:()=>s(null),onAdvance:A,onChanged:t}),(0,H.jsx)($,{open:f,onClose:()=>p(!1),onCreated:()=>{p(!1),t()}}),(0,H.jsx)(D,{open:m!==null,onClose:()=>h(null),children:m&&(0,H.jsxs)(`div`,{className:`px-1 pb-2`,children:[(0,H.jsx)(`h3`,{className:`text-[20px] font-bold`,children:S(`Create a {category} goal`,{category:S(m.label)})}),(0,H.jsx)(`p`,{className:`mt-3.5 text-[15px] leading-[22px]`,children:S(`First, we'll shape the goal together in the chat. I'll ask a few questions so I understand exactly what you're after.`)}),(0,H.jsx)(`p`,{className:`mt-3.5 text-[15px] leading-[22px]`,children:S(`Once it's set, I'll track your progress here.`)}),(0,H.jsxs)(`button`,{type:`button`,onClick:()=>P(m),className:`mt-6 flex h-[50px] w-full items-center justify-center gap-2 rounded-full bg-accent text-[16px] font-semibold text-accent-fg`,children:[(0,H.jsx)(w,{size:18}),` `,S(`Start`)]})]})})]})}function K({label:e,dot:n=!1,onAdd:r}){return(0,H.jsxs)(`div`,{className:`flex items-center pl-5 pr-2 pt-1`,children:[n&&(0,H.jsx)(`span`,{className:`mr-2.5 h-2 w-2 rounded-full bg-emerald-500`}),(0,H.jsx)(`span`,{className:t(`flex-1 text-[15px] font-semibold`,n&&`text-emerald-600 dark:text-emerald-400`),children:e}),r?(0,H.jsx)(`button`,{type:`button`,onClick:r,"aria-label":e,className:`flex h-10 w-10 items-center justify-center text-muted`,children:(0,H.jsx)(_,{size:22})}):(0,H.jsx)(`span`,{className:`h-10`})]})}function q({id:e,size:n=`sm`}){let i=r(),a=x(e);return a?(0,H.jsxs)(`span`,{className:t(`inline-flex items-center gap-1 rounded-full font-medium`,a.tone,n===`sm`?`px-2 py-0.5 text-[11.5px]`:`px-2.5 py-1 text-[12.5px]`),children:[a.icon({size:n===`sm`?11:13}),` `,i(a.label)]}):null}function J({goal:n,onOpen:i,onToggle:a}){let o=r(),s=n.status===`done`,c=n.progress.total?Math.round(n.progress.done/n.progress.total*100):0,l=E(n.due,n.overdue),u=n.next_step?o(`Next: {step}`,{step:n.next_step}):n.description||``,d=n.status===`paused`?o(`Paused`):n.status===`cancelled`?o(`Cancelled`):s?o(`Done`):n.check_in?v(n.check_in):o(`Updated {when}`,{when:e(n.updated_at)});return(0,H.jsxs)(`div`,{className:`flex items-start pl-[18px] pr-1 pt-2 pb-2.5`,children:[(0,H.jsx)(`button`,{type:`button`,onClick:a,"aria-label":o(s?`Mark as not done`:`Mark as done`),className:`mt-0.5 flex h-7 w-7 shrink-0 items-center justify-center text-muted`,children:s?(0,H.jsx)(B,{size:22}):(0,H.jsx)(f,{size:22})}),(0,H.jsxs)(`button`,{type:`button`,onClick:i,className:`ml-2.5 min-w-0 flex-1 pt-[3px] text-left`,children:[(0,H.jsx)(`span`,{className:t(`line-clamp-2 block text-[15px] font-semibold leading-snug`,s&&`text-muted`),children:n.title}),u&&(0,H.jsx)(`span`,{className:`mt-0.5 line-clamp-2 block text-[13px] leading-[18px] text-muted`,children:u}),(0,H.jsxs)(`span`,{className:`mt-0.5 flex items-center gap-2 text-[12px] text-muted/80`,children:[(0,H.jsxs)(`span`,{className:`truncate`,children:[d,l&&n.status===`active`?` · ${l}`:``]}),c>0&&!s&&(0,H.jsxs)(`span`,{className:`shrink-0 font-medium text-emerald-600 dark:text-emerald-400`,children:[c,`%`]})]})]}),(0,H.jsx)(`button`,{type:`button`,onClick:i,"aria-label":o(`More`),className:`flex h-10 w-10 shrink-0 items-center justify-center text-muted`,children:(0,H.jsx)(L,{size:20})})]})}function Y({goal:e,onChanged:t,onOpen:n}){let{toast:i,state:a}=c(),[o,s]=(0,V.useState)(!1),l=a.profile?.name??`nanoMuse`,d=r(),f=e.proposal;if(!f)return null;let p=async n=>{s(!0);try{n?await u.acceptProposal(e.id):await u.dismissProposal(e.id),i(d(n?`Plan updated`:`Kept your plan`)),t()}catch(e){i(e.message)}finally{s(!1)}},m=e.steps.filter(e=>e.status===`done`||e.status===`skipped`).length;return(0,H.jsxs)(`div`,{className:`rounded-3xl border border-accent/30 bg-accent/5 px-4 py-3.5`,children:[(0,H.jsxs)(`button`,{type:`button`,onClick:n,className:`w-full text-left`,children:[(0,H.jsxs)(`div`,{className:`flex items-center gap-2 text-[12px] font-semibold uppercase tracking-wide text-accent`,children:[(0,H.jsx)(g,{size:13}),` `,d(`Adjust the plan for “{title}”?`,{title:e.title})]}),(0,H.jsx)(`p`,{className:`mt-1.5 text-[14px] leading-snug`,children:f.reason}),(0,H.jsxs)(`div`,{className:`mt-2 text-[12px] text-muted`,children:[m>0&&(0,H.jsxs)(`span`,{children:[m===1?d(`Keeps the 1 step already done.`):d(`Keeps the {n} steps already done.`,{n:m}),` `]}),d(`New remaining steps:`)]}),(0,H.jsx)(`ol`,{className:`mt-1 space-y-0.5 text-[13.5px] list-decimal pl-5`,children:f.steps.map((e,t)=>(0,H.jsx)(`li`,{children:e},t))})]}),(0,H.jsxs)(`div`,{className:`mt-3 flex gap-2`,children:[(0,H.jsx)(`button`,{type:`button`,disabled:o,onClick:()=>void p(!1),className:`flex-1 rounded-2xl border border-border py-2 text-[13.5px] font-medium disabled:opacity-50`,children:d(`Keep my plan`)}),(0,H.jsx)(`button`,{type:`button`,disabled:o,onClick:()=>void p(!0),className:`flex-1 rounded-2xl bg-accent text-accent-fg py-2 text-[13.5px] font-medium disabled:opacity-50`,children:d(`Use {name}'s plan`,{name:l})})]})]})}function X({value:e,onChange:n}){let i=r();return(0,H.jsx)(`div`,{className:`flex flex-wrap gap-1.5`,children:C.map(r=>(0,H.jsxs)(`button`,{type:`button`,onClick:()=>n(e===r.id?``:r.id),className:t(`inline-flex items-center gap-1 rounded-full px-2.5 py-1 text-[12.5px] font-medium transition border`,e===r.id?t(r.tone,`border-transparent ring-2 ring-accent/40`):`border-border text-muted`),children:[r.icon({size:12}),` `,i(r.label)]},r.id))})}function Z({value:e,onChange:n}){let i=r(),{cadence:a,anchor:o,time:s}=k(e),c=(e,t,r)=>n(j(e,t,r));return(0,H.jsxs)(`div`,{className:`space-y-2`,children:[(0,H.jsx)(`div`,{className:`flex flex-wrap gap-1.5`,children:T.map(e=>(0,H.jsx)(`button`,{type:`button`,onClick:()=>c(e.id,e.id===`weekly`?o||`mon`:e.id===`monthly`?o||`1`:``,s),className:t(`rounded-full px-2.5 py-1 text-[12.5px] font-medium border transition`,a===e.id?`bg-accent text-accent-fg border-transparent`:`border-border text-muted`),children:i(e.label)},e.id))}),a&&(0,H.jsxs)(`div`,{className:`flex items-center gap-2 text-[13.5px]`,children:[a===`weekly`&&(0,H.jsx)(`select`,{value:o||`mon`,onChange:e=>c(a,e.target.value,s),className:`rounded-xl bg-surface-2 px-2.5 py-1.5 outline-none`,children:S.map(e=>(0,H.jsx)(`option`,{value:e,children:m(e)},e))}),a===`monthly`&&(0,H.jsx)(`select`,{value:o||`1`,onChange:e=>c(a,e.target.value,s),className:`rounded-xl bg-surface-2 px-2.5 py-1.5 outline-none`,children:Array.from({length:28},(e,t)=>String(t+1)).map(e=>(0,H.jsx)(`option`,{value:e,children:y(Number(e))},e))}),(0,H.jsx)(`span`,{className:`text-muted`,children:i(`at`)}),(0,H.jsx)(`input`,{type:`time`,value:s,onChange:e=>c(a,o,e.target.value||`09:00`),className:`rounded-xl bg-surface-2 px-2.5 py-1.5 outline-none`})]})]})}function Q({goal:n,onClose:a,onAdvance:o,onChanged:s}){let{toast:l,send:d,openThread:f,state:m}=c(),[g,y]=(0,V.useState)(``),[b,x]=(0,V.useState)(!1),S=m.profile?.name??`nanoMuse`,C=r(),w=async e=>{if(n)try{await u.patchGoal(n.id,e),s()}catch(e){l(e.message)}},T=async()=>{if(n&&g.trim())try{await u.addStep(n.id,g.trim()),y(``),s()}catch(e){l(e.message)}},k=async()=>{if(n)try{await u.checkInGoal(n.id),l(C(`{name} will check in with you in the main chat`,{name:S})),f(`main`),a()}catch(e){l(e.message)}},j=async()=>{if(n&&window.confirm(C(`Delete “{title}”?`,{title:n.title})))try{await u.deleteGoal(n.id),s(),a()}catch(e){l(e.message)}},N=n?E(n.due,n.overdue):``;return(0,H.jsx)(D,{open:!!n,onClose:a,title:n?.title,footer:n&&(0,H.jsxs)(`div`,{className:`flex gap-2`,children:[n.status===`active`?(0,H.jsxs)(`button`,{type:`button`,onClick:()=>void w({status:`paused`}),className:`flex-1 rounded-2xl border border-border py-2.5 font-medium flex items-center justify-center gap-1.5`,children:[(0,H.jsx)(z,{size:16}),` `,C(`Pause`)]}):n.status===`paused`?(0,H.jsxs)(`button`,{type:`button`,onClick:()=>void w({status:`active`}),className:`flex-1 rounded-2xl border border-border py-2.5 font-medium flex items-center justify-center gap-1.5`,children:[(0,H.jsx)(p,{size:16}),` `,C(`Resume`)]}):null,n.status===`active`&&(0,H.jsxs)(`button`,{type:`button`,onClick:()=>o(n),className:`flex-1 rounded-2xl bg-accent text-accent-fg py-2.5 font-medium flex items-center justify-center gap-1.5`,children:[(0,H.jsx)(p,{size:16}),` `,C(`Work on it now`)]}),(0,H.jsx)(`button`,{type:`button`,onClick:()=>void j(),"aria-label":C(`Delete goal`),className:`rounded-2xl border border-border px-3 text-muted hover:text-rose-500`,children:(0,H.jsx)(h,{size:18})})]}),children:n&&(0,H.jsxs)(`div`,{className:`space-y-4`,children:[n.proposal&&(0,H.jsx)(Y,{goal:n,onChanged:s,onOpen:()=>void 0}),n.description&&(0,H.jsx)(`p`,{className:`text-[14px] text-muted leading-snug`,children:n.description}),(0,H.jsx)(`div`,{className:`rounded-2xl bg-surface-2/60 px-3.5 py-3`,children:b?(0,H.jsxs)(`div`,{className:`space-y-3`,children:[(0,H.jsxs)(`div`,{children:[(0,H.jsx)(`div`,{className:`text-[12px] font-semibold uppercase tracking-wide text-muted mb-1.5`,children:C(`Area of life`)}),(0,H.jsx)(X,{value:n.category,onChange:e=>void w({category:e})})]}),(0,H.jsxs)(`div`,{children:[(0,H.jsx)(`div`,{className:`text-[12px] font-semibold uppercase tracking-wide text-muted mb-1.5`,children:C(`Target date`)}),(0,H.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,H.jsx)(`input`,{type:`date`,value:n.due,onChange:e=>void w({due:e.target.value}),className:`rounded-xl bg-surface px-2.5 py-1.5 text-[13.5px] outline-none`}),n.due&&(0,H.jsx)(`button`,{type:`button`,onClick:()=>void w({due:``}),className:`text-[12.5px] text-muted`,children:C(`Clear`)})]})]}),(0,H.jsxs)(`div`,{children:[(0,H.jsx)(`div`,{className:`text-[12px] font-semibold uppercase tracking-wide text-muted mb-1.5`,children:C(`Reminders from {name}`,{name:S})}),(0,H.jsx)(Z,{value:n.check_in,onChange:e=>void w({check_in:e})})]}),(0,H.jsx)(`button`,{type:`button`,onClick:()=>x(!1),className:`text-[12.5px] text-accent font-medium`,children:C(`Done`)})]}):(0,H.jsxs)(`button`,{type:`button`,onClick:()=>x(!0),className:`w-full text-left`,children:[(0,H.jsxs)(`div`,{className:`flex flex-wrap items-center gap-1.5 text-[12.5px]`,children:[n.category?(0,H.jsx)(q,{id:n.category,size:`md`}):(0,H.jsx)(`span`,{className:`rounded-full border border-dashed border-border px-2.5 py-1 text-muted`,children:C(`No category`)}),(0,H.jsxs)(`span`,{className:t(`inline-flex items-center gap-1 rounded-full px-2.5 py-1`,n.overdue?`bg-rose-500/12 text-rose-600 dark:text-rose-300 font-medium`:`bg-surface text-muted`),children:[(0,H.jsx)(A,{size:13}),` `,N||C(`No target date`)]}),(0,H.jsxs)(`span`,{className:`inline-flex items-center gap-1 rounded-full bg-surface px-2.5 py-1 text-muted`,children:[(0,H.jsx)(O,{size:13}),` `,n.check_in?v(n.check_in):C(`No reminders`)]})]}),n.next_check_in&&n.status===`active`&&(0,H.jsxs)(`div`,{className:`mt-1.5 text-[12px] text-muted`,children:[C(`Next check-in {when}`,{when:e(n.next_check_in)}),` · `,i(n.next_check_in)]}),(0,H.jsx)(`div`,{className:`mt-1.5 text-[12px] text-accent font-medium`,children:C(`Edit`)})]})}),(0,H.jsxs)(`div`,{children:[(0,H.jsxs)(`div`,{className:`text-[12px] font-semibold uppercase tracking-wide text-muted mb-2`,children:[C(`Plan`),` · `,n.progress.done,`/`,n.progress.total]}),(0,H.jsx)(`ul`,{className:`space-y-1`,children:n.steps.map(e=>{let n=U[e.status];return(0,H.jsxs)(`li`,{className:`flex items-start gap-2.5 rounded-2xl px-2 py-1.5 hover:bg-surface-2/60`,children:[(0,H.jsx)(`button`,{type:`button`,"aria-label":C(`Mark step {n} {status}`,{n:e.idx,status:C(W[e.status])}),onClick:()=>void w({step_index:e.idx,step_status:W[e.status]}),className:`mt-0.5 text-muted`,children:(0,H.jsx)(n,{size:20})}),(0,H.jsxs)(`div`,{className:`flex-1 min-w-0`,children:[(0,H.jsxs)(`div`,{className:t(`text-[14.5px] leading-snug`,(e.status===`done`||e.status===`skipped`)&&`line-through text-muted`),children:[e.idx,`. `,e.title]}),e.note&&(0,H.jsx)(`div`,{className:`text-[12.5px] text-muted mt-0.5 whitespace-pre-wrap`,children:e.note})]})]},e.idx)})}),(0,H.jsxs)(`div`,{className:`mt-2 flex gap-2`,children:[(0,H.jsx)(`input`,{value:g,onChange:e=>y(e.target.value),onKeyDown:e=>e.key===`Enter`&&void T(),placeholder:C(`Add a step`),className:`flex-1 rounded-2xl bg-surface-2 px-3.5 py-2 text-[14px] outline-none focus:ring-2 focus:ring-accent/40`}),(0,H.jsx)(`button`,{type:`button`,onClick:()=>void T(),className:`rounded-2xl bg-surface-2 px-3 text-accent`,"aria-label":C(`Add step`),children:(0,H.jsx)(_,{size:18})})]})]}),n.notes&&(0,H.jsxs)(`div`,{children:[(0,H.jsx)(`div`,{className:`text-[12px] font-semibold uppercase tracking-wide text-muted mb-1.5`,children:C(`Notes from {name}`,{name:S})}),(0,H.jsx)(`pre`,{className:`whitespace-pre-wrap break-words text-[13px] leading-snug text-muted font-sans`,children:n.notes})]}),(0,H.jsxs)(`div`,{className:`flex flex-wrap gap-x-4 gap-y-1.5`,children:[(0,H.jsx)(`button`,{type:`button`,onClick:()=>{d(`main`,C(`About my goal “{title}” ({id}): what's the status, and what should we do next?`,{title:n.title,id:n.id})).catch(e=>l(e.message||C(`Could not send`))),f(`main`),a()},className:`text-[13.5px] text-accent font-medium`,children:C(`Discuss this goal in chat →`)}),n.status===`active`&&(0,H.jsxs)(`button`,{type:`button`,onClick:()=>void k(),className:`text-[13.5px] text-accent font-medium inline-flex items-center gap-1`,children:[(0,H.jsx)(M,{size:14}),` `,C(`Check in with me now`)]})]})]})})}function $({open:e,onClose:t,onCreated:n}){let{toast:i,send:a,openThread:o,state:s}=c(),[l,d]=(0,V.useState)(``),[f,p]=(0,V.useState)(``),[m,h]=(0,V.useState)(``),[_,v]=(0,V.useState)(``),[y,b]=(0,V.useState)(``),[x,S]=(0,V.useState)(``),[C,w]=(0,V.useState)(!1),T=s.profile?.name??`nanoMuse`,E=r(),O=()=>{d(``),p(``),h(``),v(``),b(``),S(``)},k=async()=>{if(l.trim()){w(!0);try{await u.createGoal({title:l.trim(),description:f.trim(),steps:m.split(` `).map(e=>e.trim()).filter(Boolean),category:_,due:y,check_in:x}),O(),n()}catch(e){i(e.message)}finally{w(!1)}}};return(0,H.jsx)(D,{open:e,onClose:t,title:E(`New goal`),footer:(0,H.jsxs)(`div`,{className:`flex gap-2`,children:[(0,H.jsxs)(`button`,{type:`button`,onClick:()=>{if(!l.trim())return;let e=[_?`category: ${_}`:``,y?`target date: ${y}`:``,x?`check_in "${x}"`:``].filter(Boolean);a(`main`,E(`Create a goal for me: "{title}"{description}{extras}. Break it into concrete steps with the goals tool, then tell me the plan.`,{title:l.trim(),description:f.trim()?` (${f.trim()})`:``,extras:e.length?` (${e.join(`, `)})`:``})).catch(e=>i(e.message||E(`Could not send`))),O(),t(),o(`main`)},disabled:!l.trim(),className:`flex-1 rounded-2xl border border-border py-2.5 font-medium disabled:opacity-50 flex items-center justify-center gap-1.5`,children:[(0,H.jsx)(g,{size:16}),` `,E(`Let {name} plan it`,{name:T})]}),(0,H.jsx)(`button`,{type:`button`,onClick:()=>void k(),disabled:!l.trim()||C,className:`flex-1 rounded-2xl bg-accent text-accent-fg py-2.5 font-medium disabled:opacity-50`,children:E(`Create`)})]}),children:(0,H.jsxs)(`div`,{className:`space-y-3.5`,children:[(0,H.jsx)(`input`,{value:l,onChange:e=>d(e.target.value),placeholder:E(`What do you want to achieve?`),className:`w-full rounded-2xl bg-surface-2 px-3.5 py-2.5 text-[15px] outline-none focus:ring-2 focus:ring-accent/40`}),(0,H.jsxs)(`div`,{children:[(0,H.jsx)(`div`,{className:`text-[12px] font-semibold uppercase tracking-wide text-muted mb-1.5`,children:E(`Area of life`)}),(0,H.jsx)(X,{value:_,onChange:v})]}),(0,H.jsxs)(`div`,{className:`flex items-center gap-3`,children:[(0,H.jsx)(`div`,{className:`text-[12px] font-semibold uppercase tracking-wide text-muted flex-1`,children:E(`Target date`)}),(0,H.jsx)(`input`,{type:`date`,value:y,onChange:e=>b(e.target.value),className:`rounded-xl bg-surface-2 px-2.5 py-1.5 text-[13.5px] outline-none`})]}),(0,H.jsxs)(`div`,{children:[(0,H.jsx)(`div`,{className:`text-[12px] font-semibold uppercase tracking-wide text-muted mb-1.5`,children:E(`Reminders from {name}`,{name:T})}),(0,H.jsx)(Z,{value:x,onChange:S})]}),(0,H.jsx)(`textarea`,{value:f,onChange:e=>p(e.target.value),placeholder:E(`Why it matters, constraints (optional)`),rows:2,className:`w-full rounded-2xl bg-surface-2 px-3.5 py-2.5 text-[14px] outline-none focus:ring-2 focus:ring-accent/40 resize-none`}),(0,H.jsx)(`textarea`,{value:m,onChange:e=>h(e.target.value),placeholder:E(`Steps, one per line (optional, or let {name} plan them)`,{name:T}),rows:3,className:`w-full rounded-2xl bg-surface-2 px-3.5 py-2.5 text-[14px] outline-none focus:ring-2 focus:ring-accent/40 resize-none`})]})})}export{G as GoalsScreen}; \ No newline at end of file diff --git a/nanomuse/server/static/assets/IdeasScreen-BVCFCRSV.js b/nanomuse/server/static/assets/IdeasScreen-CGfvq5H-.js similarity index 99% rename from nanomuse/server/static/assets/IdeasScreen-BVCFCRSV.js rename to nanomuse/server/static/assets/IdeasScreen-CGfvq5H-.js index 76de16b8a..8f582f3a2 100644 --- a/nanomuse/server/static/assets/IdeasScreen-BVCFCRSV.js +++ b/nanomuse/server/static/assets/IdeasScreen-CGfvq5H-.js @@ -1 +1 @@ -import{A as e,J as t,K as n,Q as r,W as i,Y as a,b as o,f as s,q as c,x as l}from"./MuseHeader-Pw-NI98v.js";import{t as u}from"./refresh-cw-BKgIzslL.js";import{f as d,m as f,ot as p,w as m,yt as h}from"./index-BjYzdKkG.js";var g=t(`flag`,[[`path`,{d:`M4 22V4a1 1 0 0 1 .4-.8A6 6 0 0 1 8 2c3 0 5 2 7.333 2q2 0 3.067-.8A1 1 0 0 1 20 4v10a1 1 0 0 1-.4.8A6 6 0 0 1 16 16c-3 0-5-2-8-2a6 6 0 0 0-4 1.528`,key:`1jaruq`}]]),_=r(a(),1),v={sections:[{id:`travel`,title:`Travel`,ideas:[{id:`train-watch`,emoji:`🚄`,title:`Tell me where you're going and when; I'll watch for seats and lower fares.`,body:`I set up the lookup tools in my sandbox, check trains, classes and availability as often as you like, and tell you the moment something opens up. Booking and paying stay in your hands.`,kind:`GOAL`,category:`other`,prompt:`I want to watch a train route: ask me for the origin, destination, date and acceptable departure window, then set up a goal that checks availability regularly.`},{id:`trip-plan`,emoji:`🗺️`,title:`Name a city and a number of days; I'll plan an itinerary you can follow as is.`,body:`Weather, opening hours and travel time between stops go into a day-by-day plan saved to your Library. Change one sentence and I'll rearrange the rest.`,kind:`CHAT`,prompt:`Help me plan a trip. Ask me where, how many days, with whom, a rough budget and the style I like, then give me a day-by-day itinerary as a file.`},{id:`commute-brief`,emoji:`🚦`,title:`Before you leave each morning, I'll tell you the traffic, the weather and the first thing on your plate.`,body:`A morning routine: I check the weather where you are, the traffic on your commute, glance at your calendar and boil the morning down to three sentences.`,kind:`ROUTINE`,time:`07:30`,prompt:`Morning brief: check today's weather and commute traffic, read my calendar for today, and tell me in at most five sentences the three things that matter most and what to bring.`},{id:`parcel-track`,emoji:`📦`,title:`Send me a tracking number; I'll tell you where the parcel is and when it lands.`,body:`I follow the shipment through the carrier's tracking, tell you about every new scan, and remind you to keep the phone nearby on delivery day.`,kind:`CHAT`,prompt:`Help me track a parcel. Ask me for the tracking number and carrier, check the current status once, then set a routine that checks every morning and reminds me the day before delivery.`}]},{id:`work`,title:`Work`,ideas:[{id:`meeting-prep`,emoji:`📝`,title:`Ten minutes before a meeting, I'll have the background and the questions ready.`,body:`I read the meeting's title and attendees from your calendar, look through what we've discussed and what you've put in the Library, and hand you one page: purpose, talking points, three questions worth asking.`,kind:`ROUTINE`,time:`08:50`,prompt:`Look at the meetings on my calendar today and prepare a one-page brief for each: the purpose, the points I should make, and three questions worth asking.`},{id:`weekly-review`,emoji:`📊`,title:`Every Friday afternoon, I'll review what you did this week and what next week needs.`,body:`From our conversations, your calendar and the notes I keep, I list what got done, what didn't, and three priorities for next week, as a draft you can send.`,kind:`ROUTINE`,time:`17:00`,prompt:`Write my weekly review: from this week's conversations, my calendar and what you remember, list what was completed, what is still open, and three priorities for next week. Save it as a Markdown file.`},{id:`inbox-triage`,emoji:`📬`,title:`Dump a pile of messages or emails on me; I'll sort them and draft the replies.`,body:`Paste text or screenshots. I sort them into 'reply today', 'this week' and 'just so you know', and draft each reply so you only need to edit and send.`,kind:`CHAT`,prompt:`I'm handing you a batch of messages to triage: sort them into 'reply today / this week / just so you know' and draft a reply for each one that needs it. Ask me to paste the content first.`},{id:`doc-digest`,emoji:`📄`,title:`Long documents, PDFs, web pages: I'll read them and give you the three-minute version.`,body:`Drop the file in a shared folder or send me the link. You get the conclusions, the key numbers and the decisions you need to make; ask follow-ups any time.`,kind:`CHAT`,prompt:`I have something long for you to read and summarise: ask me for the file or link, then give me conclusions, key numbers and decisions I need to make, at most five bullets each.`}]},{id:`life`,title:`Everyday`,ideas:[{id:`price-watch`,emoji:`🏷️`,title:`Tell me what you want to buy; the moment it hits your price, you'll know.`,body:`I check the product page on a schedule, keep the price history, and notify you at your target. Ordering and paying are yours; I don't touch them.`,kind:`GOAL`,category:`finance`,prompt:`I want to watch the price of a product: ask me for the link or name, my target price and how often to check, then create a goal that alerts me when it drops.`},{id:`photo-sort`,emoji:`🖼️`,title:`Mount your photos and I'll sort screenshots and pictures by what's in them.`,body:`Once your gallery is mounted as a shared folder I look at each image (receipts, chat screenshots, landscapes, documents), file it into the right folder and note anything important.`,kind:`CHAT`,prompt:`Help me sort my photos: ask me to mount the gallery in Shared Folders first, then sort by content (receipts, screenshots, scenery, documents, other) and list what you did.`},{id:`meal-log`,emoji:`🥗`,title:`Photograph what you eat; I'll estimate the calories and keep the log.`,body:`A photo or a sentence is enough: I estimate nutrition and calories, log it in the day's memory, and give you a summary each evening with one small suggestion for tomorrow.`,kind:`CHAT`,prompt:`From now on, log my meals: whenever I send a photo or a description, estimate calories and nutrition and write it into today's memory. Tell me first how best to send them.`},{id:`subscriptions`,emoji:`🔁`,title:`Send me your bills; I'll list every subscription that charges you each month, and you decide which to stop.`,body:`Give me bill screenshots or statements. I list every recurring charge, its next date and the yearly total; you decide what to cancel and I walk you through each cancellation.`,kind:`CHAT`,prompt:`Audit my subscriptions: ask me for bill screenshots or statements, then list every recurring charge, its next billing date and the yearly total, and flag the ones I may not need.`}]},{id:`learn`,title:`Learning`,ideas:[{id:`daily-words`,emoji:`🔤`,title:`Five new words every morning, a quick quiz every night.`,body:`You pick the language and level; I pick words by theme with examples and a memory hook, quiz you in the evening, and bring back the ones you missed.`,kind:`ROUTINE`,time:`08:00`,prompt:`Daily vocabulary: pick five new words for me (ask which language, level and topics first), each with a definition, one example sentence and a memory hook, plus a review quiz on yesterday's words.`},{id:`study-plan`,emoji:`🎯`,title:`Something you want to learn? I'll break it into weekly chunks and keep you honest.`,body:`Tell me the goal and the hours you can spare; I lay out four to eight weeks, check progress weekly, and adjust the pace so you actually finish.`,kind:`GOAL`,category:`interests`,prompt:`I want to learn something new and stick with it: ask me what, my current level, hours per week and the timeframe, then create a goal with a weekly progress check.`},{id:`explain`,emoji:`💡`,title:`Send me a concept you don't get; I'll explain it with things you already know.`,body:`I ask what you already understand and start from there, then check with two quick questions and leave you a flashcard if you want one.`,kind:`CHAT`,prompt:`There's a concept I don't understand: ask me what it is and what related things I already know, explain it with analogies, then check with two short questions.`},{id:`reading-notes`,emoji:`📚`,title:`Finished a book? I'll turn it into notes you'll actually reread.`,body:`Tell me the highlights, or send the passages you marked. I write structured notes into your Library and remember what stayed with you.`,kind:`CHAT`,prompt:`Help me write notes on a book: ask me the title, the three things that struck me most and the quotes I want to keep, then save structured Markdown notes.`}]},{id:`family`,title:`Family & friends`,ideas:[{id:`birthdays`,emoji:`🎂`,title:`Birthdays and anniversaries: I remind you a week ahead, gift ideas included.`,body:`Give me names and dates and I keep them. A week before each one I remind you, with a few gift directions based on what you've told me about them.`,kind:`CHAT`,prompt:`Remember the birthdays and anniversaries of the people who matter to me: ask for the list and dates, store them in long-term memory, and set a routine that reminds me a week before each.`},{id:`keep-in-touch`,emoji:`💬`,title:`Lost touch with old friends? Once a week I'll suggest who to reach out to, and how to start.`,body:`Give me a list of people you want to stay close to. I rotate through them and write a natural opening line based on what you last talked about.`,kind:`ROUTINE`,time:`19:00`,prompt:`Weekly keep-in-touch: from my list of people I want to stay close to, pick the one I've gone longest without contacting, remind me, and write a natural opening line based on what I noted about our last conversation.`},{id:`family-calendar`,emoji:`📅`,title:`Tell me the family's plans and I'll put them on the calendar and catch clashes.`,body:`Kids' lessons, a parent's appointment, a weekend get-together: one sentence and it's in the calendar; if two things collide, I say so first.`,kind:`CHAT`,prompt:`Help me run the family calendar: I'll tell you plans as they come up; write them into the calendar, confirm each before creating it, and warn me about conflicts.`},{id:`gift-ideas`,emoji:`🎁`,title:`Describe the person and I'll give you gift ideas that aren't the obvious ones.`,body:`Budget, relationship, what they're into lately: three questions, then five directions with one line each on why it fits.`,kind:`CHAT`,prompt:`Help me think of a gift: ask who it's for, my budget, their interests and what's going on in their life, then give me five directions with one line of reasoning each.`}]},{id:`more`,title:`More ideas`,ideas:[{id:`id-renewal`,emoji:`🪪`,title:`Tell me when your documents expire; I'll book the renewal and prep the paperwork list.`,body:`Passport, licence, visa: I note the dates, remind you three months ahead, list the documents and the office, and look up appointment slots where I can.`,kind:`CHAT`,prompt:`Help me track document expiry: ask which documents I have and when they expire, store them in memory, and set a reminder three months ahead of each with the renewal checklist.`},{id:`personality-quiz`,emoji:`❓`,title:`Two small questions a day; after a week I'll tell you what I've noticed about you.`,body:`Light questions, quick answers. I keep them and, once a week, write a short observation about your preferences and rhythm so I understand you better.`,kind:`ROUTINE`,time:`21:00`,prompt:`Two questions a day: ask me two small questions about preferences, habits or how things are going (never repeat one), store the answers in memory; every Sunday add a short observation about my week.`},{id:`event-plan`,emoji:`🎉`,title:`Name the occasion; I'll plan the run of show and draft the invitation.`,body:`Birthday, team outing, family dinner: give me the headcount, budget and date, and you get a timeline, a shopping list and an invitation you can send as is.`,kind:`CHAT`,prompt:`Help me plan an event: ask me the occasion, date, headcount and budget, then give me a timeline, a to-do list and an invitation text I can send.`},{id:`phone-cleanup`,emoji:`🧹`,title:`Let me look through the sandbox and shared folders; I'll clear the junk and organise the rest.`,body:`I list the big files and duplicates, show you the list first and only act when you say so; anything worth keeping goes into the Library.`,kind:`CHAT`,prompt:`Help me tidy the workspace and shared folders: list large files, duplicates and files untouched for a long time, and give me the list. Do not delete anything before I confirm.`}]}]},y={sections:[{id:`travel`,title:`出行`,ideas:[{id:`train-watch`,emoji:`🚄`,title:`告诉我你要去哪、哪天走,我盯着 12306 的余票和低价票。`,body:`我会在沙盒里装好查询工具,按你说的频率查车次、席别和余票,有票或价格合适时马上通知你;订票和付款那一步留给你自己点。`,kind:`GOAL`,category:`other`,prompt:`我想盯一趟火车票:请先问我出发地、目的地、日期和可接受的车次时段,然后为我建一个定期检查余票的目标。`},{id:`trip-plan`,emoji:`🗺️`,title:`说一个城市和几天,我给你排一份能直接照着走的行程。`,body:`我会查天气、开放时间和两点之间的路程,把每天的顺序排顺,写成一份文件放进资源库;你改一句,我就重排。`,kind:`CHAT`,prompt:`帮我规划一次出行。先问我去哪、几天、和谁、预算大概多少、喜欢什么风格,再给我一份按天排好的行程文件。`},{id:`commute-brief`,emoji:`🚦`,title:`每天出门前,我告诉你今天的路况、天气和第一件事。`,body:`一条早间例程:查你所在城市的天气、通勤路线的路况,翻一下日历,把上午的安排浓缩成三句话推给你。`,kind:`ROUTINE`,time:`07:30`,prompt:`早间简报:查询今天的天气和通勤路况,读取我今天的日历安排,用不超过五句话告诉我今天最重要的三件事和出门要带的东西。`},{id:`parcel-track`,emoji:`📦`,title:`把快递单号发我,到哪了、什么时候到,我随时告诉你。`,body:`我会用快递查询接口跟踪包裹,有新的物流节点就更新你;派送当天提醒你留意电话。`,kind:`CHAT`,prompt:`帮我跟踪一个快递。先问我单号和快递公司,然后查一次当前进度,并设一个每天早上检查一次、到派送前一天提醒我的例程。`}]},{id:`work`,title:`工作`,ideas:[{id:`meeting-prep`,emoji:`📝`,title:`开会前十分钟,我把这场会的背景和该问的问题整理好。`,body:`读日历里的会议主题和参会人,翻我们聊过的相关内容和你放进资源库的资料,给你一页纸:目的、要点、三个值得问的问题。`,kind:`ROUTINE`,time:`08:50`,prompt:`查看我今天日历里接下来的会议,为每一场准备一页会前提纲:这场会的目的、需要我发言的要点、三个值得提出的问题。`},{id:`weekly-review`,emoji:`📊`,title:`每周五下午,我帮你回顾这一周做了什么,下周该抓什么。`,body:`从我们的对话、你的日历和我记下的备忘里,整理出本周完成的事、没做完的事和下周的三个重点,写成一份周报草稿。`,kind:`ROUTINE`,time:`17:00`,prompt:`写一份本周回顾:根据我们这周的对话、我的日历和你记住的事项,列出完成了什么、什么没做完、下周三个重点,保存为一份 Markdown 文件。`},{id:`inbox-triage`,emoji:`📬`,title:`把一堆消息或邮件丢给我,我分好轻重缓急,写好回复草稿。`,body:`粘贴文字或截图给我,我按“今天必须回、这周处理、只需知道”分类,把每条要回的先拟好一版,你改一改就能发。`,kind:`CHAT`,prompt:`我要把一批消息交给你整理:请按“今天必须回 / 这周处理 / 只需知道”分类,并为需要回复的每一条写好回复草稿。请先让我粘贴内容。`},{id:`doc-digest`,emoji:`📄`,title:`长文档、PDF、网页,我读完给你三分钟版本。`,body:`把文件放进共享文件夹或把链接发我,我提炼结论、关键数字和你需要做的决定,问题可以接着追问。`,kind:`CHAT`,prompt:`我有一份长内容需要你读并总结:请先让我提供文件或链接,然后给我结论、关键数字、需要我做的决定三部分,每部分不超过五条。`}]},{id:`life`,title:`生活`,ideas:[{id:`price-watch`,emoji:`🏷️`,title:`想买的东西告诉我,降到你说的价格我立刻告诉你。`,body:`我会定期去商品页看价格,记录走势;到价就通知你。下单和付款由你来点,我不会碰。`,kind:`GOAL`,category:`finance`,prompt:`我想盯一件商品的价格:请先问我商品链接或名称、目标价格和检查频率,然后建一个到价提醒我的目标。`},{id:`photo-sort`,emoji:`🖼️`,title:`把相册挂给我,我按内容给截图和照片分类整理。`,body:`在「共享文件夹」里挂载相册后,我会看图识别内容(票据、聊天截图、风景、证件),归到对应文件夹,重要的信息顺手记下来。`,kind:`CHAT`,prompt:`帮我整理照片:请先让我在共享文件夹里挂载相册目录,然后按内容(票据、截图、风景、证件、其他)分类整理,并把整理结果列给我。`},{id:`meal-log`,emoji:`🥗`,title:`拍下你吃的,我帮你估热量、记下每一餐。`,body:`发一张照片或一句话,我估算营养和热量,记进当天的日记;晚上给你一天的小结和明天的一个小建议。`,kind:`CHAT`,prompt:`从现在起帮我记录饮食:每次我发照片或描述,估算热量与营养并记入当天记忆;请先告诉我怎么发给你最方便。`},{id:`subscriptions`,emoji:`🔁`,title:`帮你把每月自动扣费的订阅列出来,看看哪些该停。`,body:`把账单截图或消费记录给我,我列出所有周期性扣费、下一次扣款日和一年花多少;你决定停哪个,退订的步骤我一步步陪你走。`,kind:`CHAT`,prompt:`帮我盘点订阅扣费:请先让我提供账单截图或记录,然后列出所有周期性扣费、下一次扣款日、年费合计,并标出可能不再需要的。`}]},{id:`learn`,title:`学习`,ideas:[{id:`daily-words`,emoji:`🔤`,title:`每天早上五个新词,晚上考你一遍。`,body:`你定语言和难度,我按主题挑词、给例句和记忆点,晚上出五道小题,错的第二天再来。`,kind:`ROUTINE`,time:`08:00`,prompt:`每日词汇:为我挑五个新词(先问我学什么语言、什么水平和感兴趣的主题),每个给释义、一个例句和一个记忆点,并附上昨天的复习题。`},{id:`study-plan`,emoji:`🎯`,title:`有个想学会的东西?我陪你拆成每周能做完的小块。`,body:`告诉我目标和每周能投入的时间,我排一份四到八周的计划,每周检查进度、调整难度,帮你坚持到最后。`,kind:`GOAL`,category:`interests`,prompt:`我想学一样新东西并坚持下去:请先问我想学什么、现在的水平、每周能投入多少时间和希望多久见效,然后帮我建一个每周检查进度的目标。`},{id:`explain`,emoji:`💡`,title:`看不懂的概念发给我,我用你熟悉的东西讲明白。`,body:`先问你已经懂什么,再从那里出发讲;讲完出两道题确认你真懂了,需要的话给你一张记忆卡。`,kind:`CHAT`,prompt:`我有一个不太懂的概念想让你讲明白:请先问我这个概念是什么、我已经了解哪些相关知识,然后用类比讲解,最后出两道小题检验。`},{id:`reading-notes`,emoji:`📚`,title:`读完一本书,我帮你整理成能重读的笔记。`,body:`你说重点和感受,或者把划线的句子发我,我整理成结构化笔记,存进资源库,并记住你的收获。`,kind:`CHAT`,prompt:`帮我整理一本书的读书笔记:请先问我书名、最触动我的三点和我想记住的引文,然后整理成结构化的 Markdown 笔记并保存。`}]},{id:`family`,title:`家庭与关系`,ideas:[{id:`birthdays`,emoji:`🎂`,title:`重要的人的生日和纪念日,我提前一周提醒,顺手想好礼物。`,body:`把名字和日期告诉我,我记住;到日子前一周提醒你,并根据你说过的 TA 的喜好给几个礼物方向。`,kind:`CHAT`,prompt:`帮我记住重要的人的生日和纪念日:请先问我名单和日期,记入长期记忆,并为每个日期设一个提前一周提醒我的例程。`},{id:`keep-in-touch`,emoji:`💬`,title:`老朋友太久没联系?我每周提醒你该找谁聊聊,帮你开个头。`,body:`你给我一份想保持联系的名单,我按间隔轮着提醒,并根据上次聊的内容帮你写一句自然的开场。`,kind:`ROUTINE`,time:`19:00`,prompt:`每周联系提醒:从我告诉你的“想保持联系的人”名单里,挑一位最近最久没联系的,提醒我,并根据我记录过的上次聊天内容写一句自然的开场白。`},{id:`family-calendar`,emoji:`📅`,title:`把全家的安排告诉我,我帮你排进日历、发现冲突。`,body:`孩子的课、家人的门诊、周末的聚会,说一句我就写进日历,时间撞了我先提醒你。`,kind:`CHAT`,prompt:`帮我管理家庭日程:我会陆续告诉你家人的安排,请写进日历,创建前先复述确认,发现时间冲突时提醒我。`},{id:`gift-ideas`,emoji:`🎁`,title:`说说 TA 是什么样的人,我给你几个不落俗套的礼物点子。`,body:`预算、关系、TA 最近在忙什么,三个问题之后我给你五个方向,每个附一句为什么合适。`,kind:`CHAT`,prompt:`帮我想礼物:请先问我送给谁、预算、TA 的兴趣和最近的生活状态,然后给我五个礼物方向,每个附一句理由。`}]},{id:`more`,title:`更多点子`,ideas:[{id:`id-renewal`,emoji:`🪪`,title:`告诉我证件到期时间,我提前预约续签,把材料清单准备好。`,body:`护照、驾照、签证,我记下到期日,提前三个月提醒,列出所需材料和办理地点,能预约的帮你查好时段。`,kind:`CHAT`,prompt:`帮我管理证件到期:请先问我有哪些证件和到期日期,记入长期记忆,并为每一个设置提前三个月的提醒,附上续办所需材料清单。`},{id:`personality-quiz`,emoji:`❓`,title:`每天两个小问题,一周后我告诉你我发现了什么样的你。`,body:`问题很轻,回答很快;我把答案记下来,每周整理成一段关于你偏好和节奏的观察,方便我更懂你。`,kind:`ROUTINE`,time:`21:00`,prompt:`每日两问:问我两个关于偏好、习惯或近况的小问题(不重复以前问过的),把回答记入记忆;每周日额外给我一段关于我这周状态的观察。`},{id:`event-plan`,emoji:`🎉`,title:`说个场合,我帮你安排流程、拟好邀请。`,body:`生日、团建、家宴,人数、预算和日期告诉我,我给你时间线、采购清单和一段可以直接发出去的邀请文字。`,kind:`CHAT`,prompt:`帮我策划一次活动:请先问我场合、日期、人数和预算,然后给我时间线、待办清单和一段可直接发送的邀请文字。`},{id:`phone-cleanup`,emoji:`🧹`,title:`让我看看沙盒和共享文件夹里有什么,清掉没用的、整理有用的。`,body:`我列出占空间的大文件和重复文件,先给你看清单,你点头我再动;重要的整理进资源库。`,kind:`CHAT`,prompt:`帮我整理工作区和共享文件夹:先列出大文件、重复文件和很久没动的文件,给我一份清单;在我确认之前不要删除任何东西。`}]}]};function b(e){return e.toLowerCase().startsWith(`zh`)?y:v}function x(e){return{id:e.id,emoji:e.emoji,title:e.title,detail:e.body,prompt:e.prompt,kind:e.kind.toLowerCase(),time:e.time,category:e.category}}var S=o(),C=[{id:`planning`,label:`Planning`,emoji:`🗓️`},{id:`goals`,label:`Goals`,emoji:`🎯`},{id:`research`,label:`Research`,emoji:`🔍`},{id:`money`,label:`Money`,emoji:`💰`},{id:`health`,label:`Health`,emoji:`🌿`},{id:`home`,label:`Home`,emoji:`🏠`},{id:`learning`,label:`Learning`,emoji:`📚`},{id:`people`,label:`People`,emoji:`👥`},{id:`files`,label:`Files & tools`,emoji:`📄`},{id:`fun`,label:`Just for you`,emoji:`🎈`}];function w(){let{state:t,send:r,openThread:a,toast:o}=s(),[v,y]=(0,_.useState)(null),[C,w]=(0,_.useState)(!1),E=t.profile?.name??`nanoMuse`,D=n(),O=i(),k=async(e=!1)=>{w(!0);try{let t=await l.ideas(e);y(t),t.error&&o(D(`Could not refresh ideas: {error}`,{error:t.error}))}catch(e){o(e.message)}finally{w(!1)}};(0,_.useEffect)(()=>{k(!1)},[]);let A=v?.source===`model`&&v.ideas.length>0,j=A?T(v.ideas):b(O).sections.map(e=>({id:e.id,title:e.title,ideas:e.ideas.map(x)})),[M,N]=(0,_.useState)(null),P=e=>{N(null),r(`main`,e.prompt).catch(e=>o(e.message||D(`Could not send`))),a(`main`)},F=async e=>{N(null);let t=e.time&&/^([01]\d|2[0-3]):[0-5]\d$/.test(e.time)?e.time:`09:00`;try{await l.createReminder({text:e.prompt,kind:`task`,repeat:`daily ${t}`}),o(D(`Routine set: every day at {time}. It is listed under Goals.`,{time:t}))}catch(e){o(e.message)}},I=e=>{N(null);let t=f.find(t=>t.id===e.category)??f[f.length-1],n=D(`I'd like to create a {category} goal. Ask me a few short questions, one at a time (what exactly I want, why and by when, how often to check in), then create it with concrete steps using the goals tool.`,{category:D(t.label)});r(`main`,`${n} ${e.prompt}`).catch(e=>o(e.message||D(`Could not send`))),a(`main`)},L=e=>e.kind===`routine`||e.kind===`goal`?e.kind:`chat`;return(0,S.jsxs)(`div`,{className:`flex h-full flex-col`,children:[(0,S.jsx)(d,{title:D(`Ideas`),children:(0,S.jsx)(`button`,{type:`button`,onClick:()=>void k(!0),disabled:C,"aria-label":D(`Refresh ideas`),className:`flex h-10 w-10 items-center justify-center rounded-full bg-surface text-fg shadow-[0_1px_4px_rgba(0,0,0,0.14)] disabled:opacity-60 dark:border dark:border-border dark:shadow-none`,children:C?(0,S.jsx)(c,{size:20,className:`animate-spin`}):(0,S.jsx)(u,{size:19})})}),(0,S.jsxs)(`div`,{className:`flex-1 overflow-y-auto pb-6`,children:[j.map(({id:e,title:t,ideas:n},r)=>(0,S.jsxs)(`section`,{children:[(r>0||!A)&&(0,S.jsx)(`h2`,{className:`px-5 pt-[22px] pb-1 text-[20px] font-bold`,children:A?D(t):t}),(0,S.jsx)(`ul`,{children:n.map(e=>(0,S.jsxs)(`li`,{children:[(0,S.jsxs)(`button`,{type:`button`,onClick:()=>N({idea:e,emoji:e.emoji}),className:`flex w-full items-start gap-4 px-5 py-3.5 text-left active:bg-surface-2/70`,children:[(0,S.jsx)(`span`,{className:`flex w-10 shrink-0 justify-center text-[28px] leading-[34px]`,children:e.emoji}),(0,S.jsxs)(`span`,{className:`min-w-0 flex-1 space-y-1`,children:[(0,S.jsx)(`span`,{className:`block text-[16px] font-semibold leading-[22px]`,children:e.title}),e.detail&&(0,S.jsx)(`span`,{className:`line-clamp-4 block text-[13.5px] leading-[19px] text-muted`,children:e.detail})]})]}),(0,S.jsx)(`div`,{className:`ml-[76px] mr-5 border-b border-border/70`})]},e.title))})]},e)),v&&(0,S.jsx)(`div`,{className:`px-5 pt-4 text-[12.5px] text-muted`,children:v.source===`model`?D(`Generated {when}`,{when:e(v.generated_at)}):D(`Starter ideas. Refresh once {name} knows you better.`,{name:E})})]}),(0,S.jsx)(m,{open:M!==null,onClose:()=>N(null),children:M&&(0,S.jsxs)(`div`,{className:`px-1 pb-2`,children:[(0,S.jsxs)(`div`,{className:`flex items-center gap-3`,children:[(0,S.jsx)(`span`,{className:`text-[30px] leading-none`,children:M.emoji}),(0,S.jsx)(`h3`,{className:`flex-1 text-[18px] font-bold leading-6`,children:M.idea.title})]}),M.idea.detail&&(0,S.jsx)(`p`,{className:`mt-3 text-[15px] leading-[22px]`,children:M.idea.detail}),(0,S.jsxs)(`div`,{className:`mt-3.5 flex items-center gap-1.5 text-[13px] text-muted`,children:[L(M.idea)===`routine`&&(0,S.jsxs)(S.Fragment,{children:[(0,S.jsx)(h,{size:16}),` `,D(`Creates a routine`),M.idea.time?` · ${M.idea.time}`:``]}),L(M.idea)===`goal`&&(0,S.jsxs)(S.Fragment,{children:[(0,S.jsx)(g,{size:16}),` `,D(`Creates a goal`)]}),L(M.idea)===`chat`&&(0,S.jsxs)(S.Fragment,{children:[(0,S.jsx)(p,{size:16}),` `,D(`Starts a conversation`)]})]}),L(M.idea)===`routine`&&(0,S.jsxs)(`button`,{type:`button`,onClick:()=>void F(M.idea),className:`mt-[22px] flex h-[50px] w-full items-center justify-center gap-2 rounded-full bg-accent text-[16px] font-semibold text-accent-fg`,children:[(0,S.jsx)(h,{size:18}),` `,D(`Create routine`)]}),L(M.idea)===`goal`&&(0,S.jsxs)(`button`,{type:`button`,onClick:()=>I(M.idea),className:`mt-[22px] flex h-[50px] w-full items-center justify-center gap-2 rounded-full bg-accent text-[16px] font-semibold text-accent-fg`,children:[(0,S.jsx)(g,{size:18}),` `,D(`Start goal`)]}),L(M.idea)===`chat`&&(0,S.jsxs)(`button`,{type:`button`,onClick:()=>P(M.idea),className:`mt-[22px] flex h-[50px] w-full items-center justify-center gap-2 rounded-full bg-accent text-[16px] font-semibold text-accent-fg`,children:[(0,S.jsx)(p,{size:18}),` `,D(`Send to chat`)]})]})})]})}function T(e){let t=C[C.length-1],n=C.map(e=>({id:e.id,title:e.label,ideas:[]}));for(let r of e){let e=C.find(e=>e.id===(r.area||t.id))??t;(n.find(t=>t.id===e.id)??n[n.length-1]).ideas.push({...r,emoji:e.emoji})}return n.filter(e=>e.ideas.length>0)}export{w as IdeasScreen}; \ No newline at end of file +import{A as e,J as t,K as n,Q as r,W as i,Y as a,b as o,f as s,q as c,x as l}from"./MuseHeader-Pw-NI98v.js";import{t as u}from"./refresh-cw-BKgIzslL.js";import{f as d,m as f,ot as p,w as m,yt as h}from"./index-CIdGZ5PB.js";var g=t(`flag`,[[`path`,{d:`M4 22V4a1 1 0 0 1 .4-.8A6 6 0 0 1 8 2c3 0 5 2 7.333 2q2 0 3.067-.8A1 1 0 0 1 20 4v10a1 1 0 0 1-.4.8A6 6 0 0 1 16 16c-3 0-5-2-8-2a6 6 0 0 0-4 1.528`,key:`1jaruq`}]]),_=r(a(),1),v={sections:[{id:`travel`,title:`Travel`,ideas:[{id:`train-watch`,emoji:`🚄`,title:`Tell me where you're going and when; I'll watch for seats and lower fares.`,body:`I set up the lookup tools in my sandbox, check trains, classes and availability as often as you like, and tell you the moment something opens up. Booking and paying stay in your hands.`,kind:`GOAL`,category:`other`,prompt:`I want to watch a train route: ask me for the origin, destination, date and acceptable departure window, then set up a goal that checks availability regularly.`},{id:`trip-plan`,emoji:`🗺️`,title:`Name a city and a number of days; I'll plan an itinerary you can follow as is.`,body:`Weather, opening hours and travel time between stops go into a day-by-day plan saved to your Library. Change one sentence and I'll rearrange the rest.`,kind:`CHAT`,prompt:`Help me plan a trip. Ask me where, how many days, with whom, a rough budget and the style I like, then give me a day-by-day itinerary as a file.`},{id:`commute-brief`,emoji:`🚦`,title:`Before you leave each morning, I'll tell you the traffic, the weather and the first thing on your plate.`,body:`A morning routine: I check the weather where you are, the traffic on your commute, glance at your calendar and boil the morning down to three sentences.`,kind:`ROUTINE`,time:`07:30`,prompt:`Morning brief: check today's weather and commute traffic, read my calendar for today, and tell me in at most five sentences the three things that matter most and what to bring.`},{id:`parcel-track`,emoji:`📦`,title:`Send me a tracking number; I'll tell you where the parcel is and when it lands.`,body:`I follow the shipment through the carrier's tracking, tell you about every new scan, and remind you to keep the phone nearby on delivery day.`,kind:`CHAT`,prompt:`Help me track a parcel. Ask me for the tracking number and carrier, check the current status once, then set a routine that checks every morning and reminds me the day before delivery.`}]},{id:`work`,title:`Work`,ideas:[{id:`meeting-prep`,emoji:`📝`,title:`Ten minutes before a meeting, I'll have the background and the questions ready.`,body:`I read the meeting's title and attendees from your calendar, look through what we've discussed and what you've put in the Library, and hand you one page: purpose, talking points, three questions worth asking.`,kind:`ROUTINE`,time:`08:50`,prompt:`Look at the meetings on my calendar today and prepare a one-page brief for each: the purpose, the points I should make, and three questions worth asking.`},{id:`weekly-review`,emoji:`📊`,title:`Every Friday afternoon, I'll review what you did this week and what next week needs.`,body:`From our conversations, your calendar and the notes I keep, I list what got done, what didn't, and three priorities for next week, as a draft you can send.`,kind:`ROUTINE`,time:`17:00`,prompt:`Write my weekly review: from this week's conversations, my calendar and what you remember, list what was completed, what is still open, and three priorities for next week. Save it as a Markdown file.`},{id:`inbox-triage`,emoji:`📬`,title:`Dump a pile of messages or emails on me; I'll sort them and draft the replies.`,body:`Paste text or screenshots. I sort them into 'reply today', 'this week' and 'just so you know', and draft each reply so you only need to edit and send.`,kind:`CHAT`,prompt:`I'm handing you a batch of messages to triage: sort them into 'reply today / this week / just so you know' and draft a reply for each one that needs it. Ask me to paste the content first.`},{id:`doc-digest`,emoji:`📄`,title:`Long documents, PDFs, web pages: I'll read them and give you the three-minute version.`,body:`Drop the file in a shared folder or send me the link. You get the conclusions, the key numbers and the decisions you need to make; ask follow-ups any time.`,kind:`CHAT`,prompt:`I have something long for you to read and summarise: ask me for the file or link, then give me conclusions, key numbers and decisions I need to make, at most five bullets each.`}]},{id:`life`,title:`Everyday`,ideas:[{id:`price-watch`,emoji:`🏷️`,title:`Tell me what you want to buy; the moment it hits your price, you'll know.`,body:`I check the product page on a schedule, keep the price history, and notify you at your target. Ordering and paying are yours; I don't touch them.`,kind:`GOAL`,category:`finance`,prompt:`I want to watch the price of a product: ask me for the link or name, my target price and how often to check, then create a goal that alerts me when it drops.`},{id:`photo-sort`,emoji:`🖼️`,title:`Mount your photos and I'll sort screenshots and pictures by what's in them.`,body:`Once your gallery is mounted as a shared folder I look at each image (receipts, chat screenshots, landscapes, documents), file it into the right folder and note anything important.`,kind:`CHAT`,prompt:`Help me sort my photos: ask me to mount the gallery in Shared Folders first, then sort by content (receipts, screenshots, scenery, documents, other) and list what you did.`},{id:`meal-log`,emoji:`🥗`,title:`Photograph what you eat; I'll estimate the calories and keep the log.`,body:`A photo or a sentence is enough: I estimate nutrition and calories, log it in the day's memory, and give you a summary each evening with one small suggestion for tomorrow.`,kind:`CHAT`,prompt:`From now on, log my meals: whenever I send a photo or a description, estimate calories and nutrition and write it into today's memory. Tell me first how best to send them.`},{id:`subscriptions`,emoji:`🔁`,title:`Send me your bills; I'll list every subscription that charges you each month, and you decide which to stop.`,body:`Give me bill screenshots or statements. I list every recurring charge, its next date and the yearly total; you decide what to cancel and I walk you through each cancellation.`,kind:`CHAT`,prompt:`Audit my subscriptions: ask me for bill screenshots or statements, then list every recurring charge, its next billing date and the yearly total, and flag the ones I may not need.`}]},{id:`learn`,title:`Learning`,ideas:[{id:`daily-words`,emoji:`🔤`,title:`Five new words every morning, a quick quiz every night.`,body:`You pick the language and level; I pick words by theme with examples and a memory hook, quiz you in the evening, and bring back the ones you missed.`,kind:`ROUTINE`,time:`08:00`,prompt:`Daily vocabulary: pick five new words for me (ask which language, level and topics first), each with a definition, one example sentence and a memory hook, plus a review quiz on yesterday's words.`},{id:`study-plan`,emoji:`🎯`,title:`Something you want to learn? I'll break it into weekly chunks and keep you honest.`,body:`Tell me the goal and the hours you can spare; I lay out four to eight weeks, check progress weekly, and adjust the pace so you actually finish.`,kind:`GOAL`,category:`interests`,prompt:`I want to learn something new and stick with it: ask me what, my current level, hours per week and the timeframe, then create a goal with a weekly progress check.`},{id:`explain`,emoji:`💡`,title:`Send me a concept you don't get; I'll explain it with things you already know.`,body:`I ask what you already understand and start from there, then check with two quick questions and leave you a flashcard if you want one.`,kind:`CHAT`,prompt:`There's a concept I don't understand: ask me what it is and what related things I already know, explain it with analogies, then check with two short questions.`},{id:`reading-notes`,emoji:`📚`,title:`Finished a book? I'll turn it into notes you'll actually reread.`,body:`Tell me the highlights, or send the passages you marked. I write structured notes into your Library and remember what stayed with you.`,kind:`CHAT`,prompt:`Help me write notes on a book: ask me the title, the three things that struck me most and the quotes I want to keep, then save structured Markdown notes.`}]},{id:`family`,title:`Family & friends`,ideas:[{id:`birthdays`,emoji:`🎂`,title:`Birthdays and anniversaries: I remind you a week ahead, gift ideas included.`,body:`Give me names and dates and I keep them. A week before each one I remind you, with a few gift directions based on what you've told me about them.`,kind:`CHAT`,prompt:`Remember the birthdays and anniversaries of the people who matter to me: ask for the list and dates, store them in long-term memory, and set a routine that reminds me a week before each.`},{id:`keep-in-touch`,emoji:`💬`,title:`Lost touch with old friends? Once a week I'll suggest who to reach out to, and how to start.`,body:`Give me a list of people you want to stay close to. I rotate through them and write a natural opening line based on what you last talked about.`,kind:`ROUTINE`,time:`19:00`,prompt:`Weekly keep-in-touch: from my list of people I want to stay close to, pick the one I've gone longest without contacting, remind me, and write a natural opening line based on what I noted about our last conversation.`},{id:`family-calendar`,emoji:`📅`,title:`Tell me the family's plans and I'll put them on the calendar and catch clashes.`,body:`Kids' lessons, a parent's appointment, a weekend get-together: one sentence and it's in the calendar; if two things collide, I say so first.`,kind:`CHAT`,prompt:`Help me run the family calendar: I'll tell you plans as they come up; write them into the calendar, confirm each before creating it, and warn me about conflicts.`},{id:`gift-ideas`,emoji:`🎁`,title:`Describe the person and I'll give you gift ideas that aren't the obvious ones.`,body:`Budget, relationship, what they're into lately: three questions, then five directions with one line each on why it fits.`,kind:`CHAT`,prompt:`Help me think of a gift: ask who it's for, my budget, their interests and what's going on in their life, then give me five directions with one line of reasoning each.`}]},{id:`more`,title:`More ideas`,ideas:[{id:`id-renewal`,emoji:`🪪`,title:`Tell me when your documents expire; I'll book the renewal and prep the paperwork list.`,body:`Passport, licence, visa: I note the dates, remind you three months ahead, list the documents and the office, and look up appointment slots where I can.`,kind:`CHAT`,prompt:`Help me track document expiry: ask which documents I have and when they expire, store them in memory, and set a reminder three months ahead of each with the renewal checklist.`},{id:`personality-quiz`,emoji:`❓`,title:`Two small questions a day; after a week I'll tell you what I've noticed about you.`,body:`Light questions, quick answers. I keep them and, once a week, write a short observation about your preferences and rhythm so I understand you better.`,kind:`ROUTINE`,time:`21:00`,prompt:`Two questions a day: ask me two small questions about preferences, habits or how things are going (never repeat one), store the answers in memory; every Sunday add a short observation about my week.`},{id:`event-plan`,emoji:`🎉`,title:`Name the occasion; I'll plan the run of show and draft the invitation.`,body:`Birthday, team outing, family dinner: give me the headcount, budget and date, and you get a timeline, a shopping list and an invitation you can send as is.`,kind:`CHAT`,prompt:`Help me plan an event: ask me the occasion, date, headcount and budget, then give me a timeline, a to-do list and an invitation text I can send.`},{id:`phone-cleanup`,emoji:`🧹`,title:`Let me look through the sandbox and shared folders; I'll clear the junk and organise the rest.`,body:`I list the big files and duplicates, show you the list first and only act when you say so; anything worth keeping goes into the Library.`,kind:`CHAT`,prompt:`Help me tidy the workspace and shared folders: list large files, duplicates and files untouched for a long time, and give me the list. Do not delete anything before I confirm.`}]}]},y={sections:[{id:`travel`,title:`出行`,ideas:[{id:`train-watch`,emoji:`🚄`,title:`告诉我你要去哪、哪天走,我盯着 12306 的余票和低价票。`,body:`我会在沙盒里装好查询工具,按你说的频率查车次、席别和余票,有票或价格合适时马上通知你;订票和付款那一步留给你自己点。`,kind:`GOAL`,category:`other`,prompt:`我想盯一趟火车票:请先问我出发地、目的地、日期和可接受的车次时段,然后为我建一个定期检查余票的目标。`},{id:`trip-plan`,emoji:`🗺️`,title:`说一个城市和几天,我给你排一份能直接照着走的行程。`,body:`我会查天气、开放时间和两点之间的路程,把每天的顺序排顺,写成一份文件放进资源库;你改一句,我就重排。`,kind:`CHAT`,prompt:`帮我规划一次出行。先问我去哪、几天、和谁、预算大概多少、喜欢什么风格,再给我一份按天排好的行程文件。`},{id:`commute-brief`,emoji:`🚦`,title:`每天出门前,我告诉你今天的路况、天气和第一件事。`,body:`一条早间例程:查你所在城市的天气、通勤路线的路况,翻一下日历,把上午的安排浓缩成三句话推给你。`,kind:`ROUTINE`,time:`07:30`,prompt:`早间简报:查询今天的天气和通勤路况,读取我今天的日历安排,用不超过五句话告诉我今天最重要的三件事和出门要带的东西。`},{id:`parcel-track`,emoji:`📦`,title:`把快递单号发我,到哪了、什么时候到,我随时告诉你。`,body:`我会用快递查询接口跟踪包裹,有新的物流节点就更新你;派送当天提醒你留意电话。`,kind:`CHAT`,prompt:`帮我跟踪一个快递。先问我单号和快递公司,然后查一次当前进度,并设一个每天早上检查一次、到派送前一天提醒我的例程。`}]},{id:`work`,title:`工作`,ideas:[{id:`meeting-prep`,emoji:`📝`,title:`开会前十分钟,我把这场会的背景和该问的问题整理好。`,body:`读日历里的会议主题和参会人,翻我们聊过的相关内容和你放进资源库的资料,给你一页纸:目的、要点、三个值得问的问题。`,kind:`ROUTINE`,time:`08:50`,prompt:`查看我今天日历里接下来的会议,为每一场准备一页会前提纲:这场会的目的、需要我发言的要点、三个值得提出的问题。`},{id:`weekly-review`,emoji:`📊`,title:`每周五下午,我帮你回顾这一周做了什么,下周该抓什么。`,body:`从我们的对话、你的日历和我记下的备忘里,整理出本周完成的事、没做完的事和下周的三个重点,写成一份周报草稿。`,kind:`ROUTINE`,time:`17:00`,prompt:`写一份本周回顾:根据我们这周的对话、我的日历和你记住的事项,列出完成了什么、什么没做完、下周三个重点,保存为一份 Markdown 文件。`},{id:`inbox-triage`,emoji:`📬`,title:`把一堆消息或邮件丢给我,我分好轻重缓急,写好回复草稿。`,body:`粘贴文字或截图给我,我按“今天必须回、这周处理、只需知道”分类,把每条要回的先拟好一版,你改一改就能发。`,kind:`CHAT`,prompt:`我要把一批消息交给你整理:请按“今天必须回 / 这周处理 / 只需知道”分类,并为需要回复的每一条写好回复草稿。请先让我粘贴内容。`},{id:`doc-digest`,emoji:`📄`,title:`长文档、PDF、网页,我读完给你三分钟版本。`,body:`把文件放进共享文件夹或把链接发我,我提炼结论、关键数字和你需要做的决定,问题可以接着追问。`,kind:`CHAT`,prompt:`我有一份长内容需要你读并总结:请先让我提供文件或链接,然后给我结论、关键数字、需要我做的决定三部分,每部分不超过五条。`}]},{id:`life`,title:`生活`,ideas:[{id:`price-watch`,emoji:`🏷️`,title:`想买的东西告诉我,降到你说的价格我立刻告诉你。`,body:`我会定期去商品页看价格,记录走势;到价就通知你。下单和付款由你来点,我不会碰。`,kind:`GOAL`,category:`finance`,prompt:`我想盯一件商品的价格:请先问我商品链接或名称、目标价格和检查频率,然后建一个到价提醒我的目标。`},{id:`photo-sort`,emoji:`🖼️`,title:`把相册挂给我,我按内容给截图和照片分类整理。`,body:`在「共享文件夹」里挂载相册后,我会看图识别内容(票据、聊天截图、风景、证件),归到对应文件夹,重要的信息顺手记下来。`,kind:`CHAT`,prompt:`帮我整理照片:请先让我在共享文件夹里挂载相册目录,然后按内容(票据、截图、风景、证件、其他)分类整理,并把整理结果列给我。`},{id:`meal-log`,emoji:`🥗`,title:`拍下你吃的,我帮你估热量、记下每一餐。`,body:`发一张照片或一句话,我估算营养和热量,记进当天的日记;晚上给你一天的小结和明天的一个小建议。`,kind:`CHAT`,prompt:`从现在起帮我记录饮食:每次我发照片或描述,估算热量与营养并记入当天记忆;请先告诉我怎么发给你最方便。`},{id:`subscriptions`,emoji:`🔁`,title:`帮你把每月自动扣费的订阅列出来,看看哪些该停。`,body:`把账单截图或消费记录给我,我列出所有周期性扣费、下一次扣款日和一年花多少;你决定停哪个,退订的步骤我一步步陪你走。`,kind:`CHAT`,prompt:`帮我盘点订阅扣费:请先让我提供账单截图或记录,然后列出所有周期性扣费、下一次扣款日、年费合计,并标出可能不再需要的。`}]},{id:`learn`,title:`学习`,ideas:[{id:`daily-words`,emoji:`🔤`,title:`每天早上五个新词,晚上考你一遍。`,body:`你定语言和难度,我按主题挑词、给例句和记忆点,晚上出五道小题,错的第二天再来。`,kind:`ROUTINE`,time:`08:00`,prompt:`每日词汇:为我挑五个新词(先问我学什么语言、什么水平和感兴趣的主题),每个给释义、一个例句和一个记忆点,并附上昨天的复习题。`},{id:`study-plan`,emoji:`🎯`,title:`有个想学会的东西?我陪你拆成每周能做完的小块。`,body:`告诉我目标和每周能投入的时间,我排一份四到八周的计划,每周检查进度、调整难度,帮你坚持到最后。`,kind:`GOAL`,category:`interests`,prompt:`我想学一样新东西并坚持下去:请先问我想学什么、现在的水平、每周能投入多少时间和希望多久见效,然后帮我建一个每周检查进度的目标。`},{id:`explain`,emoji:`💡`,title:`看不懂的概念发给我,我用你熟悉的东西讲明白。`,body:`先问你已经懂什么,再从那里出发讲;讲完出两道题确认你真懂了,需要的话给你一张记忆卡。`,kind:`CHAT`,prompt:`我有一个不太懂的概念想让你讲明白:请先问我这个概念是什么、我已经了解哪些相关知识,然后用类比讲解,最后出两道小题检验。`},{id:`reading-notes`,emoji:`📚`,title:`读完一本书,我帮你整理成能重读的笔记。`,body:`你说重点和感受,或者把划线的句子发我,我整理成结构化笔记,存进资源库,并记住你的收获。`,kind:`CHAT`,prompt:`帮我整理一本书的读书笔记:请先问我书名、最触动我的三点和我想记住的引文,然后整理成结构化的 Markdown 笔记并保存。`}]},{id:`family`,title:`家庭与关系`,ideas:[{id:`birthdays`,emoji:`🎂`,title:`重要的人的生日和纪念日,我提前一周提醒,顺手想好礼物。`,body:`把名字和日期告诉我,我记住;到日子前一周提醒你,并根据你说过的 TA 的喜好给几个礼物方向。`,kind:`CHAT`,prompt:`帮我记住重要的人的生日和纪念日:请先问我名单和日期,记入长期记忆,并为每个日期设一个提前一周提醒我的例程。`},{id:`keep-in-touch`,emoji:`💬`,title:`老朋友太久没联系?我每周提醒你该找谁聊聊,帮你开个头。`,body:`你给我一份想保持联系的名单,我按间隔轮着提醒,并根据上次聊的内容帮你写一句自然的开场。`,kind:`ROUTINE`,time:`19:00`,prompt:`每周联系提醒:从我告诉你的“想保持联系的人”名单里,挑一位最近最久没联系的,提醒我,并根据我记录过的上次聊天内容写一句自然的开场白。`},{id:`family-calendar`,emoji:`📅`,title:`把全家的安排告诉我,我帮你排进日历、发现冲突。`,body:`孩子的课、家人的门诊、周末的聚会,说一句我就写进日历,时间撞了我先提醒你。`,kind:`CHAT`,prompt:`帮我管理家庭日程:我会陆续告诉你家人的安排,请写进日历,创建前先复述确认,发现时间冲突时提醒我。`},{id:`gift-ideas`,emoji:`🎁`,title:`说说 TA 是什么样的人,我给你几个不落俗套的礼物点子。`,body:`预算、关系、TA 最近在忙什么,三个问题之后我给你五个方向,每个附一句为什么合适。`,kind:`CHAT`,prompt:`帮我想礼物:请先问我送给谁、预算、TA 的兴趣和最近的生活状态,然后给我五个礼物方向,每个附一句理由。`}]},{id:`more`,title:`更多点子`,ideas:[{id:`id-renewal`,emoji:`🪪`,title:`告诉我证件到期时间,我提前预约续签,把材料清单准备好。`,body:`护照、驾照、签证,我记下到期日,提前三个月提醒,列出所需材料和办理地点,能预约的帮你查好时段。`,kind:`CHAT`,prompt:`帮我管理证件到期:请先问我有哪些证件和到期日期,记入长期记忆,并为每一个设置提前三个月的提醒,附上续办所需材料清单。`},{id:`personality-quiz`,emoji:`❓`,title:`每天两个小问题,一周后我告诉你我发现了什么样的你。`,body:`问题很轻,回答很快;我把答案记下来,每周整理成一段关于你偏好和节奏的观察,方便我更懂你。`,kind:`ROUTINE`,time:`21:00`,prompt:`每日两问:问我两个关于偏好、习惯或近况的小问题(不重复以前问过的),把回答记入记忆;每周日额外给我一段关于我这周状态的观察。`},{id:`event-plan`,emoji:`🎉`,title:`说个场合,我帮你安排流程、拟好邀请。`,body:`生日、团建、家宴,人数、预算和日期告诉我,我给你时间线、采购清单和一段可以直接发出去的邀请文字。`,kind:`CHAT`,prompt:`帮我策划一次活动:请先问我场合、日期、人数和预算,然后给我时间线、待办清单和一段可直接发送的邀请文字。`},{id:`phone-cleanup`,emoji:`🧹`,title:`让我看看沙盒和共享文件夹里有什么,清掉没用的、整理有用的。`,body:`我列出占空间的大文件和重复文件,先给你看清单,你点头我再动;重要的整理进资源库。`,kind:`CHAT`,prompt:`帮我整理工作区和共享文件夹:先列出大文件、重复文件和很久没动的文件,给我一份清单;在我确认之前不要删除任何东西。`}]}]};function b(e){return e.toLowerCase().startsWith(`zh`)?y:v}function x(e){return{id:e.id,emoji:e.emoji,title:e.title,detail:e.body,prompt:e.prompt,kind:e.kind.toLowerCase(),time:e.time,category:e.category}}var S=o(),C=[{id:`planning`,label:`Planning`,emoji:`🗓️`},{id:`goals`,label:`Goals`,emoji:`🎯`},{id:`research`,label:`Research`,emoji:`🔍`},{id:`money`,label:`Money`,emoji:`💰`},{id:`health`,label:`Health`,emoji:`🌿`},{id:`home`,label:`Home`,emoji:`🏠`},{id:`learning`,label:`Learning`,emoji:`📚`},{id:`people`,label:`People`,emoji:`👥`},{id:`files`,label:`Files & tools`,emoji:`📄`},{id:`fun`,label:`Just for you`,emoji:`🎈`}];function w(){let{state:t,send:r,openThread:a,toast:o}=s(),[v,y]=(0,_.useState)(null),[C,w]=(0,_.useState)(!1),E=t.profile?.name??`nanoMuse`,D=n(),O=i(),k=async(e=!1)=>{w(!0);try{let t=await l.ideas(e);y(t),t.error&&o(D(`Could not refresh ideas: {error}`,{error:t.error}))}catch(e){o(e.message)}finally{w(!1)}};(0,_.useEffect)(()=>{k(!1)},[]);let A=v?.source===`model`&&v.ideas.length>0,j=A?T(v.ideas):b(O).sections.map(e=>({id:e.id,title:e.title,ideas:e.ideas.map(x)})),[M,N]=(0,_.useState)(null),P=e=>{N(null),r(`main`,e.prompt).catch(e=>o(e.message||D(`Could not send`))),a(`main`)},F=async e=>{N(null);let t=e.time&&/^([01]\d|2[0-3]):[0-5]\d$/.test(e.time)?e.time:`09:00`;try{await l.createReminder({text:e.prompt,kind:`task`,repeat:`daily ${t}`}),o(D(`Routine set: every day at {time}. It is listed under Goals.`,{time:t}))}catch(e){o(e.message)}},I=e=>{N(null);let t=f.find(t=>t.id===e.category)??f[f.length-1],n=D(`I'd like to create a {category} goal. Ask me a few short questions, one at a time (what exactly I want, why and by when, how often to check in), then create it with concrete steps using the goals tool.`,{category:D(t.label)});r(`main`,`${n} ${e.prompt}`).catch(e=>o(e.message||D(`Could not send`))),a(`main`)},L=e=>e.kind===`routine`||e.kind===`goal`?e.kind:`chat`;return(0,S.jsxs)(`div`,{className:`flex h-full flex-col`,children:[(0,S.jsx)(d,{title:D(`Ideas`),children:(0,S.jsx)(`button`,{type:`button`,onClick:()=>void k(!0),disabled:C,"aria-label":D(`Refresh ideas`),className:`flex h-10 w-10 items-center justify-center rounded-full bg-surface text-fg shadow-[0_1px_4px_rgba(0,0,0,0.14)] disabled:opacity-60 dark:border dark:border-border dark:shadow-none`,children:C?(0,S.jsx)(c,{size:20,className:`animate-spin`}):(0,S.jsx)(u,{size:19})})}),(0,S.jsxs)(`div`,{className:`flex-1 overflow-y-auto pb-6`,children:[j.map(({id:e,title:t,ideas:n},r)=>(0,S.jsxs)(`section`,{children:[(r>0||!A)&&(0,S.jsx)(`h2`,{className:`px-5 pt-[22px] pb-1 text-[20px] font-bold`,children:A?D(t):t}),(0,S.jsx)(`ul`,{children:n.map(e=>(0,S.jsxs)(`li`,{children:[(0,S.jsxs)(`button`,{type:`button`,onClick:()=>N({idea:e,emoji:e.emoji}),className:`flex w-full items-start gap-4 px-5 py-3.5 text-left active:bg-surface-2/70`,children:[(0,S.jsx)(`span`,{className:`flex w-10 shrink-0 justify-center text-[28px] leading-[34px]`,children:e.emoji}),(0,S.jsxs)(`span`,{className:`min-w-0 flex-1 space-y-1`,children:[(0,S.jsx)(`span`,{className:`block text-[16px] font-semibold leading-[22px]`,children:e.title}),e.detail&&(0,S.jsx)(`span`,{className:`line-clamp-4 block text-[13.5px] leading-[19px] text-muted`,children:e.detail})]})]}),(0,S.jsx)(`div`,{className:`ml-[76px] mr-5 border-b border-border/70`})]},e.title))})]},e)),v&&(0,S.jsx)(`div`,{className:`px-5 pt-4 text-[12.5px] text-muted`,children:v.source===`model`?D(`Generated {when}`,{when:e(v.generated_at)}):D(`Starter ideas. Refresh once {name} knows you better.`,{name:E})})]}),(0,S.jsx)(m,{open:M!==null,onClose:()=>N(null),children:M&&(0,S.jsxs)(`div`,{className:`px-1 pb-2`,children:[(0,S.jsxs)(`div`,{className:`flex items-center gap-3`,children:[(0,S.jsx)(`span`,{className:`text-[30px] leading-none`,children:M.emoji}),(0,S.jsx)(`h3`,{className:`flex-1 text-[18px] font-bold leading-6`,children:M.idea.title})]}),M.idea.detail&&(0,S.jsx)(`p`,{className:`mt-3 text-[15px] leading-[22px]`,children:M.idea.detail}),(0,S.jsxs)(`div`,{className:`mt-3.5 flex items-center gap-1.5 text-[13px] text-muted`,children:[L(M.idea)===`routine`&&(0,S.jsxs)(S.Fragment,{children:[(0,S.jsx)(h,{size:16}),` `,D(`Creates a routine`),M.idea.time?` · ${M.idea.time}`:``]}),L(M.idea)===`goal`&&(0,S.jsxs)(S.Fragment,{children:[(0,S.jsx)(g,{size:16}),` `,D(`Creates a goal`)]}),L(M.idea)===`chat`&&(0,S.jsxs)(S.Fragment,{children:[(0,S.jsx)(p,{size:16}),` `,D(`Starts a conversation`)]})]}),L(M.idea)===`routine`&&(0,S.jsxs)(`button`,{type:`button`,onClick:()=>void F(M.idea),className:`mt-[22px] flex h-[50px] w-full items-center justify-center gap-2 rounded-full bg-accent text-[16px] font-semibold text-accent-fg`,children:[(0,S.jsx)(h,{size:18}),` `,D(`Create routine`)]}),L(M.idea)===`goal`&&(0,S.jsxs)(`button`,{type:`button`,onClick:()=>I(M.idea),className:`mt-[22px] flex h-[50px] w-full items-center justify-center gap-2 rounded-full bg-accent text-[16px] font-semibold text-accent-fg`,children:[(0,S.jsx)(g,{size:18}),` `,D(`Start goal`)]}),L(M.idea)===`chat`&&(0,S.jsxs)(`button`,{type:`button`,onClick:()=>P(M.idea),className:`mt-[22px] flex h-[50px] w-full items-center justify-center gap-2 rounded-full bg-accent text-[16px] font-semibold text-accent-fg`,children:[(0,S.jsx)(p,{size:18}),` `,D(`Send to chat`)]})]})})]})}function T(e){let t=C[C.length-1],n=C.map(e=>({id:e.id,title:e.label,ideas:[]}));for(let r of e){let e=C.find(e=>e.id===(r.area||t.id))??t;(n.find(t=>t.id===e.id)??n[n.length-1]).ideas.push({...r,emoji:e.emoji})}return n.filter(e=>e.ideas.length>0)}export{w as IdeasScreen}; \ No newline at end of file diff --git a/nanomuse/server/static/assets/IdentityForm-Dhx4FiQY.js b/nanomuse/server/static/assets/IdentityForm-BTGczGT_.js similarity index 97% rename from nanomuse/server/static/assets/IdentityForm-Dhx4FiQY.js rename to nanomuse/server/static/assets/IdentityForm-BTGczGT_.js index bcc66917e..38f94da52 100644 --- a/nanomuse/server/static/assets/IdentityForm-Dhx4FiQY.js +++ b/nanomuse/server/static/assets/IdentityForm-BTGczGT_.js @@ -1 +1 @@ -import{E as e,J as t,K as n,Q as r,Y as i,b as a,i as o}from"./MuseHeader-Pw-NI98v.js";import{r as s}from"./AvatarPicker-oSjVM8L3.js";var c=t(`shuffle`,[[`path`,{d:`m18 14 4 4-4 4`,key:`10pe0f`}],[`path`,{d:`m18 2 4 4-4 4`,key:`pucp1d`}],[`path`,{d:`M2 18h1.973a4 4 0 0 0 3.3-1.7l5.454-8.6a4 4 0 0 1 3.3-1.7H22`,key:`1ailkh`}],[`path`,{d:`M2 6h1.972a4 4 0 0 1 3.6 2.2`,key:`km57vx`}],[`path`,{d:`M22 18h-6.041a4 4 0 0 1-3.3-1.8l-.359-.45`,key:`os18l9`}]]),l=r(i(),1),u=a(),d=[`Muse`,`Veda`,`Nova`,`Pip`,`Sage`,`Juno`,`Kit`,`Wren`,`Iris`,`Milo`,`Echo`,`Remy`,`Otto`,`Luna`,`Ari`,`Bea`,`Nico`,`Zed`,`小墨`,`阿柒`,`小满`,`知了`,`豆豆`,`小竹`],f=[`formal`,`casual`,`playful`,`concise`],p=[`short`,`detailed`,`bullets`],m={formal:`Formal`,casual:`Casual`,playful:`Playful`,concise:`Concise`},h={short:`Short replies`,detailed:`Detailed`,bullets:`Bullet points`};function g(e,t){let n=d.filter(t=>t!==e),r=[],i=t||1,a=[...n];for(;r.length<6&&a.length;)i=(i*9301+49297)%233280,r.push(a.splice(i%a.length,1)[0]);return r}function _({active:t,onClick:n,children:r}){return(0,u.jsx)(`button`,{type:`button`,onClick:n,className:e(`rounded-full px-3 py-1.5 text-[13px] border transition-colors`,t?`border-accent bg-accent/10 text-accent font-medium`:`border-border text-muted`),children:r})}function v({value:t,onChange:r,suggestions:i=!0,askUserName:a=!0,inputCls:d,onStudio:v}){let y=n(),b=(0,l.useId)(),[x,S]=(0,l.useState)(7),C=(0,l.useMemo)(()=>g(t.name,x),[t.name,x]),w=e=>r({...t,...e}),T={...t,proactivity:`default`,proactive:!0,goal_interval_minutes:60,quiet_hours:``};return(0,u.jsxs)(`div`,{className:`space-y-5`,children:[(0,u.jsxs)(`div`,{className:`flex items-start gap-4`,children:[(0,u.jsx)(o,{profile:T,size:72}),(0,u.jsxs)(`div`,{className:`flex-1 min-w-0 space-y-2`,children:[(0,u.jsx)(`div`,{children:(0,u.jsx)(`input`,{value:t.name,onChange:e=>w({name:e.target.value.slice(0,20)}),maxLength:20,className:e(d,`text-[17px] font-medium`),placeholder:`nanoMuse`,"aria-label":y(`Name`),autoCapitalize:`words`})}),(0,u.jsx)(`input`,{value:t.tagline,onChange:e=>w({tagline:e.target.value.slice(0,60)}),maxLength:60,className:e(d,`text-[14px]`),placeholder:y(`A line under the name, e.g. Your day, sorted.`),"aria-label":y(`Tagline`)})]})]}),i&&(0,u.jsxs)(`div`,{className:`flex flex-wrap items-center gap-1.5`,children:[C.map(e=>(0,u.jsx)(_,{active:t.name===e,onClick:()=>w({name:e}),children:e},e)),(0,u.jsx)(`button`,{type:`button`,onClick:()=>S(e=>e+1),"aria-label":y(`More names`),className:`rounded-full border border-border p-1.5 text-muted`,children:(0,u.jsx)(c,{size:14})})]}),(0,u.jsx)(s,{value:{avatar:t.avatar,emoji:t.emoji,color:t.color},onChange:e=>w(e),onStudio:v}),(0,u.jsxs)(`div`,{children:[(0,u.jsx)(`label`,{className:`text-[12px] text-muted`,children:y(`Tone`)}),(0,u.jsx)(`div`,{className:`mt-1.5 flex flex-wrap gap-1.5`,children:f.map(e=>(0,u.jsx)(_,{active:t.tone===e,onClick:()=>w({tone:t.tone===e?``:e}),children:y(m[e])},e))})]}),(0,u.jsxs)(`div`,{children:[(0,u.jsx)(`label`,{className:`text-[12px] text-muted`,children:y(`How much it says`)}),(0,u.jsx)(`div`,{className:`mt-1.5 flex flex-wrap gap-1.5`,children:p.map(e=>(0,u.jsx)(_,{active:t.communication===e,onClick:()=>w({communication:t.communication===e?``:e}),children:y(h[e])},e))})]}),(0,u.jsxs)(`div`,{children:[(0,u.jsx)(`label`,{htmlFor:`${b}-style`,className:`text-[12px] text-muted`,children:y(`Anything else about how it should be`)}),(0,u.jsx)(`textarea`,{id:`${b}-style`,value:t.style,onChange:e=>w({style:e.target.value}),rows:2,placeholder:y(`e.g. A little witty. Uses metric units. Never uses emoji.`),className:e(d,`mt-1 resize-none text-[14px]`)})]}),a&&(0,u.jsxs)(`div`,{children:[(0,u.jsx)(`label`,{htmlFor:`${b}-user`,className:`text-[12px] text-muted`,children:y(`What it calls you`)}),(0,u.jsx)(`input`,{id:`${b}-user`,value:t.user_name,onChange:e=>w({user_name:e.target.value}),maxLength:60,placeholder:y(`Your name`),className:e(d,`mt-1 text-[14px]`)})]})]})}function y(e,t,n){return{name:e?.name??`nanoMuse`,tagline:e?.tagline??``,avatar:e?.avatar??t,emoji:e?.emoji??`✨`,color:e?.color??n,tone:e?.tone??``,communication:e?.communication??``,style:e?.style??``,user_name:e?.user_name??``}}function b(e){return{...e,name:e.name.trim()||`nanoMuse`,tagline:e.tagline.trim(),style:e.style.trim(),user_name:e.user_name.trim()}}export{b as n,y as r,v as t}; \ No newline at end of file +import{E as e,J as t,K as n,Q as r,Y as i,b as a,i as o}from"./MuseHeader-Pw-NI98v.js";import{r as s}from"./AvatarPicker-gR2knlot.js";var c=t(`shuffle`,[[`path`,{d:`m18 14 4 4-4 4`,key:`10pe0f`}],[`path`,{d:`m18 2 4 4-4 4`,key:`pucp1d`}],[`path`,{d:`M2 18h1.973a4 4 0 0 0 3.3-1.7l5.454-8.6a4 4 0 0 1 3.3-1.7H22`,key:`1ailkh`}],[`path`,{d:`M2 6h1.972a4 4 0 0 1 3.6 2.2`,key:`km57vx`}],[`path`,{d:`M22 18h-6.041a4 4 0 0 1-3.3-1.8l-.359-.45`,key:`os18l9`}]]),l=r(i(),1),u=a(),d=[`Muse`,`Veda`,`Nova`,`Pip`,`Sage`,`Juno`,`Kit`,`Wren`,`Iris`,`Milo`,`Echo`,`Remy`,`Otto`,`Luna`,`Ari`,`Bea`,`Nico`,`Zed`,`小墨`,`阿柒`,`小满`,`知了`,`豆豆`,`小竹`],f=[`formal`,`casual`,`playful`,`concise`],p=[`short`,`detailed`,`bullets`],m={formal:`Formal`,casual:`Casual`,playful:`Playful`,concise:`Concise`},h={short:`Short replies`,detailed:`Detailed`,bullets:`Bullet points`};function g(e,t){let n=d.filter(t=>t!==e),r=[],i=t||1,a=[...n];for(;r.length<6&&a.length;)i=(i*9301+49297)%233280,r.push(a.splice(i%a.length,1)[0]);return r}function _({active:t,onClick:n,children:r}){return(0,u.jsx)(`button`,{type:`button`,onClick:n,className:e(`rounded-full px-3 py-1.5 text-[13px] border transition-colors`,t?`border-accent bg-accent/10 text-accent font-medium`:`border-border text-muted`),children:r})}function v({value:t,onChange:r,suggestions:i=!0,askUserName:a=!0,inputCls:d,onStudio:v}){let y=n(),b=(0,l.useId)(),[x,S]=(0,l.useState)(7),C=(0,l.useMemo)(()=>g(t.name,x),[t.name,x]),w=e=>r({...t,...e}),T={...t,proactivity:`default`,proactive:!0,goal_interval_minutes:60,quiet_hours:``};return(0,u.jsxs)(`div`,{className:`space-y-5`,children:[(0,u.jsxs)(`div`,{className:`flex items-start gap-4`,children:[(0,u.jsx)(o,{profile:T,size:72}),(0,u.jsxs)(`div`,{className:`flex-1 min-w-0 space-y-2`,children:[(0,u.jsx)(`div`,{children:(0,u.jsx)(`input`,{value:t.name,onChange:e=>w({name:e.target.value.slice(0,20)}),maxLength:20,className:e(d,`text-[17px] font-medium`),placeholder:`nanoMuse`,"aria-label":y(`Name`),autoCapitalize:`words`})}),(0,u.jsx)(`input`,{value:t.tagline,onChange:e=>w({tagline:e.target.value.slice(0,60)}),maxLength:60,className:e(d,`text-[14px]`),placeholder:y(`A line under the name, e.g. Your day, sorted.`),"aria-label":y(`Tagline`)})]})]}),i&&(0,u.jsxs)(`div`,{className:`flex flex-wrap items-center gap-1.5`,children:[C.map(e=>(0,u.jsx)(_,{active:t.name===e,onClick:()=>w({name:e}),children:e},e)),(0,u.jsx)(`button`,{type:`button`,onClick:()=>S(e=>e+1),"aria-label":y(`More names`),className:`rounded-full border border-border p-1.5 text-muted`,children:(0,u.jsx)(c,{size:14})})]}),(0,u.jsx)(s,{value:{avatar:t.avatar,emoji:t.emoji,color:t.color},onChange:e=>w(e),onStudio:v}),(0,u.jsxs)(`div`,{children:[(0,u.jsx)(`label`,{className:`text-[12px] text-muted`,children:y(`Tone`)}),(0,u.jsx)(`div`,{className:`mt-1.5 flex flex-wrap gap-1.5`,children:f.map(e=>(0,u.jsx)(_,{active:t.tone===e,onClick:()=>w({tone:t.tone===e?``:e}),children:y(m[e])},e))})]}),(0,u.jsxs)(`div`,{children:[(0,u.jsx)(`label`,{className:`text-[12px] text-muted`,children:y(`How much it says`)}),(0,u.jsx)(`div`,{className:`mt-1.5 flex flex-wrap gap-1.5`,children:p.map(e=>(0,u.jsx)(_,{active:t.communication===e,onClick:()=>w({communication:t.communication===e?``:e}),children:y(h[e])},e))})]}),(0,u.jsxs)(`div`,{children:[(0,u.jsx)(`label`,{htmlFor:`${b}-style`,className:`text-[12px] text-muted`,children:y(`Anything else about how it should be`)}),(0,u.jsx)(`textarea`,{id:`${b}-style`,value:t.style,onChange:e=>w({style:e.target.value}),rows:2,placeholder:y(`e.g. A little witty. Uses metric units. Never uses emoji.`),className:e(d,`mt-1 resize-none text-[14px]`)})]}),a&&(0,u.jsxs)(`div`,{children:[(0,u.jsx)(`label`,{htmlFor:`${b}-user`,className:`text-[12px] text-muted`,children:y(`What it calls you`)}),(0,u.jsx)(`input`,{id:`${b}-user`,value:t.user_name,onChange:e=>w({user_name:e.target.value}),maxLength:60,placeholder:y(`Your name`),className:e(d,`mt-1 text-[14px]`)})]})]})}function y(e,t,n){return{name:e?.name??`nanoMuse`,tagline:e?.tagline??``,avatar:e?.avatar??t,emoji:e?.emoji??`✨`,color:e?.color??n,tone:e?.tone??``,communication:e?.communication??``,style:e?.style??``,user_name:e?.user_name??``}}function b(e){return{...e,name:e.name.trim()||`nanoMuse`,tagline:e.tagline.trim(),style:e.style.trim(),user_name:e.user_name.trim()}}export{b as n,y as r,v as t}; \ No newline at end of file diff --git a/nanomuse/server/static/assets/LibraryScreen-U8NV3qaf.js b/nanomuse/server/static/assets/LibraryScreen-B8JlrC_n.js similarity index 98% rename from nanomuse/server/static/assets/LibraryScreen-U8NV3qaf.js rename to nanomuse/server/static/assets/LibraryScreen-B8JlrC_n.js index 89f28dace..a5701e101 100644 --- a/nanomuse/server/static/assets/LibraryScreen-U8NV3qaf.js +++ b/nanomuse/server/static/assets/LibraryScreen-B8JlrC_n.js @@ -1 +1 @@ -import{D as e,E as t,J as n,K as r,Q as i,S as a,Y as o,b as s,f as c,q as l,x as u}from"./MuseHeader-Pw-NI98v.js";import{C as d,I as f,X as p,_t as m,f as h,mt as g,pt as _,xt as v}from"./index-BjYzdKkG.js";var y=n(`file-image`,[[`path`,{d:`M6 22a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h8a2.4 2.4 0 0 1 1.704.706l3.588 3.588A2.4 2.4 0 0 1 20 8v12a2 2 0 0 1-2 2z`,key:`1oefj6`}],[`path`,{d:`M14 2v5a1 1 0 0 0 1 1h5`,key:`wfsgrz`}],[`circle`,{cx:`10`,cy:`12`,r:`2`,key:`737tya`}],[`path`,{d:`m20 17-1.296-1.296a2.41 2.41 0 0 0-3.408 0L9 22`,key:`wt3hpn`}]]),b=n(`file-spreadsheet`,[[`path`,{d:`M6 22a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h8a2.4 2.4 0 0 1 1.704.706l3.588 3.588A2.4 2.4 0 0 1 20 8v12a2 2 0 0 1-2 2z`,key:`1oefj6`}],[`path`,{d:`M14 2v5a1 1 0 0 0 1 1h5`,key:`wfsgrz`}],[`path`,{d:`M8 13h2`,key:`yr2amv`}],[`path`,{d:`M14 13h2`,key:`un5t4a`}],[`path`,{d:`M8 17h2`,key:`2yhykz`}],[`path`,{d:`M14 17h2`,key:`10kma7`}]]),x=n(`library-big`,[[`rect`,{width:`8`,height:`18`,x:`3`,y:`3`,rx:`1`,key:`oynpb5`}],[`path`,{d:`M7 3v18`,key:`bbkbws`}],[`path`,{d:`M20.4 18.9c.2.5-.1 1.1-.6 1.3l-1.9.7c-.5.2-1.1-.1-1.3-.6L11.1 5.1c-.2-.5.1-1.1.6-1.3l1.9-.7c.5-.2 1.1.1 1.3.6Z`,key:`1qboyk`}]]),S=i(o(),1),C=s(),w=new Set([`png`,`jpg`,`jpeg`,`gif`,`webp`,`svg`,`heic`,`mp3`,`wav`,`m4a`,`ogg`,`flac`,`mp4`,`mov`,`webm`,`mkv`]);function T(e){return w.has(e.toLowerCase().split(`.`).pop()??``)}function E(){let{state:e,openFile:t}=c(),[n,i]=(0,S.useState)(null),[a,o]=(0,S.useState)(null),[s,f]=(0,S.useState)(0),[m,g]=(0,S.useState)(0),[_,v]=(0,S.useState)(``),y=r(),b=Object.values(e.events).reduce((e,t)=>e+t.length,0);(0,S.useEffect)(()=>{let e=!0;return u.files(500).then(t=>{e&&(i(t),o(null))}).catch(t=>e&&o(t.message)),()=>{e=!1}},[b,e.feedVersion,s]);let w=(0,S.useMemo)(()=>{let e=_.trim().toLowerCase();return(n??[]).filter(t=>T(t.name)===(m===1)&&(!e||t.path.toLowerCase().includes(e)))},[n,m,_]);return(0,C.jsxs)(`div`,{className:`flex h-full flex-col`,children:[(0,C.jsx)(h,{title:y(`Library`)}),(0,C.jsxs)(`div`,{className:`shrink-0 px-4 pt-1 pb-2.5`,children:[(0,C.jsx)(D,{labels:[y(`Artifacts`),y(`Media`)],selected:m,onSelect:e=>g(e)}),(n?.length??0)>8&&(0,C.jsxs)(`label`,{className:`mt-2.5 flex items-center gap-2 rounded-full bg-surface-2 px-3.5 py-2`,children:[(0,C.jsx)(p,{size:16,className:`text-muted`}),(0,C.jsx)(`input`,{value:_,onChange:e=>v(e.target.value),placeholder:y(`Search files`),className:`flex-1 bg-transparent text-[14.5px] outline-none`})]})]}),(0,C.jsxs)(`div`,{className:`flex-1 overflow-y-auto pb-6`,children:[n===null&&a&&(0,C.jsx)(d,{message:a,onRetry:()=>f(e=>e+1)}),n===null&&!a&&(0,C.jsx)(`div`,{className:`flex justify-center py-10 text-muted`,children:(0,C.jsx)(l,{className:`animate-spin`,size:20})}),n!==null&&w.length===0&&(0,C.jsxs)(`div`,{className:`flex flex-col items-center px-8 pt-9 text-center`,children:[(0,C.jsx)(x,{size:34,className:`text-muted`}),(0,C.jsx)(`div`,{className:`mt-3.5 text-[16px] font-medium text-muted`,children:y(_?`No files match.`:m===0?`Nothing created yet`:`No media yet`)}),!_&&(0,C.jsx)(`p`,{className:`mt-1 text-[12px] text-muted`,children:y(m===0?`Documents, tables and pages I write for you will show up here.`:`Photos, screenshots and recordings I produce will show up here.`)})]}),(0,C.jsx)(`ul`,{children:w.map(e=>(0,C.jsx)(`li`,{children:(0,C.jsx)(O,{file:e,onOpen:()=>t(e.path)})},e.path))})]})]})}function D({labels:e,selected:n,onSelect:r}){return(0,C.jsx)(`div`,{role:`tablist`,className:`flex h-12 w-full rounded-full border border-border bg-surface p-1`,children:e.map((e,i)=>(0,C.jsx)(`button`,{type:`button`,role:`tab`,"aria-selected":i===n,onClick:()=>r(i),className:t(`flex-1 rounded-full text-[14px] font-semibold transition`,i===n?`bg-surface-2`:`bg-transparent`),children:e},e))})}function O({file:t,onOpen:n}){let r=e(t.name),i=r===`html`?(0,C.jsx)(_,{size:22}):r===`image`?(0,C.jsx)(y,{size:22}):r===`data`?(0,C.jsx)(b,{size:22}):r===`code`?(0,C.jsx)(m,{size:22}):r===`event`?(0,C.jsx)(v,{size:22}):(0,C.jsx)(g,{size:22}),o=t.path.includes(`/`)?t.path.slice(0,t.path.lastIndexOf(`/`)):``;return(0,C.jsxs)(`button`,{type:`button`,onClick:n,className:`flex w-full items-center gap-3.5 px-4 py-2 text-left active:bg-surface-2/70`,children:[(0,C.jsx)(`span`,{className:`flex h-[46px] w-[46px] shrink-0 items-center justify-center overflow-hidden rounded-[10px] bg-surface-2 text-muted`,children:r===`image`?(0,C.jsx)(`img`,{src:a(t.path),alt:``,loading:`lazy`,className:`h-full w-full object-cover`}):i}),(0,C.jsxs)(`span`,{className:`min-w-0 flex-1 space-y-0.5`,children:[(0,C.jsx)(`span`,{className:`block truncate text-[15px] font-medium`,children:t.name}),(0,C.jsx)(`span`,{className:`block truncate text-[12px] text-muted`,children:[f(t.modified),k(t.size),o].filter(Boolean).join(` · `)})]})]})}function k(e){return e<1024?`${e} B`:e<1048576?`${(e/1024).toFixed(+(e<10240))} KB`:`${(e/1024/1024).toFixed(1)} MB`}export{E as LibraryScreen}; \ No newline at end of file +import{D as e,E as t,J as n,K as r,Q as i,S as a,Y as o,b as s,f as c,q as l,x as u}from"./MuseHeader-Pw-NI98v.js";import{C as d,I as f,X as p,_t as m,f as h,mt as g,pt as _,xt as v}from"./index-CIdGZ5PB.js";var y=n(`file-image`,[[`path`,{d:`M6 22a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h8a2.4 2.4 0 0 1 1.704.706l3.588 3.588A2.4 2.4 0 0 1 20 8v12a2 2 0 0 1-2 2z`,key:`1oefj6`}],[`path`,{d:`M14 2v5a1 1 0 0 0 1 1h5`,key:`wfsgrz`}],[`circle`,{cx:`10`,cy:`12`,r:`2`,key:`737tya`}],[`path`,{d:`m20 17-1.296-1.296a2.41 2.41 0 0 0-3.408 0L9 22`,key:`wt3hpn`}]]),b=n(`file-spreadsheet`,[[`path`,{d:`M6 22a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h8a2.4 2.4 0 0 1 1.704.706l3.588 3.588A2.4 2.4 0 0 1 20 8v12a2 2 0 0 1-2 2z`,key:`1oefj6`}],[`path`,{d:`M14 2v5a1 1 0 0 0 1 1h5`,key:`wfsgrz`}],[`path`,{d:`M8 13h2`,key:`yr2amv`}],[`path`,{d:`M14 13h2`,key:`un5t4a`}],[`path`,{d:`M8 17h2`,key:`2yhykz`}],[`path`,{d:`M14 17h2`,key:`10kma7`}]]),x=n(`library-big`,[[`rect`,{width:`8`,height:`18`,x:`3`,y:`3`,rx:`1`,key:`oynpb5`}],[`path`,{d:`M7 3v18`,key:`bbkbws`}],[`path`,{d:`M20.4 18.9c.2.5-.1 1.1-.6 1.3l-1.9.7c-.5.2-1.1-.1-1.3-.6L11.1 5.1c-.2-.5.1-1.1.6-1.3l1.9-.7c.5-.2 1.1.1 1.3.6Z`,key:`1qboyk`}]]),S=i(o(),1),C=s(),w=new Set([`png`,`jpg`,`jpeg`,`gif`,`webp`,`svg`,`heic`,`mp3`,`wav`,`m4a`,`ogg`,`flac`,`mp4`,`mov`,`webm`,`mkv`]);function T(e){return w.has(e.toLowerCase().split(`.`).pop()??``)}function E(){let{state:e,openFile:t}=c(),[n,i]=(0,S.useState)(null),[a,o]=(0,S.useState)(null),[s,f]=(0,S.useState)(0),[m,g]=(0,S.useState)(0),[_,v]=(0,S.useState)(``),y=r(),b=Object.values(e.events).reduce((e,t)=>e+t.length,0);(0,S.useEffect)(()=>{let e=!0;return u.files(500).then(t=>{e&&(i(t),o(null))}).catch(t=>e&&o(t.message)),()=>{e=!1}},[b,e.feedVersion,s]);let w=(0,S.useMemo)(()=>{let e=_.trim().toLowerCase();return(n??[]).filter(t=>T(t.name)===(m===1)&&(!e||t.path.toLowerCase().includes(e)))},[n,m,_]);return(0,C.jsxs)(`div`,{className:`flex h-full flex-col`,children:[(0,C.jsx)(h,{title:y(`Library`)}),(0,C.jsxs)(`div`,{className:`shrink-0 px-4 pt-1 pb-2.5`,children:[(0,C.jsx)(D,{labels:[y(`Artifacts`),y(`Media`)],selected:m,onSelect:e=>g(e)}),(n?.length??0)>8&&(0,C.jsxs)(`label`,{className:`mt-2.5 flex items-center gap-2 rounded-full bg-surface-2 px-3.5 py-2`,children:[(0,C.jsx)(p,{size:16,className:`text-muted`}),(0,C.jsx)(`input`,{value:_,onChange:e=>v(e.target.value),placeholder:y(`Search files`),className:`flex-1 bg-transparent text-[14.5px] outline-none`})]})]}),(0,C.jsxs)(`div`,{className:`flex-1 overflow-y-auto pb-6`,children:[n===null&&a&&(0,C.jsx)(d,{message:a,onRetry:()=>f(e=>e+1)}),n===null&&!a&&(0,C.jsx)(`div`,{className:`flex justify-center py-10 text-muted`,children:(0,C.jsx)(l,{className:`animate-spin`,size:20})}),n!==null&&w.length===0&&(0,C.jsxs)(`div`,{className:`flex flex-col items-center px-8 pt-9 text-center`,children:[(0,C.jsx)(x,{size:34,className:`text-muted`}),(0,C.jsx)(`div`,{className:`mt-3.5 text-[16px] font-medium text-muted`,children:y(_?`No files match.`:m===0?`Nothing created yet`:`No media yet`)}),!_&&(0,C.jsx)(`p`,{className:`mt-1 text-[12px] text-muted`,children:y(m===0?`Documents, tables and pages I write for you will show up here.`:`Photos, screenshots and recordings I produce will show up here.`)})]}),(0,C.jsx)(`ul`,{children:w.map(e=>(0,C.jsx)(`li`,{children:(0,C.jsx)(O,{file:e,onOpen:()=>t(e.path)})},e.path))})]})]})}function D({labels:e,selected:n,onSelect:r}){return(0,C.jsx)(`div`,{role:`tablist`,className:`flex h-12 w-full rounded-full border border-border bg-surface p-1`,children:e.map((e,i)=>(0,C.jsx)(`button`,{type:`button`,role:`tab`,"aria-selected":i===n,onClick:()=>r(i),className:t(`flex-1 rounded-full text-[14px] font-semibold transition`,i===n?`bg-surface-2`:`bg-transparent`),children:e},e))})}function O({file:t,onOpen:n}){let r=e(t.name),i=r===`html`?(0,C.jsx)(_,{size:22}):r===`image`?(0,C.jsx)(y,{size:22}):r===`data`?(0,C.jsx)(b,{size:22}):r===`code`?(0,C.jsx)(m,{size:22}):r===`event`?(0,C.jsx)(v,{size:22}):(0,C.jsx)(g,{size:22}),o=t.path.includes(`/`)?t.path.slice(0,t.path.lastIndexOf(`/`)):``;return(0,C.jsxs)(`button`,{type:`button`,onClick:n,className:`flex w-full items-center gap-3.5 px-4 py-2 text-left active:bg-surface-2/70`,children:[(0,C.jsx)(`span`,{className:`flex h-[46px] w-[46px] shrink-0 items-center justify-center overflow-hidden rounded-[10px] bg-surface-2 text-muted`,children:r===`image`?(0,C.jsx)(`img`,{src:a(t.path),alt:``,loading:`lazy`,className:`h-full w-full object-cover`}):i}),(0,C.jsxs)(`span`,{className:`min-w-0 flex-1 space-y-0.5`,children:[(0,C.jsx)(`span`,{className:`block truncate text-[15px] font-medium`,children:t.name}),(0,C.jsx)(`span`,{className:`block truncate text-[12px] text-muted`,children:[f(t.modified),k(t.size),o].filter(Boolean).join(` · `)})]})]})}function k(e){return e<1024?`${e} B`:e<1048576?`${(e/1024).toFixed(+(e<10240))} KB`:`${(e/1024/1024).toFixed(1)} MB`}export{E as LibraryScreen}; \ No newline at end of file diff --git a/nanomuse/server/static/assets/MemoryScreen-B5a6LPAu.js b/nanomuse/server/static/assets/MemoryScreen-M8j03G3u.js similarity index 98% rename from nanomuse/server/static/assets/MemoryScreen-B5a6LPAu.js rename to nanomuse/server/static/assets/MemoryScreen-M8j03G3u.js index 6b9c43d78..c49d41a42 100644 --- a/nanomuse/server/static/assets/MemoryScreen-B5a6LPAu.js +++ b/nanomuse/server/static/assets/MemoryScreen-M8j03G3u.js @@ -1 +1 @@ -import{A as e,J as t,K as n,Q as r,Y as i,b as a,f as o,q as s,x as c}from"./MuseHeader-Pw-NI98v.js";import{C as l,St as u,V as d,W as f,Z as p}from"./index-BjYzdKkG.js";import{t as m}from"./BackBar-Dli0L0O_.js";var h=t(`undo-2`,[[`path`,{d:`M9 14 4 9l5-5`,key:`102s5s`}],[`path`,{d:`M4 9h10.5a5.5 5.5 0 0 1 5.5 5.5a5.5 5.5 0 0 1-5.5 5.5H11`,key:`f3b9sd`}]]),g=r(i(),1),_=a(),v=[`profile`,`preference`,`people`,`routine`,`constraint`,`general`];function y(){let{state:t,toast:r,openThread:i,setTab:a}=o(),[y,b]=(0,g.useState)(null),[x,S]=(0,g.useState)(null),[C,w]=(0,g.useState)([]),[T,E]=(0,g.useState)(``),[D,O]=(0,g.useState)(`profile`),[k,A]=(0,g.useState)(!1),[j,M]=(0,g.useState)(!1),N=t.profile?.name??`nanoMuse`,P=n(),F=()=>Promise.all([c.memory().then(b),c.memoryChanges().then(w)]).then(()=>S(null)).catch(e=>y===null?S(e.message):r(e.message));(0,g.useEffect)(()=>{F()},[t.memoryVersion]);let I=(0,g.useMemo)(()=>{let e=new Map;for(let t of y??[])e.set(t.category,[...e.get(t.category)??[],t]);return[...e.entries()].sort((e,t)=>t[1].length-e[1].length)},[y]),L=async()=>{if(T.trim()){A(!0);try{await c.addMemory(T.trim(),D),E(``),await F()}catch(e){r(e.message)}finally{A(!1)}}},R=async e=>{if(window.confirm(P(`Forget “{text}”?`,{text:e.content.slice(0,60)})))try{await c.forgetMemory(e.id),b(t=>t?.filter(t=>t.id!==e.id)??t)}catch(e){r(e.message)}},z=async()=>{M(!0);try{let e=await c.tidyMemory();r(e.changed===0?P(`Nothing to tidy: {n} memories, all distinct.`,{n:e.considered}):P(`Tidied: {merged} merged, {dropped} dropped. Undo below if needed.`,{merged:e.merged.length,dropped:e.dropped.length})),await F()}catch(e){r(e.message)}finally{M(!1)}},B=async e=>{try{await c.restoreMemoryChange(e.id),await F()}catch(e){r(e.message)}};return(0,_.jsxs)(`div`,{className:`flex h-full flex-col`,children:[(0,_.jsx)(m,{title:P(`Memory`),description:P(`What {name} remembers about you. Read it, add to it, or make {name} forget; nothing here is hidden from you.`,{name:N}),actions:(y?.length??0)>=2&&(0,_.jsxs)(`button`,{type:`button`,disabled:j,onClick:()=>void z(),title:P(`Merge lines that say the same thing and drop what was never a fact about you. Every change can be undone.`),className:`flex h-10 items-center gap-1.5 rounded-full bg-surface px-3.5 text-[13.5px] font-medium shadow-[0_1px_4px_rgba(0,0,0,0.14)] disabled:opacity-50 dark:border dark:border-border dark:shadow-none`,children:[(0,_.jsx)(f,{size:15,className:j?`animate-pulse text-accent`:`text-accent`}),P(j?`Tidying…`:`Tidy up`)]})}),(0,_.jsxs)(`div`,{className:`flex-1 overflow-y-auto px-4 pb-6 space-y-5`,children:[(0,_.jsxs)(`div`,{className:`rounded-3xl bg-surface border border-border/70 shadow-sm p-3.5 space-y-2.5`,children:[(0,_.jsx)(`textarea`,{value:T,onChange:e=>E(e.target.value),rows:2,placeholder:P(`Tell {name} something to remember, e.g. “I'm vegetarian” or “My sister's birthday is 14 May”`,{name:N}),className:`w-full resize-none rounded-2xl bg-surface-2 px-3.5 py-2.5 text-[14.5px] outline-none focus:ring-2 focus:ring-accent/40`}),(0,_.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,_.jsx)(`select`,{value:D,onChange:e=>O(e.target.value),className:`rounded-2xl bg-surface-2 px-3 py-2 text-[13.5px] outline-none`,children:v.map(e=>(0,_.jsx)(`option`,{value:e,children:P(e)},e))}),(0,_.jsx)(`div`,{className:`flex-1`}),(0,_.jsxs)(`button`,{type:`button`,disabled:!T.trim()||k,onClick:()=>void L(),className:`rounded-2xl bg-accent text-accent-fg px-3.5 py-2 text-[14px] font-medium flex items-center gap-1.5 disabled:opacity-50`,children:[(0,_.jsx)(p,{size:16}),` `,P(`Remember`)]})]})]}),y===null&&x&&(0,_.jsx)(l,{message:x,onRetry:()=>void F()}),y===null&&!x&&(0,_.jsx)(`div`,{className:`flex justify-center py-10 text-muted`,children:(0,_.jsx)(s,{className:`animate-spin`,size:20})}),y!==null&&y.length===0&&(0,_.jsxs)(`div`,{className:`rounded-3xl border border-dashed border-border p-6 text-center`,children:[(0,_.jsx)(u,{className:`mx-auto text-accent`}),(0,_.jsx)(`div`,{className:`mt-2 font-semibold`,children:P(`Nothing remembered yet`)}),(0,_.jsx)(`p`,{className:`mt-1 text-[13.5px] text-muted`,children:P(`{name} saves durable facts you share in chat (preferences, people, routines) and never secrets.`,{name:N})}),(0,_.jsx)(`button`,{type:`button`,onClick:()=>{i(`main`),a(`chat`)},className:`mt-3 rounded-full bg-accent px-4 py-2 text-[13.5px] font-semibold text-accent-fg`,children:P(`Tell {name} something to remember`,{name:N})})]}),I.map(([t,n])=>(0,_.jsxs)(`section`,{children:[(0,_.jsxs)(`div`,{className:`px-1 mb-2 text-[12px] font-semibold uppercase tracking-wide text-muted`,children:[P(t),` · `,n.length]}),(0,_.jsx)(`ul`,{className:`rounded-3xl bg-surface border border-border/70 shadow-sm divide-y divide-border/70 overflow-hidden`,children:n.map(t=>(0,_.jsxs)(`li`,{className:`flex items-start gap-3 px-4 py-3`,children:[(0,_.jsxs)(`div`,{className:`flex-1 min-w-0`,children:[(0,_.jsx)(`div`,{className:`text-[14.5px] leading-snug break-words`,children:t.content}),(0,_.jsxs)(`div`,{className:`mt-0.5 text-[11.5px] text-muted`,children:[t.source===`user`?P(`added by you`):P(`saved by {name}`,{name:N}),` · `,e(t.created_at),t.updated_at?` · ${P(`updated {when}`,{when:e(t.updated_at)})}`:``]})]}),(0,_.jsx)(`button`,{type:`button`,"aria-label":P(`Forget`),onClick:()=>void R(t),className:`p-1.5 text-muted hover:text-rose-500`,children:(0,_.jsx)(d,{size:17})})]},t.id))})]},t)),C.length>0&&(0,_.jsxs)(`section`,{children:[(0,_.jsx)(`div`,{className:`px-1 mb-2 text-[12px] font-semibold uppercase tracking-wide text-muted`,children:P(`Recent changes`)}),(0,_.jsx)(`ul`,{className:`rounded-3xl bg-surface border border-border/70 shadow-sm divide-y divide-border/70 overflow-hidden`,children:C.map(t=>(0,_.jsx)(`li`,{className:`px-4 py-3 ${t.restored?`opacity-60`:``}`,children:(0,_.jsxs)(`div`,{className:`flex items-start gap-3`,children:[(0,_.jsxs)(`div`,{className:`flex-1 min-w-0 text-[13.5px] leading-snug`,children:[(0,_.jsxs)(`div`,{className:`text-muted`,children:[t.action===`merge`?P(`Merged`):t.action===`drop`?P(`Dropped`):P(`Updated`),t.reason?` · ${t.reason}`:``,` · `,e(t.at),t.restored?` · ${P(`restored`)}`:``]}),t.before.map(e=>(0,_.jsx)(`div`,{className:`break-words line-through text-muted`,children:e.content},e.id)),t.after&&(0,_.jsxs)(`div`,{className:`break-words`,children:[`→ `,t.after.content]})]}),!t.restored&&(0,_.jsxs)(`button`,{type:`button`,onClick:()=>void B(t),className:`shrink-0 rounded-xl bg-surface-2 px-2.5 py-1.5 text-[12.5px] font-medium flex items-center gap-1`,children:[(0,_.jsx)(h,{size:14}),` `,P(`Undo`)]})]})},t.id))})]})]})]})}export{y as MemoryScreen}; \ No newline at end of file +import{A as e,J as t,K as n,Q as r,Y as i,b as a,f as o,q as s,x as c}from"./MuseHeader-Pw-NI98v.js";import{C as l,St as u,V as d,W as f,Z as p}from"./index-CIdGZ5PB.js";import{t as m}from"./BackBar-Dl56jHZM.js";var h=t(`undo-2`,[[`path`,{d:`M9 14 4 9l5-5`,key:`102s5s`}],[`path`,{d:`M4 9h10.5a5.5 5.5 0 0 1 5.5 5.5a5.5 5.5 0 0 1-5.5 5.5H11`,key:`f3b9sd`}]]),g=r(i(),1),_=a(),v=[`profile`,`preference`,`people`,`routine`,`constraint`,`general`];function y(){let{state:t,toast:r,openThread:i,setTab:a}=o(),[y,b]=(0,g.useState)(null),[x,S]=(0,g.useState)(null),[C,w]=(0,g.useState)([]),[T,E]=(0,g.useState)(``),[D,O]=(0,g.useState)(`profile`),[k,A]=(0,g.useState)(!1),[j,M]=(0,g.useState)(!1),N=t.profile?.name??`nanoMuse`,P=n(),F=()=>Promise.all([c.memory().then(b),c.memoryChanges().then(w)]).then(()=>S(null)).catch(e=>y===null?S(e.message):r(e.message));(0,g.useEffect)(()=>{F()},[t.memoryVersion]);let I=(0,g.useMemo)(()=>{let e=new Map;for(let t of y??[])e.set(t.category,[...e.get(t.category)??[],t]);return[...e.entries()].sort((e,t)=>t[1].length-e[1].length)},[y]),L=async()=>{if(T.trim()){A(!0);try{await c.addMemory(T.trim(),D),E(``),await F()}catch(e){r(e.message)}finally{A(!1)}}},R=async e=>{if(window.confirm(P(`Forget “{text}”?`,{text:e.content.slice(0,60)})))try{await c.forgetMemory(e.id),b(t=>t?.filter(t=>t.id!==e.id)??t)}catch(e){r(e.message)}},z=async()=>{M(!0);try{let e=await c.tidyMemory();r(e.changed===0?P(`Nothing to tidy: {n} memories, all distinct.`,{n:e.considered}):P(`Tidied: {merged} merged, {dropped} dropped. Undo below if needed.`,{merged:e.merged.length,dropped:e.dropped.length})),await F()}catch(e){r(e.message)}finally{M(!1)}},B=async e=>{try{await c.restoreMemoryChange(e.id),await F()}catch(e){r(e.message)}};return(0,_.jsxs)(`div`,{className:`flex h-full flex-col`,children:[(0,_.jsx)(m,{title:P(`Memory`),description:P(`What {name} remembers about you. Read it, add to it, or make {name} forget; nothing here is hidden from you.`,{name:N}),actions:(y?.length??0)>=2&&(0,_.jsxs)(`button`,{type:`button`,disabled:j,onClick:()=>void z(),title:P(`Merge lines that say the same thing and drop what was never a fact about you. Every change can be undone.`),className:`flex h-10 items-center gap-1.5 rounded-full bg-surface px-3.5 text-[13.5px] font-medium shadow-[0_1px_4px_rgba(0,0,0,0.14)] disabled:opacity-50 dark:border dark:border-border dark:shadow-none`,children:[(0,_.jsx)(f,{size:15,className:j?`animate-pulse text-accent`:`text-accent`}),P(j?`Tidying…`:`Tidy up`)]})}),(0,_.jsxs)(`div`,{className:`flex-1 overflow-y-auto px-4 pb-6 space-y-5`,children:[(0,_.jsxs)(`div`,{className:`rounded-3xl bg-surface border border-border/70 shadow-sm p-3.5 space-y-2.5`,children:[(0,_.jsx)(`textarea`,{value:T,onChange:e=>E(e.target.value),rows:2,placeholder:P(`Tell {name} something to remember, e.g. “I'm vegetarian” or “My sister's birthday is 14 May”`,{name:N}),className:`w-full resize-none rounded-2xl bg-surface-2 px-3.5 py-2.5 text-[14.5px] outline-none focus:ring-2 focus:ring-accent/40`}),(0,_.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,_.jsx)(`select`,{value:D,onChange:e=>O(e.target.value),className:`rounded-2xl bg-surface-2 px-3 py-2 text-[13.5px] outline-none`,children:v.map(e=>(0,_.jsx)(`option`,{value:e,children:P(e)},e))}),(0,_.jsx)(`div`,{className:`flex-1`}),(0,_.jsxs)(`button`,{type:`button`,disabled:!T.trim()||k,onClick:()=>void L(),className:`rounded-2xl bg-accent text-accent-fg px-3.5 py-2 text-[14px] font-medium flex items-center gap-1.5 disabled:opacity-50`,children:[(0,_.jsx)(p,{size:16}),` `,P(`Remember`)]})]})]}),y===null&&x&&(0,_.jsx)(l,{message:x,onRetry:()=>void F()}),y===null&&!x&&(0,_.jsx)(`div`,{className:`flex justify-center py-10 text-muted`,children:(0,_.jsx)(s,{className:`animate-spin`,size:20})}),y!==null&&y.length===0&&(0,_.jsxs)(`div`,{className:`rounded-3xl border border-dashed border-border p-6 text-center`,children:[(0,_.jsx)(u,{className:`mx-auto text-accent`}),(0,_.jsx)(`div`,{className:`mt-2 font-semibold`,children:P(`Nothing remembered yet`)}),(0,_.jsx)(`p`,{className:`mt-1 text-[13.5px] text-muted`,children:P(`{name} saves durable facts you share in chat (preferences, people, routines) and never secrets.`,{name:N})}),(0,_.jsx)(`button`,{type:`button`,onClick:()=>{i(`main`),a(`chat`)},className:`mt-3 rounded-full bg-accent px-4 py-2 text-[13.5px] font-semibold text-accent-fg`,children:P(`Tell {name} something to remember`,{name:N})})]}),I.map(([t,n])=>(0,_.jsxs)(`section`,{children:[(0,_.jsxs)(`div`,{className:`px-1 mb-2 text-[12px] font-semibold uppercase tracking-wide text-muted`,children:[P(t),` · `,n.length]}),(0,_.jsx)(`ul`,{className:`rounded-3xl bg-surface border border-border/70 shadow-sm divide-y divide-border/70 overflow-hidden`,children:n.map(t=>(0,_.jsxs)(`li`,{className:`flex items-start gap-3 px-4 py-3`,children:[(0,_.jsxs)(`div`,{className:`flex-1 min-w-0`,children:[(0,_.jsx)(`div`,{className:`text-[14.5px] leading-snug break-words`,children:t.content}),(0,_.jsxs)(`div`,{className:`mt-0.5 text-[11.5px] text-muted`,children:[t.source===`user`?P(`added by you`):P(`saved by {name}`,{name:N}),` · `,e(t.created_at),t.updated_at?` · ${P(`updated {when}`,{when:e(t.updated_at)})}`:``]})]}),(0,_.jsx)(`button`,{type:`button`,"aria-label":P(`Forget`),onClick:()=>void R(t),className:`p-1.5 text-muted hover:text-rose-500`,children:(0,_.jsx)(d,{size:17})})]},t.id))})]},t)),C.length>0&&(0,_.jsxs)(`section`,{children:[(0,_.jsx)(`div`,{className:`px-1 mb-2 text-[12px] font-semibold uppercase tracking-wide text-muted`,children:P(`Recent changes`)}),(0,_.jsx)(`ul`,{className:`rounded-3xl bg-surface border border-border/70 shadow-sm divide-y divide-border/70 overflow-hidden`,children:C.map(t=>(0,_.jsx)(`li`,{className:`px-4 py-3 ${t.restored?`opacity-60`:``}`,children:(0,_.jsxs)(`div`,{className:`flex items-start gap-3`,children:[(0,_.jsxs)(`div`,{className:`flex-1 min-w-0 text-[13.5px] leading-snug`,children:[(0,_.jsxs)(`div`,{className:`text-muted`,children:[t.action===`merge`?P(`Merged`):t.action===`drop`?P(`Dropped`):P(`Updated`),t.reason?` · ${t.reason}`:``,` · `,e(t.at),t.restored?` · ${P(`restored`)}`:``]}),t.before.map(e=>(0,_.jsx)(`div`,{className:`break-words line-through text-muted`,children:e.content},e.id)),t.after&&(0,_.jsxs)(`div`,{className:`break-words`,children:[`→ `,t.after.content]})]}),!t.restored&&(0,_.jsxs)(`button`,{type:`button`,onClick:()=>void B(t),className:`shrink-0 rounded-xl bg-surface-2 px-2.5 py-1.5 text-[12.5px] font-medium flex items-center gap-1`,children:[(0,_.jsx)(h,{size:14}),` `,P(`Undo`)]})]})},t.id))})]})]})]})}export{y as MemoryScreen}; \ No newline at end of file diff --git a/nanomuse/server/static/assets/Onboarding-rP8qAahh.js b/nanomuse/server/static/assets/Onboarding-CtVO6gdK.js similarity index 97% rename from nanomuse/server/static/assets/Onboarding-rP8qAahh.js rename to nanomuse/server/static/assets/Onboarding-CtVO6gdK.js index 5f5f68766..b4d23db46 100644 --- a/nanomuse/server/static/assets/Onboarding-rP8qAahh.js +++ b/nanomuse/server/static/assets/Onboarding-CtVO6gdK.js @@ -1 +1 @@ -import{E as e,J as t,K as n,L as r,Q as i,Y as a,a as o,b as s,f as c,i as l,q as u,x as d}from"./MuseHeader-Pw-NI98v.js";import{A as f}from"./StarNudge-DjXecvWj.js";import{n as p}from"./external-link-Xj5fjR8v.js";import"./Form-DwKuBk1V.js";import{r as m}from"./IdentityForm-Dhx4FiQY.js";import{Et as h,bt as g,t as _,vt as v}from"./index-BjYzdKkG.js";import{t as y}from"./AvatarPicker-oSjVM8L3.js";import{CalendarCard as b,ContactsCard as x,EmailCard as S,ModelCard as C}from"./ConnectionsScreen-0U0bXAf7.js";var w=t(`lock`,[[`rect`,{width:`18`,height:`11`,x:`3`,y:`11`,rx:`2`,ry:`2`,key:`1w4ew1`}],[`path`,{d:`M7 11V7a5 5 0 0 1 10 0v4`,key:`fwvmzm`}]]),T=i(a(),1),E=s();function D(){let{state:t,setTab:i,dismissOnboarding:a,refreshSettings:s,toast:p}=c(),[w,D]=(0,T.useState)(`welcome`),[M,N]=(0,T.useState)(null),[P,F]=(0,T.useState)(!1),[I,L]=(0,T.useState)(!1),R=n(),z=async()=>{L(!0);try{await d.cloudUseAsModel(),p(R(`The Cloud model is in use.`)),await H()}catch(e){p(e.message)}finally{L(!1)}},[B,V]=(0,T.useState)(null),H=async()=>{try{V(null),N(await d.connections())}catch(e){V(R(e.message)||R(`Could not load the connections.`))}};(0,T.useEffect)(()=>{H()},[t.connectionsVersion]);let U=async()=>{try{await d.onboarded(!0),await s()}catch{}a(),i(`chat`)},W=async()=>{F(!0);try{await d.firstrunStart(r()===`zh-CN`?`zh`:`en`)}catch{await d.onboarded(!0).catch(()=>void 0)}try{await s()}catch{}F(!1),a(),i(`chat`)},G={...m(t.profile,o,y[0]),proactivity:`default`,proactive:!0,goal_interval_minutes:60,quiet_hours:``},K=M?M.llm.key_source===`vault`||M.llm.key_source===`config`||!!M.providers[j(M)]?.no_key:!1,q=!!M&&(M.email.configured||M.calendar.feeds.length>0||M.contacts.sources.length>0),J=[`welcome`,`list`],Y=w===`welcome`?0:1;return(0,E.jsxs)(`div`,{className:`mx-auto flex h-[100dvh] max-w-[760px] flex-col bg-bg sm:border-x sm:border-border`,children:[(0,E.jsx)(`div`,{className:`titlebar-room`}),(0,E.jsxs)(`header`,{className:`safe-top shrink-0 px-5 pt-4 pb-2 flex items-center justify-between`,children:[(0,E.jsx)(`div`,{className:`flex gap-1`,children:J.map((t,n)=>(0,E.jsx)(`span`,{className:e(`h-1.5 rounded-full transition-all`,n<=Y?`w-5 bg-accent`:`w-1.5 bg-border`)},t))}),(0,E.jsx)(`button`,{type:`button`,onClick:()=>void U(),className:`text-[13px] text-muted`,children:R(`Skip setup`)})]}),(0,E.jsxs)(`div`,{className:`flex-1 overflow-y-auto px-5 pb-6`,children:[w===`welcome`&&(0,E.jsxs)(`div`,{className:`flex h-full flex-col items-center justify-center text-center`,children:[(0,E.jsx)(l,{profile:G,size:96}),(0,E.jsx)(`h1`,{className:`mt-6 text-[28px] font-bold tracking-tight`,children:R(`Meet your nanoMuse`)}),(0,E.jsx)(`p`,{className:`mt-2 text-[15px] text-muted`,children:R(`A personal agent of your own. Three things to know:`)}),(0,E.jsxs)(`ul`,{className:`mt-6 w-full max-w-sm space-y-2.5 text-left`,children:[(0,E.jsx)(O,{n:1,title:R(`It does things for you.`),body:R(`Searches, browses, writes, books, reads mail, and hands you the result, not a list of links.`)}),(0,E.jsx)(O,{n:2,title:R(`It keeps working when you close the app.`),body:R(`Goals move forward between your visits; it reports in the Feed and notifies you when something is worth it.`)}),(0,E.jsx)(O,{n:3,title:R(`It asks you first where it matters.`),body:R(`A separate Sentinel reviews every action. Sending, paying, deleting: it stops and asks; your keys stay in a vault the model cannot read.`)})]}),(0,E.jsx)(`p`,{className:`mt-5 max-w-sm text-[13px] text-muted`,children:R(`There is no form to fill in: once it has a model, it introduces itself in the chat and asks what to call you.`)}),(0,E.jsx)(`p`,{className:`mt-2 max-w-sm text-[13px] text-muted`,children:(0,E.jsx)(`a`,{href:`https://nanomuse.cn/#open-source`,target:`_blank`,rel:`noreferrer`,className:`underline decoration-dotted underline-offset-2 hover:text-accent`,children:R(`nanoMuse is a non-profit open-source community project, free forever.`)})})]}),w===`list`&&(0,E.jsxs)(`div`,{className:`pt-6`,children:[(0,E.jsxs)(`div`,{className:`flex items-center gap-3`,children:[(0,E.jsx)(l,{profile:G,size:56}),(0,E.jsxs)(`div`,{className:`min-w-0`,children:[(0,E.jsx)(`h1`,{className:`text-[24px] font-bold tracking-tight truncate`,children:R(`Set it up`)}),(0,E.jsx)(`p`,{className:`text-[13.5px] text-muted truncate`,children:R(`A model, then the chat. A minute.`)})]})]}),(0,E.jsxs)(`ol`,{className:`mt-6 space-y-2`,children:[(0,E.jsx)(k,{done:K,title:R(`Add a model`),body:K?M?.llm.cloud?`nanoMuse Cloud · ${M.llm.model}`:`${M?.llm.model} · ${A(M?.llm.base_url??``)}`:t.hub?.account.signed_in?R(`Your account's model, or a key of your own.`):R(`Pick a provider and paste a key. Yours, stored in the vault.`),onClick:()=>D(`model`)}),(0,E.jsx)(k,{done:q,optional:!0,title:R(`Connect mail, calendar, contacts`),body:R(q?`Connected. Tap to add more.`:`Optional. It can read what came in, know your day, and who is who.`),onClick:()=>D(`connect`)}),(0,E.jsx)(k,{locked:!K,done:!1,title:R(`Start`),body:R(K?`Open the chat. It introduces itself and asks your name.`:`Needs a model first.`),onClick:()=>K&&!P&&void W()})]})]}),w===`model`&&(0,E.jsxs)(`div`,{className:`pt-6 space-y-4`,children:[(0,E.jsxs)(`div`,{children:[(0,E.jsx)(`h1`,{className:`text-[26px] font-bold tracking-tight`,children:R(`The model behind it`)}),(0,E.jsx)(`p`,{className:`mt-1 text-[14px] text-muted`,children:K?M?.llm.cloud?R(`Your account's model, with its free allowance. Keep it, or switch to a key of your own here.`):R(`A model is already set up on the server. Keep it, or switch here.`):R(`Your account brings a model with a free allowance, nothing to set up. Or paste a key of your own; it is stored encrypted in the vault on the server, never shown to the model, and nothing you say passes through the relay.`)})]}),M?(0,E.jsxs)(E.Fragment,{children:[!K&&t.hub?.account.signed_in&&(0,E.jsxs)(`button`,{type:`button`,disabled:I,onClick:()=>void z(),className:`flex w-full items-center gap-3 rounded-3xl border border-accent/30 bg-accent/5 px-4 py-3.5 text-left`,children:[(0,E.jsx)(`span`,{className:`flex h-10 w-10 shrink-0 items-center justify-center rounded-2xl bg-accent text-white`,children:I?(0,E.jsx)(u,{size:18,className:`animate-spin`}):(0,E.jsx)(v,{size:18})}),(0,E.jsxs)(`span`,{className:`min-w-0 flex-1`,children:[(0,E.jsx)(`span`,{className:`block text-[15px] font-medium`,children:R(`Use the nanoMuse Cloud model`)}),(0,E.jsx)(`span`,{className:`block text-[12.5px] text-muted`,children:R(`Signed in as {hint}. A free allowance, nothing to paste. Recommended to start.`,{hint:t.hub.account.hint})})]}),(0,E.jsx)(g,{size:16,className:`shrink-0 text-muted`})]}),!K&&!t.hub?.account.signed_in&&(0,E.jsx)(`div`,{className:`rounded-3xl border border-border/70 bg-surface p-4`,children:(0,E.jsx)(_,{onSignedIn:()=>void H(),useAsModel:!0})}),!K&&(0,E.jsxs)(`p`,{className:`px-1 text-[12.5px] text-muted`,children:[(0,E.jsx)(`span`,{className:`font-medium`,children:R(`Or bring your own key`)}),` · `,f(R,t.hub?.account)]}),(0,E.jsx)(C,{data:M,onChange:()=>void H(),compact:!0})]}):B?(0,E.jsxs)(`div`,{className:`rounded-3xl border border-border/70 bg-surface p-4 text-center`,children:[(0,E.jsx)(`p`,{className:`text-[13.5px] text-muted`,children:B}),(0,E.jsx)(`button`,{type:`button`,onClick:()=>void H(),className:`mt-3 rounded-full bg-surface-2 px-4 py-1.5 text-[13px] font-medium`,children:R(`Retry`)})]}):(0,E.jsx)(`div`,{className:`flex justify-center py-8 text-muted`,children:(0,E.jsx)(u,{className:`animate-spin`,size:20})})]}),w===`connect`&&(0,E.jsxs)(`div`,{className:`pt-6 space-y-4`,children:[(0,E.jsxs)(`div`,{children:[(0,E.jsx)(`h1`,{className:`text-[26px] font-bold tracking-tight`,children:R(`Connect your mail, calendar and contacts`)}),(0,E.jsx)(`p`,{className:`mt-1 text-[14px] text-muted`,children:R(`Optional. With a mailbox connected it can read what came in and draft replies; it will always ask before sending. With a calendar it knows your day and finds free time. With your contacts it knows who is who. The browser and MCP servers are under Connections later.`)})]}),M?(0,E.jsxs)(E.Fragment,{children:[(0,E.jsx)(S,{data:M,onChange:()=>void H(),compact:!0}),(0,E.jsx)(b,{data:M,onChange:()=>void H(),compact:!0}),(0,E.jsx)(x,{data:M,onChange:()=>void H(),compact:!0})]}):B?(0,E.jsxs)(`div`,{className:`rounded-3xl border border-border/70 bg-surface p-4 text-center`,children:[(0,E.jsx)(`p`,{className:`text-[13.5px] text-muted`,children:B}),(0,E.jsx)(`button`,{type:`button`,onClick:()=>void H(),className:`mt-3 rounded-full bg-surface-2 px-4 py-1.5 text-[13px] font-medium`,children:R(`Retry`)})]}):(0,E.jsx)(`div`,{className:`flex justify-center py-8 text-muted`,children:(0,E.jsx)(u,{className:`animate-spin`,size:20})})]})]}),(0,E.jsxs)(`footer`,{className:`safe-bottom shrink-0 px-5 pb-5 pt-2 flex gap-2`,children:[(w===`model`||w===`connect`)&&(0,E.jsx)(`button`,{type:`button`,onClick:()=>D(`list`),className:`flex items-center justify-center gap-1.5 rounded-2xl border border-border px-4 py-2.5 text-[14px] font-medium text-muted disabled:opacity-40`,children:R(`Back`)}),w===`welcome`&&(0,E.jsxs)(`button`,{type:`button`,onClick:()=>D(`list`),className:e(`flex items-center justify-center gap-1.5 rounded-2xl bg-accent text-accent-fg px-4 py-2.5 text-[14px] font-medium disabled:opacity-40`,`flex-1 py-3`),children:[R(`Get started`),` `,(0,E.jsx)(h,{size:16})]}),w===`list`&&(0,E.jsxs)(`button`,{type:`button`,disabled:!K||P,onClick:()=>void W(),className:e(`flex items-center justify-center gap-1.5 rounded-2xl bg-accent text-accent-fg px-4 py-2.5 text-[14px] font-medium disabled:opacity-40`,`flex-1 py-3`),children:[P?(0,E.jsx)(u,{size:16,className:`animate-spin`}):null,` `,R(K?`Start`:`Add a model to start`),` `,(0,E.jsx)(h,{size:16})]}),w===`model`&&(0,E.jsxs)(`button`,{type:`button`,disabled:!K,onClick:()=>D(`list`),className:e(`flex items-center justify-center gap-1.5 rounded-2xl bg-accent text-accent-fg px-4 py-2.5 text-[14px] font-medium disabled:opacity-40`,`flex-1 py-3`),children:[R(K?`Done`:`Save a model to continue`),` `,(0,E.jsx)(h,{size:16})]}),w===`connect`&&(0,E.jsxs)(`button`,{type:`button`,onClick:()=>D(`list`),className:e(`flex items-center justify-center gap-1.5 rounded-2xl bg-accent text-accent-fg px-4 py-2.5 text-[14px] font-medium disabled:opacity-40`,`flex-1 py-3`),children:[R(q?`Done`:`Skip for now`),` `,(0,E.jsx)(h,{size:16})]})]})]})}function O({n:e,title:t,body:n}){return(0,E.jsxs)(`li`,{className:`flex gap-3 rounded-3xl bg-surface border border-border/70 p-4`,children:[(0,E.jsx)(`span`,{className:`flex h-7 w-7 shrink-0 items-center justify-center rounded-full bg-accent/12 text-[13px] font-semibold text-accent`,children:e}),(0,E.jsxs)(`div`,{className:`text-[13.5px] leading-relaxed`,children:[(0,E.jsx)(`div`,{className:`font-medium text-fg`,children:t}),(0,E.jsx)(`div`,{className:`text-muted`,children:n})]})]})}function k({done:t,locked:r,optional:i,title:a,body:o,onClick:s}){let c=n();return(0,E.jsx)(`li`,{children:(0,E.jsxs)(`button`,{type:`button`,onClick:s,disabled:r,"aria-disabled":r,className:e(`w-full flex items-center gap-3 rounded-3xl border px-4 py-3.5 text-left transition-colors`,t?`border-accent/30 bg-accent/5`:`border-border/70 bg-surface`,r&&`opacity-50`),children:[(0,E.jsx)(`span`,{className:e(`flex h-7 w-7 shrink-0 items-center justify-center rounded-full`,t?`bg-accent text-white`:r?`bg-surface-2 text-muted`:`border border-border text-muted`),children:t?(0,E.jsx)(p,{size:15,strokeWidth:3}):r?(0,E.jsx)(w,{size:13}):null}),(0,E.jsxs)(`span`,{className:`min-w-0 flex-1`,children:[(0,E.jsxs)(`span`,{className:`flex items-center gap-2 text-[15px] font-medium`,children:[(0,E.jsx)(`span`,{className:`truncate`,children:a}),i&&(0,E.jsx)(`span`,{className:`rounded-full bg-surface-2 px-2 py-0.5 text-[10.5px] font-medium text-muted`,children:c(`optional`)})]}),(0,E.jsx)(`span`,{className:`block truncate text-[12.5px] text-muted`,children:o})]}),!r&&(0,E.jsx)(g,{size:16,className:`shrink-0 text-muted`})]})})}function A(e){try{return new URL(e).host}catch{return e}}function j(e){return Object.entries(e.providers).find(([t,n])=>t!==`custom`&&n.base_url&&e.llm.base_url.startsWith(n.base_url))?.[0]??`custom`}export{D as Onboarding}; \ No newline at end of file +import{E as e,J as t,K as n,L as r,Q as i,Y as a,a as o,b as s,f as c,i as l,q as u,x as d}from"./MuseHeader-Pw-NI98v.js";import{A as f}from"./StarNudge-DjXecvWj.js";import{n as p}from"./external-link-Xj5fjR8v.js";import"./Form-DwKuBk1V.js";import{r as m}from"./IdentityForm-BTGczGT_.js";import{Et as h,bt as g,t as _,vt as v}from"./index-CIdGZ5PB.js";import{t as y}from"./AvatarPicker-gR2knlot.js";import{CalendarCard as b,ContactsCard as x,EmailCard as S,ModelCard as C}from"./ConnectionsScreen-CMt7GOff.js";var w=t(`lock`,[[`rect`,{width:`18`,height:`11`,x:`3`,y:`11`,rx:`2`,ry:`2`,key:`1w4ew1`}],[`path`,{d:`M7 11V7a5 5 0 0 1 10 0v4`,key:`fwvmzm`}]]),T=i(a(),1),E=s();function D(){let{state:t,setTab:i,dismissOnboarding:a,refreshSettings:s,toast:p}=c(),[w,D]=(0,T.useState)(`welcome`),[M,N]=(0,T.useState)(null),[P,F]=(0,T.useState)(!1),[I,L]=(0,T.useState)(!1),R=n(),z=async()=>{L(!0);try{await d.cloudUseAsModel(),p(R(`The Cloud model is in use.`)),await H()}catch(e){p(e.message)}finally{L(!1)}},[B,V]=(0,T.useState)(null),H=async()=>{try{V(null),N(await d.connections())}catch(e){V(R(e.message)||R(`Could not load the connections.`))}};(0,T.useEffect)(()=>{H()},[t.connectionsVersion]);let U=async()=>{try{await d.onboarded(!0),await s()}catch{}a(),i(`chat`)},W=async()=>{F(!0);try{await d.firstrunStart(r()===`zh-CN`?`zh`:`en`)}catch{await d.onboarded(!0).catch(()=>void 0)}try{await s()}catch{}F(!1),a(),i(`chat`)},G={...m(t.profile,o,y[0]),proactivity:`default`,proactive:!0,goal_interval_minutes:60,quiet_hours:``},K=M?M.llm.key_source===`vault`||M.llm.key_source===`config`||!!M.providers[j(M)]?.no_key:!1,q=!!M&&(M.email.configured||M.calendar.feeds.length>0||M.contacts.sources.length>0),J=[`welcome`,`list`],Y=w===`welcome`?0:1;return(0,E.jsxs)(`div`,{className:`mx-auto flex h-[100dvh] max-w-[760px] flex-col bg-bg sm:border-x sm:border-border`,children:[(0,E.jsx)(`div`,{className:`titlebar-room`}),(0,E.jsxs)(`header`,{className:`safe-top shrink-0 px-5 pt-4 pb-2 flex items-center justify-between`,children:[(0,E.jsx)(`div`,{className:`flex gap-1`,children:J.map((t,n)=>(0,E.jsx)(`span`,{className:e(`h-1.5 rounded-full transition-all`,n<=Y?`w-5 bg-accent`:`w-1.5 bg-border`)},t))}),(0,E.jsx)(`button`,{type:`button`,onClick:()=>void U(),className:`text-[13px] text-muted`,children:R(`Skip setup`)})]}),(0,E.jsxs)(`div`,{className:`flex-1 overflow-y-auto px-5 pb-6`,children:[w===`welcome`&&(0,E.jsxs)(`div`,{className:`flex h-full flex-col items-center justify-center text-center`,children:[(0,E.jsx)(l,{profile:G,size:96}),(0,E.jsx)(`h1`,{className:`mt-6 text-[28px] font-bold tracking-tight`,children:R(`Meet your nanoMuse`)}),(0,E.jsx)(`p`,{className:`mt-2 text-[15px] text-muted`,children:R(`A personal agent of your own. Three things to know:`)}),(0,E.jsxs)(`ul`,{className:`mt-6 w-full max-w-sm space-y-2.5 text-left`,children:[(0,E.jsx)(O,{n:1,title:R(`It does things for you.`),body:R(`Searches, browses, writes, books, reads mail, and hands you the result, not a list of links.`)}),(0,E.jsx)(O,{n:2,title:R(`It keeps working when you close the app.`),body:R(`Goals move forward between your visits; it reports in the Feed and notifies you when something is worth it.`)}),(0,E.jsx)(O,{n:3,title:R(`It asks you first where it matters.`),body:R(`A separate Sentinel reviews every action. Sending, paying, deleting: it stops and asks; your keys stay in a vault the model cannot read.`)})]}),(0,E.jsx)(`p`,{className:`mt-5 max-w-sm text-[13px] text-muted`,children:R(`There is no form to fill in: once it has a model, it introduces itself in the chat and asks what to call you.`)}),(0,E.jsx)(`p`,{className:`mt-2 max-w-sm text-[13px] text-muted`,children:(0,E.jsx)(`a`,{href:`https://nanomuse.cn/#open-source`,target:`_blank`,rel:`noreferrer`,className:`underline decoration-dotted underline-offset-2 hover:text-accent`,children:R(`nanoMuse is a non-profit open-source community project, free forever.`)})})]}),w===`list`&&(0,E.jsxs)(`div`,{className:`pt-6`,children:[(0,E.jsxs)(`div`,{className:`flex items-center gap-3`,children:[(0,E.jsx)(l,{profile:G,size:56}),(0,E.jsxs)(`div`,{className:`min-w-0`,children:[(0,E.jsx)(`h1`,{className:`text-[24px] font-bold tracking-tight truncate`,children:R(`Set it up`)}),(0,E.jsx)(`p`,{className:`text-[13.5px] text-muted truncate`,children:R(`A model, then the chat. A minute.`)})]})]}),(0,E.jsxs)(`ol`,{className:`mt-6 space-y-2`,children:[(0,E.jsx)(k,{done:K,title:R(`Add a model`),body:K?M?.llm.cloud?`nanoMuse Cloud · ${M.llm.model}`:`${M?.llm.model} · ${A(M?.llm.base_url??``)}`:t.hub?.account.signed_in?R(`Your account's model, or a key of your own.`):R(`Pick a provider and paste a key. Yours, stored in the vault.`),onClick:()=>D(`model`)}),(0,E.jsx)(k,{done:q,optional:!0,title:R(`Connect mail, calendar, contacts`),body:R(q?`Connected. Tap to add more.`:`Optional. It can read what came in, know your day, and who is who.`),onClick:()=>D(`connect`)}),(0,E.jsx)(k,{locked:!K,done:!1,title:R(`Start`),body:R(K?`Open the chat. It introduces itself and asks your name.`:`Needs a model first.`),onClick:()=>K&&!P&&void W()})]})]}),w===`model`&&(0,E.jsxs)(`div`,{className:`pt-6 space-y-4`,children:[(0,E.jsxs)(`div`,{children:[(0,E.jsx)(`h1`,{className:`text-[26px] font-bold tracking-tight`,children:R(`The model behind it`)}),(0,E.jsx)(`p`,{className:`mt-1 text-[14px] text-muted`,children:K?M?.llm.cloud?R(`Your account's model, with its free allowance. Keep it, or switch to a key of your own here.`):R(`A model is already set up on the server. Keep it, or switch here.`):R(`Your account brings a model with a free allowance, nothing to set up. Or paste a key of your own; it is stored encrypted in the vault on the server, never shown to the model, and nothing you say passes through the relay.`)})]}),M?(0,E.jsxs)(E.Fragment,{children:[!K&&t.hub?.account.signed_in&&(0,E.jsxs)(`button`,{type:`button`,disabled:I,onClick:()=>void z(),className:`flex w-full items-center gap-3 rounded-3xl border border-accent/30 bg-accent/5 px-4 py-3.5 text-left`,children:[(0,E.jsx)(`span`,{className:`flex h-10 w-10 shrink-0 items-center justify-center rounded-2xl bg-accent text-white`,children:I?(0,E.jsx)(u,{size:18,className:`animate-spin`}):(0,E.jsx)(v,{size:18})}),(0,E.jsxs)(`span`,{className:`min-w-0 flex-1`,children:[(0,E.jsx)(`span`,{className:`block text-[15px] font-medium`,children:R(`Use the nanoMuse Cloud model`)}),(0,E.jsx)(`span`,{className:`block text-[12.5px] text-muted`,children:R(`Signed in as {hint}. A free allowance, nothing to paste. Recommended to start.`,{hint:t.hub.account.hint})})]}),(0,E.jsx)(g,{size:16,className:`shrink-0 text-muted`})]}),!K&&!t.hub?.account.signed_in&&(0,E.jsx)(`div`,{className:`rounded-3xl border border-border/70 bg-surface p-4`,children:(0,E.jsx)(_,{onSignedIn:()=>void H(),useAsModel:!0})}),!K&&(0,E.jsxs)(`p`,{className:`px-1 text-[12.5px] text-muted`,children:[(0,E.jsx)(`span`,{className:`font-medium`,children:R(`Or bring your own key`)}),` · `,f(R,t.hub?.account)]}),(0,E.jsx)(C,{data:M,onChange:()=>void H(),compact:!0})]}):B?(0,E.jsxs)(`div`,{className:`rounded-3xl border border-border/70 bg-surface p-4 text-center`,children:[(0,E.jsx)(`p`,{className:`text-[13.5px] text-muted`,children:B}),(0,E.jsx)(`button`,{type:`button`,onClick:()=>void H(),className:`mt-3 rounded-full bg-surface-2 px-4 py-1.5 text-[13px] font-medium`,children:R(`Retry`)})]}):(0,E.jsx)(`div`,{className:`flex justify-center py-8 text-muted`,children:(0,E.jsx)(u,{className:`animate-spin`,size:20})})]}),w===`connect`&&(0,E.jsxs)(`div`,{className:`pt-6 space-y-4`,children:[(0,E.jsxs)(`div`,{children:[(0,E.jsx)(`h1`,{className:`text-[26px] font-bold tracking-tight`,children:R(`Connect your mail, calendar and contacts`)}),(0,E.jsx)(`p`,{className:`mt-1 text-[14px] text-muted`,children:R(`Optional. With a mailbox connected it can read what came in and draft replies; it will always ask before sending. With a calendar it knows your day and finds free time. With your contacts it knows who is who. The browser and MCP servers are under Connections later.`)})]}),M?(0,E.jsxs)(E.Fragment,{children:[(0,E.jsx)(S,{data:M,onChange:()=>void H(),compact:!0}),(0,E.jsx)(b,{data:M,onChange:()=>void H(),compact:!0}),(0,E.jsx)(x,{data:M,onChange:()=>void H(),compact:!0})]}):B?(0,E.jsxs)(`div`,{className:`rounded-3xl border border-border/70 bg-surface p-4 text-center`,children:[(0,E.jsx)(`p`,{className:`text-[13.5px] text-muted`,children:B}),(0,E.jsx)(`button`,{type:`button`,onClick:()=>void H(),className:`mt-3 rounded-full bg-surface-2 px-4 py-1.5 text-[13px] font-medium`,children:R(`Retry`)})]}):(0,E.jsx)(`div`,{className:`flex justify-center py-8 text-muted`,children:(0,E.jsx)(u,{className:`animate-spin`,size:20})})]})]}),(0,E.jsxs)(`footer`,{className:`safe-bottom shrink-0 px-5 pb-5 pt-2 flex gap-2`,children:[(w===`model`||w===`connect`)&&(0,E.jsx)(`button`,{type:`button`,onClick:()=>D(`list`),className:`flex items-center justify-center gap-1.5 rounded-2xl border border-border px-4 py-2.5 text-[14px] font-medium text-muted disabled:opacity-40`,children:R(`Back`)}),w===`welcome`&&(0,E.jsxs)(`button`,{type:`button`,onClick:()=>D(`list`),className:e(`flex items-center justify-center gap-1.5 rounded-2xl bg-accent text-accent-fg px-4 py-2.5 text-[14px] font-medium disabled:opacity-40`,`flex-1 py-3`),children:[R(`Get started`),` `,(0,E.jsx)(h,{size:16})]}),w===`list`&&(0,E.jsxs)(`button`,{type:`button`,disabled:!K||P,onClick:()=>void W(),className:e(`flex items-center justify-center gap-1.5 rounded-2xl bg-accent text-accent-fg px-4 py-2.5 text-[14px] font-medium disabled:opacity-40`,`flex-1 py-3`),children:[P?(0,E.jsx)(u,{size:16,className:`animate-spin`}):null,` `,R(K?`Start`:`Add a model to start`),` `,(0,E.jsx)(h,{size:16})]}),w===`model`&&(0,E.jsxs)(`button`,{type:`button`,disabled:!K,onClick:()=>D(`list`),className:e(`flex items-center justify-center gap-1.5 rounded-2xl bg-accent text-accent-fg px-4 py-2.5 text-[14px] font-medium disabled:opacity-40`,`flex-1 py-3`),children:[R(K?`Done`:`Save a model to continue`),` `,(0,E.jsx)(h,{size:16})]}),w===`connect`&&(0,E.jsxs)(`button`,{type:`button`,onClick:()=>D(`list`),className:e(`flex items-center justify-center gap-1.5 rounded-2xl bg-accent text-accent-fg px-4 py-2.5 text-[14px] font-medium disabled:opacity-40`,`flex-1 py-3`),children:[R(q?`Done`:`Skip for now`),` `,(0,E.jsx)(h,{size:16})]})]})]})}function O({n:e,title:t,body:n}){return(0,E.jsxs)(`li`,{className:`flex gap-3 rounded-3xl bg-surface border border-border/70 p-4`,children:[(0,E.jsx)(`span`,{className:`flex h-7 w-7 shrink-0 items-center justify-center rounded-full bg-accent/12 text-[13px] font-semibold text-accent`,children:e}),(0,E.jsxs)(`div`,{className:`text-[13.5px] leading-relaxed`,children:[(0,E.jsx)(`div`,{className:`font-medium text-fg`,children:t}),(0,E.jsx)(`div`,{className:`text-muted`,children:n})]})]})}function k({done:t,locked:r,optional:i,title:a,body:o,onClick:s}){let c=n();return(0,E.jsx)(`li`,{children:(0,E.jsxs)(`button`,{type:`button`,onClick:s,disabled:r,"aria-disabled":r,className:e(`w-full flex items-center gap-3 rounded-3xl border px-4 py-3.5 text-left transition-colors`,t?`border-accent/30 bg-accent/5`:`border-border/70 bg-surface`,r&&`opacity-50`),children:[(0,E.jsx)(`span`,{className:e(`flex h-7 w-7 shrink-0 items-center justify-center rounded-full`,t?`bg-accent text-white`:r?`bg-surface-2 text-muted`:`border border-border text-muted`),children:t?(0,E.jsx)(p,{size:15,strokeWidth:3}):r?(0,E.jsx)(w,{size:13}):null}),(0,E.jsxs)(`span`,{className:`min-w-0 flex-1`,children:[(0,E.jsxs)(`span`,{className:`flex items-center gap-2 text-[15px] font-medium`,children:[(0,E.jsx)(`span`,{className:`truncate`,children:a}),i&&(0,E.jsx)(`span`,{className:`rounded-full bg-surface-2 px-2 py-0.5 text-[10.5px] font-medium text-muted`,children:c(`optional`)})]}),(0,E.jsx)(`span`,{className:`block truncate text-[12.5px] text-muted`,children:o})]}),!r&&(0,E.jsx)(g,{size:16,className:`shrink-0 text-muted`})]})})}function A(e){try{return new URL(e).host}catch{return e}}function j(e){return Object.entries(e.providers).find(([t,n])=>t!==`custom`&&n.base_url&&e.llm.base_url.startsWith(n.base_url))?.[0]??`custom`}export{D as Onboarding}; \ No newline at end of file diff --git a/nanomuse/server/static/assets/SettingsScreen-DoXURXet.js b/nanomuse/server/static/assets/SettingsScreen-CHVg61To.js similarity index 99% rename from nanomuse/server/static/assets/SettingsScreen-DoXURXet.js rename to nanomuse/server/static/assets/SettingsScreen-CHVg61To.js index fc3ab82fd..1761d74a0 100644 --- a/nanomuse/server/static/assets/SettingsScreen-DoXURXet.js +++ b/nanomuse/server/static/assets/SettingsScreen-CHVg61To.js @@ -1 +1 @@ -import{A as e,E as t,F as n,G as r,H as i,J as a,K as o,L as s,Q as c,T as l,Y as u,_ as d,a as f,b as p,f as m,g as h,h as g,m as _,v,x as y}from"./MuseHeader-Pw-NI98v.js";import{C as b,E as ee,T as te,_ as x,j as S,u as C,w}from"./StarNudge-DjXecvWj.js";import{n as ne}from"./external-link-Xj5fjR8v.js";import{n as T}from"./Form-DwKuBk1V.js";import{t as E}from"./clapperboard-BokpXv9J.js";import{t as re}from"./database-zap-CzaFBl6C.js";import{t as D}from"./plug-Bj_5EEV3.js";import{n as ie,r as O,t as ae}from"./IdentityForm-Dhx4FiQY.js";import{D as k,E as A,K as j,L as M,M as oe,O as se,R as N,St as P,U as ce,W as F,_t as I,a as L,at as R,bt as z,ct as le,d as ue,dt as B,ft as V,i as H,k as de,n as fe,nt as U,o as W,q as G,r as pe,rt as me,s as K,tt as he,u as ge,vt as _e,wt as ve}from"./index-BjYzdKkG.js";import{t as q}from"./BackBar-Dli0L0O_.js";import{t as J}from"./AvatarPicker-oSjVM8L3.js";var ye=a(`battery-full`,[[`path`,{d:`M10 10v4`,key:`1mb2ec`}],[`path`,{d:`M14 10v4`,key:`1nt88p`}],[`path`,{d:`M22 14v-4`,key:`14q9d5`}],[`path`,{d:`M6 10v4`,key:`1n77qd`}],[`rect`,{x:`2`,y:`6`,width:`16`,height:`12`,rx:`2`,key:`13zb55`}]]),be=a(`box`,[[`path`,{d:`M21 8a2 2 0 0 0-1-1.73l-7-4a2 2 0 0 0-2 0l-7 4A2 2 0 0 0 3 8v8a2 2 0 0 0 1 1.73l7 4a2 2 0 0 0 2 0l7-4A2 2 0 0 0 21 16Z`,key:`hh9hay`}],[`path`,{d:`m3.3 7 8.7 5 8.7-5`,key:`g66t2b`}],[`path`,{d:`M12 22V12`,key:`d0xqtd`}]]),xe=a(`chart-column`,[[`path`,{d:`M3 3v16a2 2 0 0 0 2 2h16`,key:`c24i48`}],[`path`,{d:`M18 17V9`,key:`2bz60n`}],[`path`,{d:`M13 17V5`,key:`1frdt8`}],[`path`,{d:`M8 17v-3`,key:`17ska0`}]]),Se=a(`message-square-warning`,[[`path`,{d:`M22 17a2 2 0 0 1-2 2H6.828a2 2 0 0 0-1.414.586l-2.202 2.202A.71.71 0 0 1 2 21.286V5a2 2 0 0 1 2-2h16a2 2 0 0 1 2 2z`,key:`18887p`}],[`path`,{d:`M12 15h.01`,key:`q59x07`}],[`path`,{d:`M12 7v4`,key:`xawao1`}]]),Ce=a(`puzzle`,[[`path`,{d:`M15.39 4.39a1 1 0 0 0 1.68-.474 2.5 2.5 0 1 1 3.014 3.015 1 1 0 0 0-.474 1.68l1.683 1.682a2.414 2.414 0 0 1 0 3.414L19.61 15.39a1 1 0 0 1-1.68-.474 2.5 2.5 0 1 0-3.014 3.015 1 1 0 0 1 .474 1.68l-1.683 1.682a2.414 2.414 0 0 1-3.414 0L8.61 19.61a1 1 0 0 0-1.68.474 2.5 2.5 0 1 1-3.014-3.015 1 1 0 0 0 .474-1.68l-1.683-1.682a2.414 2.414 0 0 1 0-3.414L4.39 8.61a1 1 0 0 1 1.68.474 2.5 2.5 0 1 0 3.014-3.015 1 1 0 0 1-.474-1.68l1.683-1.682a2.414 2.414 0 0 1 3.414 0z`,key:`w46dr5`}]]),we=a(`shield`,[[`path`,{d:`M20 13c0 5-3.5 7.5-7.66 8.95a1 1 0 0 1-.67-.01C7.5 20.5 4 18 4 13V6a1 1 0 0 1 1-1c2 0 4.5-1.2 6.24-2.72a1.17 1.17 0 0 1 1.52 0C14.51 3.81 17 5 19 5a1 1 0 0 1 1 1z`,key:`oel41y`}]]),Te=a(`smile`,[[`circle`,{cx:`12`,cy:`12`,r:`10`,key:`1mglay`}],[`path`,{d:`M8 14s1.5 2 4 2 4-2 4-2`,key:`1y1vjs`}],[`line`,{x1:`9`,x2:`9.01`,y1:`9`,y2:`9`,key:`yxxnd0`}],[`line`,{x1:`15`,x2:`15.01`,y1:`9`,y2:`9`,key:`1p4y9e`}]]),Ee=a(`zap`,[[`path`,{d:`M4 14a1 1 0 0 1-.78-1.63l9.9-10.2a.5.5 0 0 1 .86.46l-1.92 6.02A1 1 0 0 0 13 10h7a1 1 0 0 1 .78 1.63l-9.9 10.2a.5.5 0 0 1-.86-.46l1.92-6.02A1 1 0 0 0 11 14z`,key:`1xq2db`}]]),Y=c(u(),1),De=`(min-width: 64rem)`;function Oe(){return typeof window>`u`?!1:document.documentElement.classList.contains(`desktop`)?!0:typeof window.matchMedia==`function`&&window.matchMedia(De).matches}function ke(){let[e,t]=(0,Y.useState)(Oe);return(0,Y.useEffect)(()=>{if(typeof window.matchMedia!=`function`)return;let e=window.matchMedia(De),n=()=>t(Oe());return e.addEventListener(`change`,n),()=>e.removeEventListener(`change`,n)},[]),e}var X=p(),Ae=`w-full rounded-2xl bg-surface-2 px-3.5 py-2.5 outline-none focus:ring-2 focus:ring-accent/40`,je=[{id:`ask`,title:`Balanced`,text:`Browse, read and write files freely; stop for anything hard to undo: email, purchases, shell commands.`,icon:(0,X.jsx)(j,{size:18})},{id:`strict`,title:`Cautious`,text:`Also ask before moderate actions like fetching web pages or writing files.`,icon:(0,X.jsx)(we,{size:18})},{id:`auto`,title:`Hands-off`,text:`Approve everything automatically except explicit deny rules. For trusted, unattended runs only.`,icon:(0,X.jsx)(G,{size:18})}];function Me(){let{state:e,refreshSettings:a,setTab:s,toast:c}=m(),u=e.settings,[d,p]=(0,Y.useState)(()=>O(e.profile,f,J[0])),[h,v]=(0,Y.useState)(!1),b=o(),te=r(),x=g(),[w,E]=(0,Y.useState)(null),[re,D]=(0,Y.useState)(!1);(0,Y.useEffect)(()=>{u||a()},[u,a]);let j=(0,Y.useCallback)(async(e=!1)=>{D(!0);try{E(await y.update(e))}catch{E(null)}finally{D(!1)}},[]);(0,Y.useEffect)(()=>{j()},[j]),(0,Y.useEffect)(()=>{e.profile&&p(O(e.profile,``,J[0]))},[e.profile]);let M=async(e,t)=>{v(!0);try{await y.updateSettings(e),await a(),t&&c(t)}catch(e){c(e.message)}finally{v(!1)}},P=O(e.profile,``,J[0]),ce=!!e.profile&&Object.keys(d).some(e=>d[e]!==P[e]),F=e.profile?.name??`nanoMuse`,I=de(),L=ue(),R=ke()&&!e.lite,[B,V]=(0,Y.useState)(null),H=[{id:`who`,title:F},{id:`sentinel`,title:b(`Safety · Sentinel`)},{id:`proactivity`,title:b(`Proactivity`)},{id:`notifications`,title:b(`Notifications`)},...k()?[{id:`keep-running`,title:b(`Keep it running`)}]:[],{id:`model`,title:b(`Model`)},{id:`appearance`,title:b(`Appearance`)},...N()?[{id:`desktop`,title:b(`Desktop app`)}]:[],{id:`data`,title:b(`Data controls`)},{id:`developer`,title:b(`Developer`)},{id:`about`,title:b(`About`)}],U=e=>R||B===e,[W,G]=(0,Y.useState)(()=>{let e=window.location.hash.slice(1);return Ne.includes(e)?e:null});if((0,Y.useEffect)(()=>{if(W&&u){if(G(null),history.replaceState(null,``,window.location.pathname+window.location.search),!R){V(W);return}requestAnimationFrame(()=>document.getElementById(W)?.scrollIntoView({behavior:`smooth`,block:`start`}))}},[W,u,R]),!R&&B===null)return(0,X.jsx)(Fe,{release:w,onOpen:V});let pe=H.find(e=>e.id===B);return(0,X.jsxs)(`div`,{className:`flex h-full flex-col`,children:[R?(0,X.jsx)(q,{title:b(`Settings`),description:b(`Its name and look, how careful it is, how often it speaks up.`)}):(0,X.jsx)(q,{title:pe?.title??b(`Settings`),onBack:()=>V(null),backLabel:b(`Settings`)}),(0,X.jsxs)(`div`,{className:`flex min-h-0 flex-1`,children:[R&&(0,X.jsx)(`nav`,{className:`flex w-[188px] shrink-0 flex-col gap-0.5 self-start pl-4 pr-2 pt-1`,"aria-label":b(`Settings`),children:H.map(e=>(0,X.jsx)(`button`,{type:`button`,onClick:()=>document.getElementById(e.id)?.scrollIntoView({behavior:`smooth`,block:`start`}),className:`truncate rounded-xl px-3 py-1.5 text-left text-[13px] font-medium text-fg/75 hover:bg-surface-2 hover:text-fg`,children:e.title},e.id))}),(0,X.jsxs)(`div`,{className:`flex-1 overflow-y-auto px-4 pb-8 space-y-5`,children:[U(`who`)&&(0,X.jsxs)($,{title:F,id:`who`,plain:!R,children:[(0,X.jsx)(ae,{value:d,onChange:p,suggestions:!1,inputCls:Ae,onStudio:()=>s(`avatar`)}),(0,X.jsx)(`button`,{type:`button`,disabled:!ce||h,onClick:()=>void M({profile:ie(d)},b(`Saved`)),className:`w-full rounded-2xl bg-accent text-accent-fg py-2.5 font-medium disabled:opacity-40`,children:b(`Save`)})]}),U(`sentinel`)&&(0,X.jsxs)($,{title:b(`Safety · Sentinel`),id:`sentinel`,plain:!R,children:[(0,X.jsx)(`p`,{className:`text-[13px] text-muted -mt-1`,children:b(`A separate gatekeeper reviews every action. Pick how often it should check in with you.`)}),(0,X.jsx)(`div`,{className:`space-y-2`,children:je.map(e=>(0,X.jsxs)(`button`,{type:`button`,onClick:()=>void M({sentinel_mode:e.id}),"aria-pressed":u?.sentinel.mode===e.id,className:t(`w-full text-left rounded-2xl border px-3.5 py-3 flex items-start gap-3 transition`,u?.sentinel.mode===e.id?`border-accent bg-accent/8`:`border-border`),children:[(0,X.jsx)(`div`,{className:t(`mt-0.5`,e.id===`auto`?`text-rose-500`:`text-accent`),children:e.icon}),(0,X.jsxs)(`div`,{className:`flex-1`,children:[(0,X.jsx)(`div`,{className:`font-medium text-[14.5px]`,children:b(e.title)}),(0,X.jsx)(`div`,{className:`text-[12.5px] text-muted leading-snug mt-0.5`,children:b(e.text)})]}),u?.sentinel.mode===e.id&&(0,X.jsx)(ne,{size:18,className:`text-accent mt-0.5`})]},e.id))}),u&&(0,X.jsxs)(`div`,{className:`text-[12.5px] text-muted leading-relaxed`,children:[b(`Always asks before: {tools}.`,{tools:u.sentinel.always_ask_tools.map(e=>b(e)).join(`, `)||`—`}),` `,u.sentinel.taint_tracking&&b(`After reading private data, new network destinations need approval.`)]}),u?.sandbox&&(0,X.jsxs)(`div`,{className:`flex items-start gap-2.5 rounded-2xl bg-surface-2/60 px-3.5 py-2.5 text-[12.5px] leading-snug`,children:[(0,X.jsx)(be,{size:15,className:t(`shrink-0 mt-[2px]`,u.sandbox.active?`text-emerald-500`:`text-muted`)}),(0,X.jsxs)(`div`,{children:[(0,X.jsxs)(`div`,{className:`font-medium text-fg`,children:[u.sandbox.active?b(`Commands run in a sandbox`):b(`Commands run without a sandbox`),(0,X.jsxs)(`span`,{className:`text-muted font-normal`,children:[` · `,u.sandbox.status]})]}),(0,X.jsx)(`div`,{className:`text-muted mt-0.5`,children:u.sandbox.active?b(`Each shell or Python call gets its own namespace: only the workspace is writable, your home directory is not there, and there is no network unless the command needs it.`):u.sandbox.status.includes(`container`)?b(`Each shell or Python call runs in the workspace with a scrubbed environment; the container is the boundary.`):b(`Each shell or Python call runs in the workspace with a scrubbed environment. On Linux, installing bubblewrap gives each one its own namespace.`)})]})]})]}),U(`proactivity`)&&(0,X.jsxs)($,{title:b(`Proactivity`),id:`proactivity`,plain:!R,children:[(0,X.jsx)(ze,{value:e.profile?.proactivity??`default`,onChange:e=>void M({profile:{proactivity:e}})}),(0,X.jsxs)(`div`,{className:`flex items-center gap-3`,children:[(0,X.jsxs)(`label`,{className:`text-[13.5px] flex-1`,children:[b(`Check-in interval`),e.profile&&e.profile.proactivity!=="default"&&e.profile.proactivity!==`off`&&(0,X.jsx)(`span`,{className:`block text-[12px] text-muted`,children:e.profile.proactivity===`low`?b(`Doubled at this level`):b(`Halved at this level`)})]}),(0,X.jsx)(`select`,{value:e.profile?.goal_interval_minutes??60,onChange:e=>void M({profile:{goal_interval_minutes:Number(e.target.value)}}),className:`rounded-2xl bg-surface-2 px-3 py-2 text-[13.5px] outline-none`,children:[...new Set([15,30,60,120,240,480,1440,e.profile?.goal_interval_minutes??60])].sort((e,t)=>e-t).map(e=>(0,X.jsx)(`option`,{value:e,children:e<60?b(`{n} min`,{n:e}):e%60?`${b(`{n} h`,{n:Math.floor(e/60)})} ${b(`{n} min`,{n:e%60})}`:b(`{n} h`,{n:e/60})},e))})]}),(0,X.jsx)(Be,{value:e.profile?.quiet_hours??``,onChange:e=>void M({profile:{quiet_hours:e}})})]}),U(`notifications`)&&(0,X.jsx)($,{title:b(`Notifications`),id:`notifications`,plain:!R,children:A()?(0,X.jsx)(Ie,{name:e.profile?.name??`nanoMuse`}):(0,X.jsx)(Re,{name:e.profile?.name??`nanoMuse`})}),k()&&U(`keep-running`)&&(0,X.jsx)($,{title:b(`Keep it running`),id:`keep-running`,plain:!R,children:(0,X.jsx)(Le,{name:e.profile?.name??`nanoMuse`})}),U(`model`)&&(0,X.jsxs)($,{title:b(`Model`),id:`model`,plain:!R,children:[u&&(0,X.jsxs)(`button`,{type:`button`,onClick:()=>s(`connections`),className:`w-full text-[13.5px] flex items-center justify-between`,children:[(0,X.jsx)(`span`,{className:`text-muted`,children:b(`Provider / model`)}),(0,X.jsxs)(`span`,{className:`font-mono text-[12.5px] flex items-center gap-1`,children:[u.llm.model,` `,(0,X.jsx)(z,{size:14,className:`text-muted`})]})]}),u?.llm.cloud&&(0,X.jsxs)(`button`,{type:`button`,onClick:()=>oe(s,S(e.hub?.account).preset),className:`w-full text-[13.5px] flex items-center justify-between`,children:[(0,X.jsx)(`span`,{className:`text-muted`,children:b(`Use my own API key or a plan I pay for`)}),(0,X.jsxs)(`span`,{className:`text-[12.5px] text-muted flex items-center gap-1`,children:[b(`{first} first, then {others}`,{first:S(e.hub?.account).label,others:ee(e.hub?.account)?b(`DeepSeek, Kimi, OpenAI, ChatGPT…`):b(`OpenAI, ChatGPT, Gemini, DeepSeek…`)}),` `,(0,X.jsx)(z,{size:14})]})]}),(0,X.jsxs)(`button`,{type:`button`,onClick:()=>s(`connections`),className:`w-full text-[13.5px] flex items-center justify-between`,children:[(0,X.jsx)(`span`,{className:`text-muted`,children:b(`Connections`)}),(0,X.jsxs)(`span`,{className:`text-[12.5px] text-muted flex items-center gap-1`,children:[b(`E-mail, calendar, browser, MCP servers`),` `,(0,X.jsx)(z,{size:14})]})]})]}),U(`appearance`)&&(0,X.jsxs)($,{title:b(`Appearance`),id:`appearance`,plain:!R,children:[(0,X.jsx)(T,{label:b(`Show the agent's steps`),hint:b(`Every tool it uses becomes a chip in the chat. Off, the chat keeps to the conversation and the line under the name says what it is on. This device only.`),checked:L,onChange:ge}),(0,X.jsx)(T,{label:b(`Show thinking`),hint:b(`Reveal the model's reasoning under each reply when the provider exposes it.`),checked:!!u?.agent.show_thinking,onChange:e=>void M({show_thinking:e})}),(0,X.jsxs)(`div`,{className:`flex items-center gap-3`,children:[(0,X.jsxs)(`label`,{className:`text-[13.5px] flex-1`,children:[b(`Appearance`),(0,X.jsx)(`span`,{className:`block text-[12px] text-muted`,children:b(`This device only`)})]}),(0,X.jsxs)(`select`,{value:x,onChange:e=>_(e.target.value),className:`rounded-2xl bg-surface-2 px-3 py-2 text-[13.5px] outline-none`,children:[(0,X.jsx)(`option`,{value:`light`,children:b(`Light`)}),(0,X.jsx)(`option`,{value:`dark`,children:b(`Dark`)}),(0,X.jsx)(`option`,{value:`system`,children:b(`Follow the system`)})]})]}),(0,X.jsxs)(`div`,{className:`flex items-center gap-3`,children:[(0,X.jsxs)(`label`,{className:`text-[13.5px] flex-1`,children:[b(`App language`),(0,X.jsx)(`span`,{className:`block text-[12px] text-muted`,children:b(`This device only`)})]}),(0,X.jsx)(`select`,{value:te,onChange:e=>i(e.target.value),className:`rounded-2xl bg-surface-2 px-3 py-2 text-[13.5px] outline-none`,children:n.map(e=>(0,X.jsx)(`option`,{value:e.value,children:e.value===`auto`?b(`Auto`):e.label},e.value))})]}),(0,X.jsxs)(`div`,{className:`flex items-center gap-3`,children:[(0,X.jsxs)(`label`,{className:`text-[13.5px] flex-1`,children:[b(`Reply language`),(0,X.jsx)(`span`,{className:`block text-[12px] text-muted`,children:b(`What {name} writes in`,{name:e.profile?.name??`nanoMuse`})})]}),(0,X.jsxs)(`select`,{value:u?.agent.language??`auto`,onChange:e=>void M({language:e.target.value}),className:`rounded-2xl bg-surface-2 px-3 py-2 text-[13.5px] outline-none`,children:[(0,X.jsx)(`option`,{value:`auto`,children:b(`Match mine`)}),(0,X.jsx)(`option`,{value:`English`,children:`English`}),(0,X.jsx)(`option`,{value:`中文`,children:`中文`}),(0,X.jsx)(`option`,{value:`日本語`,children:`日本語`}),(0,X.jsx)(`option`,{value:`Español`,children:`Español`}),(0,X.jsx)(`option`,{value:`Deutsch`,children:`Deutsch`}),(0,X.jsx)(`option`,{value:`Français`,children:`Français`})]})]})]}),N()&&U(`desktop`)&&(0,X.jsx)($,{title:b(`Desktop app`),id:`desktop`,plain:!R,children:(0,X.jsx)(Ve,{})}),U(`data`)&&(0,X.jsx)($,{title:b(`Data controls`),id:`data`,plain:!R,children:(0,X.jsx)(fe,{flush:!0})}),U(`developer`)&&(0,X.jsxs)($,{title:b(`Developer`),id:`developer`,plain:!R,children:[(0,X.jsx)(T,{label:b(`Developer tools`),hint:b(`The Coding screen (Cursor, Codex and the other coding agents on this computer) in the sidebar, and the runtime's address below. This device only.`),checked:I,onChange:se}),I&&(0,X.jsxs)(`div`,{className:`text-[13px] text-muted space-y-1`,children:[(0,X.jsxs)(`div`,{className:`break-all`,children:[b(`Runtime:`),` `,window.location.origin,` · `,(0,X.jsx)(`span`,{className:`text-fg/70`,children:b(`the token is in the server_token file in the data folder`)})]}),(0,X.jsxs)(`div`,{children:[(0,X.jsx)(`a`,{href:`https://github.com/nano-muse/nanoMuse/blob/main/docs/cli.md`,target:`_blank`,rel:`noreferrer`,className:`text-accent underline-offset-2 hover:underline`,children:b(`The command line and the API`)}),` · `,(0,X.jsx)(`a`,{href:`https://github.com/nano-muse/nanoMuse/blob/main/docs/harness.md`,target:`_blank`,rel:`noreferrer`,className:`text-accent underline-offset-2 hover:underline`,children:b(`nanoMuse on DeepSeek Harness`)})]})]})]}),U(`about`)&&(0,X.jsxs)($,{title:b(`About`),id:`about`,plain:!R,children:[(0,X.jsx)(C,{}),(0,X.jsx)(Pe,{installed:e.version,release:w,checking:re,onCheck:()=>void j(!0)}),(0,X.jsxs)(`div`,{className:`text-[13px] text-muted space-y-1`,children:[u&&(0,X.jsxs)(`div`,{className:`break-all`,children:[b(`Data:`),` `,u.data_dir]}),u&&(0,X.jsxs)(`div`,{className:`break-all`,children:[b(`Workspace:`),` `,u.agent.workspace]}),(0,X.jsx)(`div`,{children:e.connected?b(`Connected`):b(`Reconnecting…`)})]}),(0,X.jsxs)(`button`,{type:`button`,onClick:()=>{let e=A();if(e){e.disconnect();return}l(``),window.location.reload()},className:`w-full rounded-2xl border border-border py-2.5 text-[14px] font-medium flex items-center justify-center gap-2 text-muted`,children:[(0,X.jsx)(le,{size:16}),` `,A()?b(`Disconnect from this server`):b(`Forget this device's access token`)]})]})]})]})]})}var Ne=[`who`,`sentinel`,`proactivity`,`notifications`,`keep-running`,`model`,`appearance`,`desktop`,`data`,`developer`,`about`];function Pe({installed:t,release:n,checking:r,onCheck:i}){let a=o(),s=!!A(),c=(0,X.jsx)(`button`,{type:`button`,onClick:i,disabled:r,className:`text-accent underline-offset-2 hover:underline disabled:opacity-60`,children:a(r?`Checking…`:`Check now`)}),l;return l=s?a(`The phone app checks for updates on its own.`):n&&!n.enabled?a(`Update checks are off here.`):r&&!n?a(`Checking…`):n?.latest&&n.newer?(0,X.jsxs)(X.Fragment,{children:[a(`{version} is out`,{version:n.latest}),` · `,(0,X.jsx)(`a`,{href:n.download_url||n.url,target:`_blank`,rel:`noreferrer`,className:`font-medium text-accent underline-offset-2 hover:underline`,children:a(`Update`)})]}):n?.latest?(0,X.jsxs)(X.Fragment,{children:[a(`Latest {version}; you have it`,{version:n.latest}),` · `,c]}):(0,X.jsxs)(X.Fragment,{children:[a(`Could not check`),` · `,c]}),(0,X.jsxs)(`div`,{className:`rounded-2xl bg-surface-2/60 px-3.5 py-2.5 text-[13px]`,children:[(0,X.jsx)(`div`,{className:`font-medium`,children:a(`nanoMuse {version}`,{version:t})}),(0,X.jsx)(`div`,{className:`mt-0.5 text-muted`,children:l}),!s&&n?.latest&&n.newer&&(0,X.jsx)(`div`,{className:`mt-1 text-[12px] text-muted`,children:a(`To update: pip install -U nanomuse, pull the new image, or use the desktop app's Update.`)}),!s&&n?.checked_at&&(0,X.jsx)(`div`,{className:`mt-1 text-[12px] text-muted`,children:a(`Checked {when}`,{when:e(n.checked_at)})})]})}function Fe({release:e,onOpen:t}){let{state:n,setTab:r}=m(),i=o(),a=n.settings,c=n.hub,l=te(),u=n.profile?.name??`nanoMuse`,d=g(),f=c?.devices.filter(e=>!e.this&&e.kind!==`web`)??[],p=f.filter(e=>e.kind===`computer`),h=f.filter(e=>e.online&&e.actions?.includes(`coding.sessions`)),_=a?.sentinel.mode,v=_===`ask`?i(`Balanced`):_===`strict`?i(`Cautious`):_===`auto`?i(`Hands-off`):``,y=n.profile?.proactivity??`default`,ee=i(y===`off`?`Off`:y===`low`?`Low`:y===`high`?`High`:`Default`),S=i(d===`dark`?`Dark`:d===`light`?`Light`:`Follow the system`),C=i(`none`);return(0,X.jsxs)(`div`,{className:`flex h-full flex-col`,children:[(0,X.jsx)(q,{title:i(`Settings`)}),(0,X.jsxs)(`div`,{className:`flex-1 overflow-y-auto pb-8 pt-2`,children:[(0,X.jsxs)(L,{className:`mb-3`,children:[(0,X.jsxs)(`button`,{type:`button`,onClick:()=>r(`connections`),className:`flex w-full items-center gap-3 px-4 py-3.5 text-left hover:bg-surface-2/60`,children:[(0,X.jsxs)(`span`,{className:`min-w-0 flex-1`,children:[(0,X.jsx)(`span`,{className:`block truncate text-[16px] font-medium leading-[21px]`,children:a?.llm.model||i(`No model yet`)}),(0,X.jsx)(`span`,{className:`mt-0.5 block truncate text-[12.5px] leading-4 text-muted`,children:a?a.llm.cloud?`nanoMuse Cloud`:a.llm.provider:i(`Add a provider and pick its models`)})]}),(0,X.jsx)(`span`,{className:`text-[14px] font-medium text-accent`,children:i(`Change`)})]}),(0,X.jsx)(W,{}),(0,X.jsx)(K,{icon:(0,X.jsx)(_e,{size:22}),label:`nanoMuse Cloud`,value:c?.account.signed_in?c.account.hint:i(`Sign in`),onClick:()=>r(`account`)}),(0,X.jsx)(W,{}),(0,X.jsx)(K,{icon:(0,X.jsx)(E,{size:22}),label:i(`Image & video models`),value:x(l,`image`)===!1?w(i,`image`,b(c?.account),s()):x(l,`video`)===!1?w(i,`video`,b(c?.account),s()):void 0,onClick:()=>r(`connections`)}),(0,X.jsx)(W,{}),(0,X.jsx)(K,{icon:(0,X.jsx)(xe,{size:22}),label:i(`Usage`),onClick:()=>r(`account`)})]}),(0,X.jsxs)(L,{className:`mb-3`,children:[(0,X.jsx)(K,{icon:(0,X.jsx)(F,{size:22}),label:i(`Name & personality`),value:u,onClick:()=>t(`who`)}),(0,X.jsx)(W,{}),(0,X.jsx)(K,{icon:(0,X.jsx)(Te,{size:22}),label:i(`Avatar`),onClick:()=>r(`avatar`)}),(0,X.jsx)(W,{}),(0,X.jsx)(K,{icon:(0,X.jsx)(P,{size:22}),label:i(`Memory`),onClick:()=>r(`memory`)}),a?.skills?.enabled!==!1&&(0,X.jsxs)(X.Fragment,{children:[(0,X.jsx)(W,{}),(0,X.jsx)(K,{icon:(0,X.jsx)(Ce,{size:22}),label:i(`Skills`),value:a?String(a.skills.count):void 0,onClick:()=>r(`skills`)})]}),(0,X.jsx)(W,{}),(0,X.jsx)(K,{icon:(0,X.jsx)(D,{size:22}),label:i(`Connections`),value:a?.connectors.mcp.length?`${a.connectors.mcp.length} MCP`:void 0,onClick:()=>r(`connections`)}),(0,X.jsx)(W,{}),(0,X.jsx)(K,{icon:(0,X.jsx)(R,{size:22}),label:i(`Chat apps`),onClick:()=>r(`channels`)}),(0,X.jsx)(W,{}),(0,X.jsx)(K,{icon:(0,X.jsx)(me,{size:22}),label:i(`Devices`),value:p.length?String(p.length):C,onClick:()=>r(`devices`)}),(0,X.jsx)(W,{}),(0,X.jsx)(K,{icon:(0,X.jsx)(ce,{size:22}),label:i(`Coding agents`),value:h.length?String(h.length):C,onClick:()=>r(`coding`)})]}),(0,X.jsxs)(L,{className:`mb-3`,children:[(0,X.jsx)(K,{icon:(0,X.jsx)(j,{size:22}),label:i(`Safety · Sentinel`),value:v,onClick:()=>t(`sentinel`)}),(0,X.jsx)(W,{}),(0,X.jsx)(K,{icon:(0,X.jsx)(Ee,{size:22}),label:i(`Proactivity`),value:ee,onClick:()=>t(`proactivity`)}),(0,X.jsx)(W,{}),(0,X.jsx)(K,{icon:(0,X.jsx)(ve,{size:22}),label:i(`Notifications`),onClick:()=>t(`notifications`)}),k()&&(0,X.jsxs)(X.Fragment,{children:[(0,X.jsx)(W,{}),(0,X.jsx)(K,{icon:(0,X.jsx)(ye,{size:22}),label:i(`Keep it running`),onClick:()=>t(`keep-running`)})]})]}),(0,X.jsxs)(L,{className:`mb-3`,children:[(0,X.jsx)(K,{icon:(0,X.jsx)(he,{size:22}),label:i(`Appearance`),value:S,onClick:()=>t(`appearance`)}),N()&&(0,X.jsxs)(X.Fragment,{children:[(0,X.jsx)(W,{}),(0,X.jsx)(K,{icon:(0,X.jsx)(me,{size:22}),label:i(`Desktop app`),onClick:()=>t(`desktop`)})]}),(0,X.jsx)(W,{}),(0,X.jsx)(K,{icon:(0,X.jsx)(re,{size:22}),label:i(`Data controls`),onClick:()=>t(`data`)}),(0,X.jsx)(W,{}),(0,X.jsx)(K,{icon:(0,X.jsx)(I,{size:22}),label:i(`Developer`),onClick:()=>t(`developer`)})]}),(0,X.jsxs)(L,{className:`mb-3`,children:[(0,X.jsx)(K,{icon:(0,X.jsx)(B,{size:22}),label:i(`About nanoMuse`),value:e?.newer&&e.latest?i(`{version} is out`,{version:e.latest}):void 0,onClick:()=>t(`about`)}),(0,X.jsx)(W,{}),(0,X.jsx)(K,{icon:(0,X.jsx)(V,{size:22}),label:i(`Privacy policy`),onClick:()=>window.open(pe,`_blank`,`noopener`),external:!0}),(0,X.jsx)(W,{}),(0,X.jsx)(K,{icon:(0,X.jsx)(Se,{size:22}),label:i(`Feedback`),onClick:()=>window.open(`https://github.com/nano-muse/nanoMuse/issues/new/choose`,`_blank`,`noopener`),external:!0})]}),(0,X.jsxs)(H,{children:[`nanoMuse `,n.version]})]})]})}function Ie({name:e}){let t=o(),n=A(),[r,i]=(0,Y.useState)(()=>n?.notificationsEnabled()??!1);return n?(0,X.jsxs)(X.Fragment,{children:[(0,X.jsx)(T,{label:t(`Let {name} notify this phone`,{name:e}),hint:t(`The app stays connected to your server in the background. Approvals, questions and finished background work arrive as notifications and open the right chat.`),checked:r,onChange:e=>{n.setNotificationsEnabled(e),i(e)}}),(0,X.jsx)(`div`,{className:`text-[12.5px] text-muted`,children:t(`nanoMuse for Android {version}`,{version:n.version()})})]}):null}function Le({name:e}){let t=o(),n=A(),[r,i]=(0,Y.useState)(k);if((0,Y.useEffect)(()=>{let e=()=>i(k());return document.addEventListener(`visibilitychange`,e),window.addEventListener(`focus`,e),()=>{document.removeEventListener(`visibilitychange`,e),window.removeEventListener(`focus`,e)}},[]),!n||!r)return null;let a=e=>n.openKeepRunning?.(e),s={xiaomi:t(`Xiaomi / Redmi / POCO: Settings → Apps → Manage apps → {name} → Autostart on; Battery saver → No restrictions; Other permissions → Display pop-up windows while running in the background on.`),huawei:t(`Huawei: Settings → Battery → App launch → {name} → Manage manually, all three on (auto-launch, secondary launch, run in background); Settings → Apps → {name} → Battery → Launch: manage manually.`),honor:t(`Honor: Settings → Battery → App launch → {name} → Manage manually, all three on; Battery → More battery settings → Stay connected while asleep on.`),oppo:t(`OPPO / realme / OnePlus: Settings → Battery → More settings → Optimise battery use → {name} → Don't optimise; Settings → Apps → {name} → Battery usage → Allow background activity, Allow auto launch.`),vivo:t(`vivo / iQOO: i Manager → App manager → Autostart → {name} on; Settings → Battery → Background power consumption management → {name} → Allow high background power consumption.`),samsung:t(`Samsung: Settings → Battery → Background usage limits → {name} not in Sleeping or Deep sleeping apps (add it to Never sleeping apps); turn off Adaptive battery if it keeps stopping.`),meizu:t(`Meizu: Settings → Apps → {name} → Background management → Keep running in the background; Battery → App power management → Allow.`)}[r.vendor];return(0,X.jsxs)(X.Fragment,{children:[(0,X.jsx)(`p`,{className:`text-[12.5px] text-muted leading-snug`,children:t(`Android stops apps that seem idle. {name} runs as a foreground service and holds the phone awake only while a task runs; these switches let it keep that promise on this phone.`,{name:e})}),(0,X.jsx)(Z,{label:t(`Battery`),value:r.battery_unrestricted?t(`Unrestricted`):t(`Optimised`),ok:r.battery_unrestricted,hint:t(`Optimised means Android may freeze the agent after a while with the screen off; routines and check-ins then wait until the phone wakes.`),action:r.battery_unrestricted?void 0:{label:t(`Allow`),onClick:()=>a(`battery`)}}),(0,X.jsx)(Z,{label:t(`Display over other apps`),value:r.overlay?t(`Allowed`):t(`Not allowed`),ok:r.overlay,hint:t(`Lets the agent bring an app to the front from the background and show its status capsule while it works in other apps.`),action:r.overlay?void 0:{label:t(`Allow`),onClick:()=>a(`overlay`)}}),r.exact_alarms!==`n/a`&&r.local&&(0,X.jsx)(Z,{label:t(`Alarms & reminders`),value:r.exact_alarms===`granted`?t(`Exact`):t(`Approximate`),ok:r.exact_alarms===`granted`,hint:t(`With exact alarms a reminder fires at the minute you named even when the phone is asleep; without them Android may deliver it up to a quarter of an hour late.`),action:r.exact_alarms===`granted`?void 0:{label:t(`Allow`),onClick:()=>a(`alarms`)}}),(0,X.jsx)(T,{label:t(`Start after a reboot`),hint:r.local?t(`Bring the runtime back when the phone restarts, so routines and check-ins do not stop.`):t(`Reconnect to your computer when the phone restarts, so approvals keep arriving.`),checked:r.boot_start,onChange:e=>{n.setStartOnBoot?.(e),i({...r,boot_start:e})}}),s&&(0,X.jsxs)(`div`,{className:`rounded-2xl bg-surface-2 px-3 py-2.5 text-[12.5px] leading-snug space-y-2`,children:[(0,X.jsx)(`div`,{className:`font-medium`,children:t(`On this phone's Android`)}),(0,X.jsx)(`div`,{className:`text-muted`,children:s}),r.autostart_settings&&(0,X.jsx)(`button`,{type:`button`,onClick:()=>a(`autostart`),className:`rounded-full border border-border px-3 py-1.5 text-[12.5px]`,children:t(`Open the auto-start settings`)})]}),(0,X.jsxs)(`div`,{className:`flex items-center justify-between gap-3 pt-1`,children:[(0,X.jsx)(`div`,{className:`text-[12.5px] text-muted leading-snug`,children:t(`Crashes are written to a file on this phone and nowhere else. Export bundles them with the runtime's log for someone you choose.`)}),(0,X.jsx)(`button`,{type:`button`,onClick:()=>n.exportLogs?.(),className:`shrink-0 rounded-full border border-border px-3 py-1.5 text-[12.5px]`,children:t(`Export logs`)})]})]})}function Z({label:e,value:n,ok:r,hint:i,action:a}){return(0,X.jsxs)(`div`,{className:`flex items-start gap-3`,children:[(0,X.jsxs)(`div`,{className:`flex-1`,children:[(0,X.jsxs)(`div`,{className:`flex items-center gap-2 text-[14px]`,children:[(0,X.jsx)(`span`,{children:e}),(0,X.jsx)(`span`,{className:t(`rounded-full px-2 py-0.5 text-[11px] font-medium`,r?`bg-emerald-500/12 text-emerald-700 dark:text-emerald-300`:`bg-amber-500/15 text-amber-700 dark:text-amber-300`),children:n})]}),i&&(0,X.jsx)(`div`,{className:`text-[12.5px] text-muted leading-snug`,children:i})]}),a&&(0,X.jsx)(`button`,{type:`button`,onClick:a.onClick,className:`shrink-0 rounded-full bg-accent px-3 py-1.5 text-[12.5px] font-medium text-white`,children:a.label})]})}function Re({name:e}){let{toast:t}=m(),[n,r]=(0,Y.useState)(null),[i,a]=(0,Y.useState)(`off`),[s,c]=(0,Y.useState)(!1),l=o(),u=async()=>{a(await v());try{r(await y.push())}catch{}};(0,Y.useEffect)(()=>{u()},[]);let f=async()=>{if(n){c(!0);try{let e=i===`on`?await h():await d(n.public_key);a(e),e===`denied`&&t(l(`Notifications are blocked for this site in the browser settings`)),await u()}catch(e){let n=e;t(n.name===`AbortError`?l(`This browser has no push service (embedded browsers often don't). Use Chrome, Edge, Firefox or Safari 16.4+ on the phone.`):n.message)}finally{c(!1)}}},p=async()=>{try{let e=await y.pushTest();t(e.ok?l(`Sent. It should arrive in a moment`):e.error??l(`Could not send`))}catch(e){t(e.message)}},g=i===`unsupported`?l(`This browser cannot receive push notifications.`):i===`insecure`?l(`Notifications need https:// (or localhost). Over plain http on your LAN the app works, this part stays off; see docs/deployment.md.`):i===`denied`?l(`Blocked for this site. Allow notifications in the browser's site settings, then try again.`):n&&!n.available?l(`The server was installed without pywebpush.`):``;return(0,X.jsxs)(X.Fragment,{children:[(0,X.jsx)(T,{label:l(`Let {name} notify this device`,{name:e}),hint:l(`Approvals, questions, finished background work and check-ins; nothing while the app is on screen.`),checked:i===`on`,onChange:()=>void f(),disabled:s||!!g}),g&&(0,X.jsx)(`div`,{className:`text-[12.5px] text-muted`,children:g}),n&&n.subscriptions>0&&(0,X.jsxs)(`div`,{className:`flex items-center justify-between text-[12.5px] text-muted`,children:[(0,X.jsx)(`span`,{children:n.subscriptions===1?l(`1 device subscribed`):l(`{n} devices subscribed`,{n:n.subscriptions})}),(0,X.jsx)(`button`,{type:`button`,onClick:()=>void p(),className:`text-accent font-medium`,children:l(`Send a test`)})]}),!N()&&(0,X.jsx)(`div`,{className:`text-[12.5px] text-muted`,children:l(`On a phone, add the app to the home screen first; the icon then shows a badge and notifications open the right chat.`)})]})}var Q=[{id:`off`,title:`Off`,text:`Only works when you ask.`},{id:`low`,title:`Low`,text:`Checks in half as often; speaks up only when a step is done or it needs you.`},{id:`default`,title:`Default`,text:`Works on goals on schedule; reports real progress, stays quiet otherwise.`},{id:`high`,title:`High`,text:`Checks in twice as often and always reports, even 'still on track'.`}];function ze({value:e,onChange:n}){let r=o(),i=Q.find(t=>t.id===e)??Q[2];return(0,X.jsxs)(`div`,{children:[(0,X.jsx)(`div`,{className:`flex items-center gap-3`,children:(0,X.jsx)(`div`,{className:`flex-1 text-[13px] text-muted leading-snug`,children:r(i.text)})}),(0,X.jsx)(`div`,{className:`mt-2 grid grid-cols-4 gap-1 rounded-2xl bg-surface-2 p-1`,children:Q.map(i=>(0,X.jsx)(`button`,{type:`button`,onClick:()=>n(i.id),"aria-pressed":e===i.id,className:t(`rounded-xl py-1.5 text-[13px] font-medium transition`,e===i.id?`bg-surface shadow-sm text-accent`:`text-muted`),children:r(i.title)},i.id))})]})}function Be({value:e,onChange:n}){let[r,i]=e?e.split(`-`):[``,``],a=!!e,s=o(),c=(e,t)=>n(e&&t?`${e}-${t}`:``);return(0,X.jsxs)(`div`,{children:[(0,X.jsxs)(`label`,{className:`flex items-start gap-3 cursor-pointer`,children:[(0,X.jsxs)(`div`,{className:`flex-1`,children:[(0,X.jsxs)(`div`,{className:`text-[14px] flex items-center gap-1.5`,children:[(0,X.jsx)(U,{size:15,className:`text-muted`}),` `,s(`Quiet hours`)]}),(0,X.jsx)(`div`,{className:`text-[12.5px] text-muted leading-snug`,children:s(`No background work in this window; anything due waits until it ends.`)})]}),(0,X.jsx)(`button`,{type:`button`,role:`switch`,"aria-checked":a,onClick:()=>c(a?``:`22:00`,a?``:`08:00`),className:t(`relative mt-0.5 h-7 w-12 shrink-0 rounded-full transition`,a?`bg-accent`:`bg-surface-2 border border-border`),children:(0,X.jsx)(`span`,{className:t(`absolute top-0.5 h-6 w-6 rounded-full bg-white shadow transition`,a?`left-[22px]`:`left-0.5`)})})]}),a&&(0,X.jsxs)(`div`,{className:`mt-2 flex items-center gap-2 text-[13.5px]`,children:[(0,X.jsx)(`span`,{className:`text-muted`,children:s(`From`)}),(0,X.jsx)(`input`,{type:`time`,value:r,onChange:e=>c(e.target.value,i),className:`rounded-xl bg-surface-2 px-2.5 py-1.5 outline-none`}),(0,X.jsx)(`span`,{className:`text-muted`,children:s(`to`)}),(0,X.jsx)(`input`,{type:`time`,value:i,onChange:e=>c(r,e.target.value),className:`rounded-xl bg-surface-2 px-2.5 py-1.5 outline-none`})]})]})}function Ve(){let e=o(),t=M(),[n,r]=(0,Y.useState)(null);(0,Y.useEffect)(()=>{let e=!0;return t?.loginItem?.().then(t=>{e&&r(t)}),()=>{e=!1}},[t]);let i=t?.platform===`darwin`,a=[[e(`Quick chat`),i?`⌥ Space`:`Ctrl+Shift+Space`],[e(`Show the window`),i?`⌘⇧M`:`Ctrl+Shift+M`],[e(`Stop the hands`),i?`⌘⇧Esc`:`Ctrl+Shift+Esc`]];return(0,X.jsxs)(X.Fragment,{children:[t?.setLoginItem&&n!==null&&t.platform!==`linux`&&(0,X.jsx)(T,{label:e(`Start with the computer`),hint:e(`Opens in the tray at sign-in; the agent's goals and check-ins run from then on.`),checked:n,onChange:e=>{r(e),t.setLoginItem?.(e)}}),(0,X.jsxs)(`div`,{className:`text-[13.5px]`,children:[e(`In the tray`),(0,X.jsx)(`span`,{className:`block text-[12px] text-muted`,children:e(`The icon by the clock shows what the hands are doing and has Stop; closing the window keeps the agent running.`)})]}),(0,X.jsxs)(`div`,{className:`space-y-1`,children:[(0,X.jsx)(`div`,{className:`text-[13.5px]`,children:e(`Shortcuts`)}),a.map(([e,t])=>(0,X.jsxs)(`div`,{className:`flex items-center justify-between text-[13px]`,children:[(0,X.jsx)(`span`,{className:`text-muted`,children:e}),(0,X.jsx)(`kbd`,{className:`rounded-md border border-border bg-surface-2 px-1.5 py-0.5 font-sans text-[12px] text-fg/80`,children:t})]},e))]})]})}function $({title:e,children:n,id:r,plain:i=!1}){return(0,X.jsxs)(`section`,{id:r,className:t(`space-y-3 scroll-mt-4`,i?`pt-1`:`rounded-3xl bg-surface border border-border/70 shadow-sm p-4`),children:[!i&&(0,X.jsx)(`h2`,{className:`text-[12px] font-semibold uppercase tracking-wide text-muted`,children:e}),n]})}export{Me as SettingsScreen}; \ No newline at end of file +import{A as e,E as t,F as n,G as r,H as i,J as a,K as o,L as s,Q as c,T as l,Y as u,_ as d,a as f,b as p,f as m,g as h,h as g,m as _,v,x as y}from"./MuseHeader-Pw-NI98v.js";import{C as b,E as ee,T as te,_ as x,j as S,u as C,w}from"./StarNudge-DjXecvWj.js";import{n as ne}from"./external-link-Xj5fjR8v.js";import{n as T}from"./Form-DwKuBk1V.js";import{t as E}from"./clapperboard-BokpXv9J.js";import{t as re}from"./database-zap-CzaFBl6C.js";import{t as D}from"./plug-Bj_5EEV3.js";import{n as ie,r as O,t as ae}from"./IdentityForm-BTGczGT_.js";import{D as k,E as A,K as j,L as M,M as oe,O as se,R as N,St as P,U as ce,W as F,_t as I,a as L,at as R,bt as z,ct as le,d as ue,dt as B,ft as V,i as H,k as de,n as fe,nt as U,o as W,q as G,r as pe,rt as me,s as K,tt as he,u as ge,vt as _e,wt as ve}from"./index-CIdGZ5PB.js";import{t as q}from"./BackBar-Dl56jHZM.js";import{t as J}from"./AvatarPicker-gR2knlot.js";var ye=a(`battery-full`,[[`path`,{d:`M10 10v4`,key:`1mb2ec`}],[`path`,{d:`M14 10v4`,key:`1nt88p`}],[`path`,{d:`M22 14v-4`,key:`14q9d5`}],[`path`,{d:`M6 10v4`,key:`1n77qd`}],[`rect`,{x:`2`,y:`6`,width:`16`,height:`12`,rx:`2`,key:`13zb55`}]]),be=a(`box`,[[`path`,{d:`M21 8a2 2 0 0 0-1-1.73l-7-4a2 2 0 0 0-2 0l-7 4A2 2 0 0 0 3 8v8a2 2 0 0 0 1 1.73l7 4a2 2 0 0 0 2 0l7-4A2 2 0 0 0 21 16Z`,key:`hh9hay`}],[`path`,{d:`m3.3 7 8.7 5 8.7-5`,key:`g66t2b`}],[`path`,{d:`M12 22V12`,key:`d0xqtd`}]]),xe=a(`chart-column`,[[`path`,{d:`M3 3v16a2 2 0 0 0 2 2h16`,key:`c24i48`}],[`path`,{d:`M18 17V9`,key:`2bz60n`}],[`path`,{d:`M13 17V5`,key:`1frdt8`}],[`path`,{d:`M8 17v-3`,key:`17ska0`}]]),Se=a(`message-square-warning`,[[`path`,{d:`M22 17a2 2 0 0 1-2 2H6.828a2 2 0 0 0-1.414.586l-2.202 2.202A.71.71 0 0 1 2 21.286V5a2 2 0 0 1 2-2h16a2 2 0 0 1 2 2z`,key:`18887p`}],[`path`,{d:`M12 15h.01`,key:`q59x07`}],[`path`,{d:`M12 7v4`,key:`xawao1`}]]),Ce=a(`puzzle`,[[`path`,{d:`M15.39 4.39a1 1 0 0 0 1.68-.474 2.5 2.5 0 1 1 3.014 3.015 1 1 0 0 0-.474 1.68l1.683 1.682a2.414 2.414 0 0 1 0 3.414L19.61 15.39a1 1 0 0 1-1.68-.474 2.5 2.5 0 1 0-3.014 3.015 1 1 0 0 1 .474 1.68l-1.683 1.682a2.414 2.414 0 0 1-3.414 0L8.61 19.61a1 1 0 0 0-1.68.474 2.5 2.5 0 1 1-3.014-3.015 1 1 0 0 0 .474-1.68l-1.683-1.682a2.414 2.414 0 0 1 0-3.414L4.39 8.61a1 1 0 0 1 1.68.474 2.5 2.5 0 1 0 3.014-3.015 1 1 0 0 1-.474-1.68l1.683-1.682a2.414 2.414 0 0 1 3.414 0z`,key:`w46dr5`}]]),we=a(`shield`,[[`path`,{d:`M20 13c0 5-3.5 7.5-7.66 8.95a1 1 0 0 1-.67-.01C7.5 20.5 4 18 4 13V6a1 1 0 0 1 1-1c2 0 4.5-1.2 6.24-2.72a1.17 1.17 0 0 1 1.52 0C14.51 3.81 17 5 19 5a1 1 0 0 1 1 1z`,key:`oel41y`}]]),Te=a(`smile`,[[`circle`,{cx:`12`,cy:`12`,r:`10`,key:`1mglay`}],[`path`,{d:`M8 14s1.5 2 4 2 4-2 4-2`,key:`1y1vjs`}],[`line`,{x1:`9`,x2:`9.01`,y1:`9`,y2:`9`,key:`yxxnd0`}],[`line`,{x1:`15`,x2:`15.01`,y1:`9`,y2:`9`,key:`1p4y9e`}]]),Ee=a(`zap`,[[`path`,{d:`M4 14a1 1 0 0 1-.78-1.63l9.9-10.2a.5.5 0 0 1 .86.46l-1.92 6.02A1 1 0 0 0 13 10h7a1 1 0 0 1 .78 1.63l-9.9 10.2a.5.5 0 0 1-.86-.46l1.92-6.02A1 1 0 0 0 11 14z`,key:`1xq2db`}]]),Y=c(u(),1),De=`(min-width: 64rem)`;function Oe(){return typeof window>`u`?!1:document.documentElement.classList.contains(`desktop`)?!0:typeof window.matchMedia==`function`&&window.matchMedia(De).matches}function ke(){let[e,t]=(0,Y.useState)(Oe);return(0,Y.useEffect)(()=>{if(typeof window.matchMedia!=`function`)return;let e=window.matchMedia(De),n=()=>t(Oe());return e.addEventListener(`change`,n),()=>e.removeEventListener(`change`,n)},[]),e}var X=p(),Ae=`w-full rounded-2xl bg-surface-2 px-3.5 py-2.5 outline-none focus:ring-2 focus:ring-accent/40`,je=[{id:`ask`,title:`Balanced`,text:`Browse, read and write files freely; stop for anything hard to undo: email, purchases, shell commands.`,icon:(0,X.jsx)(j,{size:18})},{id:`strict`,title:`Cautious`,text:`Also ask before moderate actions like fetching web pages or writing files.`,icon:(0,X.jsx)(we,{size:18})},{id:`auto`,title:`Hands-off`,text:`Approve everything automatically except explicit deny rules. For trusted, unattended runs only.`,icon:(0,X.jsx)(G,{size:18})}];function Me(){let{state:e,refreshSettings:a,setTab:s,toast:c}=m(),u=e.settings,[d,p]=(0,Y.useState)(()=>O(e.profile,f,J[0])),[h,v]=(0,Y.useState)(!1),b=o(),te=r(),x=g(),[w,E]=(0,Y.useState)(null),[re,D]=(0,Y.useState)(!1);(0,Y.useEffect)(()=>{u||a()},[u,a]);let j=(0,Y.useCallback)(async(e=!1)=>{D(!0);try{E(await y.update(e))}catch{E(null)}finally{D(!1)}},[]);(0,Y.useEffect)(()=>{j()},[j]),(0,Y.useEffect)(()=>{e.profile&&p(O(e.profile,``,J[0]))},[e.profile]);let M=async(e,t)=>{v(!0);try{await y.updateSettings(e),await a(),t&&c(t)}catch(e){c(e.message)}finally{v(!1)}},P=O(e.profile,``,J[0]),ce=!!e.profile&&Object.keys(d).some(e=>d[e]!==P[e]),F=e.profile?.name??`nanoMuse`,I=de(),L=ue(),R=ke()&&!e.lite,[B,V]=(0,Y.useState)(null),H=[{id:`who`,title:F},{id:`sentinel`,title:b(`Safety · Sentinel`)},{id:`proactivity`,title:b(`Proactivity`)},{id:`notifications`,title:b(`Notifications`)},...k()?[{id:`keep-running`,title:b(`Keep it running`)}]:[],{id:`model`,title:b(`Model`)},{id:`appearance`,title:b(`Appearance`)},...N()?[{id:`desktop`,title:b(`Desktop app`)}]:[],{id:`data`,title:b(`Data controls`)},{id:`developer`,title:b(`Developer`)},{id:`about`,title:b(`About`)}],U=e=>R||B===e,[W,G]=(0,Y.useState)(()=>{let e=window.location.hash.slice(1);return Ne.includes(e)?e:null});if((0,Y.useEffect)(()=>{if(W&&u){if(G(null),history.replaceState(null,``,window.location.pathname+window.location.search),!R){V(W);return}requestAnimationFrame(()=>document.getElementById(W)?.scrollIntoView({behavior:`smooth`,block:`start`}))}},[W,u,R]),!R&&B===null)return(0,X.jsx)(Fe,{release:w,onOpen:V});let pe=H.find(e=>e.id===B);return(0,X.jsxs)(`div`,{className:`flex h-full flex-col`,children:[R?(0,X.jsx)(q,{title:b(`Settings`),description:b(`Its name and look, how careful it is, how often it speaks up.`)}):(0,X.jsx)(q,{title:pe?.title??b(`Settings`),onBack:()=>V(null),backLabel:b(`Settings`)}),(0,X.jsxs)(`div`,{className:`flex min-h-0 flex-1`,children:[R&&(0,X.jsx)(`nav`,{className:`flex w-[188px] shrink-0 flex-col gap-0.5 self-start pl-4 pr-2 pt-1`,"aria-label":b(`Settings`),children:H.map(e=>(0,X.jsx)(`button`,{type:`button`,onClick:()=>document.getElementById(e.id)?.scrollIntoView({behavior:`smooth`,block:`start`}),className:`truncate rounded-xl px-3 py-1.5 text-left text-[13px] font-medium text-fg/75 hover:bg-surface-2 hover:text-fg`,children:e.title},e.id))}),(0,X.jsxs)(`div`,{className:`flex-1 overflow-y-auto px-4 pb-8 space-y-5`,children:[U(`who`)&&(0,X.jsxs)($,{title:F,id:`who`,plain:!R,children:[(0,X.jsx)(ae,{value:d,onChange:p,suggestions:!1,inputCls:Ae,onStudio:()=>s(`avatar`)}),(0,X.jsx)(`button`,{type:`button`,disabled:!ce||h,onClick:()=>void M({profile:ie(d)},b(`Saved`)),className:`w-full rounded-2xl bg-accent text-accent-fg py-2.5 font-medium disabled:opacity-40`,children:b(`Save`)})]}),U(`sentinel`)&&(0,X.jsxs)($,{title:b(`Safety · Sentinel`),id:`sentinel`,plain:!R,children:[(0,X.jsx)(`p`,{className:`text-[13px] text-muted -mt-1`,children:b(`A separate gatekeeper reviews every action. Pick how often it should check in with you.`)}),(0,X.jsx)(`div`,{className:`space-y-2`,children:je.map(e=>(0,X.jsxs)(`button`,{type:`button`,onClick:()=>void M({sentinel_mode:e.id}),"aria-pressed":u?.sentinel.mode===e.id,className:t(`w-full text-left rounded-2xl border px-3.5 py-3 flex items-start gap-3 transition`,u?.sentinel.mode===e.id?`border-accent bg-accent/8`:`border-border`),children:[(0,X.jsx)(`div`,{className:t(`mt-0.5`,e.id===`auto`?`text-rose-500`:`text-accent`),children:e.icon}),(0,X.jsxs)(`div`,{className:`flex-1`,children:[(0,X.jsx)(`div`,{className:`font-medium text-[14.5px]`,children:b(e.title)}),(0,X.jsx)(`div`,{className:`text-[12.5px] text-muted leading-snug mt-0.5`,children:b(e.text)})]}),u?.sentinel.mode===e.id&&(0,X.jsx)(ne,{size:18,className:`text-accent mt-0.5`})]},e.id))}),u&&(0,X.jsxs)(`div`,{className:`text-[12.5px] text-muted leading-relaxed`,children:[b(`Always asks before: {tools}.`,{tools:u.sentinel.always_ask_tools.map(e=>b(e)).join(`, `)||`—`}),` `,u.sentinel.taint_tracking&&b(`After reading private data, new network destinations need approval.`)]}),u?.sandbox&&(0,X.jsxs)(`div`,{className:`flex items-start gap-2.5 rounded-2xl bg-surface-2/60 px-3.5 py-2.5 text-[12.5px] leading-snug`,children:[(0,X.jsx)(be,{size:15,className:t(`shrink-0 mt-[2px]`,u.sandbox.active?`text-emerald-500`:`text-muted`)}),(0,X.jsxs)(`div`,{children:[(0,X.jsxs)(`div`,{className:`font-medium text-fg`,children:[u.sandbox.active?b(`Commands run in a sandbox`):b(`Commands run without a sandbox`),(0,X.jsxs)(`span`,{className:`text-muted font-normal`,children:[` · `,u.sandbox.status]})]}),(0,X.jsx)(`div`,{className:`text-muted mt-0.5`,children:u.sandbox.active?b(`Each shell or Python call gets its own namespace: only the workspace is writable, your home directory is not there, and there is no network unless the command needs it.`):u.sandbox.status.includes(`container`)?b(`Each shell or Python call runs in the workspace with a scrubbed environment; the container is the boundary.`):b(`Each shell or Python call runs in the workspace with a scrubbed environment. On Linux, installing bubblewrap gives each one its own namespace.`)})]})]})]}),U(`proactivity`)&&(0,X.jsxs)($,{title:b(`Proactivity`),id:`proactivity`,plain:!R,children:[(0,X.jsx)(ze,{value:e.profile?.proactivity??`default`,onChange:e=>void M({profile:{proactivity:e}})}),(0,X.jsxs)(`div`,{className:`flex items-center gap-3`,children:[(0,X.jsxs)(`label`,{className:`text-[13.5px] flex-1`,children:[b(`Check-in interval`),e.profile&&e.profile.proactivity!=="default"&&e.profile.proactivity!==`off`&&(0,X.jsx)(`span`,{className:`block text-[12px] text-muted`,children:e.profile.proactivity===`low`?b(`Doubled at this level`):b(`Halved at this level`)})]}),(0,X.jsx)(`select`,{value:e.profile?.goal_interval_minutes??60,onChange:e=>void M({profile:{goal_interval_minutes:Number(e.target.value)}}),className:`rounded-2xl bg-surface-2 px-3 py-2 text-[13.5px] outline-none`,children:[...new Set([15,30,60,120,240,480,1440,e.profile?.goal_interval_minutes??60])].sort((e,t)=>e-t).map(e=>(0,X.jsx)(`option`,{value:e,children:e<60?b(`{n} min`,{n:e}):e%60?`${b(`{n} h`,{n:Math.floor(e/60)})} ${b(`{n} min`,{n:e%60})}`:b(`{n} h`,{n:e/60})},e))})]}),(0,X.jsx)(Be,{value:e.profile?.quiet_hours??``,onChange:e=>void M({profile:{quiet_hours:e}})})]}),U(`notifications`)&&(0,X.jsx)($,{title:b(`Notifications`),id:`notifications`,plain:!R,children:A()?(0,X.jsx)(Ie,{name:e.profile?.name??`nanoMuse`}):(0,X.jsx)(Re,{name:e.profile?.name??`nanoMuse`})}),k()&&U(`keep-running`)&&(0,X.jsx)($,{title:b(`Keep it running`),id:`keep-running`,plain:!R,children:(0,X.jsx)(Le,{name:e.profile?.name??`nanoMuse`})}),U(`model`)&&(0,X.jsxs)($,{title:b(`Model`),id:`model`,plain:!R,children:[u&&(0,X.jsxs)(`button`,{type:`button`,onClick:()=>s(`connections`),className:`w-full text-[13.5px] flex items-center justify-between`,children:[(0,X.jsx)(`span`,{className:`text-muted`,children:b(`Provider / model`)}),(0,X.jsxs)(`span`,{className:`font-mono text-[12.5px] flex items-center gap-1`,children:[u.llm.model,` `,(0,X.jsx)(z,{size:14,className:`text-muted`})]})]}),u?.llm.cloud&&(0,X.jsxs)(`button`,{type:`button`,onClick:()=>oe(s,S(e.hub?.account).preset),className:`w-full text-[13.5px] flex items-center justify-between`,children:[(0,X.jsx)(`span`,{className:`text-muted`,children:b(`Use my own API key or a plan I pay for`)}),(0,X.jsxs)(`span`,{className:`text-[12.5px] text-muted flex items-center gap-1`,children:[b(`{first} first, then {others}`,{first:S(e.hub?.account).label,others:ee(e.hub?.account)?b(`DeepSeek, Kimi, OpenAI, ChatGPT…`):b(`OpenAI, ChatGPT, Gemini, DeepSeek…`)}),` `,(0,X.jsx)(z,{size:14})]})]}),(0,X.jsxs)(`button`,{type:`button`,onClick:()=>s(`connections`),className:`w-full text-[13.5px] flex items-center justify-between`,children:[(0,X.jsx)(`span`,{className:`text-muted`,children:b(`Connections`)}),(0,X.jsxs)(`span`,{className:`text-[12.5px] text-muted flex items-center gap-1`,children:[b(`E-mail, calendar, browser, MCP servers`),` `,(0,X.jsx)(z,{size:14})]})]})]}),U(`appearance`)&&(0,X.jsxs)($,{title:b(`Appearance`),id:`appearance`,plain:!R,children:[(0,X.jsx)(T,{label:b(`Show the agent's steps`),hint:b(`Every tool it uses becomes a chip in the chat. Off, the chat keeps to the conversation and the line under the name says what it is on. This device only.`),checked:L,onChange:ge}),(0,X.jsx)(T,{label:b(`Show thinking`),hint:b(`Reveal the model's reasoning under each reply when the provider exposes it.`),checked:!!u?.agent.show_thinking,onChange:e=>void M({show_thinking:e})}),(0,X.jsxs)(`div`,{className:`flex items-center gap-3`,children:[(0,X.jsxs)(`label`,{className:`text-[13.5px] flex-1`,children:[b(`Appearance`),(0,X.jsx)(`span`,{className:`block text-[12px] text-muted`,children:b(`This device only`)})]}),(0,X.jsxs)(`select`,{value:x,onChange:e=>_(e.target.value),className:`rounded-2xl bg-surface-2 px-3 py-2 text-[13.5px] outline-none`,children:[(0,X.jsx)(`option`,{value:`light`,children:b(`Light`)}),(0,X.jsx)(`option`,{value:`dark`,children:b(`Dark`)}),(0,X.jsx)(`option`,{value:`system`,children:b(`Follow the system`)})]})]}),(0,X.jsxs)(`div`,{className:`flex items-center gap-3`,children:[(0,X.jsxs)(`label`,{className:`text-[13.5px] flex-1`,children:[b(`App language`),(0,X.jsx)(`span`,{className:`block text-[12px] text-muted`,children:b(`This device only`)})]}),(0,X.jsx)(`select`,{value:te,onChange:e=>i(e.target.value),className:`rounded-2xl bg-surface-2 px-3 py-2 text-[13.5px] outline-none`,children:n.map(e=>(0,X.jsx)(`option`,{value:e.value,children:e.value===`auto`?b(`Auto`):e.label},e.value))})]}),(0,X.jsxs)(`div`,{className:`flex items-center gap-3`,children:[(0,X.jsxs)(`label`,{className:`text-[13.5px] flex-1`,children:[b(`Reply language`),(0,X.jsx)(`span`,{className:`block text-[12px] text-muted`,children:b(`What {name} writes in`,{name:e.profile?.name??`nanoMuse`})})]}),(0,X.jsxs)(`select`,{value:u?.agent.language??`auto`,onChange:e=>void M({language:e.target.value}),className:`rounded-2xl bg-surface-2 px-3 py-2 text-[13.5px] outline-none`,children:[(0,X.jsx)(`option`,{value:`auto`,children:b(`Match mine`)}),(0,X.jsx)(`option`,{value:`English`,children:`English`}),(0,X.jsx)(`option`,{value:`中文`,children:`中文`}),(0,X.jsx)(`option`,{value:`日本語`,children:`日本語`}),(0,X.jsx)(`option`,{value:`Español`,children:`Español`}),(0,X.jsx)(`option`,{value:`Deutsch`,children:`Deutsch`}),(0,X.jsx)(`option`,{value:`Français`,children:`Français`})]})]})]}),N()&&U(`desktop`)&&(0,X.jsx)($,{title:b(`Desktop app`),id:`desktop`,plain:!R,children:(0,X.jsx)(Ve,{})}),U(`data`)&&(0,X.jsx)($,{title:b(`Data controls`),id:`data`,plain:!R,children:(0,X.jsx)(fe,{flush:!0})}),U(`developer`)&&(0,X.jsxs)($,{title:b(`Developer`),id:`developer`,plain:!R,children:[(0,X.jsx)(T,{label:b(`Developer tools`),hint:b(`The Coding screen (Cursor, Codex and the other coding agents on this computer) in the sidebar, and the runtime's address below. This device only.`),checked:I,onChange:se}),I&&(0,X.jsxs)(`div`,{className:`text-[13px] text-muted space-y-1`,children:[(0,X.jsxs)(`div`,{className:`break-all`,children:[b(`Runtime:`),` `,window.location.origin,` · `,(0,X.jsx)(`span`,{className:`text-fg/70`,children:b(`the token is in the server_token file in the data folder`)})]}),(0,X.jsxs)(`div`,{children:[(0,X.jsx)(`a`,{href:`https://github.com/nano-muse/nanoMuse/blob/main/docs/cli.md`,target:`_blank`,rel:`noreferrer`,className:`text-accent underline-offset-2 hover:underline`,children:b(`The command line and the API`)}),` · `,(0,X.jsx)(`a`,{href:`https://github.com/nano-muse/nanoMuse/blob/main/docs/harness.md`,target:`_blank`,rel:`noreferrer`,className:`text-accent underline-offset-2 hover:underline`,children:b(`nanoMuse on DeepSeek Harness`)})]})]})]}),U(`about`)&&(0,X.jsxs)($,{title:b(`About`),id:`about`,plain:!R,children:[(0,X.jsx)(C,{}),(0,X.jsx)(Pe,{installed:e.version,release:w,checking:re,onCheck:()=>void j(!0)}),(0,X.jsxs)(`div`,{className:`text-[13px] text-muted space-y-1`,children:[u&&(0,X.jsxs)(`div`,{className:`break-all`,children:[b(`Data:`),` `,u.data_dir]}),u&&(0,X.jsxs)(`div`,{className:`break-all`,children:[b(`Workspace:`),` `,u.agent.workspace]}),(0,X.jsx)(`div`,{children:e.connected?b(`Connected`):b(`Reconnecting…`)})]}),(0,X.jsxs)(`button`,{type:`button`,onClick:()=>{let e=A();if(e){e.disconnect();return}l(``),window.location.reload()},className:`w-full rounded-2xl border border-border py-2.5 text-[14px] font-medium flex items-center justify-center gap-2 text-muted`,children:[(0,X.jsx)(le,{size:16}),` `,A()?b(`Disconnect from this server`):b(`Forget this device's access token`)]})]})]})]})]})}var Ne=[`who`,`sentinel`,`proactivity`,`notifications`,`keep-running`,`model`,`appearance`,`desktop`,`data`,`developer`,`about`];function Pe({installed:t,release:n,checking:r,onCheck:i}){let a=o(),s=!!A(),c=(0,X.jsx)(`button`,{type:`button`,onClick:i,disabled:r,className:`text-accent underline-offset-2 hover:underline disabled:opacity-60`,children:a(r?`Checking…`:`Check now`)}),l;return l=s?a(`The phone app checks for updates on its own.`):n&&!n.enabled?a(`Update checks are off here.`):r&&!n?a(`Checking…`):n?.latest&&n.newer?(0,X.jsxs)(X.Fragment,{children:[a(`{version} is out`,{version:n.latest}),` · `,(0,X.jsx)(`a`,{href:n.download_url||n.url,target:`_blank`,rel:`noreferrer`,className:`font-medium text-accent underline-offset-2 hover:underline`,children:a(`Update`)})]}):n?.latest?(0,X.jsxs)(X.Fragment,{children:[a(`Latest {version}; you have it`,{version:n.latest}),` · `,c]}):(0,X.jsxs)(X.Fragment,{children:[a(`Could not check`),` · `,c]}),(0,X.jsxs)(`div`,{className:`rounded-2xl bg-surface-2/60 px-3.5 py-2.5 text-[13px]`,children:[(0,X.jsx)(`div`,{className:`font-medium`,children:a(`nanoMuse {version}`,{version:t})}),(0,X.jsx)(`div`,{className:`mt-0.5 text-muted`,children:l}),!s&&n?.latest&&n.newer&&(0,X.jsx)(`div`,{className:`mt-1 text-[12px] text-muted`,children:a(`To update: pip install -U nanomuse, pull the new image, or use the desktop app's Update.`)}),!s&&n?.checked_at&&(0,X.jsx)(`div`,{className:`mt-1 text-[12px] text-muted`,children:a(`Checked {when}`,{when:e(n.checked_at)})})]})}function Fe({release:e,onOpen:t}){let{state:n,setTab:r}=m(),i=o(),a=n.settings,c=n.hub,l=te(),u=n.profile?.name??`nanoMuse`,d=g(),f=c?.devices.filter(e=>!e.this&&e.kind!==`web`)??[],p=f.filter(e=>e.kind===`computer`),h=f.filter(e=>e.online&&e.actions?.includes(`coding.sessions`)),_=a?.sentinel.mode,v=_===`ask`?i(`Balanced`):_===`strict`?i(`Cautious`):_===`auto`?i(`Hands-off`):``,y=n.profile?.proactivity??`default`,ee=i(y===`off`?`Off`:y===`low`?`Low`:y===`high`?`High`:`Default`),S=i(d===`dark`?`Dark`:d===`light`?`Light`:`Follow the system`),C=i(`none`);return(0,X.jsxs)(`div`,{className:`flex h-full flex-col`,children:[(0,X.jsx)(q,{title:i(`Settings`)}),(0,X.jsxs)(`div`,{className:`flex-1 overflow-y-auto pb-8 pt-2`,children:[(0,X.jsxs)(L,{className:`mb-3`,children:[(0,X.jsxs)(`button`,{type:`button`,onClick:()=>r(`connections`),className:`flex w-full items-center gap-3 px-4 py-3.5 text-left hover:bg-surface-2/60`,children:[(0,X.jsxs)(`span`,{className:`min-w-0 flex-1`,children:[(0,X.jsx)(`span`,{className:`block truncate text-[16px] font-medium leading-[21px]`,children:a?.llm.model||i(`No model yet`)}),(0,X.jsx)(`span`,{className:`mt-0.5 block truncate text-[12.5px] leading-4 text-muted`,children:a?a.llm.cloud?`nanoMuse Cloud`:a.llm.provider:i(`Add a provider and pick its models`)})]}),(0,X.jsx)(`span`,{className:`text-[14px] font-medium text-accent`,children:i(`Change`)})]}),(0,X.jsx)(W,{}),(0,X.jsx)(K,{icon:(0,X.jsx)(_e,{size:22}),label:`nanoMuse Cloud`,value:c?.account.signed_in?c.account.hint:i(`Sign in`),onClick:()=>r(`account`)}),(0,X.jsx)(W,{}),(0,X.jsx)(K,{icon:(0,X.jsx)(E,{size:22}),label:i(`Image & video models`),value:x(l,`image`)===!1?w(i,`image`,b(c?.account),s()):x(l,`video`)===!1?w(i,`video`,b(c?.account),s()):void 0,onClick:()=>r(`connections`)}),(0,X.jsx)(W,{}),(0,X.jsx)(K,{icon:(0,X.jsx)(xe,{size:22}),label:i(`Usage`),onClick:()=>r(`account`)})]}),(0,X.jsxs)(L,{className:`mb-3`,children:[(0,X.jsx)(K,{icon:(0,X.jsx)(F,{size:22}),label:i(`Name & personality`),value:u,onClick:()=>t(`who`)}),(0,X.jsx)(W,{}),(0,X.jsx)(K,{icon:(0,X.jsx)(Te,{size:22}),label:i(`Avatar`),onClick:()=>r(`avatar`)}),(0,X.jsx)(W,{}),(0,X.jsx)(K,{icon:(0,X.jsx)(P,{size:22}),label:i(`Memory`),onClick:()=>r(`memory`)}),a?.skills?.enabled!==!1&&(0,X.jsxs)(X.Fragment,{children:[(0,X.jsx)(W,{}),(0,X.jsx)(K,{icon:(0,X.jsx)(Ce,{size:22}),label:i(`Skills`),value:a?String(a.skills.count):void 0,onClick:()=>r(`skills`)})]}),(0,X.jsx)(W,{}),(0,X.jsx)(K,{icon:(0,X.jsx)(D,{size:22}),label:i(`Connections`),value:a?.connectors.mcp.length?`${a.connectors.mcp.length} MCP`:void 0,onClick:()=>r(`connections`)}),(0,X.jsx)(W,{}),(0,X.jsx)(K,{icon:(0,X.jsx)(R,{size:22}),label:i(`Chat apps`),onClick:()=>r(`channels`)}),(0,X.jsx)(W,{}),(0,X.jsx)(K,{icon:(0,X.jsx)(me,{size:22}),label:i(`Devices`),value:p.length?String(p.length):C,onClick:()=>r(`devices`)}),(0,X.jsx)(W,{}),(0,X.jsx)(K,{icon:(0,X.jsx)(ce,{size:22}),label:i(`Coding agents`),value:h.length?String(h.length):C,onClick:()=>r(`coding`)})]}),(0,X.jsxs)(L,{className:`mb-3`,children:[(0,X.jsx)(K,{icon:(0,X.jsx)(j,{size:22}),label:i(`Safety · Sentinel`),value:v,onClick:()=>t(`sentinel`)}),(0,X.jsx)(W,{}),(0,X.jsx)(K,{icon:(0,X.jsx)(Ee,{size:22}),label:i(`Proactivity`),value:ee,onClick:()=>t(`proactivity`)}),(0,X.jsx)(W,{}),(0,X.jsx)(K,{icon:(0,X.jsx)(ve,{size:22}),label:i(`Notifications`),onClick:()=>t(`notifications`)}),k()&&(0,X.jsxs)(X.Fragment,{children:[(0,X.jsx)(W,{}),(0,X.jsx)(K,{icon:(0,X.jsx)(ye,{size:22}),label:i(`Keep it running`),onClick:()=>t(`keep-running`)})]})]}),(0,X.jsxs)(L,{className:`mb-3`,children:[(0,X.jsx)(K,{icon:(0,X.jsx)(he,{size:22}),label:i(`Appearance`),value:S,onClick:()=>t(`appearance`)}),N()&&(0,X.jsxs)(X.Fragment,{children:[(0,X.jsx)(W,{}),(0,X.jsx)(K,{icon:(0,X.jsx)(me,{size:22}),label:i(`Desktop app`),onClick:()=>t(`desktop`)})]}),(0,X.jsx)(W,{}),(0,X.jsx)(K,{icon:(0,X.jsx)(re,{size:22}),label:i(`Data controls`),onClick:()=>t(`data`)}),(0,X.jsx)(W,{}),(0,X.jsx)(K,{icon:(0,X.jsx)(I,{size:22}),label:i(`Developer`),onClick:()=>t(`developer`)})]}),(0,X.jsxs)(L,{className:`mb-3`,children:[(0,X.jsx)(K,{icon:(0,X.jsx)(B,{size:22}),label:i(`About nanoMuse`),value:e?.newer&&e.latest?i(`{version} is out`,{version:e.latest}):void 0,onClick:()=>t(`about`)}),(0,X.jsx)(W,{}),(0,X.jsx)(K,{icon:(0,X.jsx)(V,{size:22}),label:i(`Privacy policy`),onClick:()=>window.open(pe,`_blank`,`noopener`),external:!0}),(0,X.jsx)(W,{}),(0,X.jsx)(K,{icon:(0,X.jsx)(Se,{size:22}),label:i(`Feedback`),onClick:()=>window.open(`https://github.com/nano-muse/nanoMuse/issues/new/choose`,`_blank`,`noopener`),external:!0})]}),(0,X.jsxs)(H,{children:[`nanoMuse `,n.version]})]})]})}function Ie({name:e}){let t=o(),n=A(),[r,i]=(0,Y.useState)(()=>n?.notificationsEnabled()??!1);return n?(0,X.jsxs)(X.Fragment,{children:[(0,X.jsx)(T,{label:t(`Let {name} notify this phone`,{name:e}),hint:t(`The app stays connected to your server in the background. Approvals, questions and finished background work arrive as notifications and open the right chat.`),checked:r,onChange:e=>{n.setNotificationsEnabled(e),i(e)}}),(0,X.jsx)(`div`,{className:`text-[12.5px] text-muted`,children:t(`nanoMuse for Android {version}`,{version:n.version()})})]}):null}function Le({name:e}){let t=o(),n=A(),[r,i]=(0,Y.useState)(k);if((0,Y.useEffect)(()=>{let e=()=>i(k());return document.addEventListener(`visibilitychange`,e),window.addEventListener(`focus`,e),()=>{document.removeEventListener(`visibilitychange`,e),window.removeEventListener(`focus`,e)}},[]),!n||!r)return null;let a=e=>n.openKeepRunning?.(e),s={xiaomi:t(`Xiaomi / Redmi / POCO: Settings → Apps → Manage apps → {name} → Autostart on; Battery saver → No restrictions; Other permissions → Display pop-up windows while running in the background on.`),huawei:t(`Huawei: Settings → Battery → App launch → {name} → Manage manually, all three on (auto-launch, secondary launch, run in background); Settings → Apps → {name} → Battery → Launch: manage manually.`),honor:t(`Honor: Settings → Battery → App launch → {name} → Manage manually, all three on; Battery → More battery settings → Stay connected while asleep on.`),oppo:t(`OPPO / realme / OnePlus: Settings → Battery → More settings → Optimise battery use → {name} → Don't optimise; Settings → Apps → {name} → Battery usage → Allow background activity, Allow auto launch.`),vivo:t(`vivo / iQOO: i Manager → App manager → Autostart → {name} on; Settings → Battery → Background power consumption management → {name} → Allow high background power consumption.`),samsung:t(`Samsung: Settings → Battery → Background usage limits → {name} not in Sleeping or Deep sleeping apps (add it to Never sleeping apps); turn off Adaptive battery if it keeps stopping.`),meizu:t(`Meizu: Settings → Apps → {name} → Background management → Keep running in the background; Battery → App power management → Allow.`)}[r.vendor];return(0,X.jsxs)(X.Fragment,{children:[(0,X.jsx)(`p`,{className:`text-[12.5px] text-muted leading-snug`,children:t(`Android stops apps that seem idle. {name} runs as a foreground service and holds the phone awake only while a task runs; these switches let it keep that promise on this phone.`,{name:e})}),(0,X.jsx)(Z,{label:t(`Battery`),value:r.battery_unrestricted?t(`Unrestricted`):t(`Optimised`),ok:r.battery_unrestricted,hint:t(`Optimised means Android may freeze the agent after a while with the screen off; routines and check-ins then wait until the phone wakes.`),action:r.battery_unrestricted?void 0:{label:t(`Allow`),onClick:()=>a(`battery`)}}),(0,X.jsx)(Z,{label:t(`Display over other apps`),value:r.overlay?t(`Allowed`):t(`Not allowed`),ok:r.overlay,hint:t(`Lets the agent bring an app to the front from the background and show its status capsule while it works in other apps.`),action:r.overlay?void 0:{label:t(`Allow`),onClick:()=>a(`overlay`)}}),r.exact_alarms!==`n/a`&&r.local&&(0,X.jsx)(Z,{label:t(`Alarms & reminders`),value:r.exact_alarms===`granted`?t(`Exact`):t(`Approximate`),ok:r.exact_alarms===`granted`,hint:t(`With exact alarms a reminder fires at the minute you named even when the phone is asleep; without them Android may deliver it up to a quarter of an hour late.`),action:r.exact_alarms===`granted`?void 0:{label:t(`Allow`),onClick:()=>a(`alarms`)}}),(0,X.jsx)(T,{label:t(`Start after a reboot`),hint:r.local?t(`Bring the runtime back when the phone restarts, so routines and check-ins do not stop.`):t(`Reconnect to your computer when the phone restarts, so approvals keep arriving.`),checked:r.boot_start,onChange:e=>{n.setStartOnBoot?.(e),i({...r,boot_start:e})}}),s&&(0,X.jsxs)(`div`,{className:`rounded-2xl bg-surface-2 px-3 py-2.5 text-[12.5px] leading-snug space-y-2`,children:[(0,X.jsx)(`div`,{className:`font-medium`,children:t(`On this phone's Android`)}),(0,X.jsx)(`div`,{className:`text-muted`,children:s}),r.autostart_settings&&(0,X.jsx)(`button`,{type:`button`,onClick:()=>a(`autostart`),className:`rounded-full border border-border px-3 py-1.5 text-[12.5px]`,children:t(`Open the auto-start settings`)})]}),(0,X.jsxs)(`div`,{className:`flex items-center justify-between gap-3 pt-1`,children:[(0,X.jsx)(`div`,{className:`text-[12.5px] text-muted leading-snug`,children:t(`Crashes are written to a file on this phone and nowhere else. Export bundles them with the runtime's log for someone you choose.`)}),(0,X.jsx)(`button`,{type:`button`,onClick:()=>n.exportLogs?.(),className:`shrink-0 rounded-full border border-border px-3 py-1.5 text-[12.5px]`,children:t(`Export logs`)})]})]})}function Z({label:e,value:n,ok:r,hint:i,action:a}){return(0,X.jsxs)(`div`,{className:`flex items-start gap-3`,children:[(0,X.jsxs)(`div`,{className:`flex-1`,children:[(0,X.jsxs)(`div`,{className:`flex items-center gap-2 text-[14px]`,children:[(0,X.jsx)(`span`,{children:e}),(0,X.jsx)(`span`,{className:t(`rounded-full px-2 py-0.5 text-[11px] font-medium`,r?`bg-emerald-500/12 text-emerald-700 dark:text-emerald-300`:`bg-amber-500/15 text-amber-700 dark:text-amber-300`),children:n})]}),i&&(0,X.jsx)(`div`,{className:`text-[12.5px] text-muted leading-snug`,children:i})]}),a&&(0,X.jsx)(`button`,{type:`button`,onClick:a.onClick,className:`shrink-0 rounded-full bg-accent px-3 py-1.5 text-[12.5px] font-medium text-white`,children:a.label})]})}function Re({name:e}){let{toast:t}=m(),[n,r]=(0,Y.useState)(null),[i,a]=(0,Y.useState)(`off`),[s,c]=(0,Y.useState)(!1),l=o(),u=async()=>{a(await v());try{r(await y.push())}catch{}};(0,Y.useEffect)(()=>{u()},[]);let f=async()=>{if(n){c(!0);try{let e=i===`on`?await h():await d(n.public_key);a(e),e===`denied`&&t(l(`Notifications are blocked for this site in the browser settings`)),await u()}catch(e){let n=e;t(n.name===`AbortError`?l(`This browser has no push service (embedded browsers often don't). Use Chrome, Edge, Firefox or Safari 16.4+ on the phone.`):n.message)}finally{c(!1)}}},p=async()=>{try{let e=await y.pushTest();t(e.ok?l(`Sent. It should arrive in a moment`):e.error??l(`Could not send`))}catch(e){t(e.message)}},g=i===`unsupported`?l(`This browser cannot receive push notifications.`):i===`insecure`?l(`Notifications need https:// (or localhost). Over plain http on your LAN the app works, this part stays off; see docs/deployment.md.`):i===`denied`?l(`Blocked for this site. Allow notifications in the browser's site settings, then try again.`):n&&!n.available?l(`The server was installed without pywebpush.`):``;return(0,X.jsxs)(X.Fragment,{children:[(0,X.jsx)(T,{label:l(`Let {name} notify this device`,{name:e}),hint:l(`Approvals, questions, finished background work and check-ins; nothing while the app is on screen.`),checked:i===`on`,onChange:()=>void f(),disabled:s||!!g}),g&&(0,X.jsx)(`div`,{className:`text-[12.5px] text-muted`,children:g}),n&&n.subscriptions>0&&(0,X.jsxs)(`div`,{className:`flex items-center justify-between text-[12.5px] text-muted`,children:[(0,X.jsx)(`span`,{children:n.subscriptions===1?l(`1 device subscribed`):l(`{n} devices subscribed`,{n:n.subscriptions})}),(0,X.jsx)(`button`,{type:`button`,onClick:()=>void p(),className:`text-accent font-medium`,children:l(`Send a test`)})]}),!N()&&(0,X.jsx)(`div`,{className:`text-[12.5px] text-muted`,children:l(`On a phone, add the app to the home screen first; the icon then shows a badge and notifications open the right chat.`)})]})}var Q=[{id:`off`,title:`Off`,text:`Only works when you ask.`},{id:`low`,title:`Low`,text:`Checks in half as often; speaks up only when a step is done or it needs you.`},{id:`default`,title:`Default`,text:`Works on goals on schedule; reports real progress, stays quiet otherwise.`},{id:`high`,title:`High`,text:`Checks in twice as often and always reports, even 'still on track'.`}];function ze({value:e,onChange:n}){let r=o(),i=Q.find(t=>t.id===e)??Q[2];return(0,X.jsxs)(`div`,{children:[(0,X.jsx)(`div`,{className:`flex items-center gap-3`,children:(0,X.jsx)(`div`,{className:`flex-1 text-[13px] text-muted leading-snug`,children:r(i.text)})}),(0,X.jsx)(`div`,{className:`mt-2 grid grid-cols-4 gap-1 rounded-2xl bg-surface-2 p-1`,children:Q.map(i=>(0,X.jsx)(`button`,{type:`button`,onClick:()=>n(i.id),"aria-pressed":e===i.id,className:t(`rounded-xl py-1.5 text-[13px] font-medium transition`,e===i.id?`bg-surface shadow-sm text-accent`:`text-muted`),children:r(i.title)},i.id))})]})}function Be({value:e,onChange:n}){let[r,i]=e?e.split(`-`):[``,``],a=!!e,s=o(),c=(e,t)=>n(e&&t?`${e}-${t}`:``);return(0,X.jsxs)(`div`,{children:[(0,X.jsxs)(`label`,{className:`flex items-start gap-3 cursor-pointer`,children:[(0,X.jsxs)(`div`,{className:`flex-1`,children:[(0,X.jsxs)(`div`,{className:`text-[14px] flex items-center gap-1.5`,children:[(0,X.jsx)(U,{size:15,className:`text-muted`}),` `,s(`Quiet hours`)]}),(0,X.jsx)(`div`,{className:`text-[12.5px] text-muted leading-snug`,children:s(`No background work in this window; anything due waits until it ends.`)})]}),(0,X.jsx)(`button`,{type:`button`,role:`switch`,"aria-checked":a,onClick:()=>c(a?``:`22:00`,a?``:`08:00`),className:t(`relative mt-0.5 h-7 w-12 shrink-0 rounded-full transition`,a?`bg-accent`:`bg-surface-2 border border-border`),children:(0,X.jsx)(`span`,{className:t(`absolute top-0.5 h-6 w-6 rounded-full bg-white shadow transition`,a?`left-[22px]`:`left-0.5`)})})]}),a&&(0,X.jsxs)(`div`,{className:`mt-2 flex items-center gap-2 text-[13.5px]`,children:[(0,X.jsx)(`span`,{className:`text-muted`,children:s(`From`)}),(0,X.jsx)(`input`,{type:`time`,value:r,onChange:e=>c(e.target.value,i),className:`rounded-xl bg-surface-2 px-2.5 py-1.5 outline-none`}),(0,X.jsx)(`span`,{className:`text-muted`,children:s(`to`)}),(0,X.jsx)(`input`,{type:`time`,value:i,onChange:e=>c(r,e.target.value),className:`rounded-xl bg-surface-2 px-2.5 py-1.5 outline-none`})]})]})}function Ve(){let e=o(),t=M(),[n,r]=(0,Y.useState)(null);(0,Y.useEffect)(()=>{let e=!0;return t?.loginItem?.().then(t=>{e&&r(t)}),()=>{e=!1}},[t]);let i=t?.platform===`darwin`,a=[[e(`Quick chat`),i?`⌥ Space`:`Ctrl+Shift+Space`],[e(`Show the window`),i?`⌘⇧M`:`Ctrl+Shift+M`],[e(`Stop the hands`),i?`⌘⇧Esc`:`Ctrl+Shift+Esc`]];return(0,X.jsxs)(X.Fragment,{children:[t?.setLoginItem&&n!==null&&t.platform!==`linux`&&(0,X.jsx)(T,{label:e(`Start with the computer`),hint:e(`Opens in the tray at sign-in; the agent's goals and check-ins run from then on.`),checked:n,onChange:e=>{r(e),t.setLoginItem?.(e)}}),(0,X.jsxs)(`div`,{className:`text-[13.5px]`,children:[e(`In the tray`),(0,X.jsx)(`span`,{className:`block text-[12px] text-muted`,children:e(`The icon by the clock shows what the hands are doing and has Stop; closing the window keeps the agent running.`)})]}),(0,X.jsxs)(`div`,{className:`space-y-1`,children:[(0,X.jsx)(`div`,{className:`text-[13.5px]`,children:e(`Shortcuts`)}),a.map(([e,t])=>(0,X.jsxs)(`div`,{className:`flex items-center justify-between text-[13px]`,children:[(0,X.jsx)(`span`,{className:`text-muted`,children:e}),(0,X.jsx)(`kbd`,{className:`rounded-md border border-border bg-surface-2 px-1.5 py-0.5 font-sans text-[12px] text-fg/80`,children:t})]},e))]})]})}function $({title:e,children:n,id:r,plain:i=!1}){return(0,X.jsxs)(`section`,{id:r,className:t(`space-y-3 scroll-mt-4`,i?`pt-1`:`rounded-3xl bg-surface border border-border/70 shadow-sm p-4`),children:[!i&&(0,X.jsx)(`h2`,{className:`text-[12px] font-semibold uppercase tracking-wide text-muted`,children:e}),n]})}export{Me as SettingsScreen}; \ No newline at end of file diff --git a/nanomuse/server/static/assets/SkillsScreen-DZP-6db6.js b/nanomuse/server/static/assets/SkillsScreen-Dr-d7iS7.js similarity index 99% rename from nanomuse/server/static/assets/SkillsScreen-DZP-6db6.js rename to nanomuse/server/static/assets/SkillsScreen-Dr-d7iS7.js index a65b0e569..d6a9f8cc7 100644 --- a/nanomuse/server/static/assets/SkillsScreen-DZP-6db6.js +++ b/nanomuse/server/static/assets/SkillsScreen-Dr-d7iS7.js @@ -1,4 +1,4 @@ -import{A as e,E as t,J as n,K as r,Q as i,Y as a,b as o,f as s,q as c,r as l,x as u}from"./MuseHeader-Pw-NI98v.js";import{B as d,C as f,F as p,Q as m,V as h,Z as g,bt as _,et as v}from"./index-BjYzdKkG.js";import{t as y}from"./BackBar-Dli0L0O_.js";var b=n(`file-code-corner`,[[`path`,{d:`M4 12.15V4a2 2 0 0 1 2-2h8a2.4 2.4 0 0 1 1.706.706l3.588 3.588A2.4 2.4 0 0 1 20 8v12a2 2 0 0 1-2 2h-3.35`,key:`1wthlu`}],[`path`,{d:`M14 2v5a1 1 0 0 0 1 1h5`,key:`wfsgrz`}],[`path`,{d:`m5 16-3 3 3 3`,key:`331omg`}],[`path`,{d:`m9 22 3-3-3-3`,key:`lsp7cz`}]]),x=n(`link-2`,[[`path`,{d:`M9 17H7A5 5 0 0 1 7 7h2`,key:`8i5ue5`}],[`path`,{d:`M15 7h2a5 5 0 1 1 0 10h-2`,key:`1b9ql8`}],[`line`,{x1:`8`,x2:`16`,y1:`12`,y2:`12`,key:`1jonct`}]]),S=i(a(),1),C=o(),w=e=>`--- +import{A as e,E as t,J as n,K as r,Q as i,Y as a,b as o,f as s,q as c,r as l,x as u}from"./MuseHeader-Pw-NI98v.js";import{B as d,C as f,F as p,Q as m,V as h,Z as g,bt as _,et as v}from"./index-CIdGZ5PB.js";import{t as y}from"./BackBar-Dl56jHZM.js";var b=n(`file-code-corner`,[[`path`,{d:`M4 12.15V4a2 2 0 0 1 2-2h8a2.4 2.4 0 0 1 1.706.706l3.588 3.588A2.4 2.4 0 0 1 20 8v12a2 2 0 0 1-2 2h-3.35`,key:`1wthlu`}],[`path`,{d:`M14 2v5a1 1 0 0 0 1 1h5`,key:`wfsgrz`}],[`path`,{d:`m5 16-3 3 3 3`,key:`331omg`}],[`path`,{d:`m9 22 3-3-3-3`,key:`lsp7cz`}]]),x=n(`link-2`,[[`path`,{d:`M9 17H7A5 5 0 0 1 7 7h2`,key:`8i5ue5`}],[`path`,{d:`M15 7h2a5 5 0 1 1 0 10h-2`,key:`1b9ql8`}],[`line`,{x1:`8`,x2:`16`,y1:`12`,y2:`12`,key:`1jonct`}]]),S=i(a(),1),C=o(),w=e=>`--- name: ${e} description: What this does, and when to use it; the model picks the skill from this line. --- diff --git a/nanomuse/server/static/assets/index-BjYzdKkG.js b/nanomuse/server/static/assets/index-CIdGZ5PB.js similarity index 98% rename from nanomuse/server/static/assets/index-BjYzdKkG.js rename to nanomuse/server/static/assets/index-CIdGZ5PB.js index 5744bf6a3..0ba4f0f94 100644 --- a/nanomuse/server/static/assets/index-BjYzdKkG.js +++ b/nanomuse/server/static/assets/index-CIdGZ5PB.js @@ -1,4 +1,4 @@ -const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["assets/AccountScreen-DvBFnisI.js","assets/MuseHeader-Pw-NI98v.js","assets/StarNudge-DjXecvWj.js","assets/external-link-Xj5fjR8v.js","assets/Form-DwKuBk1V.js","assets/clapperboard-BokpXv9J.js","assets/database-zap-CzaFBl6C.js","assets/image-crWy0a06.js","assets/BackBar-Dli0L0O_.js","assets/AvatarStudioScreen-C1Q0sV3j.js","assets/refresh-cw-BKgIzslL.js","assets/AvatarPicker-oSjVM8L3.js","assets/ChannelsScreen-Bt6eBqvc.js","assets/CodingScreen-CTT5Jjn2.js","assets/ConnectionsScreen-0U0bXAf7.js","assets/plug-Bj_5EEV3.js","assets/CloudCard-CdydxD3H.js","assets/DevicesScreen-P67eLmyB.js","assets/GoalsScreen-BGb02qG6.js","assets/IdeasScreen-BVCFCRSV.js","assets/LibraryScreen-U8NV3qaf.js","assets/MemoryScreen-B5a6LPAu.js","assets/Onboarding-rP8qAahh.js","assets/IdentityForm-Dhx4FiQY.js","assets/SettingsScreen-DoXURXet.js","assets/SkillsScreen-DZP-6db6.js"])))=>i.map(i=>d[i]); +const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["assets/AccountScreen-bHMDrVr5.js","assets/MuseHeader-Pw-NI98v.js","assets/StarNudge-DjXecvWj.js","assets/external-link-Xj5fjR8v.js","assets/Form-DwKuBk1V.js","assets/clapperboard-BokpXv9J.js","assets/database-zap-CzaFBl6C.js","assets/image-crWy0a06.js","assets/BackBar-Dl56jHZM.js","assets/AvatarStudioScreen-DD2X0R8P.js","assets/refresh-cw-BKgIzslL.js","assets/AvatarPicker-gR2knlot.js","assets/ChannelsScreen-mBzj7BLf.js","assets/CodingScreen-C_tutsx0.js","assets/ConnectionsScreen-CMt7GOff.js","assets/plug-Bj_5EEV3.js","assets/CloudCard-CtVHK0qc.js","assets/DevicesScreen-g6FUY327.js","assets/GoalsScreen-Dp2fRaLA.js","assets/IdeasScreen-CGfvq5H-.js","assets/LibraryScreen-B8JlrC_n.js","assets/MemoryScreen-M8j03G3u.js","assets/Onboarding-CtVO6gdK.js","assets/IdentityForm-BTGczGT_.js","assets/SettingsScreen-CHVg61To.js","assets/SkillsScreen-Dr-d7iS7.js"])))=>i.map(i=>d[i]); import{A as e,B as t,C as n,D as r,E as i,I as a,J as o,K as s,L as c,M as l,N as u,O as d,P as f,Q as p,R as m,S as h,T as g,U as _,V as v,W as y,X as b,Y as x,Z as S,b as C,c as w,d as T,f as E,i as D,j as O,n as k,p as ee,q as A,r as te,s as j,t as ne,u as re,x as M,y as N,z as P}from"./MuseHeader-Pw-NI98v.js";import{A as ie,C as ae,D as oe,E as se,M as ce,N as le,P as ue,S as de,a as fe,b as pe,c as me,h as he,i as ge,j as _e,l as ve,n as ye,o as be,p as xe,r as Se,s as Ce,t as we,u as Te,v as Ee,x as De,y as Oe}from"./StarNudge-DjXecvWj.js";import{n as ke,t as Ae}from"./external-link-Xj5fjR8v.js";import{a as je,c as Me,i as Ne,n as Pe,o as Fe,r as Ie,s as Le}from"./Form-DwKuBk1V.js";import{t as Re}from"./refresh-cw-BKgIzslL.js";(function(){let e=document.createElement(`link`).relList;if(e&&e.supports&&e.supports(`modulepreload`))return;for(let e of document.querySelectorAll(`link[rel="modulepreload"]`))n(e);new MutationObserver(e=>{for(let t of e)if(t.type===`childList`)for(let e of t.addedNodes)e.tagName===`LINK`&&e.rel===`modulepreload`&&n(e)}).observe(document,{childList:!0,subtree:!0});function t(e){let t={};return e.integrity&&(t.integrity=e.integrity),e.referrerPolicy&&(t.referrerPolicy=e.referrerPolicy),t.credentials=e.crossOrigin===`use-credentials`?`include`:e.crossOrigin===`anonymous`?`omit`:`same-origin`,t}function n(e){if(e.ep)return;e.ep=!0;let n=t(e);fetch(e.href,n)}})();var ze=b((e=>{function t(e,t){var n=e.length;e.push(t);a:for(;0>>1,a=e[r];if(0>>1;ri(c,n))li(u,c)?(e[r]=u,e[l]=n,r=l):(e[r]=c,e[s]=n,r=s);else if(li(u,n))e[r]=u,e[l]=n,r=l;else break a}}return t}function i(e,t){var n=e.sortIndex-t.sortIndex;return n===0?e.id-t.id:n}if(typeof performance==`object`&&typeof performance.now==`function`){var a=performance;e.unstable_now=function(){return a.now()}}else{var o=Date,s=o.now();e.unstable_now=function(){return o.now()-s}}var c=[],l=[],u=1,d=null,f=3,p=!1,m=!1,h=!1,g=typeof setTimeout==`function`?setTimeout:null,_=typeof clearTimeout==`function`?clearTimeout:null,v=typeof setImmediate<`u`?setImmediate:null;typeof navigator<`u`&&navigator.scheduling!==void 0&&navigator.scheduling.isInputPending!==void 0&&navigator.scheduling.isInputPending.bind(navigator.scheduling);function y(e){for(var i=n(l);i!==null;){if(i.callback===null)r(l);else if(i.startTime<=e)r(l),i.sortIndex=i.expirationTime,t(c,i);else break;i=n(l)}}function b(e){if(h=!1,y(e),!m){if(n(c)!==null)m=!0,te(x);else{var t=n(l);t!==null&&j(b,t.startTime-e)}}}function x(t,i){m=!1,h&&(h=!1,_(w),w=-1),p=!0;var a=f;try{for(y(i),d=n(c);d!==null&&(!(d.expirationTime>i)||t&&!D());){var o=d.callback;if(typeof o==`function`){d.callback=null,f=d.priorityLevel;var s=o(d.expirationTime<=i);i=e.unstable_now(),typeof s==`function`?d.callback=s:d===n(c)&&r(c),y(i)}else r(c);d=n(c)}if(d!==null)var u=!0;else{var g=n(l);g!==null&&j(b,g.startTime-i),u=!1}return u}finally{d=null,f=a,p=!1}}var S=!1,C=null,w=-1,T=5,E=-1;function D(){return!(e.unstable_now()-Ee||125o?(r.sortIndex=a,t(l,r),n(c)===null&&r===n(l)&&(h?(_(w),w=-1):h=!0,j(b,a-o))):(r.sortIndex=s,t(c,r),m||p||(m=!0,te(x))),r},e.unstable_shouldYield=D,e.unstable_wrapCallback=function(e){var t=f;return function(){var n=f;f=t;try{return e.apply(this,arguments)}finally{f=n}}}})),Be=b(((e,t)=>{t.exports=ze()})),Ve=b((e=>{var t=x(),n=Be();function r(e){for(var t=`https://reactjs.org/docs/error-decoder.html?invariant=`+e,n=1;nt}return!1}function g(e,t,n,r,i,a,o){this.acceptsBooleans=t===2||t===3||t===4,this.attributeName=r,this.attributeNamespace=i,this.mustUseProperty=n,this.propertyName=e,this.type=t,this.sanitizeURL=a,this.removeEmptyString=o}var _={};`children dangerouslySetInnerHTML defaultValue defaultChecked innerHTML suppressContentEditableWarning suppressHydrationWarning style`.split(` `).forEach(function(e){_[e]=new g(e,0,!1,e,null,!1,!1)}),[[`acceptCharset`,`accept-charset`],[`className`,`class`],[`htmlFor`,`for`],[`httpEquiv`,`http-equiv`]].forEach(function(e){var t=e[0];_[t]=new g(t,1,!1,e[1],null,!1,!1)}),[`contentEditable`,`draggable`,`spellCheck`,`value`].forEach(function(e){_[e]=new g(e,2,!1,e.toLowerCase(),null,!1,!1)}),[`autoReverse`,`externalResourcesRequired`,`focusable`,`preserveAlpha`].forEach(function(e){_[e]=new g(e,2,!1,e,null,!1,!1)}),`allowFullScreen async autoFocus autoPlay controls default defer disabled disablePictureInPicture disableRemotePlayback formNoValidate hidden loop noModule noValidate open playsInline readOnly required reversed scoped seamless itemScope`.split(` `).forEach(function(e){_[e]=new g(e,3,!1,e.toLowerCase(),null,!1,!1)}),[`checked`,`multiple`,`muted`,`selected`].forEach(function(e){_[e]=new g(e,3,!0,e,null,!1,!1)}),[`capture`,`download`].forEach(function(e){_[e]=new g(e,4,!1,e,null,!1,!1)}),[`cols`,`rows`,`size`,`span`].forEach(function(e){_[e]=new g(e,6,!1,e,null,!1,!1)}),[`rowSpan`,`start`].forEach(function(e){_[e]=new g(e,5,!1,e.toLowerCase(),null,!1,!1)});var v=/[\-:]([a-z])/g;function y(e){return e[1].toUpperCase()}`accent-height alignment-baseline arabic-form baseline-shift cap-height clip-path clip-rule color-interpolation color-interpolation-filters color-profile color-rendering dominant-baseline enable-background fill-opacity fill-rule flood-color flood-opacity font-family font-size font-size-adjust font-stretch font-style font-variant font-weight glyph-name glyph-orientation-horizontal glyph-orientation-vertical horiz-adv-x horiz-origin-x image-rendering letter-spacing lighting-color marker-end marker-mid marker-start overline-position overline-thickness paint-order panose-1 pointer-events rendering-intent shape-rendering stop-color stop-opacity strikethrough-position strikethrough-thickness stroke-dasharray stroke-dashoffset stroke-linecap stroke-linejoin stroke-miterlimit stroke-opacity stroke-width text-anchor text-decoration text-rendering underline-position underline-thickness unicode-bidi unicode-range units-per-em v-alphabetic v-hanging v-ideographic v-mathematical vector-effect vert-adv-y vert-origin-x vert-origin-y word-spacing writing-mode xmlns:xlink x-height`.split(` `).forEach(function(e){var t=e.replace(v,y);_[t]=new g(t,1,!1,e,null,!1,!1)}),`xlink:actuate xlink:arcrole xlink:role xlink:show xlink:title xlink:type`.split(` `).forEach(function(e){var t=e.replace(v,y);_[t]=new g(t,1,!1,e,`http://www.w3.org/1999/xlink`,!1,!1)}),[`xml:base`,`xml:lang`,`xml:space`].forEach(function(e){var t=e.replace(v,y);_[t]=new g(t,1,!1,e,`http://www.w3.org/XML/1998/namespace`,!1,!1)}),[`tabIndex`,`crossOrigin`].forEach(function(e){_[e]=new g(e,1,!1,e.toLowerCase(),null,!1,!1)}),_.xlinkHref=new g(`xlinkHref`,1,!1,`xlink:href`,`http://www.w3.org/1999/xlink`,!0,!1),[`src`,`href`,`action`,`formAction`].forEach(function(e){_[e]=new g(e,1,!1,e.toLowerCase(),null,!0,!0)});function b(e,t,n,r){var i=_.hasOwnProperty(t)?_[t]:null;(i===null?r||!(2n&&e&&t.length>0?uf(e,t):null,i=e=>n?.(e),a=n&&t.length>0?ff(e,t):e;return(0,R.jsx)(`div`,{className:`md text-[15px] leading-[1.5] break-words`,children:(0,R.jsx)(il,{remarkPlugins:[lf],components:{a:({href:e,children:t,...n})=>{let a=e&&!/^[a-z]+:/i.test(e)?r(O(e)):null;return a?(0,R.jsx)(`button`,{type:`button`,className:`md-file`,onClick:()=>i(a),children:t}):(0,R.jsx)(`a`,{href:e,...n,target:`_blank`,rel:`noreferrer noopener`,children:t})},code:({children:e,...t})=>{let n=pf({children:e,...t})&&typeof e==`string`?r(e):null;return n?(0,R.jsx)(`button`,{type:`button`,className:`md-file`,onClick:()=>i(n),title:n,children:e}):(0,R.jsx)(`code`,{...t,children:e})}},children:a})})}function gf({path:e,onClose:t}){let n=s(),i=(0,L.useRef)(null);if(On(i,!!e),(0,L.useEffect)(()=>{if(!e)return;let n=e=>e.key===`Escape`&&t();return window.addEventListener(`keydown`,n),()=>window.removeEventListener(`keydown`,n)},[e,t]),!e)return null;let a=e.split(`/`).pop()??e,o=r(a);return(0,R.jsxs)(`div`,{ref:i,role:`dialog`,"aria-modal":`true`,"aria-label":a,className:`fixed inset-0 z-[60] flex flex-col bg-bg`,children:[(0,R.jsxs)(`header`,{className:`safe-top shrink-0 flex items-center gap-2 border-b border-border bg-surface/90 px-3 py-2 backdrop-blur`,children:[(0,R.jsx)(`button`,{type:`button`,onClick:t,"aria-label":n(`Close`),className:`p-2 rounded-full text-muted hover:bg-surface-2`,children:(0,R.jsx)(Fe,{size:20})}),(0,R.jsxs)(`div`,{className:`flex-1 min-w-0`,children:[(0,R.jsx)(`div`,{className:`font-semibold text-[15px] truncate`,children:a}),(0,R.jsx)(`div`,{className:`text-[12px] text-muted truncate`,children:e})]}),o!==`html`&&(0,R.jsx)(`a`,{href:h(e),target:`_blank`,rel:`noreferrer noopener`,"aria-label":n(`Open in a new tab`),className:`p-2 rounded-full text-muted hover:bg-surface-2`,children:(0,R.jsx)(Ae,{size:19})}),(0,R.jsx)(`a`,{href:h(e,!0),"aria-label":n(`Download`),className:`p-2 rounded-full text-muted hover:bg-surface-2`,children:(0,R.jsx)(ft,{size:19})})]}),(0,R.jsx)(`div`,{className:`min-h-0 flex-1 overflow-auto`,children:(0,R.jsx)(_f,{path:e,kind:o})})]})}function _f({path:e,kind:t}){let n=s();return t===`image`?(0,R.jsx)(`div`,{className:`flex h-full items-center justify-center p-3`,children:(0,R.jsx)(`img`,{src:h(e),alt:e,className:`max-h-full max-w-full rounded-2xl object-contain`})}):t===`pdf`?(0,R.jsx)(`iframe`,{title:e,src:h(e),className:`h-full w-full bg-white`}):t===`html`?(0,R.jsx)(yf,{path:e}):t===`event`?(0,R.jsx)(bf,{path:e}):t===`text`||t===`code`||t===`data`?(0,R.jsx)(Cf,{path:e,kind:t}):(0,R.jsxs)(`div`,{className:`p-8 text-center text-muted text-[14px]`,children:[n(`No preview for this file type.`),` `,(0,R.jsx)(`a`,{href:h(e,!0),className:`text-accent font-medium`,children:n(`Download it`)})]})}function vf(e){let[t,n]=(0,L.useState)(null),[r,i]=(0,L.useState)(null);return(0,L.useEffect)(()=>{let t=!0;return n(null),i(null),M.fileText(e).then(e=>t&&n(e)).catch(e=>t&&i(e.message)),()=>{t=!1}},[e]),{text:t,error:r}}function yf({path:e}){let{text:t,error:n}=vf(e);return n?(0,R.jsx)(Ef,{error:n}):t===null?(0,R.jsx)(Tf,{}):(0,R.jsx)(`iframe`,{title:e,srcDoc:t,sandbox:`allow-scripts allow-popups allow-forms allow-modals`,referrerPolicy:`no-referrer`,className:`h-full w-full bg-white`})}function bf({path:e}){let t=s(),{text:n,error:r}=vf(e);if(r)return(0,R.jsx)(Ef,{error:r});if(n===null)return(0,R.jsx)(Tf,{});let i=xf(n);return(0,R.jsxs)(`div`,{className:`mx-auto max-w-[560px] px-5 py-6 space-y-4`,children:[i.length===0&&(0,R.jsx)(`div`,{className:`text-center text-muted text-[14px]`,children:t(`No event in this file.`)}),i.map((e,n)=>(0,R.jsxs)(`div`,{className:`rounded-3xl border border-border/70 bg-surface shadow-sm p-5`,children:[(0,R.jsxs)(`div`,{className:`flex items-start gap-3`,children:[(0,R.jsx)(`div`,{className:`rounded-2xl bg-accent/12 text-accent p-2.5`,children:(0,R.jsx)(tt,{size:22})}),(0,R.jsxs)(`div`,{className:`min-w-0 flex-1`,children:[(0,R.jsx)(`div`,{className:`text-[18px] font-semibold leading-snug`,children:e.summary||t(`Untitled event`)}),(0,R.jsx)(`div`,{className:`mt-1 text-[14px] text-muted`,children:Sf(e)}),e.location&&(0,R.jsxs)(`div`,{className:`mt-1 flex items-center gap-1 text-[14px] text-muted`,children:[(0,R.jsx)(Dt,{size:14}),` `,e.location]})]})]}),e.description&&(0,R.jsx)(`div`,{className:`mt-4 whitespace-pre-wrap text-[14px] leading-relaxed`,children:e.description})]},n)),(0,R.jsxs)(`a`,{href:h(e,!0),download:!0,className:`flex items-center justify-center gap-2 rounded-2xl bg-accent text-accent-fg px-4 py-3 text-[15px] font-medium`,children:[(0,R.jsx)(nt,{size:18}),` `,t(`Add to calendar`)]}),(0,R.jsx)(`p`,{className:`text-center text-[12.5px] text-muted`,children:t(`Opens in your calendar app, which asks before it saves anything.`)})]})}function xf(e){let t=e.replace(/\r\n/g,` `).replace(/\n[ \t]/g,``).split(` `),n=[],r=null,i=e=>e.replace(/\\n/gi,` -`).replace(/\\([,;\\])/g,`$1`),a=(e,t)=>{if(/VALUE=DATE(?![-])/i.test(t)||/^\d{8}$/.test(e)){let t=/^(\d{4})(\d{2})(\d{2})/.exec(e);return{at:t?new Date(+t[1],t[2]-1,+t[3]):null,allDay:!0}}let n=/^(\d{4})(\d{2})(\d{2})T(\d{2})(\d{2})(\d{2})?(Z?)$/.exec(e);if(!n)return{at:null,allDay:!1};let r=[+n[1],n[2]-1,+n[3],+n[4],+n[5],+(n[6]??0)];return{at:n[7]?new Date(Date.UTC(...r)):new Date(...r),allDay:!1}};for(let e of t)if(e===`BEGIN:VEVENT`)r={summary:``,location:``,description:``,start:null,end:null,allDay:!1};else if(e===`END:VEVENT`&&r)n.push(r),r=null;else if(r){let t=e.indexOf(`:`);if(t<0)continue;let[n,...o]=e.slice(0,t).split(`;`),s=e.slice(t+1),c=o.join(`;`);if(n===`SUMMARY`)r.summary=i(s);else if(n===`LOCATION`)r.location=i(s);else if(n===`DESCRIPTION`)r.description=i(s);else if(n===`DTSTART`){let e=a(s,c);r.start=e.at,r.allDay=e.allDay}else n===`DTEND`&&(r.end=a(s,c).at)}return n}function Sf(e){if(!e.start)return``;let t=m(),n=e=>e.toLocaleDateString(t,{weekday:`short`,year:`numeric`,month:`short`,day:`numeric`}),r=e=>e.toLocaleTimeString(t,{hour:`numeric`,minute:`2-digit`});if(e.allDay){let t=e.end?new Date(e.end.getTime()-864e5):e.start;return t>e.start?`${n(e.start)} – ${n(t)}`:`${n(e.start)} · ${_(`all day`)}`}return e.end?e.start.toDateString()===e.end.toDateString()?`${n(e.start)} ${r(e.start)}–${r(e.end)}`:`${n(e.start)} ${r(e.start)} – ${n(e.end)} ${r(e.end)}`:`${n(e.start)} ${r(e.start)}`}function Cf({path:e,kind:t}){let{text:n,error:r}=vf(e);return r?(0,R.jsx)(Ef,{error:r}):n===null?(0,R.jsx)(Tf,{}):t===`text`&&/\.md$/i.test(e)?(0,R.jsx)(`div`,{className:`mx-auto max-w-[720px] px-5 py-4`,children:(0,R.jsx)(hf,{text:n})}):t===`data`&&/\.csv$/i.test(e)?(0,R.jsx)(wf,{text:n}):(0,R.jsx)(`pre`,{className:`whitespace-pre-wrap break-words px-4 py-3 font-mono text-[12.5px] leading-relaxed`,children:n})}function wf({text:e}){let t=s(),n=e.split(/\r?\n/).filter(e=>e.trim()).slice(0,500).map(e=>e.split(`,`));if(!n.length)return(0,R.jsx)(`div`,{className:`p-6 text-muted text-center`,children:t(`Empty file.`)});let[r,...i]=n;return(0,R.jsx)(`div`,{className:`overflow-auto p-3`,children:(0,R.jsxs)(`table`,{className:`min-w-full text-[13px] border-separate border-spacing-0`,children:[(0,R.jsx)(`thead`,{children:(0,R.jsx)(`tr`,{children:r.map((e,t)=>(0,R.jsx)(`th`,{className:`sticky top-0 bg-surface-2 text-left font-semibold px-3 py-2 border-b border-border whitespace-nowrap`,children:e},t))})}),(0,R.jsx)(`tbody`,{children:i.map((e,t)=>(0,R.jsx)(`tr`,{className:`odd:bg-surface`,children:e.map((e,t)=>(0,R.jsx)(`td`,{className:`px-3 py-1.5 border-b border-border/60 whitespace-nowrap`,children:e},t))},t))})]})})}function Tf(){return(0,R.jsx)(`div`,{className:`flex h-full items-center justify-center text-muted`,children:(0,R.jsx)(A,{className:`animate-spin`,size:22})})}function Ef({error:e}){let t=s();return(0,R.jsx)(`div`,{className:`p-8 text-center text-rose-600 dark:text-rose-300 text-[14px]`,children:t(`Could not load the file: {error}`,{error:e})})}var Df=`OpenAI's terms cover using a ChatGPT plan inside OpenAI's own Codex; other apps have had this access cut off before (OpenCode, January 2026). If it stops working, an API key does.`,Of=2e3,kf=6e5;function Af({compact:e,onChanged:t}){let n=s(),{toast:r}=E(),[a,o]=(0,L.useState)(null),[c,l]=(0,L.useState)(`unknown`),[u,d]=(0,L.useState)(null),[f,p]=(0,L.useState)(null),[m,h]=(0,L.useState)(!0),[g,_]=(0,L.useState)(``),[v,y]=(0,L.useState)(null),b=(0,L.useRef)(0),x=(0,L.useCallback)(async()=>{try{let e=await M.chatgptStatus();return o(e),l(`yes`),e}catch(e){return/not found/i.test(e.message)?l(`no`):y(e.message),null}},[]);(0,L.useEffect)(()=>{x().then(e=>{e?.pending&&e.url&&(b.current=Date.now(),h(e.port_bound!==!1),p(e.url))})},[x]),(0,L.useEffect)(()=>{if(!f)return;let e=setInterval(()=>{x().then(e=>{e?.signed_in?(p(null),Ee(),r(n(`Signed in with {label}.`,{label:e.label||`ChatGPT`})),t?.()):e&&e.pending===!1&&e.error?(p(null),y(n(e.error))):Date.now()-b.current>kf&&(p(null),y(n(`The sign-in did not finish in ten minutes. Try again.`)))})},Of);return()=>clearInterval(e)},[f,x,t,r,n]);let S=async()=>{d(`login`),y(null);try{let e=await M.chatgptLogin();b.current=Date.now(),h(e.port_bound!==!1),_(``),p(e.url),window.open(e.url,`_blank`,`noopener`)}catch(e){/not found/i.test(e.message)?l(`no`):y(e.message)}finally{d(null)}},C=async()=>{let e=g.trim();if(e){d(`paste`),y(null);try{await M.chatgptCallback(e),_(``)}catch(e){let t=e.message;/state/i.test(t)?y(n(`That address belongs to another sign-in attempt. Open the page again and paste the address it ends on.`)):/no sign-in|409/i.test(t)?(p(null),y(n(`The sign-in did not finish in ten minutes. Try again.`))):y(t)}finally{d(null)}}},w=async()=>{d(`use`),y(null);try{await M.setLLM({provider:`chatgpt`,model:a?.models?.[0]??``,base_url:``,api_key:``}),Ee(),r(n(`ChatGPT answers the chat now.`)),t?.()}catch(e){y(e.message)}finally{d(null)}},T=async()=>{d(`logout`),y(null);try{await M.chatgptLogout(),Ee(),await x(),t?.()}catch(e){y(e.message)}finally{d(null)}},D=n(`Covers chat and the hands. Pictures and clips are not part of it; those need a provider with image or video models.`);return(0,R.jsxs)(`div`,{className:i(`space-y-2`,!e&&`rounded-2xl bg-surface-2/60 p-3`),children:[!e&&(0,R.jsxs)(`div`,{className:`flex items-center gap-2 text-[13px] font-medium`,children:[(0,R.jsx)(Mt,{size:15,className:`text-accent`}),` `,n(`Sign in with ChatGPT`)]}),c===`no`?(0,R.jsxs)(`p`,{className:`text-[12.5px] text-muted`,children:[n(`This nanoMuse has no sign-in route yet. In a terminal on this computer, run`),` `,(0,R.jsx)(`code`,{className:`rounded bg-surface-2 px-1 py-0.5 text-[12px]`,children:`nanomuse chatgpt login`}),` `,n(`and reload this page.`)]}):a?.signed_in?(0,R.jsxs)(`div`,{className:`space-y-2`,children:[(0,R.jsxs)(`p`,{className:`text-[12.5px]`,children:[(0,R.jsx)(`span`,{className:`font-medium`,children:n(`Signed in with {label}.`,{label:a.label||`ChatGPT`})}),` `,(0,R.jsx)(`span`,{className:`text-muted`,children:D})]}),(0,R.jsxs)(`div`,{className:`flex flex-wrap gap-2`,children:[(0,R.jsxs)(`button`,{type:`button`,disabled:u!==null,onClick:()=>void w(),className:i(Ne,`inline-flex items-center gap-1.5 py-2`),children:[u===`use`?(0,R.jsx)(A,{size:14,className:`animate-spin`}):(0,R.jsx)(Mt,{size:14}),` `,n(`Use it for the chat`)]}),(0,R.jsxs)(`button`,{type:`button`,disabled:u!==null,onClick:()=>void T(),className:i(je,`inline-flex items-center gap-1.5`),children:[u===`logout`?(0,R.jsx)(A,{size:14,className:`animate-spin`}):(0,R.jsx)(Tt,{size:14}),` `,n(`Sign out of ChatGPT`)]})]})]}):f?(0,R.jsxs)(`div`,{className:`space-y-2`,children:[(0,R.jsxs)(`p`,{className:`flex items-start gap-2 text-[12.5px] text-muted`,children:[(0,R.jsx)(A,{size:14,className:`mt-0.5 shrink-0 animate-spin`}),(0,R.jsx)(`span`,{children:n(m?`A page from OpenAI opened in a new tab. Sign in there; this card follows on its own.`:`A page from OpenAI opened in a new tab. Sign in there; when the browser ends on an address that will not load, paste that address below.`)})]}),(0,R.jsxs)(`div`,{className:`flex flex-wrap gap-2`,children:[(0,R.jsxs)(`a`,{href:f,target:`_blank`,rel:`noopener noreferrer`,className:i(je,`inline-flex items-center gap-1.5`),children:[(0,R.jsx)(Ae,{size:14}),` `,n(`Open the page again`)]}),(0,R.jsx)(`button`,{type:`button`,onClick:()=>p(null),className:je,children:n(`Cancel`)})]}),(0,R.jsxs)(`form`,{className:`flex flex-wrap items-center gap-2`,onSubmit:e=>{e.preventDefault(),C()},children:[(0,R.jsx)(`input`,{type:`url`,value:g,onChange:e=>_(e.target.value),placeholder:`http://localhost:1455/auth/callback?code=…`,"aria-label":n(`The address the browser ended on`),className:`min-w-0 flex-1 rounded-lg border border-border bg-surface px-2 py-1.5 text-[12.5px]`}),(0,R.jsxs)(`button`,{type:`submit`,disabled:u!==null||!g.trim(),className:i(je,`inline-flex items-center gap-1.5`),children:[u===`paste`?(0,R.jsx)(A,{size:14,className:`animate-spin`}):null,` `,n(`Use this address`)]})]}),!m&&(0,R.jsx)(`p`,{className:`text-[11.5px] text-muted`,children:n(`This nanoMuse runs where the browser cannot reach port 1455, so it cannot pick the sign-in up by itself.`)})]}):(0,R.jsxs)(`div`,{className:`space-y-2`,children:[(0,R.jsx)(`p`,{className:`text-[12.5px] text-muted`,children:D}),(0,R.jsxs)(`button`,{type:`button`,disabled:u!==null||c===`unknown`,onClick:()=>void S(),className:i(Ne,`inline-flex items-center gap-1.5 py-2`),children:[u===`login`?(0,R.jsx)(A,{size:14,className:`animate-spin`}):(0,R.jsx)(wt,{size:14}),` `,n(`Sign in with ChatGPT`)]})]}),(0,R.jsx)(`p`,{className:`text-[11.5px] leading-snug text-muted`,children:n(Df)}),v&&(0,R.jsx)(`p`,{className:`text-[12px] text-rose-600 dark:text-rose-300`,children:v})]})}var jf=xe,Mf=`nm.connections.preset`;function Nf(e,t=_e().preset){try{sessionStorage.setItem(Mf,t)}catch{}e(`connections`)}function Pf(){try{let e=sessionStorage.getItem(Mf);return e&&sessionStorage.removeItem(Mf),e}catch{return null}}function Ff({info:e,exhausted:t,compact:n}){let r=s(),{toast:a,setTab:o,state:l}=E(),u=l.hub?.account,d=_e(u),f=ae(u),p=c(),m=e.invite_bonus_cny??5,h=e.own_key_docs||e.guidance?.docs||jf,g=e.invite_url||``,[_,v]=(0,L.useState)(!1),[y,b]=(0,L.useState)(!1),x=(e.guidance?.providers??de(f)).filter(e=>e.id!==d.id).map(e=>({id:e.id,name:De(e,p),keyUrl:e.key_url,covers:`covers`in e?e.covers:e.capabilities})),S=Oe().map(e=>e.name),C=async e=>{try{await navigator.clipboard.writeText(e),a(r(`Copied`))}catch{a(e)}},w=async()=>{let e=r(`Try nanoMuse with me, a fully open-source personal agent, free to use. Sign up with my link: {link}`,{link:g}),t=navigator;if(t.share)try{await t.share({text:e});return}catch{}await C(e)},T=Ce(),[D,O]=me(`exhausted`,t),k=ve(be(r,`exhausted`)),ee=t?r(`The free allowance is used up.`):r(`Nearly used up: ¥{left} of ¥{grant} left.`,{left:(e.left??0).toFixed(2),grant:(e.grant??0).toFixed(0)});return(0,R.jsxs)(`div`,{className:i(`space-y-2.5`,!n&&`pt-1`),children:[(0,R.jsxs)(`div`,{children:[(0,R.jsx)(`div`,{className:i(`font-semibold`,n?`text-[13.5px]`:`text-[15px]`),children:ee}),(0,R.jsx)(`div`,{className:`mt-0.5 text-[12.5px] text-muted`,children:r(`Three ways on; your sign-in and your devices keep working whichever you pick.`)})]}),(0,R.jsxs)(If,{icon:(0,R.jsx)(xt,{size:16}),tone:`bg-accent/12 text-accent`,title:r(`Use your own model key`),children:[(0,R.jsx)(`p`,{className:`text-[12.5px] text-muted`,children:ie(r,u)}),(0,R.jsxs)(`div`,{className:`flex flex-wrap gap-2`,children:[(0,R.jsxs)(`button`,{type:`button`,onClick:()=>Nf(o,d.preset),className:i(Ne,`inline-flex items-center gap-1.5 py-2`),children:[(0,R.jsx)(xt,{size:14}),` `,r(`Set it up`)]}),(0,R.jsxs)(`a`,{href:d.keyUrl,target:`_blank`,rel:`noopener noreferrer`,className:i(je,`inline-flex items-center gap-1.5`),children:[(0,R.jsx)(Ae,{size:14}),` `,r(`Get a key from {vendor}`,{vendor:d.label})]}),(0,R.jsxs)(`a`,{href:h,target:`_blank`,rel:`noopener noreferrer`,className:i(je,`inline-flex items-center gap-1.5`),children:[(0,R.jsx)(Ae,{size:14}),` `,r(`Step-by-step guide`)]})]}),x.length>0&&(0,R.jsxs)(`div`,{children:[(0,R.jsxs)(`button`,{type:`button`,onClick:()=>v(!_),className:`inline-flex items-center gap-1 text-[12px] text-muted`,children:[_?(0,R.jsx)(Le,{size:13}):(0,R.jsx)(Me,{size:13}),` `,r(`Other providers and what each key covers`)]}),_&&(0,R.jsx)(`ul`,{className:`mt-1.5 space-y-1 text-[12.5px]`,children:x.map(e=>(0,R.jsxs)(`li`,{className:`flex flex-wrap items-baseline justify-between gap-x-3`,children:[(0,R.jsxs)(`span`,{children:[(0,R.jsx)(`span`,{className:`font-medium`,children:e.name}),` `,(0,R.jsxs)(`span`,{className:`text-muted`,children:[`· `,he(r,e.covers)]})]}),(0,R.jsxs)(`span`,{className:`flex gap-2`,children:[(0,R.jsx)(`button`,{type:`button`,onClick:()=>Nf(o,pe(e.id)),className:`text-accent`,children:r(`Set it up`)}),(0,R.jsxs)(`a`,{href:e.keyUrl,target:`_blank`,rel:`noopener noreferrer`,className:`inline-flex items-center gap-0.5 text-accent`,children:[r(`Get a key`),` `,(0,R.jsx)(Ae,{size:11})]})]})]},e.id))})]})]}),(0,R.jsxs)(If,{icon:(0,R.jsx)(wt,{size:16}),tone:`bg-emerald-500/12 text-emerald-600 dark:text-emerald-300`,title:r(`Sign in with a plan you already pay for`),children:[(0,R.jsx)(`p`,{className:`text-[12.5px] text-muted`,children:r(`{plans}: the plan's models answer here, no key to make. ChatGPT works on every device, the others on the phones. A ChatGPT sign-in covers chat and the hands; pictures and clips still want a key.`,{plans:S.join(r(`, `))})}),y?(0,R.jsx)(Af,{compact:!0,onChanged:()=>b(!1)}):(0,R.jsxs)(`button`,{type:`button`,onClick:()=>b(!0),className:i(je,`inline-flex items-center gap-1.5`),children:[(0,R.jsx)(wt,{size:14}),` `,r(`Sign in with ChatGPT`)]})]}),(0,R.jsx)(If,{icon:(0,R.jsx)(hn,{size:16}),tone:`bg-violet-500/12 text-violet-600 dark:text-violet-300`,title:r(`Invite a friend: +¥{bonus} for you and +¥{bonus} for them, for each new person who signs up with your link.`,{bonus:m.toFixed(0)}),children:g?(0,R.jsxs)(`div`,{className:`flex flex-wrap gap-2`,children:[(0,R.jsxs)(`button`,{type:`button`,onClick:()=>void w(),className:i(je,`inline-flex items-center gap-1.5`),children:[(0,R.jsx)(Xt,{size:14}),` `,r(`Share the link`)]}),(0,R.jsxs)(`button`,{type:`button`,onClick:()=>void C(g),className:i(je,`inline-flex items-center gap-1.5`),children:[(0,R.jsx)(ut,{size:14}),` `,r(`Copy the link`)]})]}):(0,R.jsxs)(`button`,{type:`button`,onClick:()=>o(`account`),className:i(je,`inline-flex items-center gap-1.5`),children:[(0,R.jsx)(Xt,{size:14}),` `,r(`Your invite link is under Account`)]})}),t&&D&&(0,R.jsxs)(If,{icon:(0,R.jsx)(ce,{size:16}),tone:`bg-amber-400/15 text-amber-600 dark:text-amber-300`,title:k,children:[(0,R.jsxs)(`button`,{type:`button`,onClick:()=>fe(T.repo_url),className:i(`flex items-center justify-center gap-1.5 rounded-2xl border border-border px-4 py-2.5 text-[14px] font-medium text-muted disabled:opacity-40`,`inline-flex items-center gap-1.5`),children:[(0,R.jsx)(ce,{size:14}),` `,r(`Star on GitHub`)]}),(0,R.jsx)(`button`,{type:`button`,onClick:()=>{ge(),O(!1)},className:i(`flex items-center justify-center gap-1.5 rounded-2xl border border-border px-4 py-2.5 text-[14px] font-medium text-muted disabled:opacity-40`,`inline-flex items-center gap-1.5`),children:r(`I already starred`)})]})]})}function If({icon:e,tone:t,title:n,children:r}){return(0,R.jsxs)(`div`,{className:`flex gap-3 rounded-2xl bg-surface-2/60 p-3`,children:[(0,R.jsx)(`span`,{className:i(`flex h-8 w-8 shrink-0 items-center justify-center rounded-xl`,t),children:e}),(0,R.jsxs)(`div`,{className:`min-w-0 flex-1 space-y-2`,children:[(0,R.jsx)(`div`,{className:`text-[13px] font-medium leading-snug`,children:n}),r]})]})}var Lf=`nm.cloud.warned_grant`;function Rf(){let e=s(),{state:t,setTab:n}=E(),[r,i]=(0,L.useState)(null),a=(0,L.useRef)(0),o=t.hub?.account,c=!!o?.signed_in&&!!o.is_model,l=t.finishedAt;if((0,L.useEffect)(()=>{if(!c||!l||r||Date.now()-a.current<6e4)return;a.current=Date.now();let e=!1;return M.cloudMe().then(t=>{if(e)return;let n=t.spend,r=n.grant??n.allowance_cny??0,a=n.left??null;if(n.unlimited||!n.warn||a===null||a<=0)return;let o=null;try{o=localStorage.getItem(Lf)}catch{}o!==String(r)&&i({left:a,grant:r,invite_url:t.invite?.url,invite_bonus_cny:n.invite_bonus_cny,invitee_bonus_cny:n.invitee_bonus_cny,own_key_docs:n.own_key_docs,guidance:n.guidance})}).catch(()=>{}),()=>{e=!0}},[c,l,r]),!r)return null;let u=()=>{try{localStorage.setItem(Lf,String(r.grant??0))}catch{}i(null)};return(0,R.jsxs)(`div`,{className:`rise mx-3 mb-1.5 flex items-start gap-2 rounded-2xl bg-amber-500/12 px-3 py-2 text-[12.5px] leading-snug text-amber-800 dark:text-amber-200`,children:[(0,R.jsx)(nn,{size:14,className:`mt-0.5 shrink-0`}),(0,R.jsxs)(`div`,{className:`min-w-0 flex-1`,children:[e(`Nearly used up: ¥{left} of ¥{grant} left.`,{left:(r.left??0).toFixed(2),grant:(r.grant??0).toFixed(0)}),` `,e(`Invite a friend (+¥{invite} for each of you) or bring your own key; your sign-in keeps working either way.`,{invite:(r.invite_bonus_cny??5).toFixed(0)}),` `,(0,R.jsx)(`button`,{type:`button`,onClick:()=>{u(),n(`account`)},className:`font-semibold underline decoration-dotted underline-offset-2`,children:e(`See the ways`)})]}),(0,R.jsx)(`button`,{type:`button`,onClick:u,"aria-label":e(`Dismiss`),className:`shrink-0 rounded-full p-0.5 opacity-70 hover:opacity-100`,children:(0,R.jsx)(Fe,{size:14})})]})}var zf=`nm.cloud.first_sign_in`,Bf=`nm:first-sign-in`;function Vf(){try{sessionStorage.setItem(zf,`1`)}catch{}window.dispatchEvent(new Event(Bf))}function Hf(){try{sessionStorage.removeItem(zf)}catch{}window.dispatchEvent(new Event(Bf))}function Uf(){try{return sessionStorage.getItem(zf)===`1`}catch{return!1}}function Wf(){let[e,t]=(0,L.useState)(Uf);return(0,L.useEffect)(()=>{let e=()=>t(Uf());return window.addEventListener(Bf,e),()=>window.removeEventListener(Bf,e)},[]),e}function Gf(){let e=s(),{toast:t,refreshHub:n,setTab:r,state:a}=E(),o=_e(a.hub?.account),[c,l]=(0,L.useState)(`password`),[u,d]=(0,L.useState)(``),[f,p]=(0,L.useState)(``),[m,h]=(0,L.useState)(!1),[g,_]=(0,L.useState)(null),v=async()=>{Hf(),await n().catch(()=>void 0)},y=async()=>{if(!(u.length<8||u!==f)){h(!0),_(null);try{await M.cloudPassword(u),t(e(`Password set.`)),d(``),p(``),l(`source`)}catch(t){_(e(t.message))}finally{h(!1)}}},b=async()=>{await v(),Nf(r,o.preset)},x=(0,L.useRef)(null);On(x,!0);let S=f.length>0&&f!==u;return(0,R.jsx)(`div`,{className:`fixed inset-0 z-50 flex items-end justify-center bg-black/40 backdrop-blur-[2px] sm:items-center`,role:`dialog`,"aria-modal":`true`,children:(0,R.jsxs)(`div`,{ref:x,className:`safe-bottom w-full max-w-[520px] rounded-t-[28px] bg-bg p-6 shadow-2xl sm:rounded-[28px]`,children:[(0,R.jsxs)(`div`,{className:`mb-4 flex gap-1`,children:[(0,R.jsx)(`span`,{className:i(`h-1.5 w-5 rounded-full bg-accent`)}),(0,R.jsx)(`span`,{className:i(`h-1.5 rounded-full transition-all`,c===`source`?`w-5 bg-accent`:`w-1.5 bg-border`)})]}),c===`password`?(0,R.jsxs)(`form`,{className:`space-y-4`,onSubmit:e=>{e.preventDefault(),y()},children:[(0,R.jsxs)(`div`,{className:`flex items-start gap-3`,children:[(0,R.jsx)(`span`,{className:`flex h-11 w-11 shrink-0 items-center justify-center rounded-2xl bg-accent/12 text-accent`,children:(0,R.jsx)(xt,{size:20})}),(0,R.jsxs)(`div`,{children:[(0,R.jsx)(`h2`,{className:`text-[20px] font-bold tracking-tight`,children:e(`Set a password`)}),(0,R.jsx)(`p`,{className:`mt-1 text-[13.5px] leading-relaxed text-muted`,children:e(`Your account is in. With a password, your phone and your other computers sign in at once, without waiting for a code. Optional; you can set one later under Account.`)})]})]}),(0,R.jsxs)(`div`,{className:`space-y-2`,children:[(0,R.jsx)(`input`,{type:`password`,value:u,onChange:e=>d(e.target.value),autoComplete:`new-password`,autoFocus:!0,placeholder:e(`At least 8 characters`),className:Ie}),(0,R.jsx)(`input`,{type:`password`,value:f,onChange:e=>p(e.target.value),autoComplete:`new-password`,placeholder:e(`Once more`),className:i(Ie,S&&`border-rose-400`)}),S&&(0,R.jsx)(`p`,{className:`text-[12px] text-rose-600 dark:text-rose-300`,children:e(`The two do not match.`)})]}),g&&(0,R.jsx)(`div`,{className:`rounded-2xl bg-rose-500/12 px-3 py-2 text-[12.5px] text-rose-700 dark:text-rose-300`,children:g}),(0,R.jsxs)(`div`,{className:`flex gap-2`,children:[(0,R.jsx)(`button`,{type:`button`,disabled:m,onClick:()=>l(`source`),className:je,children:e(`Skip`)}),(0,R.jsxs)(`button`,{type:`submit`,disabled:m||u.length<8||u!==f,className:i(Ne,`flex-1 py-3`),children:[m?(0,R.jsx)(A,{size:15,className:`animate-spin`}):null,` `,e(`Set the password`),` `,(0,R.jsx)(qe,{size:16})]})]})]}):(0,R.jsxs)(`div`,{className:`space-y-4`,children:[(0,R.jsxs)(`div`,{className:`flex items-start gap-3`,children:[(0,R.jsx)(`span`,{className:`flex h-11 w-11 shrink-0 items-center justify-center rounded-2xl bg-accent/12 text-accent`,children:(0,R.jsx)(ot,{size:20})}),(0,R.jsxs)(`div`,{children:[(0,R.jsx)(`h2`,{className:`text-[20px] font-bold tracking-tight`,children:e(`Which model answers?`)}),(0,R.jsx)(`p`,{className:`mt-1 text-[13.5px] leading-relaxed text-muted`,children:e(`Your account already brings one. You can add your own API key as well and switch at any time.`)})]})]}),(0,R.jsxs)(`ul`,{className:`space-y-2 text-[13px] leading-snug`,children:[(0,R.jsxs)(`li`,{className:`flex items-start gap-2.5 rounded-2xl bg-surface-2 px-3 py-2.5`,children:[(0,R.jsx)(ot,{size:16,className:`mt-0.5 shrink-0 text-accent`}),(0,R.jsxs)(`span`,{children:[(0,R.jsx)(`span`,{className:`font-medium`,children:e(`Use the nanoMuse Cloud model`)}),(0,R.jsx)(`span`,{className:`block text-muted`,children:e(`DeepSeek for the chat and Qwen for the hands, with a free allowance per account paid by the developer. Nothing to configure.`)})]})]}),(0,R.jsxs)(`li`,{className:`flex items-start gap-2.5 rounded-2xl bg-surface-2 px-3 py-2.5`,children:[(0,R.jsx)(xt,{size:16,className:`mt-0.5 shrink-0 text-accent`}),(0,R.jsxs)(`span`,{children:[(0,R.jsx)(`span`,{className:`font-medium`,children:e(`I have my own API key`)}),(0,R.jsx)(`span`,{className:`block text-muted`,children:o.preset===`qwen`?e(`Alibaba Cloud Bailian first (one key covers chat, the hands, pictures and clips), then DeepSeek, Kimi, Zhipu, OpenAI, OpenRouter and any OpenAI-compatible endpoint. The key stays on this device.`):e(`OpenRouter first (one account, one key, pay as you go), then OpenAI, Anthropic, Gemini, DeepSeek and any OpenAI-compatible endpoint. The key stays on this device.`)})]})]}),(0,R.jsxs)(`li`,{className:`flex items-start gap-2.5 rounded-2xl bg-surface-2 px-3 py-2.5`,children:[(0,R.jsx)(wt,{size:16,className:`mt-0.5 shrink-0 text-accent`}),(0,R.jsxs)(`span`,{children:[(0,R.jsx)(`span`,{className:`font-medium`,children:e(`Sign in with a plan you already pay for`)}),(0,R.jsx)(`span`,{className:`block text-muted`,children:e(`A ChatGPT plan signs in from Connections and answers the chat and the hands. Pictures and clips still want a key.`)})]})]})]}),(0,R.jsxs)(`div`,{className:`flex gap-2`,children:[(0,R.jsx)(`button`,{type:`button`,disabled:m,onClick:()=>void b(),className:je,children:e(`I have my own API key`)}),(0,R.jsxs)(`button`,{type:`button`,disabled:m,onClick:()=>void v(),className:i(Ne,`flex-1 py-3`),children:[e(`Use the nanoMuse Cloud model`),` `,(0,R.jsx)(qe,{size:16})]})]})]})]})})}var Kf=`nanomuse_devtools`;function qf(){try{return localStorage.getItem(Kf)===`1`}catch{return!1}}var Jf=qf(),Yf=new Set;function Xf(){return Jf}function Zf(e){Jf=e;try{localStorage.setItem(Kf,e?`1`:`0`)}catch{}Yf.forEach(e=>e())}function Qf(e){return Yf.add(e),()=>Yf.delete(e)}function $f(){return(0,L.useSyncExternalStore)(Qf,Xf,Xf)}function ep(e,t,n){if(!n.signedIn||n.chatOnCloud||n.deviceChat)return;let r=e[t];if(r?.type===`notice`&&r.level===`error`&&r.code&&r.code!==`allowance`&&!r.model_used)for(let n=t-1;n>=0;n--){let t=e[n];if(t?.type===`user`){let e=(t.files??[]).map(e=>e.path);return t.text||e.length>0?{text:t.text,files:e}:void 0}}}var tp=[`idle`,`working`,`waiting`,`happy`,`error`];function np({event:e,name:t=`nanoMuse`}){let n=s(),{toast:r}=E(),[a,o]=(0,L.useState)(null),c=e.cost??{},l=e.candidates??[null,null,null,null],u=e.moods??{},d=e.clips??{},f=async(e,t)=>{o(e);try{await t()}catch(e){r(e.message)}finally{o(null)}},p=e.stage===`estimate`||e.stage===`drawing`||e.stage===`choose`||e.stage===`posing`||e.stage===`animating`,m=c.clips?n(`{n} pictures and {c} clips`,{n:c.pictures??8,c:c.clips}):n(`{n} pictures`,{n:c.pictures??8}),g=(()=>{if(c.cloud===!1)return n(`{what}, made with your own key at your provider's prices.`,{what:m});if(c.error)return n(`The cost could not be checked: {error}`,{error:c.error});if(typeof c.cny!=`number`)return n(`Checking the cost…`);if(c.unlimited)return n(`About ¥{cny} for {what}; your account has no limit.`,{cny:c.cny.toFixed(2),what:m});let e=typeof c.left_cny==`number`?c.left_cny.toFixed(2):`?`;return c.affordable===!1?n(`About ¥{cny} for {what}, more than the ¥{left} left in your allowance.`,{cny:c.cny.toFixed(2),what:m,left:e}):n(`About ¥{cny} for {what}; ¥{left} left in your allowance.`,{cny:c.cny.toFixed(2),what:m,left:e})})();return(0,R.jsx)(`div`,{className:`rise flex justify-start pr-8`,children:(0,R.jsxs)(`div`,{className:i(`w-full max-w-[360px] overflow-hidden rounded-3xl rounded-tl-lg border bg-surface shadow-sm`,p?`border-accent/50`:`border-border/70`),children:[(0,R.jsxs)(`div`,{className:`flex items-start gap-3 px-4 pt-3.5 pb-2`,children:[(0,R.jsx)(`div`,{className:i(`mt-0.5 rounded-full p-2`,p?`bg-accent/12 text-accent`:`bg-surface-2 text-fg/80`),children:(0,R.jsx)(nn,{size:18})}),(0,R.jsxs)(`div`,{className:`min-w-0 flex-1`,children:[(0,R.jsxs)(`div`,{className:`text-[12.5px] font-medium text-muted`,children:[e.stage===`estimate`&&n(`A new look for {name}`,{name:t}),e.stage===`drawing`&&n(`Drawing four to choose from…`),e.stage===`choose`&&n(`Pick one: tap it, or say which`),e.stage===`posing`&&n(`Drawing the poses…`),e.stage===`animating`&&n(`The new look is on; making the clips…`),e.stage===`done`&&n(`The new look is on`),e.stage===`cancelled`&&n(`Not this time`),e.stage===`failed`&&n(`That did not work`)]}),(0,R.jsx)(`div`,{className:`mt-0.5 text-[14px] leading-snug`,children:e.description}),e.reference&&(0,R.jsxs)(`div`,{className:`mt-1.5 flex items-center gap-2 text-[12px] text-muted`,children:[(0,R.jsx)(`img`,{src:h(e.reference),alt:``,draggable:!1,className:`h-9 w-9 rounded-lg object-cover`}),n(`drawn from the picture you attached`)]})]})]}),e.stage===`estimate`&&(0,R.jsxs)(`div`,{className:`px-4 pb-3.5 space-y-2.5`,children:[(0,R.jsx)(`p`,{className:`text-[12.5px] text-muted`,children:g}),(0,R.jsxs)(`div`,{className:`flex gap-2`,children:[(0,R.jsxs)(`button`,{type:`button`,disabled:a!==null||c.cloud!==!1&&typeof c.cny!=`number`&&!c.error,onClick:()=>f(`start`,()=>M.avatarStart(e.session)),className:i(`flex items-center justify-center gap-1.5 rounded-2xl bg-accent text-accent-fg px-4 py-2.5 text-[14px] font-medium disabled:opacity-40`,`inline-flex items-center gap-1.5 py-2`),children:[a===`start`?(0,R.jsx)(A,{size:14,className:`animate-spin`}):(0,R.jsx)(nn,{size:14}),` `,n(`Draw`)]}),(0,R.jsxs)(`button`,{type:`button`,disabled:a!==null,onClick:()=>f(`cancel`,()=>M.avatarCancel(e.session)),className:i(`flex items-center justify-center gap-1.5 rounded-2xl border border-border px-4 py-2.5 text-[14px] font-medium text-muted disabled:opacity-40`,`inline-flex items-center gap-1.5`),children:[(0,R.jsx)(Fe,{size:14}),` `,n(`Not now`)]})]})]}),(e.stage===`drawing`||e.stage===`choose`)&&(0,R.jsxs)(`div`,{className:`px-4 pb-3.5 space-y-2.5`,children:[(0,R.jsx)(`div`,{className:`grid grid-cols-2 gap-2`,children:l.map((t,r)=>(0,R.jsxs)(`button`,{type:`button`,disabled:!t||e.stage!==`choose`||a!==null,onClick:()=>f(`pick${r}`,()=>M.avatarChoose(e.session,r)),"aria-label":n(`Candidate {n}`,{n:r+1}),className:i(`relative aspect-square overflow-hidden rounded-2xl bg-[#f1efeb] transition`,t&&e.stage===`choose`?`hover:ring-2 hover:ring-accent`:``),children:[t?(0,R.jsx)(`img`,{src:h(t),alt:``,draggable:!1,className:`h-full w-full object-cover`}):(0,R.jsx)(`span`,{className:`absolute inset-0 flex items-center justify-center text-muted`,children:e.stage===`drawing`?(0,R.jsx)(A,{size:20,className:`animate-spin`}):(0,R.jsx)(Fe,{size:18,className:`opacity-50`})}),a===`pick${r}`&&(0,R.jsx)(`span`,{className:`absolute inset-0 flex items-center justify-center bg-bg/60`,children:(0,R.jsx)(A,{size:20,className:`animate-spin`})}),(0,R.jsx)(`span`,{className:`absolute left-1.5 top-1.5 rounded-full bg-bg/80 px-1.5 text-[10.5px] font-semibold text-fg/80`,children:r+1})]},r))}),e.errors&&e.errors.length>0&&(0,R.jsx)(`p`,{className:`text-[12px] text-rose-600 dark:text-rose-300`,children:n(e.errors[0])}),e.stage===`choose`&&(0,R.jsxs)(`div`,{className:`flex gap-2`,children:[(0,R.jsxs)(`button`,{type:`button`,disabled:a!==null,onClick:()=>f(`redraw`,()=>M.avatarStart(e.session)),className:i(`flex items-center justify-center gap-1.5 rounded-2xl border border-border px-4 py-2.5 text-[14px] font-medium text-muted disabled:opacity-40`,`inline-flex items-center gap-1.5`),children:[a===`redraw`?(0,R.jsx)(A,{size:14,className:`animate-spin`}):(0,R.jsx)(Re,{size:14}),` `,n(`Redraw`)]}),(0,R.jsxs)(`button`,{type:`button`,disabled:a!==null,onClick:()=>f(`cancel`,()=>M.avatarCancel(e.session)),className:i(`flex items-center justify-center gap-1.5 rounded-2xl border border-border px-4 py-2.5 text-[14px] font-medium text-muted disabled:opacity-40`,`inline-flex items-center gap-1.5`),children:[(0,R.jsx)(Fe,{size:14}),` `,n(`Not now`)]})]})]}),(e.stage===`posing`||e.stage===`animating`||e.stage===`done`)&&(0,R.jsxs)(`div`,{className:`px-4 pb-3.5 space-y-2`,children:[(0,R.jsx)(`div`,{className:`flex gap-1.5`,children:tp.map(t=>(0,R.jsxs)(`div`,{className:`relative aspect-square flex-1 overflow-hidden rounded-xl bg-[#f1efeb]`,children:[d[t]?(0,R.jsx)(`video`,{src:h(d[t]),poster:u[t]?h(u[t]):void 0,autoPlay:!0,loop:!0,muted:!0,playsInline:!0,disablePictureInPicture:!0,className:`h-full w-full object-cover`},d[t]):u[t]?(0,R.jsx)(`img`,{src:h(u[t]),alt:``,draggable:!1,className:`h-full w-full object-cover`}):(0,R.jsx)(`span`,{className:`absolute inset-0 flex items-center justify-center text-muted`,children:(0,R.jsx)(A,{size:14,className:`animate-spin`})}),e.stage===`animating`&&u[t]&&!d[t]&&t!==`error`&&(0,R.jsx)(`span`,{className:`absolute bottom-1 right-1 rounded-full bg-white/80 p-0.5 text-muted`,children:(0,R.jsx)(A,{size:10,className:`animate-spin`})})]},t))}),e.stage===`done`?(0,R.jsxs)(`p`,{className:`flex items-center gap-1.5 text-[12.5px] text-muted`,children:[(0,R.jsx)(ke,{size:14,className:`text-emerald-600`}),` `,n(`Idle, working, waiting, happy, sorry: the face follows what {name} is doing.`,{name:t})]}):e.stage===`animating`?(0,R.jsx)(`p`,{className:`text-[12.5px] text-muted`,children:n(`The face is already on; four short clips are being made from the poses, a few minutes.`)}):(0,R.jsx)(`p`,{className:`text-[12.5px] text-muted`,children:n(`Four more pictures from the one you picked; this takes a minute or two.`)}),e.errors&&e.errors.length>0&&e.stage===`done`&&(0,R.jsxs)(`p`,{className:`text-[12px] text-muted`,children:[e.errors.some(e=>!e.includes(` clip:`))&&n(`Some poses could not be drawn and show the idle picture instead.`),` `,e.errors.some(e=>e.includes(` clip:`))&&n(`Some clips could not be made; those moods stay still.`)]})]}),(e.stage===`failed`||e.stage===`cancelled`)&&e.message&&(0,R.jsx)(`p`,{className:`px-4 pb-3.5 text-[12.5px] text-muted`,children:n(e.message)})]})})}function rp(){let e=ip();if(!e||typeof e.keepRunning!=`function`)return null;try{return JSON.parse(e.keepRunning())}catch{return null}}function ip(){return window.NanoMuseAndroid??null}function ap(){let e=ip();return!!e&&typeof e.takeOverBrowser==`function`&&(typeof e.hasBrowser!=`function`||e.hasBrowser())}function op(){let e=ip();if(!e||typeof e.accessibilityState!=`function`)return null;let t=e.accessibilityState();return t===`on`||t===`off`||t===`unsupported`?t:null}function sp(e,t=15){switch(e){case`web_search`:return(0,R.jsx)(qt,{size:t});case`web_fetch`:case`browser`:return(0,R.jsx)(gt,{size:t});case`files`:return(0,R.jsx)(mt,{size:t});case`shell`:return(0,R.jsx)(dn,{size:t});case`python_execute`:return(0,R.jsx)(ct,{size:t});case`read_emails`:case`send_email`:return(0,R.jsx)(Et,{size:t});case`goals`:return(0,R.jsx)(un,{size:t});case`remember`:case`recall`:case`forget`:return(0,R.jsx)(Qe,{size:t});case`ask_user`:return(0,R.jsx)(kt,{size:t});case`devices`:return(0,R.jsx)(It,{size:t});case`device_shell`:return(0,R.jsx)(dn,{size:t});case`device_files`:case`device_get`:case`device_put`:return(0,R.jsx)(mt,{size:t});case`device_open`:return(0,R.jsx)(Ae,{size:t});case`device_screen`:return(0,R.jsx)(Lt,{size:t});case`device_notify`:return(0,R.jsx)(Xe,{size:t});case`delegate`:return(0,R.jsx)(Jt,{size:t});case`computer_screen`:return(0,R.jsx)(Lt,{size:t});case`computer_act`:return(0,R.jsx)(zt,{size:t});case`computer_task`:case`computer_app`:return(0,R.jsx)(vt,{size:t});case`phone_screen`:case`phone_act`:case`phone_task`:return(0,R.jsx)(tn,{size:t});default:return(0,R.jsx)(Ze,{size:t})}}function cp({device:e,className:t}){let n=s();return(0,R.jsxs)(`span`,{className:i(`inline-flex max-w-full items-center gap-1 rounded-full bg-accent/12 px-2 py-0.5 text-[11px] font-medium text-accent`,t),children:[(0,R.jsx)(It,{size:11,className:`shrink-0`}),` `,(0,R.jsx)(`span`,{className:`truncate`,children:n(`on {device}`,{device:e})})]})}var lp={safe:`bg-emerald-500/15 text-emerald-700 dark:text-emerald-300`,moderate:`bg-amber-500/15 text-amber-700 dark:text-amber-300`,sensitive:`bg-rose-500/15 text-rose-700 dark:text-rose-300`};function up({risk:e}){return(0,R.jsx)(`span`,{className:i(`px-2 py-0.5 rounded-full text-[11px] font-semibold uppercase tracking-wide`,lp[e]),children:_(e)})}function dp({args:e}){let t=Object.entries(e??{}).filter(([,e])=>e!=null&&e!==``);return t.length?(0,R.jsx)(`dl`,{className:`mt-2 grid grid-cols-[auto_1fr] gap-x-3 gap-y-1 text-[13px]`,children:t.map(([e,t])=>(0,R.jsxs)(`div`,{className:`contents`,children:[(0,R.jsx)(`dt`,{className:`text-muted`,children:e}),(0,R.jsx)(`dd`,{className:`break-words whitespace-pre-wrap font-mono text-[12.5px] leading-snug`,children:String(t)})]},e))}):null}function fp({event:e}){let[t,n]=(0,L.useState)(!1),r=e.status===`running`?(0,R.jsx)(A,{size:14,className:`animate-spin text-accent`}):e.status===`ok`?(0,R.jsx)(ke,{size:14,className:`text-emerald-500`}):e.status===`blocked`?(0,R.jsx)(Ye,{size:14,className:`text-rose-500`}):(0,R.jsx)(Fe,{size:14,className:`text-rose-500`});return(0,R.jsx)(`div`,{className:`rise flex justify-start pr-8`,children:(0,R.jsxs)(`button`,{type:`button`,onClick:()=>n(e=>!e),className:`max-w-full text-left rounded-2xl bg-surface-2/80 border border-border/60 px-3 py-1.5 text-[13px] text-muted hover:text-fg transition`,children:[(0,R.jsxs)(`span`,{className:`flex items-center gap-2`,children:[(0,R.jsx)(`span`,{className:`text-muted`,children:sp(e.tool)}),(0,R.jsx)(`span`,{className:`truncate flex-1`,children:e.title||e.summary||e.tool}),e.device&&(0,R.jsx)(cp,{device:e.device}),r,e.output?t?(0,R.jsx)(Me,{size:13}):(0,R.jsx)(rt,{size:13}):null]}),t&&(0,R.jsxs)(`div`,{className:`mt-2 text-fg`,children:[(0,R.jsx)(dp,{args:e.args}),e.output&&(0,R.jsx)(`pre`,{className:`mt-2 max-h-52 overflow-auto whitespace-pre-wrap break-words rounded-xl bg-bg p-2 text-[12px] leading-snug`,children:e.output})]})]})})}function pp(e,t,n){if(!t)return e.replace(/_/g,` `);switch(e){case`shell`:return _(`{what} commands`,{what:t.split(`,`).join(`, `)});case`send_email`:return _(`email to {who}`,{who:t.split(`,`).join(`, `)});case`remote_control`:return _(`the device {name}`,{name:typeof n?.device==`string`&&n.device?n.device:t});case`computer_app`:return _(`the hands in {app}`,{app:typeof n?.name==`string`&&n.name?n.name:t});default:return t}}function mp(e,t,n,r){switch(e){case`once`:return _(`Once`);case`conversation`:return _(`For this conversation`);case`session`:return _(`Until restart`);case`24h`:return _(`For 24 hours`);case`always`:return _(`Always for {subject}`,{subject:pp(t,n,r)});default:return e}}function hp({event:e,name:t=`nanoMuse`,onDecide:n}){let[r,a]=(0,L.useState)(!1),[o,c]=(0,L.useState)(!1),[l,d]=(0,L.useState)(!1),[f,p]=(0,L.useState)(!1),m=(e,t)=>{f||(p(!0),Promise.resolve(n(e,t)).finally(()=>p(!1)))},h=(0,L.useRef)(null),g=(0,L.useRef)(null),_=s(),y=e.status===`pending`,b=e.risk===`sensitive`,x=(e.grant_options??[`once`]).filter(e=>e!==`once`),S=e.egress_target||([`web_fetch`,`browser`,`web_search`].includes(e.tool)?e.target:null),C=e.tool===`send_email`?e.target:null,w=Object.values(e.args??{}).some(e=>e!=null&&e!==``);return(0,L.useEffect)(()=>{let e=g.current;e&&!r&&d(e.scrollHeight>e.clientHeight+2)},[e.args,r]),(0,L.useEffect)(()=>{(r||o)&&h.current?.scrollIntoView({block:`end`,behavior:`smooth`})},[r,o]),(0,R.jsx)(`div`,{className:`rise flex justify-start`,ref:h,children:(0,R.jsxs)(`div`,{className:i(`w-full max-w-[600px] overflow-hidden rounded-[22px] bg-surface shadow-[0_2px_12px_rgba(0,0,0,0.12)] dark:border dark:border-border dark:shadow-none`,y&&b&&`border border-rose-400/60`),children:[(0,R.jsxs)(`div`,{className:`flex items-start gap-3 px-4 pt-4 pb-2`,children:[(0,R.jsx)(`div`,{className:i(`flex h-10 w-10 shrink-0 items-center justify-center rounded-full`,b?`bg-rose-500/12 text-rose-500`:`bg-surface-2 text-fg`),children:b?(0,R.jsx)(Zt,{size:22}):sp(e.tool,22)}),(0,R.jsxs)(`div`,{className:`min-w-0 flex-1`,children:[(0,R.jsxs)(`div`,{className:`flex flex-wrap items-center gap-1.5 text-[12.5px] font-medium text-muted`,children:[(0,R.jsx)(`span`,{children:e.remote?_(`{name} on {device} wants to`,{name:t,device:e.remote.name}):_(`{name} wants to`,{name:t})}),e.remote&&(0,R.jsx)(cp,{device:e.remote.name})]}),(0,R.jsx)(`div`,{className:`mt-0.5 break-words text-[17px] font-semibold leading-[22px]`,children:e.summary}),S?(0,R.jsxs)(`div`,{className:`mt-1 flex items-center gap-1 text-[13px] text-muted`,children:[(0,R.jsx)(gt,{size:12}),` `,(0,R.jsx)(`span`,{className:`truncate`,children:_(`at {host}`,{host:S})})]}):C?(0,R.jsxs)(`div`,{className:`mt-1 flex items-center gap-1 text-[13px] text-muted`,children:[(0,R.jsx)(Et,{size:12}),` `,(0,R.jsx)(`span`,{className:`truncate`,children:_(`to {recipient}`,{recipient:C})})]}):null,e.purpose&&(0,R.jsx)(`div`,{className:`mt-1.5 break-words text-[13px] leading-snug text-muted line-clamp-2`,children:e.purpose}),b&&(0,R.jsx)(`div`,{className:`mt-1.5`,children:(0,R.jsx)(up,{risk:e.risk})})]})]}),e.warnings?.length>0&&(0,R.jsx)(`div`,{className:`space-y-1 px-4 pb-2`,children:e.warnings.map(e=>(0,R.jsxs)(`div`,{className:`flex items-start gap-1.5 text-[12.5px] text-rose-600 dark:text-rose-300`,children:[(0,R.jsx)(pn,{size:13,className:`mt-0.5 shrink-0`}),` `,(0,R.jsx)(`span`,{children:_(e)})]},e))}),(w||e.reasons?.length>0)&&(0,R.jsx)(`div`,{className:`px-4 pb-2`,children:(0,R.jsxs)(`div`,{className:`rounded-xl bg-surface-2 px-3 py-2.5`,children:[(0,R.jsx)(`div`,{className:`text-[11px] font-medium text-muted`,children:_(`Exactly what will run`)}),(0,R.jsxs)(`div`,{ref:g,className:i(`-mt-1`,!r&&`max-h-40 overflow-hidden`),children:[(0,R.jsx)(dp,{args:e.args}),e.reasons?.length>0&&(0,R.jsx)(`div`,{className:`mt-1.5 text-[12px] text-muted`,children:_(`Why it asks: {reasons}`,{reasons:e.reasons.map(v).join(` · `)})})]}),(l||r)&&(0,R.jsxs)(`button`,{type:`button`,className:`mt-1 flex items-center gap-1 text-[12.5px] text-accent`,onClick:()=>a(e=>!e),children:[r?(0,R.jsx)(Me,{size:13}):(0,R.jsx)(rt,{size:13}),` `,_(r?`Fewer options`:`Show all`)]})]})}),y?(0,R.jsxs)(`div`,{className:`flex flex-col gap-2 px-4 pb-4 pt-2`,children:[(0,R.jsx)(`button`,{type:`button`,onClick:()=>m(!0,`once`),disabled:f,className:`h-[46px] w-full rounded-full bg-accent text-[15px] font-semibold text-accent-fg transition active:scale-[0.98] disabled:opacity-60`,children:_(`Allow once`)}),x.filter(e=>o||e===`conversation`||e===`always`).map(t=>(0,R.jsx)(`button`,{type:`button`,onClick:()=>m(!0,t),disabled:f,className:`h-11 w-full truncate rounded-full bg-surface-2 px-4 text-[15px] font-medium transition active:scale-[0.98] disabled:opacity-60`,children:mp(t,e.tool,e.target,e.args)},t)),(0,R.jsx)(`button`,{type:`button`,onClick:()=>m(!1,`once`),disabled:f,className:`h-11 w-full rounded-full bg-surface-2 text-[15px] font-medium transition active:scale-[0.98] disabled:opacity-60`,children:_(`Deny`)}),x.length===0?(0,R.jsx)(`div`,{className:`text-center text-[12px] text-muted`,children:_(`This kind of action is approved one at a time.`)}):!o&&x.some(e=>e!==`conversation`&&e!==`always`)&&(0,R.jsx)(`button`,{type:`button`,className:`self-center text-[12.5px] text-muted`,onClick:()=>c(!0),children:_(`Allow {subject} for longer…`,{subject:pp(e.tool,e.target,e.args)})})]}):(0,R.jsxs)(`div`,{className:i(`flex items-center gap-1.5 border-t border-border px-4 py-2.5 text-[13px] font-medium`,e.status===`approved`?`text-emerald-600 dark:text-emerald-300`:`text-muted`),children:[e.status===`approved`?(0,R.jsx)(ke,{size:15}):(0,R.jsx)(Fe,{size:15}),e.status===`approved`?`${_(`Approved`)}${e.scope&&e.scope!==`once`?` · ${mp(e.scope,e.tool,e.target).toLowerCase()}`:``}`:e.status===`denied`?_(`Denied`):_(`Expired without an answer`),(0,R.jsx)(`span`,{className:`ml-auto font-normal`,children:u(e.updated_ts??e.ts)})]})]})})}function gp({event:e,name:t}){let n=s();return(0,R.jsx)(`div`,{className:`rise flex justify-start pr-8`,children:(0,R.jsxs)(`div`,{className:`max-w-full rounded-[20px] rounded-bl-md border border-accent/30 bg-surface px-4 py-3`,children:[(0,R.jsxs)(`div`,{className:`flex items-center gap-1.5 text-[12.5px] font-medium text-accent`,children:[(0,R.jsx)(kt,{size:14}),` `,n(`{name} asks`,{name:t})]}),(0,R.jsx)(`div`,{className:`mt-1 text-[15px] leading-snug whitespace-pre-wrap break-words`,children:e.text}),e.status===`pending`&&(0,R.jsx)(`div`,{className:`mt-1.5 text-[12.5px] text-muted`,children:n(`Reply below to continue.`)}),e.status===`answered`&&e.answer&&(0,R.jsxs)(`div`,{className:`mt-2 text-[13px] text-muted border-t border-border pt-2`,children:[n(`You:`),` `,(0,R.jsx)(`span`,{className:`text-fg`,children:e.answer})]})]})})}function _p(e){return e.source===`reminder`||e.source===`memory`?t(e.text):_(e.text,e.vars)}function vp({event:e,onCloudRetry:t}){let n=s(),[r,a]=(0,L.useState)(!1),[o,c]=(0,L.useState)(!1),[l,u]=(0,L.useState)(null),d=e.detail&&e.detail!==e.text?e.detail:null;return e.code===`allowance`&&e.allowance?(0,R.jsxs)(`div`,{className:`rise flex flex-col items-center gap-2 px-6`,children:[(0,R.jsx)(`div`,{className:`max-w-full rounded-2xl bg-amber-500/12 px-3 py-1.5 text-center text-[12.5px] leading-snug text-amber-700 dark:text-amber-300`,children:n(e.text)}),(0,R.jsx)(`div`,{className:`w-full max-w-[520px]`,children:(0,R.jsx)(Ff,{info:e.allowance,exhausted:!0,compact:!0})})]}):(0,R.jsx)(`div`,{className:`rise flex justify-center px-6`,children:(0,R.jsxs)(`div`,{className:i(`max-w-full rounded-2xl px-3 py-1.5 text-center text-[12.5px] leading-snug`,e.level===`info`&&`bg-surface-2/70 text-muted`,e.level===`warn`&&`bg-amber-500/12 text-amber-700 dark:text-amber-300`,e.level===`error`&&`bg-rose-500/12 text-rose-700 dark:text-rose-300`),children:[_p(e),d&&(0,R.jsxs)(R.Fragment,{children:[` `,(0,R.jsx)(`button`,{type:`button`,onClick:()=>a(e=>!e),className:`underline decoration-dotted underline-offset-2 opacity-70 hover:opacity-100`,children:n(r?`Hide details`:`Details`)}),r&&(0,R.jsx)(`div`,{className:`mt-1.5 break-all text-left font-mono text-[11px] opacity-80`,children:d})]}),t&&(0,R.jsxs)(`div`,{className:`mt-1.5 flex flex-col items-center gap-1`,children:[(0,R.jsx)(`button`,{type:`button`,disabled:o,onClick:()=>{t&&(c(!0),u(null),t().catch(e=>u(n(e.message||`Could not send`))).finally(()=>c(!1)))},className:`rounded-full bg-accent/12 px-3 py-1 text-[12px] font-medium text-accent disabled:opacity-50`,children:n(`Use nanoMuse Cloud this time`)}),l&&(0,R.jsx)(`div`,{className:`text-[12px] text-rose-700 dark:text-rose-300`,children:l})]})]})})}function yp({event:e,onOpen:t}){let[r,i]=(0,L.useState)(!1),a=s(),o=e.status===`live`,c=e.url;try{c=new URL(e.url).host}catch{}return(0,R.jsx)(`div`,{className:`rise flex justify-start pr-8`,children:(0,R.jsxs)(`button`,{type:`button`,onClick:()=>t(e.id),"aria-label":a(`Browser: {title}`,{title:e.title||c}),className:`w-full max-w-[340px] overflow-hidden rounded-3xl rounded-tl-lg border border-border bg-surface shadow-sm hover:bg-surface-2 transition text-left`,children:[(0,R.jsxs)(`div`,{className:`relative aspect-[16/10] bg-surface-2`,children:[r?(0,R.jsxs)(`div`,{className:`absolute inset-0 flex flex-col items-center justify-center gap-1 text-muted`,children:[(0,R.jsx)(gt,{size:22}),(0,R.jsx)(`span`,{className:`text-[12px]`,children:a(`Frame no longer available`)})]}):(0,R.jsx)(`img`,{src:n(e.thread,e.frame),alt:e.title||c,onError:()=>i(!0),className:`absolute inset-0 h-full w-full object-cover object-top`},e.frame),(0,R.jsx)(`div`,{className:`absolute left-2.5 top-2.5 flex items-center gap-1.5 rounded-full bg-black/60 px-2 py-0.5 text-[10.5px] font-semibold text-white`,children:o?(0,R.jsxs)(R.Fragment,{children:[(0,R.jsx)(`span`,{className:`h-1.5 w-1.5 rounded-full bg-rose-400 animate-pulse`}),` `,a(`LIVE`)]}):(0,R.jsxs)(R.Fragment,{children:[(0,R.jsx)(gt,{size:11}),` `,a(`BROWSER`)]})})]}),(0,R.jsxs)(`div`,{className:`flex items-center gap-2 px-3.5 py-2.5`,children:[(0,R.jsxs)(`div`,{className:`min-w-0 flex-1`,children:[(0,R.jsx)(`div`,{className:`text-[13.5px] font-medium truncate`,children:e.title||c}),(0,R.jsxs)(`div`,{className:`text-[12px] text-muted truncate`,children:[e.by_user&&e.action.startsWith(`You`)?a(`You`)+e.action.slice(3):e.action,` · `,c]})]}),(0,R.jsx)(rt,{size:16,className:`text-muted shrink-0`})]})]})})}function bp({event:e,name:t=`nanoMuse`}){let n=s(),{state:r,toast:a}=E(),[o,c]=(0,L.useState)(!1),[l,d]=(0,L.useState)(!1),f=e.status===`live`,p=e.last,m=[e.app,e.title].filter(Boolean).join(` · `),h=r.holds.find(t=>t.thread===e.thread&&t.tool===`computer`),g=async()=>{c(!0);try{await M.stopHands()}catch{}finally{c(!1)}},_=async()=>{d(!0);try{await M.openHold(e.thread,`computer`)}catch(e){a(e.message)}finally{d(!1)}};return(0,R.jsx)(`div`,{className:`rise flex justify-start pr-8`,children:(0,R.jsxs)(`div`,{className:i(`w-full max-w-[360px] overflow-hidden rounded-3xl rounded-tl-lg border bg-surface shadow-sm`,f?`border-accent/50`:`border-border/70`),children:[(0,R.jsxs)(`div`,{className:`flex items-start gap-3 px-4 pt-3.5 pb-2`,children:[(0,R.jsx)(`div`,{className:i(`mt-0.5 rounded-full p-2`,f?`bg-accent/12 text-accent`:`bg-surface-2 text-fg/80`),children:(0,R.jsx)(vt,{size:18})}),(0,R.jsxs)(`div`,{className:`min-w-0 flex-1`,children:[(0,R.jsxs)(`div`,{className:`flex items-center gap-2 text-[12.5px] font-medium text-muted`,children:[(0,R.jsx)(`span`,{children:f?n(`{name} is using this computer`,{name:t}):e.status===`stopped`?n(`Hands stopped`):n(`Hands done`)}),f&&(0,R.jsxs)(`span`,{className:`flex items-center gap-1 rounded-full bg-accent/12 px-2 py-0.5 text-[10.5px] font-semibold text-accent`,children:[(0,R.jsx)(`span`,{className:`h-1.5 w-1.5 animate-pulse rounded-full bg-accent`}),` `,n(`LIVE`)]})]}),e.text&&(0,R.jsx)(`div`,{className:`mt-0.5 break-words text-[15px] font-semibold leading-snug`,children:e.text}),p?.action&&(0,R.jsxs)(`div`,{className:`mt-1.5 flex items-center gap-1.5 text-[13px] text-fg/90`,children:[(0,R.jsx)(zt,{size:13,className:`shrink-0 text-muted`}),(0,R.jsx)(`span`,{className:`truncate`,children:Tp(p,n)})]}),m&&(0,R.jsx)(`div`,{className:`mt-1 truncate text-[12px] text-muted`,children:m}),e.notice&&(0,R.jsx)(`div`,{className:`mt-1.5 rounded-2xl bg-amber-500/12 px-3 py-1.5 text-[12.5px] text-amber-700 dark:text-amber-300`,children:e.notice}),f&&h&&(0,R.jsx)(xp,{hold:h})]})]}),(0,R.jsxs)(`div`,{className:`flex items-center gap-2 border-t border-border/70 px-4 py-2 text-[12px] text-muted`,children:[(0,R.jsx)(`span`,{children:n(`{n} steps`,{n:e.steps})}),(0,R.jsx)(`span`,{className:`ml-auto`,children:u(e.updated_ts??e.ts)}),f&&!h&&(0,R.jsxs)(`button`,{type:`button`,onClick:()=>void _(),disabled:l,className:`ml-1 inline-flex items-center gap-1.5 rounded-full bg-accent/12 px-3 py-1 text-[12.5px] font-semibold text-accent transition active:scale-95 disabled:opacity-60`,children:[(0,R.jsx)(vt,{size:11}),` `,n(`Take over`)]}),f&&(0,R.jsxs)(`button`,{type:`button`,onClick:()=>void g(),disabled:o,className:`ml-1 inline-flex items-center gap-1.5 rounded-full bg-fg px-3 py-1 text-[12.5px] font-semibold text-bg transition active:scale-95 disabled:opacity-60`,children:[(0,R.jsx)(sn,{size:10,fill:`currentColor`}),` `,n(`Stop`)]})]})]})})}function xp({hold:e,compact:t}){let n=s(),[r,a]=(0,L.useState)(!1),o=async()=>{a(!0);try{await M.doneHold(e.id)}catch{}finally{a(!1)}};return(0,R.jsxs)(`div`,{className:i(`flex items-center gap-2 rounded-2xl bg-amber-500/12 px-3 text-amber-800 dark:text-amber-200`,t?`py-1.5 text-[12.5px]`:`mt-1.5 py-2 text-[13px]`),children:[(0,R.jsx)(vt,{size:14,className:`shrink-0`}),(0,R.jsx)(`span`,{className:`min-w-0 flex-1 leading-snug`,children:Cp(e,n)}),(0,R.jsx)(`button`,{type:`button`,onClick:()=>void o(),disabled:r,className:`shrink-0 rounded-full bg-fg px-3 py-1 text-[12.5px] font-semibold text-bg transition active:scale-95 disabled:opacity-60`,children:r?(0,R.jsx)(A,{size:13,className:`animate-spin`}):n(`Done`)})]})}function Sp(e,t){return t(e===`browser`?`the browser`:e===`phone`?`the phone`:`this computer`)}function Cp(e,t){return e.by===`agent`?e.reason?t(`Your turn: {reason}`,{reason:e.reason}):t(`Your turn`):t(`You took over {thing}`,{thing:Sp(e.tool,t)})}function wp({event:e,name:t=`nanoMuse`}){let n=s(),[r,a]=(0,L.useState)(!1),o=e.status===`on`,c=Sp(e.tool,n),l=async()=>{a(!0);try{await M.doneHold(e.id)}catch{}finally{a(!1)}},d=e.timed_out?n(`{name} waited ten minutes and went on without you.`,{name:t}):e.stale?n(`Ended when the runtime restarted.`):e.by===`agent`?n(`You did it; {name} carried on.`,{name:t}):n(`Handed back; {name} carried on.`,{name:t});return(0,R.jsx)(`div`,{className:`rise flex justify-start pr-8`,children:(0,R.jsxs)(`div`,{className:i(`w-full max-w-[360px] overflow-hidden rounded-3xl rounded-tl-lg border bg-surface shadow-sm`,o?`border-amber-500/50`:`border-border/70 opacity-70`),children:[(0,R.jsxs)(`div`,{className:`flex items-start gap-3 px-4 pt-3.5 pb-3`,children:[(0,R.jsx)(`div`,{className:i(`mt-0.5 rounded-full p-2`,o?`bg-amber-500/15 text-amber-700 dark:text-amber-300`:`bg-surface-2 text-fg/70`),children:(0,R.jsx)(vt,{size:18})}),(0,R.jsxs)(`div`,{className:`min-w-0 flex-1`,children:[(0,R.jsx)(`div`,{className:`text-[12.5px] font-medium text-muted`,children:e.tool===`browser`?n(`The browser`):e.tool===`phone`?n(`The phone`):n(`This computer`)}),(0,R.jsx)(`div`,{className:`mt-0.5 break-words text-[15px] font-semibold leading-snug`,children:e.by===`agent`?n(`Your turn`):n(`You took over {thing}`,{thing:c})}),e.by===`agent`&&e.reason&&(0,R.jsx)(`div`,{className:`mt-1 break-words text-[13.5px] leading-snug text-fg/90`,children:e.reason}),(0,R.jsx)(`div`,{className:`mt-1.5 text-[12.5px] leading-snug text-muted`,children:o?e.by===`agent`?n(`Do this part yourself, then press Done. {name} looks again and carries on from there.`,{name:t}):n(`{name} waits. Press Done when you are finished and it looks again.`,{name:t}):d})]})]}),(0,R.jsxs)(`div`,{className:`flex items-center gap-2 border-t border-border/70 px-4 py-2 text-[12px] text-muted`,children:[(0,R.jsx)(`span`,{children:u(e.ts)}),o&&(0,R.jsxs)(`button`,{type:`button`,onClick:()=>void l(),disabled:r,className:`ml-auto inline-flex items-center gap-1.5 rounded-full bg-fg px-3.5 py-1 text-[12.5px] font-semibold text-bg transition active:scale-95 disabled:opacity-60`,children:[r?(0,R.jsx)(A,{size:13,className:`animate-spin`}):(0,R.jsx)(ke,{size:12}),` `,n(`Done`)]})]})]})})}function Tp(e,t){let n=e.label?`“${e.label}”`:``;switch(e.action){case`click`:return n?t(`Clicked {label}`,{label:n}):t(`Clicked`);case`double_click`:return n?t(`Double-clicked {label}`,{label:n}):t(`Double-clicked`);case`right_click`:case`middle_click`:return n?t(`Right-clicked {label}`,{label:n}):t(`Right-clicked`);case`move`:return n?t(`Pointed at {label}`,{label:n}):t(`Moved the mouse`);case`type`:return t(`Typed {n} characters`,{n:(e.text??``).length});case`key`:return t(`Pressed {keys}`,{keys:(e.keys??[]).join(`+`)});case`scroll`:return t(`Scrolled`);case`drag`:return t(`Dragged`);case`open_app`:return n?t(`Opened {label}`,{label:n}):t(`Opened an application`);case`wait`:return t(`Waited`);default:return e.action??``}}function Ep({event:e,onOpen:t}){let n=s(),a=r(e.name),o=n(a===`html`?`Page`:a===`image`?`Image`:a===`data`?`Data`:a===`code`?`Code`:a===`event`?`Event`:`Document`),c=e.action===`update`?`${o} · ${n(`updated`)}`:o,l=a===`html`||a===`image`;return(0,R.jsx)(`div`,{className:`rise flex justify-start pr-8`,children:(0,R.jsxs)(`button`,{type:`button`,onClick:()=>t(e.path),className:i(`max-w-full overflow-hidden rounded-[20px] border border-border bg-surface text-left shadow-[0_4px_20px_-12px_rgba(0,0,0,0.2)] transition hover:bg-surface-2`,l?`w-[300px]`:``),children:[l&&(0,R.jsx)(Dp,{path:e.path,kind:a}),(0,R.jsxs)(`div`,{className:`flex items-center gap-3 px-4 py-3`,children:[!l&&(0,R.jsx)(`div`,{className:`rounded-2xl bg-accent/12 p-2.5 text-accent`,children:a===`code`?(0,R.jsx)(ct,{size:20}):a===`event`?(0,R.jsx)(tt,{size:20}):(0,R.jsx)(mt,{size:20})}),(0,R.jsxs)(`div`,{className:`min-w-0 flex-1`,children:[(0,R.jsx)(`div`,{className:`text-[11px] font-semibold uppercase tracking-wide text-muted`,children:c}),(0,R.jsx)(`div`,{className:`truncate text-[14.5px] font-medium`,children:e.name}),(0,R.jsx)(`div`,{className:`truncate text-[12px] text-muted`,children:e.path})]}),(0,R.jsx)(rt,{size:16,className:`ml-1 shrink-0 text-muted`})]})]})})}function Dp({path:e,kind:t}){return t===`image`?(0,R.jsx)(`img`,{src:h(e),alt:``,loading:`lazy`,className:`h-40 w-full object-cover`}):(0,R.jsx)(`div`,{className:`pointer-events-none relative h-40 w-full overflow-hidden bg-white`,children:(0,R.jsx)(`iframe`,{title:e,src:h(e),sandbox:``,tabIndex:-1,loading:`lazy`,scrolling:`no`,className:`absolute left-0 top-0 h-[480px] w-[900px] origin-top-left scale-[0.3333] border-0`})})}function Op({open:e,onClose:t,title:n,children:r,footer:i}){let a=s(),o=(0,L.useRef)(null);return On(o,e),(0,L.useEffect)(()=>{if(!e)return;let n=e=>e.key===`Escape`&&t();return window.addEventListener(`keydown`,n),()=>window.removeEventListener(`keydown`,n)},[e,t]),e?(0,R.jsxs)(`div`,{className:`fixed inset-0 z-50 flex items-end sm:items-center sm:justify-center`,children:[(0,R.jsx)(`div`,{className:`absolute inset-0 bg-black/45 backdrop-blur-[2px]`,onClick:t}),(0,R.jsxs)(`div`,{ref:o,role:`dialog`,"aria-modal":`true`,className:`sheet-in relative w-full sm:max-w-lg max-h-[92dvh] flex flex-col bg-surface rounded-t-3xl sm:rounded-3xl shadow-2xl border border-border`,children:[(0,R.jsxs)(`div`,{className:`flex items-center gap-3 px-5 pt-4 pb-2`,children:[(0,R.jsx)(`div`,{className:`sm:hidden absolute left-1/2 -translate-x-1/2 top-2 h-1 w-10 rounded-full bg-border`}),(0,R.jsx)(`div`,{className:`flex-1 font-semibold text-[17px] mt-1`,children:n}),(0,R.jsx)(`button`,{type:`button`,onClick:t,"aria-label":a(`Close`),className:`p-2 -mr-2 rounded-full text-muted hover:bg-surface-2`,children:(0,R.jsx)(Fe,{size:20})})]}),(0,R.jsx)(`div`,{className:`flex-1 overflow-y-auto px-5 pb-4`,children:r}),i&&(0,R.jsx)(`div`,{className:`px-5 pt-2 pb-4 safe-bottom border-t border-border`,children:i})]})]}):null}var kp=1e3;function Ap({thread:e,eventId:t,onClose:r}){let{state:a,toast:o}=E(),c=s(),l=(a.events[e]??[]).find(e=>e.id===t),u=a.holds.find(t=>t.thread===e&&t.tool===`browser`),[d,f]=(0,L.useState)(null),[p,m]=(0,L.useState)(null),[h,g]=(0,L.useState)(``),[_,v]=(0,L.useState)(``),[y,b]=(0,L.useState)(!1),x=(0,L.useRef)(null),S=d?d===`on`:!!u;(0,L.useEffect)(()=>b(!1),[l?.frame]),(0,L.useEffect)(()=>f(null),[u?.id,u?.status]);let C=l?.backend===`device`&&ap();(0,L.useEffect)(()=>{if(!C)return;let t=t=>{let n=t.detail;n?.thread&&n.thread!==e||M.browserControl(e,{action:`handed_back`}).catch(e=>o(e.message))};return window.addEventListener(`nanomuse:browser-handed-back`,t),()=>window.removeEventListener(`nanomuse:browser-handed-back`,t)},[C,e,o]);let w=(0,L.useCallback)(async t=>{m(t.action);try{await M.browserControl(e,t)}catch(e){o(e.message)}finally{m(null)}},[e,o]),T=()=>{if(C){ip()?.takeOverBrowser?.(e),M.browserControl(e,{action:`take_over`}).catch(()=>void 0);return}f(`on`),w({action:`take_over`})},D=()=>{f(`off`),w({action:`handed_back`})};(0,L.useEffect)(()=>{if(!S||C||!l||l.status!==`live`)return;let t=window.setInterval(()=>{document.hidden||M.browserControl(e,{action:`look`}).catch(()=>void 0)},kp);return()=>window.clearInterval(t)},[S,C,e,l]);let O=e=>{if(!S||p)return;let t=e.currentTarget.getBoundingClientRect(),n=(e.clientX-t.left)/t.width,r=(e.clientY-t.top)/t.height;w({action:`click`,x:Math.min(Math.max(n,0),1),y:Math.min(Math.max(r,0),1)})},k=e=>{!S||p||Math.abs(e.deltaY)<8||w({action:`scroll`,dy:Math.max(-2e3,Math.min(2e3,Math.round(e.deltaY*2)))})};if(!l)return null;let ee=l.url;try{ee=new URL(l.url).host}catch{}let te=l.status===`live`,j=a.profile?.name??`nanoMuse`,ne=u?c(`{name} is waiting for you`,{name:j}):a.status.state!==`idle`&&a.status.thread===e?c(`{name} is working`,{name:j}):l.action;return(0,R.jsxs)(Op,{open:!0,onClose:r,title:(0,R.jsxs)(`div`,{className:`flex items-center gap-2 min-w-0`,children:[(0,R.jsx)(gt,{size:17,className:`text-accent shrink-0`}),(0,R.jsx)(`span`,{className:`truncate`,children:l.title||ee}),te&&(0,R.jsxs)(`span`,{className:`ml-1 flex items-center gap-1 rounded-full bg-rose-500/12 px-2 py-0.5 text-[10.5px] font-semibold text-rose-500`,children:[(0,R.jsx)(`span`,{className:`h-1.5 w-1.5 rounded-full bg-rose-500 animate-pulse`}),` `,c(`LIVE`)]})]}),footer:S?(0,R.jsxs)(`div`,{className:`space-y-2`,children:[(0,R.jsxs)(`form`,{className:`flex items-center gap-2`,onSubmit:e=>{e.preventDefault(),h&&w({action:`type`,text:h}).then(()=>g(``))},children:[(0,R.jsx)(`input`,{value:h,onChange:e=>g(e.target.value),placeholder:c(`Type into the focused field…`),className:`flex-1 rounded-2xl bg-surface-2 px-3.5 py-2.5 text-[14px] outline-none`,autoComplete:`off`,autoCapitalize:`off`}),(0,R.jsx)(`button`,{type:`submit`,disabled:!h||!!p,"aria-label":c(`Type`),className:`rounded-full bg-accent p-2.5 text-white disabled:opacity-40`,children:p===`type`?(0,R.jsx)(A,{size:16,className:`animate-spin`}):(0,R.jsx)(qe,{size:16})}),(0,R.jsx)(`button`,{type:`button`,onClick:()=>void w({action:`key`,key:`Enter`}),disabled:!!p,"aria-label":c(`Press Enter`),className:`rounded-full bg-surface-2 p-2.5 text-fg disabled:opacity-40`,children:(0,R.jsx)(dt,{size:16})})]}),(0,R.jsxs)(`form`,{className:`flex items-center gap-2`,onSubmit:e=>{e.preventDefault(),_&&w({action:`navigate`,url:_}).then(()=>v(``))},children:[(0,R.jsx)(`button`,{type:`button`,onClick:()=>void w({action:`back`}),disabled:!!p,"aria-label":c(`Back`),className:`rounded-full bg-surface-2 p-2 text-fg disabled:opacity-40`,children:(0,R.jsx)(Ke,{size:15})}),(0,R.jsx)(`input`,{value:_,onChange:e=>v(e.target.value),placeholder:c(`Open a URL…`),inputMode:`url`,autoCapitalize:`off`,className:`flex-1 min-w-0 rounded-2xl bg-surface-2 px-3.5 py-2 text-[13px] outline-none`}),(0,R.jsx)(`button`,{type:`submit`,disabled:!_||!!p,className:`rounded-2xl bg-surface-2 px-3 py-2 text-[13px] font-medium disabled:opacity-40`,children:c(`Go`)}),(0,R.jsx)(`button`,{type:`button`,onClick:()=>void w({action:`scroll`,dy:-600}),disabled:!!p,"aria-label":c(`Scroll up`),className:`rounded-full bg-surface-2 p-2 text-fg disabled:opacity-40`,children:(0,R.jsx)(Je,{size:15})}),(0,R.jsx)(`button`,{type:`button`,onClick:()=>void w({action:`scroll`,dy:600}),disabled:!!p,"aria-label":c(`Scroll down`),className:`rounded-full bg-surface-2 p-2 text-fg disabled:opacity-40`,children:(0,R.jsx)(Ge,{size:15})})]}),(0,R.jsxs)(`div`,{className:`flex items-center justify-between gap-2`,children:[(0,R.jsx)(`span`,{className:`min-w-0 truncate text-[12px] text-muted`,children:c(`Tap the page to click. If the browser was closed, open a URL first.`)}),(0,R.jsxs)(`button`,{type:`button`,onClick:D,disabled:p===`handed_back`,className:`flex shrink-0 items-center gap-1.5 whitespace-nowrap rounded-full bg-fg px-3.5 py-1.5 text-[13px] font-semibold text-bg disabled:opacity-60`,children:[p===`handed_back`?(0,R.jsx)(A,{size:14,className:`animate-spin`}):(0,R.jsx)(ke,{size:14}),` `,c(`Done`)]})]})]}):(0,R.jsxs)(`div`,{className:`flex items-center justify-between gap-2`,children:[(0,R.jsxs)(`div`,{className:`min-w-0 text-[12.5px] text-muted truncate`,children:[ne,` · `,ee]}),(0,R.jsxs)(`div`,{className:`flex items-center gap-2 shrink-0`,children:[(0,R.jsx)(`button`,{type:`button`,onClick:()=>void w({action:`look`}),disabled:!!p,"aria-label":c(`Refresh`),className:`rounded-full bg-surface-2 p-2 text-muted disabled:opacity-40`,children:p===`look`?(0,R.jsx)(A,{size:15,className:`animate-spin`}):(0,R.jsx)(Re,{size:15})}),(0,R.jsxs)(`button`,{type:`button`,onClick:T,disabled:d===`on`,className:`flex items-center gap-1.5 rounded-full bg-accent px-3.5 py-2 text-[13px] font-semibold text-white disabled:opacity-60`,children:[(0,R.jsx)(vt,{size:14}),` `,c(`Take over`)]})]})]}),children:[u&&u.by===`agent`&&(0,R.jsx)(`div`,{className:`mb-2`,children:(0,R.jsx)(xp,{hold:u,compact:!0})}),(0,R.jsxs)(`div`,{className:i(`relative overflow-hidden rounded-2xl border border-border bg-surface-2`,S&&`ring-2 ring-accent`),children:[y?(0,R.jsxs)(`div`,{className:`flex aspect-[16/10] flex-col items-center justify-center gap-1 text-muted`,children:[(0,R.jsx)(gt,{size:24}),(0,R.jsx)(`span`,{className:`text-[12.5px]`,children:c(`This frame is no longer available.`)}),(0,R.jsx)(`button`,{type:`button`,onClick:()=>void w({action:`look`}),className:`text-accent text-[13px] font-medium`,children:c(`Look again`)})]}):(0,R.jsx)(`img`,{ref:x,src:n(e,l.frame),alt:l.title||ee,onError:()=>b(!0),onClick:O,onWheel:k,draggable:!1,className:i(`block w-full select-none`,S?`cursor-crosshair`:``)},l.frame),p&&p!==`look`&&(0,R.jsx)(`div`,{className:`absolute inset-0 flex items-center justify-center bg-black/20`,children:(0,R.jsx)(A,{size:26,className:`animate-spin text-white`})})]}),(0,R.jsxs)(`div`,{className:`mt-2 flex items-center justify-between text-[12px] text-muted`,children:[(0,R.jsx)(`span`,{className:`truncate`,children:l.url}),(0,R.jsx)(`span`,{className:`shrink-0 ml-2`,children:l.frames===1?c(`1 frame`):c(`{n} frames`,{n:l.frames})})]}),S&&(0,R.jsxs)(`div`,{className:`mt-3 rounded-2xl bg-accent/8 px-3.5 py-2.5 text-[13px] leading-snug`,children:[(0,R.jsx)(`div`,{className:`font-medium`,children:u&&u.by===`agent`?Cp(u,c):c(`You have the page. Press Done when you are finished.`)}),(0,R.jsx)(`div`,{className:`mt-1 text-muted`,children:c(`{name} waits meanwhile, then looks at the page as you left it and carries on. Passwords you type here go to the website, never to the model.`,{name:j})})]})]})}function jp(){if(typeof window>`u`)return null;let e=window;return e.SpeechRecognition??e.webkitSpeechRecognition??null}function Mp(){return jp()!==null}function Np(e,t){let[n,r]=(0,L.useState)(!1),i=(0,L.useRef)(null),a=(0,L.useRef)(``),o=s(),c=(0,L.useCallback)(()=>{i.current?.stop()},[]),l=(0,L.useCallback)(()=>{let n=jp();if(!n)return;let s=new n;s.lang=navigator.language||`en-US`,s.continuous=!0,s.interimResults=!0,a.current=``,s.onresult=t=>{let n=``;for(let e=t.resultIndex;e{let n=e.error||``;n!==`aborted`&&n!==`no-speech`&&t?.(n===`not-allowed`||n===`service-not-allowed`?o(`The microphone is not allowed. Allow it in the browser and try again.`):o(`Voice input stopped ({code}).`,{code:n}))},s.onend=()=>{i.current=null,r(!1)},i.current=s;try{s.start(),r(!0)}catch{i.current=null,r(!1)}},[e,t,o]),u=(0,L.useCallback)(()=>{i.current?c():l()},[l,c]);return(0,L.useEffect)(()=>()=>i.current?.abort(),[]),{supported:Mp(),listening:n,toggle:u,stop:c}}function Pp({listening:e,onClick:t,className:n}){let r=s();return(0,R.jsx)(`button`,{type:`button`,onClick:t,"aria-label":r(e?`Stop voice input`:`Voice input`),"aria-pressed":e,className:i(`flex h-9 w-9 shrink-0 items-center justify-center rounded-full transition active:scale-95`,e?`bg-accent/15 text-accent animate-pulse`:`text-fg/70 hover:bg-surface-2`,n),children:e?(0,R.jsx)(Pt,{size:19}):(0,R.jsx)(Ft,{size:19})})}function Fp({lines:e}){return(0,R.jsx)(`div`,{className:`flex items-end gap-2 pr-10`,children:(0,R.jsx)(`div`,{className:`min-w-0 max-w-full`,children:e.map((e,t)=>(0,R.jsx)(`div`,{className:`my-1 max-w-[340px] rounded-[20px] bg-surface-2 px-3.5 py-2.5 text-[14.5px] leading-snug whitespace-pre-wrap break-words wide:max-w-[600px]`,children:e},t))})})}function Ip({chips:e,chosen:t,busy:n,onPick:r,onElse:a}){let o=s();return e.length===0&&!t?null:(0,R.jsxs)(`section`,{className:`rise mx-1 my-2 rounded-[22px] border border-border/70 bg-surface p-3.5`,children:[(0,R.jsxs)(`div`,{className:`flex items-center gap-2 text-[13px] font-medium text-fg`,children:[(0,R.jsx)(nn,{size:14,className:`text-accent`}),` `,o(`Pick a name for me, or type one`)]}),(0,R.jsxs)(`div`,{className:`mt-2.5 flex flex-wrap gap-2`,children:[e.map(e=>{let a=t===e;return(0,R.jsxs)(`button`,{type:`button`,disabled:n||!!t,onClick:()=>r(e),className:i(`inline-flex items-center gap-1.5 rounded-full px-3.5 py-1.5 text-[13.5px] font-medium transition-colors disabled:opacity-60`,a?`bg-accent text-accent-fg`:`bg-surface-2 hover:bg-border/60`),children:[a&&(0,R.jsx)(ke,{size:13,strokeWidth:3}),e]},e)}),!t&&(0,R.jsx)(`button`,{type:`button`,disabled:n,onClick:a,className:`rounded-full border border-border px-3.5 py-1.5 text-[13.5px] text-muted hover:bg-surface-2 disabled:opacity-60`,children:o(`Something else`)})]})]})}var Lp=[{id:`pink`,background:`#F9D9E3`,accent:`#B5476A`,mood:`idle`},{id:`blue`,background:`#D6E6FA`,accent:`#2F5FA8`,mood:`working`},{id:`yellow`,background:`#FBEFC7`,accent:`#9A6B12`,mood:`waiting`},{id:`purple`,background:`#E4DDF7`,accent:`#5D44A6`,mood:`happy`},{id:`green`,background:`#D9F0DF`,accent:`#2E7D4F`,mood:`error`}],Rp=`github.com/nano-muse/nanoMuse`,zp=540,Bp=720;function Vp(e,t){return!e||w(e.avatar)?j(t):e.avatar?re(e.avatar,t):null}function Hp(e){return new Promise(t=>{let n=new Image;n.crossOrigin=`anonymous`,n.onload=()=>t(n),n.onerror=()=>t(null),n.src=e})}function Up(e,t,n){let r=t.includes(` `)?t.split(` `):Array.from(t),i=t.includes(` `)?` `:``,a=[],o=``;for(let t of r){let r=o?o+i+t:t;e.measureText(r).width>n&&o?(a.push(o),o=t):o=r}return o&&a.push(o),a}function Wp(e,t,n,r,i,a){e.beginPath(),e.moveTo(t+a,n),e.arcTo(t+r,n,t+r,n+i,a),e.arcTo(t+r,n+i,t,n+i,a),e.arcTo(t,n+i,t,n,a),e.arcTo(t,n,t+r,n,a),e.closePath()}async function Gp(e,t,n,r,i,a=2){let o=document.createElement(`canvas`);o.width=zp*a,o.height=Bp*a;let s=o.getContext(`2d`);if(!s)return o;s.scale(a,a),s.fillStyle=e.background,Wp(s,0,0,zp,Bp,36),s.fill(),s.font=`600 22px system-ui, -apple-system, 'Segoe UI', sans-serif`;let c=Up(s,r,400),l=Math.max(...c.map(e=>s.measureText(e).width))+48,u=c.length*30+36,d=(zp-l)/2;s.fillStyle=`#ffffff`,Wp(s,d,56,l,u,24),s.fill(),s.beginPath(),s.moveTo(zp/2-14,56+u-1),s.lineTo(zp/2,56+u+18),s.lineTo(284,56+u-1),s.closePath(),s.fill(),s.fillStyle=e.accent,s.textAlign=`center`,s.textBaseline=`top`,c.forEach((e,t)=>s.fillText(e,zp/2,74+t*30+3));let f=56+u+54;s.fillStyle=`#ffffff`,s.beginPath(),s.arc(zp/2,f+150,158,0,Math.PI*2),s.fill();let p=Vp(t,e.mood),m=p?await Hp(p):null;return s.save(),s.beginPath(),s.arc(zp/2,f+150,150,0,Math.PI*2),s.clip(),m?(s.fillStyle=`#f1efeb`,s.fillRect(120,f,300,300),s.drawImage(m,120,f,300,300)):(s.fillStyle=t?.color??`#0064d4`,s.fillRect(120,f,300,300),s.font=`150px system-ui, 'Apple Color Emoji', 'Segoe UI Emoji', sans-serif`,s.textAlign=`center`,s.textBaseline=`middle`,s.fillStyle=`#ffffff`,s.fillText(t?.emoji??`✨`,zp/2,f+150+6)),s.restore(),s.fillStyle=e.accent,s.textAlign=`center`,s.textBaseline=`top`,s.font=`700 30px system-ui, -apple-system, 'Segoe UI', sans-serif`,s.fillText(n,zp/2,f+300+34),s.font=`500 15px system-ui, -apple-system, 'Segoe UI', sans-serif`,s.globalAlpha=.8,Up(s,i,460).forEach((e,t)=>s.fillText(e,zp/2,644+t*22)),s.globalAlpha=1,o}function Kp(e){return new Promise(t=>e.toBlob(t,`image/png`))}function qp({open:e,onClose:t}){let{state:n,toast:r}=E(),a=s(),o=n.profile,c=o?.name??`nanoMuse`,[l,u]=(0,L.useState)(0),[d,f]=(0,L.useState)([]),[p,m]=(0,L.useState)(!1),h=(0,L.useRef)(!0),g=a(`Hi, I'm {name}, a personal AI agent. Meet nanoMuse: open source, runs on your phone.`,{name:c}),_=a(`Your personal AI agent, open source · {repo}`,{repo:Rp});(0,L.useEffect)(()=>{if(h.current=!0,e)return u(0),(async()=>{let e=[];for(let t of Lp){let n=await Gp(t,o,c,g,_,1);e.push(n.toDataURL(`image/png`))}h.current&&f(e)})(),()=>{h.current=!1}},[e,o?.avatar,o?.emoji,o?.color,c]);let v=async()=>{m(!0);try{let e=await Kp(await Gp(Lp[l]??Lp[0],o,c,g,_,2));if(!e)throw Error(a(`The card could not be drawn.`));let n=new File([e],`${c}-nanomuse.png`,{type:`image/png`}),i=`${g}\nhttps://${Rp}`,s=navigator;if(typeof s.share==`function`&&(!s.canShare||s.canShare({files:[n]})))try{await s.share({files:[n],text:i,title:c}),t();return}catch(e){if(e.name===`AbortError`)return}let u=document.createElement(`a`);u.href=URL.createObjectURL(e),u.download=n.name,u.click(),window.setTimeout(()=>URL.revokeObjectURL(u.href),2e3),r(a(`Saved the card as a picture.`))}catch(e){r(e.message)}finally{m(!1)}};return(0,R.jsxs)(Op,{open:e,onClose:t,title:a(`Share my avatar`),children:[(0,R.jsx)(`p`,{className:`mb-3 text-[13px] text-muted`,children:a(`Pick a card. It goes out through the system share sheet, or saves as a picture where there is none.`)}),(0,R.jsx)(`div`,{className:`grid grid-cols-3 gap-2.5 sm:grid-cols-5`,children:Lp.map((e,t)=>(0,R.jsx)(`button`,{type:`button`,"aria-label":e.id,"aria-pressed":l===t,onClick:()=>u(t),className:i(`overflow-hidden rounded-2xl border-2 transition`,l===t?`border-accent`:`border-transparent`),style:{background:e.background,aspectRatio:`${zp} / ${Bp}`},children:d[t]?(0,R.jsx)(`img`,{src:d[t],alt:``,className:`h-full w-full object-cover`}):(0,R.jsx)(A,{size:18,className:`mx-auto my-8 animate-spin text-muted`})},e.id))}),d[l]&&(0,R.jsx)(`img`,{src:d[l],alt:``,className:`mx-auto mt-4 w-[260px] rounded-[20px] shadow-md`}),(0,R.jsxs)(`div`,{className:`mt-4 flex justify-end gap-2`,children:[(0,R.jsx)(`button`,{type:`button`,onClick:t,className:je,children:a(`Later`)}),(0,R.jsxs)(`button`,{type:`button`,disabled:p||!d.length,onClick:()=>void v(),className:Ne,children:[p?(0,R.jsx)(A,{size:15,className:`animate-spin`}):typeof navigator.share==`function`?(0,R.jsx)(Xt,{size:15}):(0,R.jsx)(ft,{size:15}),` `,typeof navigator.share==`function`?a(`Share`):a(`Save picture`)]})]})]})}function Jp({message:e,onRetry:t}){let n=s();return(0,R.jsxs)(`div`,{className:`flex flex-col items-center gap-3 px-8 py-10 text-center`,children:[(0,R.jsx)(`p`,{className:`text-[14px] text-rose-600 dark:text-rose-300`,children:n(e)||n(`Could not load.`)}),(0,R.jsxs)(`button`,{type:`button`,onClick:t,className:`flex h-10 items-center gap-1.5 rounded-full bg-surface px-4 text-[13.5px] font-medium shadow-[0_1px_4px_rgba(0,0,0,0.14)] dark:border dark:border-border dark:shadow-none`,children:[(0,R.jsx)(Re,{size:14}),` `,n(`Try again`)]})]})}var Yp=[{id:`health`,label:`Health`,icon:e=>(0,R.jsx)(yt,{...e}),tone:`bg-rose-500/12 text-rose-600 dark:text-rose-300`},{id:`finance`,label:`Finance`,icon:e=>(0,R.jsx)(Wt,{...e}),tone:`bg-emerald-500/12 text-emerald-600 dark:text-emerald-300`},{id:`career`,label:`Career`,icon:e=>(0,R.jsx)($e,{...e}),tone:`bg-sky-500/12 text-sky-600 dark:text-sky-300`},{id:`learning`,label:`Learning`,icon:e=>(0,R.jsx)(_t,{...e}),tone:`bg-violet-500/12 text-violet-600 dark:text-violet-300`},{id:`relationships`,label:`Relationships`,icon:e=>(0,R.jsx)(le,{...e}),tone:`bg-pink-500/12 text-pink-600 dark:text-pink-300`},{id:`family`,label:`Family`,icon:e=>(0,R.jsx)(hn,{...e}),tone:`bg-amber-500/12 text-amber-600 dark:text-amber-300`},{id:`home`,label:`Home`,icon:e=>(0,R.jsx)(bt,{...e}),tone:`bg-orange-500/12 text-orange-600 dark:text-orange-300`},{id:`travel`,label:`Travel`,icon:e=>(0,R.jsx)(lt,{...e}),tone:`bg-cyan-500/12 text-cyan-600 dark:text-cyan-300`},{id:`creative`,label:`Creative`,icon:e=>(0,R.jsx)(Vt,{...e}),tone:`bg-fuchsia-500/12 text-fuchsia-600 dark:text-fuchsia-300`},{id:`other`,label:`Other`,icon:e=>(0,R.jsx)(ln,{...e}),tone:`bg-surface-2 text-muted`}];function Xp(e){return Yp.find(t=>t.id===e)??null}var Zp=[{id:``,label:`No reminders`},{id:`daily`,label:`Every day`},{id:`weekdays`,label:`Weekdays`},{id:`weekly`,label:`Once a week`},{id:`monthly`,label:`Once a month`}],Qp=[`mon`,`tue`,`wed`,`thu`,`fri`,`sat`,`sun`];function $p(e){let t=/^(daily|weekdays|weekly|monthly)(?:\s+(\S+?))?(?:\s+(\d{1,2}:\d{2}))?$/.exec(e.trim());if(!t)return{cadence:``,anchor:``,time:`09:00`};let n=t[2]??``,r=t[3]??`09:00`;return n&&/^\d{1,2}:\d{2}$/.test(n)&&(r=n,n=``),{cadence:t[1],anchor:n,time:r.padStart(5,`0`)}}function em(e,t,n){return e?[e,t,n].filter(Boolean).join(` `):``}function tm(e){let t=Qp.indexOf(e);return t<0?e:new Date(2024,0,1+t).toLocaleDateString(m(),{weekday:`long`})}function nm(e){let{cadence:t,anchor:n,time:r}=$p(e);switch(t){case`daily`:return _(`Daily at {time}`,{time:r});case`weekdays`:return _(`Weekdays at {time}`,{time:r});case`weekly`:return n&&Qp.includes(n)?_(`{day}s at {time}`,{day:tm(n),time:r}):_(`Weekly at {time}`,{time:r});case`monthly`:return _(`Monthly on the {day} at {time}`,{day:rm(Number(n||1)),time:r});default:return``}}function rm(e){if(c()!==`en`)return String(e);let t=[`th`,`st`,`nd`,`rd`],n=e%100;return`${e}${t[(n-20)%10]??t[n]??t[0]}`}function im(e,t){if(!e)return``;let n=new Date(`${e}T00:00:00`),r=n.toLocaleDateString(m(),{month:`short`,day:`numeric`,year:n.getFullYear()===new Date().getFullYear()?void 0:`numeric`});if(t)return _(`Was due {date}`,{date:r});let i=Math.ceil((n.getTime()-Date.now())/864e5);return i<=0?_(`Due today`):i===1?_(`Due tomorrow`):i<=14?_(`Due in {n} days`,{n:i}):_(`By {date}`,{date:r})}function am({open:e,onClose:t}){let{state:n,setTab:r,draft:a,toast:o}=E(),[c,l]=(0,L.useState)(0),[u,d]=(0,L.useState)(!1),[f,p]=(0,L.useState)(!1),[m,h]=(0,L.useState)(!1),g=n.profile?.name??`nanoMuse`,_=n.pendingApprovals.length,v=s();(0,L.useEffect)(()=>{e&&(l(+(_>0)),d(!1),p(!1))},[e]);let y=(e,n)=>{t(),n&&history.replaceState(null,``,`${window.location.pathname}${window.location.search}#${n}`),r(e)},b=n.status.state===`working`,x=_>0?_>1?v(`{n} approvals waiting for you`,{n:_}):v(`1 approval waiting for you`):b?n.status.detail||v(`On it`):n.status.state===`waiting`?v(`Waiting for you`):v(`online`),S=async()=>{h(!0);try{(await M.stopThread(n.status.thread||`main`)).ok||o(v(`Nothing to stop`))}catch(e){o(e.message)}finally{h(!1)}},C=[{icon:(0,R.jsx)(it,{size:22}),label:v(`Activity`)},{icon:(0,R.jsx)(Qt,{size:22}),label:v(`Approvals`),badge:_},{icon:(0,R.jsx)(at,{size:22}),label:v(`Daily`)},{icon:(0,R.jsx)(ht,{size:22}),label:v(`Soul & memory`)}];return(0,R.jsxs)(Op,{open:e,onClose:t,children:[(0,R.jsxs)(`div`,{className:`relative flex flex-col items-center px-1 pb-3 text-center`,children:[(0,R.jsx)(`button`,{type:`button`,"aria-label":v(`Share avatar`),title:v(`Share avatar`),onClick:()=>p(!0),className:`absolute right-0 top-0 flex h-9 w-9 items-center justify-center rounded-full bg-surface-2/70 text-fg hover:bg-surface-2`,children:(0,R.jsx)(Xt,{size:16})}),(0,R.jsxs)(`div`,{className:`relative`,children:[(0,R.jsx)(D,{profile:n.profile,status:n.status,size:72}),(0,R.jsx)(`button`,{type:`button`,"aria-label":v(`Edit`),"aria-expanded":u,onClick:()=>d(e=>!e),className:`absolute -bottom-0.5 -right-0.5 flex h-6 w-6 items-center justify-center rounded-full bg-surface text-fg shadow-[0_1px_4px_rgba(0,0,0,0.18)] hover:bg-surface-2 dark:border dark:border-border`,children:(0,R.jsx)(Ht,{size:13})}),u&&(0,R.jsxs)(`div`,{className:`absolute left-1/2 top-full z-20 mt-2 w-56 -translate-x-1/2 overflow-hidden rounded-2xl border border-border/70 bg-surface py-1 text-left text-[14px] shadow-lg`,children:[(0,R.jsx)(`button`,{type:`button`,onClick:()=>{a(v(`Change your avatar to `)),t(),r(`chat`)},className:`block w-full px-4 py-2.5 text-left hover:bg-surface-2`,children:v(`Change avatar`)}),(0,R.jsx)(`button`,{type:`button`,onClick:()=>y(`you`,`who`),className:`block w-full px-4 py-2.5 text-left hover:bg-surface-2`,children:v(`Edit name`)}),(0,R.jsx)(`button`,{type:`button`,onClick:()=>y(`avatar`),className:`block w-full px-4 py-2.5 text-left text-muted hover:bg-surface-2`,children:v(`Avatar studio…`)})]})]}),(0,R.jsx)(`div`,{className:`mt-2.5 text-[21px] font-semibold leading-[26px]`,children:g}),(0,R.jsxs)(`div`,{className:i(`mt-0.5 flex items-center gap-1.5 text-[14px]`,b||_>0?`text-fg`:`text-muted`),children:[b&&(0,R.jsx)(A,{size:13,className:`animate-spin text-accent`}),(0,R.jsx)(`span`,{className:`line-clamp-2`,children:x})]}),(b||n.status.state===`waiting`)&&(0,R.jsxs)(`button`,{type:`button`,onClick:()=>void S(),disabled:m,className:`mt-2.5 inline-flex items-center gap-1.5 rounded-full bg-fg px-4 py-1.5 text-[13.5px] font-semibold text-bg transition active:scale-95 disabled:opacity-60`,children:[(0,R.jsx)(sn,{size:12,fill:`currentColor`}),` `,v(`Stop`)]})]}),(0,R.jsx)(`div`,{role:`tablist`,className:`mb-5 flex rounded-2xl bg-surface-2/60 p-1`,children:C.map((e,t)=>(0,R.jsxs)(`button`,{type:`button`,role:`tab`,"aria-selected":c===t,"aria-label":e.label,title:e.label,onClick:()=>l(t),className:i(`relative flex h-11 flex-1 items-center justify-center rounded-[13px] text-fg transition`,c===t&&`bg-surface shadow-sm`),children:[e.icon,e.badge?(0,R.jsx)(`span`,{className:`absolute right-1.5 top-1 flex h-[17px] min-w-[17px] items-center justify-center rounded-full bg-rose-500 px-1 text-[10px] font-bold text-white`,children:e.badge}):null]},e.label))}),c===0&&(0,R.jsx)(ym,{open:e}),c===1&&(0,R.jsxs)(R.Fragment,{children:[_>0&&(0,R.jsx)(cm,{onDone:()=>void 0}),(0,R.jsx)(bm,{open:e})]}),c===2&&(0,R.jsx)(lm,{onSettings:()=>y(`you`,`proactivity`)}),c===3&&(0,R.jsx)(om,{name:g,onEdit:()=>y(`you`,`who`),onMemory:()=>y(`memory`)}),(0,R.jsx)(qp,{open:f,onClose:()=>p(!1)})]})}function om({name:e,onEdit:t,onMemory:n}){let{state:r}=E(),i=s(),a=r.profile?.tagline?.trim()??``;return(0,R.jsxs)(`div`,{className:`pb-2`,children:[(0,R.jsx)(`div`,{className:`px-1 text-[15px]`,children:e}),(0,R.jsxs)(`button`,{type:`button`,onClick:t,className:`mt-2 flex h-[50px] w-full items-center justify-center gap-2 rounded-2xl bg-surface-2/70 text-[15px] font-medium hover:bg-surface-2`,children:[(0,R.jsx)(Ht,{size:18}),` `,i(`Edit`)]}),(0,R.jsxs)(`div`,{className:`mt-4 grid grid-cols-2 gap-3`,children:[(0,R.jsx)(sm,{title:`SOUL`,caption:i(`Handle with care`),foot:a,colors:`from-[#7d6bc7] to-[#574494]`,onClick:t}),(0,R.jsx)(sm,{title:i(`Memory`),caption:i(`Handle with care`),foot:r.settings?.memory_enabled===!1?i(`Off`):``,colors:`from-[#b0413e] to-[#7a1f1f]`,onClick:n})]})]})}function sm({title:e,caption:t,foot:n,colors:r,onClick:a}){return(0,R.jsxs)(`button`,{type:`button`,onClick:a,className:i(`flex h-[130px] flex-col items-start rounded-[18px] bg-gradient-to-b p-3.5 text-left text-white transition active:scale-[0.98]`,r),children:[(0,R.jsx)(`span`,{className:`text-[17px] font-semibold`,children:e}),(0,R.jsx)(`span`,{className:`mt-0.5 text-[11px] text-white/85`,children:t}),(0,R.jsx)(`span`,{className:`mt-auto text-[12px] text-white/90`,children:n})]})}function cm({onDone:e}){let{state:t,decide:n,openThread:r,toast:i}=E(),a=t.profile?.name??`nanoMuse`,o=s(),c=[...t.pendingApprovals].sort((e,t)=>e.ts.localeCompare(t.ts)),l=e=>{let n=t.threads.find(t=>t.id===e);return n?n.id===`main`?o(n.title):n.title:e};return(0,L.useEffect)(()=>{if(c.length===0){let t=window.setTimeout(e,600);return()=>window.clearTimeout(t)}},[c.length,e]),c.length===0?(0,R.jsxs)(`div`,{className:`py-10 text-center text-muted text-[14px]`,children:[(0,R.jsx)(ke,{size:26,className:`mx-auto mb-2 text-emerald-500`}),o(`Nothing is waiting for you.`)]}):(0,R.jsxs)(`div`,{className:`space-y-4 pb-2`,children:[(0,R.jsx)(`p`,{className:`text-[12.5px] text-muted`,children:o(`Actions {name} wants to take but cannot without you. Each one shows what will run and why; a permission you grant is bound to that exact tool and target.`,{name:a})}),c.map(e=>(0,R.jsxs)(`div`,{children:[(0,R.jsxs)(`button`,{type:`button`,onClick:()=>r(e.thread),className:`mb-1 px-1 text-[12px] font-semibold uppercase tracking-wide text-muted hover:text-accent`,children:[l(e.thread),` · `,u(e.ts)]}),(0,R.jsx)(`div`,{className:`rounded-[22px] border border-border/70`,children:(0,R.jsx)(hp,{event:e,onDecide:(t,r)=>n(e.id,t,r).catch(e=>i(e.message))})})]},e.id))]})}function lm({onSettings:t}){let{state:n,refreshSettings:r,toast:a}=E(),[o,c]=(0,L.useState)(null),[l,d]=(0,L.useState)(null),[f,p]=(0,L.useState)(null),m=n.profile?.name??`nanoMuse`,h=s(),g=()=>M.upcoming().then(e=>{c(e),d(null)}).catch(e=>o===null?d(e.message):a(e.message));(0,L.useEffect)(()=>{g()},[n.goalsVersion,n.remindersVersion,n.profile?.proactive,n.profile?.goal_interval_minutes]);let _=async()=>{try{await M.updateSettings({profile:{proactive:!n.profile?.proactive}}),await r()}catch(e){a(e.message)}},v=async e=>{p(e);try{await M.advanceGoal(e),a(h(`{name} is working on it in the main chat`,{name:m}))}catch(e){a(e.message)}finally{p(null)}};return o?(0,R.jsxs)(`div`,{className:`space-y-4 pb-2`,children:[(0,R.jsxs)(`div`,{className:`rounded-2xl border border-border p-3.5`,children:[(0,R.jsxs)(`div`,{className:`flex items-center justify-between gap-3`,children:[(0,R.jsxs)(`div`,{children:[(0,R.jsx)(`div`,{className:`font-medium`,children:h(`Background work`)}),(0,R.jsx)(`div`,{className:`text-[12.5px] text-muted`,children:o.proactive?`${h(o.proactivity[0].toUpperCase()+o.proactivity.slice(1))} · ${h(`every {n} min {name} picks one active goal and works on its next step.`,{n:o.effective_interval_minutes,name:m})}${o.quiet_until?` ${h(`Quiet hours until {time}.`,{time:u(o.quiet_until)})}`:o.next_pass_at?` ${h(`Next around {time}.`,{time:u(o.next_pass_at)})}`:``}`:h(`Off. {name} only works when you ask.`,{name:m})})]}),(0,R.jsx)(`button`,{type:`button`,role:`switch`,"aria-checked":o.proactive,onClick:()=>void _(),className:i(`relative h-7 w-12 shrink-0 rounded-full transition`,o.proactive?`bg-accent`:`bg-border`),children:(0,R.jsx)(`span`,{className:i(`absolute top-0.5 h-6 w-6 rounded-full bg-white shadow transition`,o.proactive?`left-[26px]`:`left-0.5`)})})]}),(0,R.jsx)(`button`,{type:`button`,onClick:t,className:`mt-2 text-[12.5px] text-accent font-medium`,children:h(`Level, interval and quiet hours in Settings`)})]}),(0,R.jsxs)(`div`,{children:[(0,R.jsx)(`div`,{className:`text-[12px] uppercase tracking-wide text-muted font-semibold mb-1.5`,children:h(`In line`)}),o.queue.length===0?(0,R.jsx)(`div`,{className:`text-[13px] text-muted`,children:h(`No active goal has a next step. Add one in Goals and {name} will pick it up.`,{name:m})}):(0,R.jsx)(`ul`,{className:`space-y-1.5`,children:o.queue.map((e,t)=>(0,R.jsxs)(`li`,{className:`flex items-center gap-2.5 rounded-2xl bg-surface-2/60 px-3 py-2`,children:[(0,R.jsx)(`span`,{className:`w-5 text-center text-[12px] font-semibold text-muted`,children:t+1}),(0,R.jsxs)(`div`,{className:`min-w-0 flex-1`,children:[(0,R.jsx)(`div`,{className:`text-[13.5px] font-medium truncate`,children:e.title}),(0,R.jsxs)(`div`,{className:`text-[11.5px] text-muted truncate`,children:[e.next_step??`—`,` · `,h(`{done}/{total} done`,{done:e.progress.done,total:e.progress.total})]})]}),(0,R.jsx)(`button`,{type:`button`,onClick:()=>void v(e.goal_id),disabled:f!==null||o.busy,"aria-label":h(`Work on {title} now`,{title:e.title}),className:`rounded-full bg-accent/12 p-2 text-accent disabled:opacity-50`,children:f===e.goal_id?(0,R.jsx)(A,{size:15,className:`animate-spin`}):(0,R.jsx)(Gt,{size:15})})]},e.goal_id))})]}),o.check_ins.length>0&&(0,R.jsxs)(`div`,{children:[(0,R.jsx)(`div`,{className:`text-[12px] uppercase tracking-wide text-muted font-semibold mb-1.5`,children:h(`Check-ins`)}),(0,R.jsx)(`ul`,{className:`space-y-1.5`,children:o.check_ins.map(t=>(0,R.jsxs)(`li`,{className:`flex items-center gap-2.5 rounded-2xl bg-surface-2/60 px-3 py-2`,children:[(0,R.jsx)(Xe,{size:15,className:`text-muted shrink-0`}),(0,R.jsxs)(`div`,{className:`min-w-0 flex-1`,children:[(0,R.jsx)(`div`,{className:`text-[13.5px] font-medium truncate`,children:t.title}),(0,R.jsxs)(`div`,{className:`text-[11.5px] text-muted truncate`,children:[e(t.at),` · `,u(t.at),` · `,nm(t.cadence).toLowerCase()]})]})]},t.goal_id))}),(0,R.jsx)(`div`,{className:`mt-1.5 text-[12px] text-muted`,children:h(`Goal nudges you asked for; they arrive whatever the proactivity level, but wait out quiet hours.`)})]}),(0,R.jsx)(um,{items:o.reminders,name:m,onChange:()=>void g()}),(0,R.jsx)(mm,{data:o.triggers,name:m,onChange:()=>void g()})]}):l?(0,R.jsx)(Jp,{message:l,onRetry:()=>void g()}):(0,R.jsx)(`div`,{className:`py-10 flex justify-center text-muted`,children:(0,R.jsx)(A,{className:`animate-spin`,size:20})})}function um({items:t,name:n,onChange:r}){let{toast:i}=E(),a=s(),[o,c]=(0,L.useState)(null),[l,d]=(0,L.useState)(!1),f=t.filter(e=>e.status===`active`),p=t.filter(e=>e.status!==`active`),m=async e=>{c(e.id);try{await M.cancelReminder(e.id),r()}catch(e){i(e.message)}finally{c(null)}},h=async e=>{c(e.id);try{await M.fireReminder(e.id),i(e.kind===`task`?a(`{name} is on it`,{name:n}):a(`{name} will say it now`,{name:n})),r()}catch(e){i(e.message)}finally{c(null)}};return(0,R.jsxs)(`div`,{children:[(0,R.jsxs)(`div`,{className:`flex items-center justify-between mb-1.5`,children:[(0,R.jsx)(`div`,{className:`text-[12px] uppercase tracking-wide text-muted font-semibold`,children:a(`Reminders & routines`)}),!l&&(0,R.jsx)(`button`,{type:`button`,onClick:()=>d(!0),className:`text-[12.5px] text-accent font-medium`,children:a(`+ Add`)})]}),l&&(0,R.jsx)(dm,{onDone:()=>{d(!1),r()},onCancel:()=>d(!1)}),f.length===0&&!l?(0,R.jsx)(`div`,{className:`text-[13px] text-muted`,children:a(`Nothing scheduled. Tell {name} “remind me at six to call mum” or “every weekday morning, summarise my unread email”.`,{name:n})}):(0,R.jsx)(`ul`,{className:`space-y-1.5`,children:f.map(t=>(0,R.jsxs)(`li`,{className:`flex items-center gap-2.5 rounded-2xl bg-surface-2/60 px-3 py-2`,children:[t.kind===`task`?(0,R.jsx)(Kt,{size:15,className:`text-muted shrink-0`}):(0,R.jsx)(We,{size:15,className:`text-muted shrink-0`}),(0,R.jsxs)(`div`,{className:`min-w-0 flex-1`,children:[(0,R.jsx)(`div`,{className:`text-[13.5px] font-medium truncate`,children:t.text}),(0,R.jsxs)(`div`,{className:`text-[11.5px] text-muted truncate`,children:[t.next_at?`${e(t.next_at)} · ${u(t.next_at)}`:`—`,t.repeat&&` · ${nm(t.repeat).toLowerCase()}`,t.kind===`task`&&` · ${a(`does the work`)}`]})]}),(0,R.jsx)(`button`,{type:`button`,onClick:()=>void h(t),disabled:o!==null,"aria-label":t.kind===`task`?a(`Do “{text}” now`,{text:t.text}):a(`Remind me now: {text}`,{text:t.text}),className:`rounded-full bg-accent/12 p-2 text-accent disabled:opacity-50`,children:o===t.id?(0,R.jsx)(A,{size:15,className:`animate-spin`}):(0,R.jsx)(Gt,{size:15})}),(0,R.jsx)(`button`,{type:`button`,onClick:()=>void m(t),disabled:o!==null,"aria-label":a(`Cancel: {text}`,{text:t.text}),className:`rounded-full p-2 text-muted hover:text-fg disabled:opacity-50`,children:(0,R.jsx)(Fe,{size:15})})]},t.id))}),p.length>0&&(0,R.jsxs)(`details`,{className:`mt-2`,children:[(0,R.jsx)(`summary`,{className:`text-[12px] text-muted cursor-pointer select-none`,children:a(`{n} finished recently`,{n:p.length})}),(0,R.jsx)(`ul`,{className:`mt-1.5 space-y-1`,children:p.map(t=>(0,R.jsxs)(`li`,{className:`flex items-center gap-2 px-3 text-[12.5px] text-muted`,children:[(0,R.jsx)(`span`,{className:`min-w-0 flex-1 truncate line-through decoration-border`,children:t.text}),(0,R.jsx)(`span`,{className:`shrink-0`,children:t.status===`done`?t.last_fired_at?e(t.last_fired_at):a(`done`):a(`cancelled`)})]},t.id))})]}),(0,R.jsx)(`div`,{className:`mt-1.5 text-[12px] text-muted`,children:a(`A time you named is kept whatever the level or the quiet hours. Reminders just say it; routines do the work and report.`)})]})}function dm({onDone:e,onCancel:t}){let{toast:n}=E(),r=s(),[a,o]=(0,L.useState)(``),[c,l]=(0,L.useState)(`remind`),[u,d]=(0,L.useState)(`once`),[f,p]=(0,L.useState)(()=>_m()),[h,g]=(0,L.useState)(`daily`),[_,v]=(0,L.useState)(`09:00`),[y,b]=(0,L.useState)(`mon`),[x,S]=(0,L.useState)(`1`),[C,w]=(0,L.useState)(!1),T=h===`weekly`?`weekly ${y} ${_}`:h===`monthly`?`monthly ${x} ${_}`:`${h} ${_}`,D=async()=>{if(a.trim()){w(!0);try{await M.createReminder(u===`once`?{text:a.trim(),kind:c,at:f.replace(`T`,` `)}:{text:a.trim(),kind:c,repeat:T}),e()}catch(e){n(e.message)}finally{w(!1)}}},O=`h-9 rounded-xl bg-surface border border-border px-3 text-[13px] outline-none focus:border-accent`;return(0,R.jsxs)(`div`,{className:`mb-2 rounded-2xl border border-border p-3 space-y-2`,children:[(0,R.jsx)(`input`,{autoFocus:!0,value:a,onChange:e=>o(e.target.value),placeholder:r(c===`task`?`What should be done…`:`What to remind you of…`),className:i(O,`w-full h-10 text-[14px]`)}),(0,R.jsxs)(`div`,{className:`flex gap-1.5 text-[12.5px]`,children:[(0,R.jsx)(gm,{options:[[`remind`,r(`Remind me`)],[`task`,r(`Do it for me`)]],value:c,onChange:e=>l(e)}),(0,R.jsx)(gm,{options:[[`once`,r(`Once`)],[`repeat`,r(`Repeat`)]],value:u,onChange:e=>d(e)})]}),u===`once`?(0,R.jsx)(`input`,{type:`datetime-local`,value:f,onChange:e=>p(e.target.value),className:i(O,`w-full`)}):(0,R.jsxs)(`div`,{className:`flex flex-wrap gap-1.5`,children:[(0,R.jsxs)(`select`,{value:h,onChange:e=>g(e.target.value),className:O,children:[(0,R.jsx)(`option`,{value:`daily`,children:r(`Every day`)}),(0,R.jsx)(`option`,{value:`weekdays`,children:r(`Weekdays`)}),(0,R.jsx)(`option`,{value:`weekly`,children:r(`Weekly`)}),(0,R.jsx)(`option`,{value:`monthly`,children:r(`Monthly`)})]}),h===`weekly`&&(0,R.jsx)(`select`,{value:y,onChange:e=>b(e.target.value),className:O,children:[`mon`,`tue`,`wed`,`thu`,`fri`,`sat`,`sun`].map((e,t)=>(0,R.jsx)(`option`,{value:e,children:new Date(2024,0,1+t).toLocaleDateString(m(),{weekday:`long`})},e))}),h===`monthly`&&(0,R.jsx)(`select`,{value:x,onChange:e=>S(e.target.value),className:O,children:Array.from({length:28},(e,t)=>String(t+1)).map(e=>(0,R.jsx)(`option`,{value:e,children:r(`Day {d}`,{d:e})},e))}),(0,R.jsx)(`input`,{type:`time`,value:_,onChange:e=>v(e.target.value),className:O})]}),(0,R.jsxs)(`div`,{className:`flex justify-end gap-2 pt-0.5`,children:[(0,R.jsx)(`button`,{type:`button`,onClick:t,className:`rounded-full px-3 py-1.5 text-[13px] text-muted`,children:r(`Cancel`)}),(0,R.jsx)(`button`,{type:`button`,onClick:()=>void D(),disabled:C||!a.trim(),className:`rounded-full bg-accent px-3.5 py-1.5 text-[13px] font-medium text-accent-fg disabled:opacity-50`,children:r(C?`Saving…`:u===`once`?`Set reminder`:`Set routine`)})]})]})}var fm={mail:Et,event:et,hook:_n};function pm(e,t){if(e.kind===`mail`)return e.match?t(`mail matching “{match}”`,{match:e.match}):t(`any new mail`);if(e.kind===`event`){let n=e.match?t(`events matching “{match}”`,{match:e.match}):t(`any event`);return t(`{n} min before {what}`,{n:e.lead_minutes,what:n})}return e.match?t(`webhook “{match}”`,{match:e.match}):t(`webhook`)}function mm({data:t,name:n,onChange:r}){let{toast:a}=E(),o=s(),[c,l]=(0,L.useState)(null),[u,d]=(0,L.useState)(!1),f=t.items.filter(e=>e.status===`active`),p=f.some(e=>e.kind===`mail`),m=async e=>{l(e.id);try{await M.cancelTrigger(e.id),r()}catch(e){a(e.message)}finally{l(null)}},h=async e=>{l(e.id);try{await M.fireTrigger(e.id),a(o(`{name} is on it`,{name:n})),r()}catch(e){a(e.message)}finally{l(null)}},g=async e=>{if(e.url)try{await navigator.clipboard.writeText(e.url),a(o(`Webhook URL copied`))}catch{a(e.url)}};return(0,R.jsxs)(`div`,{children:[(0,R.jsxs)(`div`,{className:`flex items-center justify-between mb-1.5`,children:[(0,R.jsx)(`div`,{className:`text-[12px] uppercase tracking-wide text-muted font-semibold`,children:o(`When something happens`)}),!u&&(0,R.jsx)(`button`,{type:`button`,onClick:()=>d(!0),className:`text-[12.5px] text-accent font-medium`,children:o(`+ Add`)})]}),u&&(0,R.jsx)(hm,{available:t.available,onDone:()=>{d(!1),r()},onCancel:()=>d(!1)}),f.length===0&&!u?(0,R.jsx)(`div`,{className:`text-[13px] text-muted`,children:o(`Nothing yet. Tell {name} “when the landlord writes back, summarise it and draft a reply” or “half an hour before any review, brief me”.`,{name:n})}):(0,R.jsx)(`ul`,{className:`space-y-1.5`,children:f.map(t=>{let n=fm[t.kind];return(0,R.jsxs)(`li`,{className:`flex items-start gap-2.5 rounded-2xl bg-surface-2/60 px-3 py-2`,children:[(0,R.jsx)(n,{size:15,className:`text-muted shrink-0 mt-[3px]`}),(0,R.jsxs)(`div`,{className:`min-w-0 flex-1`,children:[(0,R.jsx)(`div`,{className:`text-[13.5px] font-medium`,children:pm(t,o)}),(0,R.jsx)(`div`,{className:`text-[12px] leading-snug text-fg/80 line-clamp-2`,children:t.text}),(0,R.jsxs)(`div`,{className:`text-[11.5px] text-muted flex flex-wrap items-center gap-x-1.5`,children:[t.fired>0?(0,R.jsxs)(`span`,{children:[o(`fired {n}×`,{n:t.fired}),t.last_fired_at&&` · ${e(t.last_fired_at)}`]}):(0,R.jsx)(`span`,{children:o(`not fired yet`)}),t.kind===`hook`&&t.url&&(0,R.jsxs)(`button`,{type:`button`,onClick:()=>void g(t),className:`inline-flex items-center gap-1 text-accent font-medium`,children:[(0,R.jsx)(ut,{size:11}),` `,o(`Copy URL`)]})]})]}),(0,R.jsx)(`button`,{type:`button`,onClick:()=>void h(t),disabled:c!==null,"aria-label":o(`Run now: {text}`,{text:t.text}),className:`rounded-full bg-accent/12 p-2 text-accent disabled:opacity-50`,children:c===t.id?(0,R.jsx)(A,{size:15,className:`animate-spin`}):(0,R.jsx)(Gt,{size:15})}),(0,R.jsx)(`button`,{type:`button`,onClick:()=>void m(t),disabled:c!==null,"aria-label":o(`Cancel: {text}`,{text:t.text}),className:`rounded-full p-2 text-muted hover:text-fg disabled:opacity-50`,children:(0,R.jsx)(Fe,{size:15})})]},t.id)})}),p&&(0,R.jsx)(`div`,{className:i(`mt-1.5 text-[12px]`,t.mail_error?`text-rose-500`:`text-muted`),children:t.mail_error?o(`The inbox could not be read: {error}`,{error:t.mail_error}):t.mail_checked_at?o(`Inbox checked {when}; {name} looks every {n} min.`,{when:e(t.mail_checked_at),name:n,n:t.mail_poll_minutes}):o(`{name} will look at the inbox shortly, then every {n} min.`,{name:n,n:t.mail_poll_minutes})}),(0,R.jsx)(`div`,{className:`mt-1.5 text-[12px] text-muted`,children:o(`Each time it happens {name} does the work in the chat it was set from and reports in the Feed. A mail or a request is treated as data, never as instructions.`,{name:n})})]})}function hm({available:e,onDone:t,onCancel:n}){let{toast:r}=E(),a=s(),o=[`mail`,`event`,`hook`].find(t=>e[t])??`hook`,[c,l]=(0,L.useState)(o),[u,d]=(0,L.useState)(``),[f,p]=(0,L.useState)(`30`),[m,h]=(0,L.useState)(``),[g,_]=(0,L.useState)(!1),[v,y]=(0,L.useState)(null),b=async()=>{if(m.trim()){_(!0);try{let e=await M.createTrigger({kind:c,text:m.trim(),match:u.trim(),lead_minutes:Number(f)||30});e.kind===`hook`&&e.url?y(e):t()}catch(e){r(e.message)}finally{_(!1)}}},x=`h-9 rounded-xl bg-surface border border-border px-3 text-[13px] outline-none focus:border-accent`;if(v)return(0,R.jsxs)(`div`,{className:`mb-2 rounded-2xl border border-border p-3 space-y-2`,children:[(0,R.jsx)(`div`,{className:`text-[13.5px] font-medium`,children:a(`Webhook ready`)}),(0,R.jsx)(`div`,{className:`text-[12.5px] text-muted`,children:a(`POST anything to this URL and the work starts. The key is in the URL; share it only with the program that will call it.`)}),(0,R.jsx)(`code`,{className:`block break-all rounded-xl bg-surface-2 px-3 py-2 text-[12px]`,children:v.url}),(0,R.jsxs)(`div`,{className:`flex justify-end gap-2 pt-0.5`,children:[(0,R.jsx)(`button`,{type:`button`,onClick:()=>void navigator.clipboard.writeText(v.url??``).then(()=>r(a(`Webhook URL copied`)),()=>r(v.url??``)),className:`rounded-full px-3 py-1.5 text-[13px] text-accent font-medium`,children:a(`Copy`)}),(0,R.jsx)(`button`,{type:`button`,onClick:t,className:`rounded-full bg-accent px-3.5 py-1.5 text-[13px] font-medium text-accent-fg`,children:a(`Done`)})]})]});let S=[[`mail`,a(`New mail`)],[`event`,a(`Before an event`)],[`hook`,a(`Webhook`)]];return(0,R.jsxs)(`div`,{className:`mb-2 rounded-2xl border border-border p-3 space-y-2`,children:[(0,R.jsx)(gm,{options:S,value:c,onChange:e=>l(e)}),!e[c]&&(0,R.jsx)(`div`,{className:`text-[12.5px] text-rose-500`,children:a(c===`mail`?`Connect a mailbox under Connections first.`:`Add a calendar under Connections first.`)}),(0,R.jsxs)(`div`,{className:`flex gap-1.5`,children:[(0,R.jsx)(`input`,{value:u,onChange:e=>d(e.target.value),placeholder:a(c===`mail`?`Words in the sender or subject (empty: any mail)`:c===`event`?`Words in the title or place (empty: any event)`:`A name for this hook`),className:i(x,`min-w-0 flex-1`)}),c===`event`&&(0,R.jsxs)(`label`,{className:`flex items-center gap-1 text-[12.5px] text-muted`,children:[(0,R.jsx)(`input`,{type:`number`,min:0,max:1440,value:f,onChange:e=>p(e.target.value),className:i(x,`w-[64px] px-2`),"aria-label":a(`Minutes before`)}),a(`min before`)]})]}),(0,R.jsx)(`input`,{value:m,onChange:e=>h(e.target.value),placeholder:a(`What should be done each time…`),className:i(x,`w-full h-10 text-[14px]`)}),(0,R.jsx)(`div`,{className:`text-[12px] text-muted`,children:a(`When {condition}`,{condition:pm({kind:c,match:u.trim(),lead_minutes:Number(f)||30},a)})}),(0,R.jsxs)(`div`,{className:`flex justify-end gap-2 pt-0.5`,children:[(0,R.jsx)(`button`,{type:`button`,onClick:n,className:`rounded-full px-3 py-1.5 text-[13px] text-muted`,children:a(`Cancel`)}),(0,R.jsx)(`button`,{type:`button`,onClick:()=>void b(),disabled:g||!m.trim()||!e[c],className:`rounded-full bg-accent px-3.5 py-1.5 text-[13px] font-medium text-accent-fg disabled:opacity-50`,children:a(g?`Saving…`:`Set trigger`)})]})]})}function gm({options:e,value:t,onChange:n}){return(0,R.jsx)(`div`,{className:`flex rounded-full bg-surface-2 p-0.5`,children:e.map(([e,r])=>(0,R.jsx)(`button`,{type:`button`,onClick:()=>n(e),className:i(`rounded-full px-2.5 py-1 transition`,t===e?`bg-surface shadow-sm font-medium`:`text-muted`),children:r},e))})}function _m(){let e=new Date(Date.now()+36e5);e.setMinutes(0,0,0);let t=e=>String(e).padStart(2,`0`);return`${e.getFullYear()}-${t(e.getMonth()+1)}-${t(e.getDate())}T${t(e.getHours())}:${t(e.getMinutes())}`}function vm(e){let[t,n]=(0,L.useState)(null),[r,i]=(0,L.useState)(null),a=async()=>{try{n(await M.activity(150)),i(null)}catch(e){i(e.message||`Could not load.`)}};return(0,L.useEffect)(()=>{if(!e)return;a();let t=window.setInterval(()=>void a(),4e3);return()=>window.clearInterval(t)},[e]),[t,a,r]}function ym({open:e}){let[t,n,r]=vm(e),{state:i}=E(),a=s(),o=i.profile?.name??`nanoMuse`,c=(t?.audit??[]).filter(e=>e.event===`tool_call`).reverse(),l=c.filter(e=>e.channel===`gui`).length;return(0,R.jsxs)(`div`,{className:`pb-2`,children:[(0,R.jsx)(`p`,{className:`text-[12.5px] text-muted mb-2`,children:a(`Every tool call goes through the Sentinel and is written to the audit log, including the ones it refused.`)}),l>0&&(0,R.jsx)(`p`,{className:`text-[12.5px] text-muted mb-2`,children:a(`On the phone's screen: {gui} of {total} steps ({pct}%). The screen is the last resort; a skill, a fetch or the browser comes first.`,{gui:String(l),total:String(c.length),pct:String(Math.round(l/c.length*100))})}),!t&&r&&(0,R.jsx)(Jp,{message:r,onRetry:()=>void n()}),!t&&!r&&(0,R.jsx)(`div`,{className:`py-10 flex justify-center text-muted`,children:(0,R.jsx)(A,{className:`animate-spin`,size:20})}),t&&c.length===0&&(0,R.jsx)(`div`,{className:`py-8 text-center text-muted text-[14px]`,children:a(`Nothing yet today. What you ask for and what {name} does about it shows up here.`,{name:o})}),(0,R.jsx)(`ul`,{className:`space-y-1.5`,children:c.map((e,t)=>(0,R.jsx)(Tm,{entry:e},`${e.ts}-${t}`))})]})}function bm({open:e}){let{state:t,toast:n}=E(),r=s(),[i,a]=vm(e),o=async()=>{if(window.confirm(r(`Forget every permission you granted? {name} will ask again next time.`,{name:t.profile?.name??`nanoMuse`})))try{await M.resetApprovals(),await a(),n(r(`Permissions reset`))}catch(e){n(e.message)}},c=async e=>{try{await M.revokeGrant(e.key),await a(),n(r(`Revoked: {subject}`,{subject:pp(e.tool,e.target)}))}catch(e){n(e.message)}},l=t.settings?.sentinel.mode;return(0,R.jsxs)(`div`,{className:`space-y-4 pb-2`,children:[(0,R.jsxs)(`div`,{className:`rounded-2xl border border-border p-3.5`,children:[(0,R.jsxs)(`div`,{className:`flex items-center gap-2 font-medium`,children:[(0,R.jsx)(Qt,{size:18,className:`text-accent`}),` `,r(`Sentinel mode:`),` `,(0,R.jsx)(`span`,{className:`capitalize`,children:l===`ask`?r(`balanced`):l===`strict`?r(`cautious`):l===`auto`?r(`hands-off`):l})]}),(0,R.jsxs)(`p`,{className:`mt-1 text-[12.5px] text-muted`,children:[l===`ask`&&r(`Safe and moderate actions run freely; anything sensitive (email, shell, purchases) waits for you.`),l===`strict`&&r(`Moderate and sensitive actions both wait for your approval.`),l===`auto`&&r(`Everything is approved automatically except explicit deny rules. Use with care.`)]}),i?.tainted&&(0,R.jsxs)(`p`,{className:`mt-2 text-[12.5px] text-amber-600 dark:text-amber-300 flex items-center gap-1.5`,children:[(0,R.jsx)($t,{size:14}),` `,r(`Private data was read this session: network calls to new destinations need approval.`)]})]}),(0,R.jsx)(Cm,{grants:i?.grants??[],onRevoke:c}),(0,R.jsx)(wm,{title:r(`Always ask (from config)`),tools:t.settings?.sentinel.always_ask_tools??[],muted:!0}),(i?.grants.length??0)>0&&(0,R.jsx)(`button`,{type:`button`,onClick:()=>void o(),className:`w-full rounded-2xl border border-border py-2.5 text-[14px] font-medium`,children:r(`Reset all granted permissions`)})]})}function xm(e,t){switch(e.scope){case`conversation`:return t(`for this conversation`);case`session`:return t(`until restart`);case`24h`:return e.expires_at?t(`until {time}`,{time:u(e.expires_at)}):t(`for 24 hours`);case`always`:return t(`always`);default:return e.scope}}var Sm=[`sensitive`,`moderate`,`low`,`safe`];function Cm({grants:e,onRevoke:t}){let n=s(),{state:r}=E(),i=e=>r.settings?.tools.find(t=>t.name===e)?.risk??`moderate`,a=Sm.map(t=>({risk:t,rows:e.filter(e=>i(e.tool)===t)})).filter(e=>e.rows.length>0);return(0,R.jsx)(`div`,{className:`space-y-3`,children:e.length===0?(0,R.jsxs)(`div`,{children:[(0,R.jsx)(`div`,{className:`text-[12px] uppercase tracking-wide text-muted font-semibold mb-1.5`,children:n(`Permissions you granted`)}),(0,R.jsx)(`div`,{className:`text-[13px] text-muted`,children:n(`No standing approvals. When you answer “always allow” to a risky step, it is listed here and can be revoked; approvals you give once are not kept.`)})]}):a.map((e,r)=>(0,R.jsxs)(`div`,{children:[(0,R.jsxs)(`div`,{className:`text-[12px] uppercase tracking-wide text-muted font-semibold mb-1.5`,children:[r===0?`${n(`Permissions you granted`)} · `:``,n(e.risk)]}),(0,R.jsx)(`ul`,{className:`space-y-1.5`,children:e.rows.map(e=>(0,R.jsxs)(`li`,{className:`flex items-center gap-2.5 rounded-2xl bg-surface-2/60 px-3 py-2`,children:[(0,R.jsx)(`span`,{className:`text-accent`,children:sp(e.tool,15)}),(0,R.jsxs)(`div`,{className:`min-w-0 flex-1`,children:[(0,R.jsx)(`div`,{className:`text-[13.5px] font-medium truncate`,children:pp(e.tool,e.target)}),(0,R.jsxs)(`div`,{className:`text-[11.5px] text-muted`,children:[e.tool,` · `,xm(e,n),` · `,n(`granted {time}`,{time:u(e.granted_at)})]})]}),(0,R.jsx)(`button`,{type:`button`,"aria-label":n(`Revoke {what}`,{what:mp(e.scope,e.tool,e.target)}),onClick:()=>t(e),className:`rounded-full p-1.5 text-muted hover:bg-surface active:scale-95`,children:(0,R.jsx)(Fe,{size:15})})]},e.key))})]},e.risk))})}function wm({title:e,tools:t,muted:n}){let r=s();return(0,R.jsxs)(`div`,{children:[(0,R.jsx)(`div`,{className:`text-[12px] uppercase tracking-wide text-muted font-semibold mb-1.5`,children:e}),t.length===0?(0,R.jsx)(`div`,{className:`text-[13px] text-muted`,children:r(`None`)}):(0,R.jsx)(`div`,{className:`flex flex-wrap gap-1.5`,children:t.map(e=>(0,R.jsxs)(`span`,{className:i(`rounded-full px-2.5 py-1 text-[12.5px] flex items-center gap-1`,n?`bg-surface-2 text-muted`:`bg-accent/12 text-accent`),children:[sp(e,12),` `,e]},e))})]})}function Tm({entry:e}){let t=s(),n=e.decision===`deny`,r=e.ok===!1&&!n;return(0,R.jsxs)(`li`,{className:`flex items-start gap-2.5 rounded-2xl bg-surface-2/60 px-3 py-2`,children:[(0,R.jsx)(`div`,{className:i(`mt-0.5`,n?`text-rose-500`:r?`text-amber-500`:`text-muted`),children:n||r?(0,R.jsx)(Ye,{size:15}):(0,R.jsx)(ke,{size:15})}),(0,R.jsxs)(`div`,{className:`min-w-0 flex-1`,children:[(0,R.jsxs)(`div`,{className:`flex items-center gap-2 text-[13.5px]`,children:[(0,R.jsx)(`span`,{className:`text-muted`,children:sp(e.tool??``,13)}),(0,R.jsx)(`span`,{className:`font-medium truncate`,children:e.summary||e.tool})]}),(0,R.jsxs)(`div`,{className:`mt-0.5 flex flex-wrap items-center gap-x-2 gap-y-0.5 text-[11.5px] text-muted`,children:[(0,R.jsx)(`span`,{children:u(e.ts)}),e.risk&&(0,R.jsx)(up,{risk:e.risk}),e.approved===!0&&(0,R.jsxs)(`span`,{className:`text-emerald-600 dark:text-emerald-300`,children:[t(`approved by you`),e.approval_scope&&e.approval_scope!==`once`?` (${e.approval_scope})`:``]}),e.approved==null&&e.approval_scope&&e.approval_scope!==`once`&&(0,R.jsx)(`span`,{className:`text-emerald-600 dark:text-emerald-300`,children:t(`covered by your {scope} permission`,{scope:e.approval_scope})}),n&&(0,R.jsx)(`span`,{className:`text-rose-500`,children:t(`blocked`)}),r&&(0,R.jsx)(`span`,{className:`text-amber-600`,children:t(`failed`)}),typeof e.duration_ms==`number`&&(0,R.jsxs)(`span`,{children:[(e.duration_ms/1e3).toFixed(1),`s`]})]}),n&&e.reasons&&e.reasons.length>0&&(0,R.jsx)(`div`,{className:`mt-0.5 text-[12px] text-muted`,children:e.reasons.map(v).join(` · `)})]})]})}function Em({title:e,actions:t=[],trailing:n,children:r}){let{state:i,setDrawer:a}=E(),o=s(),[c,l]=(0,L.useState)(!1),u=i.profile?.name||`nanoMuse`,d=i.pendingApprovals.length,f=d>0?d>1?o(`{n} approvals waiting for you`,{n:d}):o(`1 approval waiting for you`):i.status.state===`working`?i.status.detail||o(`On it`):i.status.state===`waiting`?o(`Waiting for you`):null;return(0,R.jsxs)(R.Fragment,{children:[(0,R.jsx)(ne,{profile:i.profile,status:i.status,name:u,statusLine:f,statusTone:f?`accent`:`muted`,spinning:i.status.state===`working`&&d===0,badge:d,onAvatar:()=>l(!0),leading:(0,R.jsx)(te,{onClick:()=>a(!0),label:o(`Chats`),className:`wide:invisible`,children:(0,R.jsx)(Ot,{size:22})}),trailing:n??(0,R.jsx)(Dm,{actions:t})}),(e||r)&&(0,R.jsxs)(`div`,{className:`flex shrink-0 items-center gap-3 pr-5`,children:[(0,R.jsx)(k,{className:`flex-1`,children:e}),r]}),(0,R.jsx)(am,{open:c,onClose:()=>l(!1)})]})}function Dm({actions:e=[]}){let{setTab:t}=E(),n=s(),[r,i]=(0,L.useState)(!1),a=(0,L.useRef)(null);(0,L.useEffect)(()=>{if(!r)return;let e=e=>{a.current?.contains(e.target)||i(!1)},t=e=>{e.key===`Escape`&&i(!1)};return window.addEventListener(`pointerdown`,e),window.addEventListener(`keydown`,t),()=>{window.removeEventListener(`pointerdown`,e),window.removeEventListener(`keydown`,t)}},[r]);let o=e=>{i(!1),t(e)},c=[...e.map(e=>({label:e.label,onClick:()=>{i(!1),e.onClick()}})),{label:n(`Memory`),onClick:()=>o(`memory`)},{label:n(`Settings`),onClick:()=>o(`you`)}];return(0,R.jsxs)(`div`,{ref:a,className:`relative`,children:[(0,R.jsx)(te,{onClick:()=>i(e=>!e),label:n(`More`),expanded:r,children:(0,R.jsx)(pt,{size:22})}),r&&(0,R.jsx)(`ul`,{role:`menu`,className:`absolute right-0 top-12 z-30 min-w-[180px] overflow-hidden rounded-2xl border border-border bg-surface py-1 shadow-xl`,children:c.map(e=>(0,R.jsx)(`li`,{children:(0,R.jsx)(`button`,{type:`button`,role:`menuitem`,onClick:e.onClick,className:`w-full px-4 py-2.5 text-left text-[14.5px] hover:bg-surface-2`,children:e.label})},e.label))})]})}var Om=`nanomuse-naming`;function km(e){return e.replace(/[.*+?^${}()|[\]\\]/g,`\\$&`)}function Am(e,t,n=!1){let r="```"+t,i=e;if(i.includes(r)){let e=RegExp("```"+km(t)+"[ \\t]*\\r?\\n[\\s\\S]*?```",`g`);i=i.replace(e,``);let n=i.lastIndexOf(r);n>=0&&(i=i.slice(0,n))}if(n){let e=i.lastIndexOf("```");e>=0&&r.startsWith(i.slice(e))&&(i=i.slice(0,e))}return i===e?e:i.replace(/\s+$/,``)}function jm(e,t=!1){return Am(e,Om,t)}function Mm(e){return e.filter(e=>!e.this&&e.kind!==`web`&&e.name.trim()!==``)}function Nm(e){let t=/^@([^\s,:;,:;]*)$/.exec(e);return t?t[1]:null}function Pm(e,t,n=6){let r=Nm(e);if(r===null)return[];let i=r.toLowerCase();return Mm(t).filter(e=>e.name.toLowerCase().startsWith(i)).sort((e,t)=>Number(t.online)-Number(e.online)||e.name.localeCompare(t.name)).slice(0,n)}function Fm(e,t){let n=e.trimStart();if(!n.startsWith(`@`))return null;let r=n.slice(1),i=r.toLowerCase(),a=Mm(t),o=a.filter(e=>{let t=e.name.trim().toLowerCase();if(!i.startsWith(t))return!1;let n=r.charAt(t.length);return n===``||/[\s,:;,:;]/.test(n)}).sort((e,t)=>t.name.length-e.name.length);if(o[0])return o[0];let s=/^[^\s,:;,:;]+/.exec(r)?.[0]?.toLowerCase()??``;if(!s)return null;let c=a.filter(e=>e.name.trim().toLowerCase().startsWith(s));if(c.length===1)return c[0];let l=c.filter(e=>e.online);return l.length===1?l[0]:null}var Im=`nm.show_steps`;function Lm(){try{return localStorage.getItem(Im)!==`0`}catch{return!0}}var Rm=Lm(),zm=new Set;function Bm(){return Rm}function Vm(e){Rm=e;try{localStorage.setItem(Im,e?`1`:`0`)}catch{}zm.forEach(e=>e())}function Hm(e){return zm.add(e),()=>zm.delete(e)}function Um(){return(0,L.useSyncExternalStore)(Hm,Bm,Bm)}function Wm(){let{state:e,send:t,sendViaCloud:n,decide:r,loadEvents:i,openFile:a,toast:o,setDrawer:c,setTab:l}=E(),u=s(),{profile:d,status:f,activeThread:p,threads:m}=e,h=e.events[p],g=(0,L.useMemo)(()=>h??[],[h]),_=h!==void 0,v=e.streams[p],b=m.find(e=>e.id===p),[x,S]=(0,L.useState)(!1),[C,w]=(0,L.useState)(null),T=d?.name??`nanoMuse`,D=b?.device?e.hub?.devices.find(e=>e.id===b.device)?.online??null:null,O=nh(e.working[p]),k=(0,L.useRef)(null),ee=(0,L.useRef)(null),A=(0,L.useRef)(!0),[j,re]=(0,L.useState)(!1),N=e.firstrun,P=!!N&&N.phase!==`none`&&N.session_id===p,ie=P&&N.running,ae=y()===`zh-CN`?`zh`:`en`,[oe,se]=(0,L.useState)(null);(0,L.useEffect)(()=>{if(!P||oe?.lang===ae)return;let e=!0;return M.firstrun(ae).then(t=>e&&t.intro&&se({lang:ae,lines:t.intro})).catch(()=>void 0),()=>{e=!1}},[P,ae,oe?.lang]);let ce=e=>{M.firstrunPick(e).then(()=>t(p,e)).catch(e=>o(e.message||u(`Could not send`)))},le=()=>window.dispatchEvent(new Event(`nanomuse:quick-chat`)),[ue,de]=(0,L.useState)(null),fe=e.settings?.onboarded===!0,pe=(0,L.useRef)(!1),me=(0,L.useRef)(!1);(0,L.useEffect)(()=>{if(b?.busy){pe.current||(me.current=ie),pe.current=!0;return}pe.current&&(pe.current=!1,fe&&!me.current&&!ie&&ch(g)&&de(Se()))},[b?.busy,g,fe,ie]);let[he,ge]=(0,L.useState)(null);(0,L.useEffect)(()=>{let{days:e,fresh:t}=ye();t&&ge(e)},[]);let _e=(0,L.useCallback)(()=>{let e=k.current;e&&(e.scrollTop=e.scrollHeight,re(!1))},[]),ve=(0,L.useCallback)(()=>{let e=k.current;if(!e)return;let t=e.scrollHeight-e.scrollTop-e.clientHeight;A.current=t<120,re(t>400)},[]),be=(0,L.useRef)(null);(0,L.useLayoutEffect)(()=>{be.current!==p&&(be.current=p,A.current=!0),A.current&&_e()},[g,v?.text,p,_e]),(0,L.useEffect)(()=>{let e=k.current,t=ee.current;if(!e||!t||typeof ResizeObserver>`u`)return;let n=new ResizeObserver(()=>{A.current?_e():ve()});return n.observe(e),n.observe(t),()=>n.disconnect()},[_e,ve]);let xe=()=>{let e=k.current;e&&e.scrollTo({top:e.scrollHeight,behavior:`smooth`})},Ce=e.pendingApprovals.length,Te=e.pendingApprovals.filter(e=>e.thread===p).length,Ee=(0,L.useMemo)(()=>{let e=!f.thread||f.thread===p;if(Te>0&&!(e&&f.state===`working`))return Te>1?u(`{n} approvals waiting for you`,{n:Te}):u(`1 approval waiting for you`);if(!e)return b?.busy?u(`On it`):void 0;if(f.state===`idle`&&!b?.busy)return;if(f.detail)return f.detail;if(f.state===`waiting`)return u(`Waiting for you`);let t=sh(g);return t?u(`On it: {request}`,{request:t}):u(`On it`)},[f,b,p,Te,g,u]),De=g.filter(e=>e.type===`approval`&&e.status===`pending`).length,Oe=Um(),ke=(0,L.useMemo)(()=>Oe?g:g.filter(e=>e.type!==`tool`),[g,Oe]),Ae={signedIn:!!e.hub?.account.signed_in,chatOnCloud:!!e.settings?.llm.cloud,deviceChat:!!b?.device},je=e=>{let t=ep(ke,e,Ae);return t?()=>n(p,t.text,t.files):void 0},Ne=(0,L.useMemo)(()=>Array.from(new Set(g.flatMap(e=>e.type===`artifact`?[e.path]:[]))),[g]);return(0,R.jsxs)(`div`,{className:`flex h-full flex-col`,children:[(0,R.jsx)(ne,{profile:d,status:f,name:T,statusLine:Ee,statusTone:f.state===`idle`&&!b?.busy?`muted`:`accent`,spinning:(f.state===`working`&&f.thread===p||!!b?.busy)&&Te===0,badge:Ce,onAvatar:()=>S(!0),leading:(0,R.jsx)(te,{onClick:()=>c(!0),label:u(`Chats`),dot:m.length>1&&p!==`main`,className:`wide:invisible`,children:(0,R.jsx)(Ot,{size:22})}),trailing:(0,R.jsx)(Dm,{actions:[{label:u(`Coding agents`),onClick:()=>l(`coding`)}]}),under:b&&b.id!==`main`?b.device?(0,R.jsxs)(`span`,{className:`flex max-w-full items-center gap-1 rounded-full bg-accent/12 px-2.5 py-0.5 text-[11.5px] font-medium text-accent`,children:[D===!1?(0,R.jsx)(`span`,{className:`h-1.5 w-1.5 rounded-full bg-border`}):(0,R.jsx)(`span`,{className:`h-1.5 w-1.5 rounded-full bg-emerald-500`}),(0,R.jsx)(`span`,{className:`truncate`,children:u(`on {device}`,{device:b.device_name||b.device})})]}):b.remote_from?(0,R.jsxs)(`span`,{className:`flex max-w-full items-center gap-1 rounded-full bg-surface-2 px-2.5 py-0.5 text-[11.5px] font-medium text-fg/80`,children:[(0,R.jsx)(It,{size:11}),` `,(0,R.jsx)(`span`,{className:`truncate`,children:u(`from {device}`,{device:b.remote_from.name})})]}):(0,R.jsx)(`span`,{className:`truncate rounded-full bg-surface-2 px-2.5 py-0.5 text-[11.5px] font-medium text-fg/80`,children:b.title}):void 0}),(0,R.jsxs)(`div`,{ref:k,onScroll:ve,className:`relative flex-1 overflow-y-auto px-3 py-3`,children:[(0,R.jsxs)(`div`,{ref:ee,className:`space-y-2.5`,children:[e.hasMore[p]&&g.length>0&&(0,R.jsx)(`div`,{className:`flex justify-center`,children:(0,R.jsx)(`button`,{type:`button`,className:`text-[12.5px] text-accent px-3 py-1 rounded-full bg-surface-2`,onClick:()=>void i(p,g[0]?.id),children:u(`Load earlier messages`)})}),P&&_&&!e.hasMore[p]&&oe&&(0,R.jsx)(Fp,{lines:oe.lines}),_&&g.length===0&&!v&&!P&&(0,R.jsx)(ih,{name:T,device:b?.device?b.device_name||b.device:void 0,onSend:e=>t(p,e).catch(e=>o(e.message||u(`Could not send`)))}),ke.map((e,t)=>(0,R.jsx)(Gm,{event:e,prev:ke[t-1],name:T,onDecide:(t,n)=>r(e.id,t,n).catch(e=>o(e.message||u(`Could not send decision`))),onOpenFile:a,onOpenBrowser:w,files:Ne,onCloudRetry:je(t)},e.id)),v&&v.text&&(0,R.jsx)($m,{text:v.text,streaming:!0,files:Ne,onOpenFile:a}),(b?.busy||f.state!==`idle`)&&!v?.text&&f.state!==`waiting`&&(0,R.jsx)(th,{label:b?.queued?u(`{n} queued`,{n:b.queued}):void 0}),P&&N.phase===`ask_agent_name`&&!b?.busy&&(0,R.jsx)(Ip,{chips:N.chips,chosen:N.chosen,onPick:ce,onElse:le}),O&&!b?.busy&&(0,R.jsx)(rh,{who:O}),!b?.busy&&f.state===`idle`&&ue!==null&&(0,R.jsx)(we,{moment:`tasks`,n:ue,className:`mx-1 my-2`}),!b?.busy&&f.state===`idle`&&he!==null&&(0,R.jsx)(we,{moment:`days_used`,n:he,className:`mx-1 my-2`})]}),j&&(0,R.jsxs)(`button`,{type:`button`,onClick:xe,className:`sticky bottom-2 left-1/2 -translate-x-1/2 rounded-full bg-surface border border-border shadow px-3 py-1.5 text-[12.5px] flex items-center gap-1`,children:[(0,R.jsx)(Me,{size:14}),` `,u(`Latest`),De?` · ${u(`{n} approval`,{n:De})}`:``]})]}),(0,R.jsx)(Rf,{}),(0,R.jsx)(ah,{name:T,busy:!!b?.busy&&De===0,waiting:g.some(e=>e.type===`question`&&e.status===`pending`),onSend:(e,n)=>t(p,e,n).catch(e=>{throw o(e.message||u(`Could not send`)),e})}),(0,R.jsx)(am,{open:x,onClose:()=>S(!1)}),C&&(0,R.jsx)(Ap,{thread:p,eventId:C,onClose:()=>w(null)})]})}function Gm({event:e,prev:t,name:n,onDecide:r,onOpenFile:i,onOpenBrowser:a,files:o,onCloudRetry:s}){let c=qm(t,e)?(0,R.jsx)(Jm,{ts:e.ts}):null,l=(()=>{switch(e.type){case`user`:return(0,R.jsx)(Ym,{event:e,onOpenFile:i});case`assistant`:return e.quiet?(0,R.jsx)(eh,{text:e.text,about:e.about,ts:e.ts}):(0,R.jsx)($m,{text:e.text,reasoning:e.reasoning,continued:t?.type===`assistant`,files:o,onOpenFile:i,spoken:e.via===`call`,modelUsed:e.model_used});case`tool`:return(0,R.jsx)(fp,{event:e});case`approval`:return(0,R.jsx)(hp,{event:e,name:n,onDecide:r});case`question`:return(0,R.jsx)(gp,{event:e,name:n});case`notice`:return(0,R.jsx)(vp,{event:e,onCloudRetry:s});case`artifact`:return(0,R.jsx)(Ep,{event:e,onOpen:i});case`browser`:return(0,R.jsx)(yp,{event:e,onOpen:a});case`hands`:return(0,R.jsx)(bp,{event:e,name:n});case`hold`:return(0,R.jsx)(wp,{event:e,name:n});case`avatar`:return(0,R.jsx)(np,{event:e,name:n});default:return null}})();return l?(0,R.jsxs)(R.Fragment,{children:[c,l]}):null}var Km=6e5;function qm(e,t){return t.ts?!e?.ts||new Date(t.ts).getTime()-new Date(e.ts).getTime()>=Km:!1}function Jm({ts:e}){let t=l(e);return t?(0,R.jsx)(`div`,{className:`pt-2 pb-0.5 text-center text-[11.5px] font-medium text-muted`,children:t}):null}function Ym({event:e,onOpenFile:t}){let n=s(),r=e.files??[],a=r.filter(e=>e.kind===`image`),o=r.filter(e=>e.kind!==`image`);return(0,R.jsxs)(`div`,{className:`rise flex flex-col items-end pl-12`,children:[e.via===`call`?(0,R.jsxs)(`span`,{className:`mb-1 flex items-center gap-1 text-[11.5px] font-medium text-muted`,children:[(0,R.jsx)(Ut,{size:11}),` `,n(`said on a call`)]}):e.via?(0,R.jsx)(`span`,{className:`mb-1 text-[11.5px] font-medium text-muted`,children:n(`asked from {device}`,{device:e.via})}):e.to_device_name||e.to_device?(0,R.jsxs)(`span`,{className:`mb-1 flex items-center gap-1 text-[11.5px] font-medium text-accent`,children:[(0,R.jsx)(It,{size:11}),` `,n(`to {device}`,{device:e.to_device_name||e.to_device||``})]}):(e.via_device_name||e.via_device)&&(0,R.jsx)(`span`,{className:`mb-1 text-[11.5px] font-medium text-muted`,children:n(`From {device}`,{device:e.via_device_name||e.via_device||``})}),a.length>0&&(0,R.jsx)(`div`,{className:`mb-1 flex max-w-full flex-wrap justify-end gap-1.5`,children:a.map(e=>(0,R.jsx)(`button`,{type:`button`,onClick:()=>t(e.path),"aria-label":e.name,className:i(`overflow-hidden rounded-2xl border border-border/60 bg-surface-2 shadow-sm active:scale-[0.98] transition`,a.length===1?`max-h-64 max-w-[240px]`:`h-28 w-28`),children:(0,R.jsx)(`img`,{src:h(e.path),alt:e.name,loading:`lazy`,className:i(`object-cover`,a.length===1?`max-h-64 w-auto max-w-full`:`h-full w-full`)})},e.path))}),o.map(e=>(0,R.jsxs)(`button`,{type:`button`,onClick:()=>t(e.path),className:`mb-1 flex max-w-full items-center gap-2.5 rounded-2xl border border-border bg-surface px-3 py-2 text-left shadow-sm hover:bg-surface-2 active:scale-[0.98] transition`,children:[(0,R.jsx)(`span`,{className:`rounded-xl bg-accent/12 p-2 text-accent`,children:e.kind===`data`?(0,R.jsx)(cn,{size:17}):(0,R.jsx)(mt,{size:17})}),(0,R.jsxs)(`span`,{className:`min-w-0`,children:[(0,R.jsx)(`span`,{className:`block truncate text-[14px] font-medium`,children:e.name}),(0,R.jsx)(`span`,{className:`block text-[11.5px] text-muted`,children:Xm(e.size)})]})]},e.path)),e.text&&(0,R.jsx)(`div`,{className:`bubble-user max-w-full rounded-[20px] bg-bubble-user px-4 py-2.5 text-bubble-user-fg`,children:(0,R.jsx)(`div`,{className:`md text-[15px] leading-[1.45] whitespace-pre-wrap break-words`,children:e.text})})]})}function Xm(e){return e<1024?`${e} B`:e<1048576?`${Math.round(e/1024)} KB`:`${(e/1048576).toFixed(1)} MB`}function Zm(e){let t=e.toLowerCase().split(`.`).pop()??``;return[`csv`,`tsv`,`json`,`xlsx`,`xls`].includes(t)?`data`:`other`}var Qm=`image/*,.pdf,.txt,.md,.csv,.tsv,.json,.log,.html,.xml,.yaml,.yml,.toml,.ics,.vcf,.xlsx,.xls,.docx`;function $m({text:e,reasoning:t,streaming:n,continued:r,files:a,onOpenFile:o,spoken:c,modelUsed:l}){let[u,d]=(0,L.useState)(!1),f=s(),p=(0,L.useMemo)(()=>mf(jm(e,!!n)),[e,n]);return p.length===0&&!n&&!t?null:(0,R.jsx)(`div`,{className:i(`rise flex items-end gap-2 pr-10`,r&&`-mt-1`),children:(0,R.jsxs)(`div`,{className:`min-w-0 max-w-full`,children:[t&&(0,R.jsx)(`button`,{type:`button`,className:`mb-1 ml-1 text-[12px] text-muted`,onClick:()=>d(e=>!e),children:f(u?`Hide thinking`:`Show thinking`)}),t&&u&&(0,R.jsx)(`div`,{className:`mb-1.5 rounded-2xl bg-surface-2/70 px-3 py-2 text-[13px] text-muted whitespace-pre-wrap break-words`,children:t}),p.map((e,t)=>e.bare?(0,R.jsx)(`div`,{className:`my-1 max-w-full`,children:(0,R.jsx)(hf,{text:e.text,files:a,onOpenFile:o})},t):(0,R.jsxs)(`div`,{className:i(`my-1 max-w-[340px] rounded-[20px] bg-surface-2 px-3.5 py-2.5 wide:max-w-[600px]`,c&&`border border-accent/15`),children:[c&&t===0&&(0,R.jsxs)(`div`,{className:`mb-0.5 flex items-center gap-1 text-[11px] font-medium text-accent/80`,children:[(0,R.jsx)(Ut,{size:10}),` `,f(`said on a call`)]}),(0,R.jsx)(hf,{text:e.text,files:a,onOpenFile:o}),n&&t===p.length-1&&(0,R.jsx)(`span`,{className:`inline-block w-1.5 h-4 ml-0.5 align-middle bg-accent/70 animate-pulse rounded-sm`})]},t)),p.length===0&&n&&(0,R.jsx)(`div`,{className:`my-1 rounded-[20px] bg-surface-2 px-3.5 py-2.5`,children:(0,R.jsx)(`span`,{className:`inline-block w-1.5 h-4 align-middle bg-accent/70 animate-pulse rounded-sm`})}),l&&!n&&(0,R.jsx)(`div`,{className:`ml-1 text-[11px] text-muted`,children:f(`Answered by nanoMuse Cloud this time ({model})`,{model:l})})]})})}function eh({text:e,about:n,ts:r}){let[i,a]=(0,L.useState)(!1),o=s(),c=n?t(n.replace(/^Working on your goal: /,``)):o(`background check`);return(0,R.jsx)(`div`,{className:`rise flex justify-center px-6`,children:(0,R.jsxs)(`button`,{type:`button`,onClick:()=>a(e=>!e),className:`max-w-full rounded-2xl px-3 py-1.5 text-[12px] text-muted text-center leading-snug`,children:[(0,R.jsxs)(`span`,{className:`inline-flex items-center gap-1.5`,children:[(0,R.jsx)(Rt,{size:12}),` `,o(`Checked on {label}: nothing new`,{label:c}),r?` · ${u(r)}`:``]}),i&&(0,R.jsx)(`span`,{className:`block mt-1 text-left whitespace-pre-wrap text-[12.5px]`,children:e})]})})}function th({label:e}){return(0,R.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,R.jsxs)(`div`,{className:`rounded-[20px] rounded-bl-md bg-surface-2 px-3.5 py-2.5 flex items-center gap-1`,children:[(0,R.jsx)(`span`,{className:`typing-dot h-2 w-2 rounded-full bg-muted`}),(0,R.jsx)(`span`,{className:`typing-dot h-2 w-2 rounded-full bg-muted`}),(0,R.jsx)(`span`,{className:`typing-dot h-2 w-2 rounded-full bg-muted`})]}),e&&(0,R.jsx)(`span`,{className:`text-[12px] text-muted`,children:e})]})}function nh(e){let t=e?e.at*1e3+N:0,[n,r]=(0,L.useState)(0);return(0,L.useEffect)(()=>{if(!t)return;let e=t-Date.now();if(e<=0){r(t);return}let n=window.setTimeout(()=>r(t),e+50);return()=>window.clearTimeout(n)},[t]),!e||n===t?null:e}function rh({who:e}){let t=s();return(0,R.jsxs)(`div`,{className:`flex items-center gap-1.5 px-1 text-[12px] text-muted`,children:[(0,R.jsx)(A,{size:12,className:`animate-spin`}),(0,R.jsx)(`span`,{children:t(`{device} is working…`,{device:e.device_name||e.device})})]})}function ih({name:e,device:t,onSend:n}){let r=s(),i=t?[r(`What is on your screen right now?`),r(`Which folder are you in, and what is in it?`),r(`Check for updates and tell me what needs a restart`)]:[r(`What can you do for me?`),r(`Plan my week: ask me what's on my plate`),r(`Research and compare two options for me`),r(`Set up a long-term goal and track it`)];return(0,R.jsxs)(`div`,{className:`flex flex-col items-center text-center px-6 pt-10 pb-6 gap-3`,children:[(0,R.jsx)(`div`,{className:`text-[20px] font-semibold`,children:t?r(`This chat goes to {device}.`,{device:t}):r(`Hi, I'm {name}.`,{name:e})}),(0,R.jsx)(`p`,{className:`text-muted text-[14.5px] leading-snug max-w-sm`,children:t?r(`Whatever you ask here, the {name} on {device} does where it is: its shell, its files, its screen. Every step shows up here, and anything that needs an approval asks you here.`,{name:e,device:t}):r(`I don't just answer; I get things done: research, plans, files, code, email, long-running goals. Everything I do shows up here, and anything hard to undo waits for your approval.`)}),(0,R.jsx)(`div`,{className:`mt-2 flex flex-wrap justify-center gap-2`,children:i.map(e=>(0,R.jsx)(`button`,{type:`button`,onClick:()=>n(e),className:`rounded-full bg-surface-2 px-3.5 py-1.5 text-[13.5px] hover:bg-border/60`,children:e},e))})]})}function ah({name:e,busy:t,waiting:n,onSend:r}){let{state:a,draft:o,draftFiles:c,toast:l}=E(),[u,d]=(0,L.useState)(``),[f,p]=(0,L.useState)(!1),m=(0,L.useRef)(``),g=Np((0,L.useCallback)((e,t)=>{let n=m.current,r=n&&!/\s$/.test(n)?` `:``;d(n+r+e+t)},[]),(0,L.useCallback)(e=>l(e),[l])),_=()=>{g.listening||(m.current=u),g.toggle()},[v,y]=(0,L.useState)([]),[b,x]=(0,L.useState)([]);(0,L.useEffect)(()=>{if(!a.draftFiles)return;let e=a.draftFiles.map(e=>({key:`shared-${e.path}`,file:new File([],e.name),preview:e.kind===`image`?h(e.path):null,info:e,error:null}));x(t=>[...t.filter(t=>!e.some(e=>e.key===t.key)),...e].slice(0,10)),c(null)},[a.draftFiles]);let S=(0,L.useRef)(null),C=(0,L.useRef)(null),w=s();(0,L.useEffect)(()=>()=>b.forEach(e=>e.preview?.startsWith(`blob:`)&&URL.revokeObjectURL(e.preview)),[b]),(0,L.useEffect)(()=>{let e=()=>S.current?.focus();return window.addEventListener(`nanomuse:quick-chat`,e),()=>window.removeEventListener(`nanomuse:quick-chat`,e)},[]);let T=e=>{let t=Array.from(e).slice(0,Math.max(0,10-b.length));if(t.length===0)return;let n=t.map(e=>({key:`${e.name}-${e.size}-${e.lastModified}-${Math.random().toString(36).slice(2,7)}`,file:e,preview:e.type.startsWith(`image/`)?URL.createObjectURL(e):null,info:null,error:null}));x(e=>[...e,...n]);for(let e of n)M.upload(e.file).then(t=>x(n=>n.map(n=>n.key===e.key?{...n,info:t}:n))).catch(t=>{let n=t.message?P(t.message):w(`Upload failed`);x(t=>t.map(t=>t.key===e.key?{...t,error:n}:t)),l(n)})},D=e=>x(t=>t.filter(t=>t.key!==e)),O=b.some(e=>!e.info&&!e.error),k=b.flatMap(e=>e.info?[e.info.path]:[]);(0,L.useEffect)(()=>{let e=S.current;e&&(e.style.height=`0px`,e.style.height=`${Math.min(e.scrollHeight,160)}px`)},[u]),(0,L.useEffect)(()=>{if(a.draft===null)return;d(a.draft),o(null);let e=S.current;e&&(e.focus(),e.setSelectionRange(e.value.length,e.value.length))},[a.draft]);let ee=a.settings?.skills?.enabled!==!1;(0,L.useEffect)(()=>{ee&&M.skills().then(e=>y(e.skills.filter(e=>e.enabled))).catch(()=>y([]))},[ee,a.skillsVersion]);let te=/^\/([a-z0-9-]*)$/i.exec(u),j=te?v.filter(e=>e.name.startsWith(te[1].toLowerCase())).slice(0,6):[],ne=e=>{d(`/${e.name} `),S.current?.focus()},re=a.hub?.devices??[],N=Pm(u,re),ie=N.length===0?Fm(u,re):null,ae=e=>{d(`@${e.name} `),S.current?.focus()},oe=e=>{e?.preventDefault();let t=u.trim();if(!t&&k.length===0||O||f)return;g.listening&&g.stop();let n=b;p(!0),d(``),x([]),S.current?.focus(),r(t,k).catch(()=>{d(e=>e||t),x(e=>e.length?e:n)}).finally(()=>p(!1))};return(0,R.jsxs)(`form`,{onSubmit:oe,className:`shrink-0 bg-bg px-3 pt-1.5 pb-1`,children:[t&&!n&&(0,R.jsx)(`div`,{className:`px-2 pb-1 text-[12px] text-muted`,children:w(`{name} is working; anything you send now is picked up right away.`,{name:e})}),j.length>0&&(0,R.jsx)(`ul`,{className:`mb-2 max-h-72 overflow-y-auto rounded-3xl border border-border/70 bg-surface shadow-lg divide-y divide-border/70`,role:`listbox`,"aria-label":w(`Skills`),children:j.map(e=>(0,R.jsx)(`li`,{children:(0,R.jsxs)(`button`,{type:`button`,onClick:()=>ne(e),className:`flex w-full items-center gap-3 px-4 py-2.5 text-left hover:bg-surface-2/70 active:bg-surface-2`,children:[(0,R.jsx)(gn,{size:16,className:`shrink-0 text-accent`}),(0,R.jsxs)(`span`,{className:`min-w-0 flex-1`,children:[(0,R.jsxs)(`span`,{className:`block text-[14px] font-medium`,children:[`/`,e.name]}),(0,R.jsx)(`span`,{className:`block truncate text-[12.5px] text-muted`,children:e.description})]})]})},e.name))}),N.length>0&&(0,R.jsx)(`ul`,{className:`mb-2 max-h-72 overflow-y-auto rounded-3xl border border-border/70 bg-surface shadow-lg divide-y divide-border/70`,role:`listbox`,"aria-label":w(`Devices`),children:N.map(e=>(0,R.jsx)(`li`,{children:(0,R.jsxs)(`button`,{type:`button`,onClick:()=>ae(e),className:`flex w-full items-center gap-3 px-4 py-2.5 text-left hover:bg-surface-2/70 active:bg-surface-2`,children:[(0,R.jsx)(`span`,{className:`shrink-0 text-accent`,children:e.kind===`computer`?(0,R.jsx)(Lt,{size:16}):(0,R.jsx)(tn,{size:16})}),(0,R.jsxs)(`span`,{className:`min-w-0 flex-1`,children:[(0,R.jsxs)(`span`,{className:`block text-[14px] font-medium`,children:[`@`,e.name]}),(0,R.jsx)(`span`,{className:`block truncate text-[12.5px] text-muted`,children:e.online?w(`Runs this there and reports back`):w(`Offline`)})]})]})},e.id))}),ie&&(0,R.jsxs)(`div`,{className:`flex items-center gap-1.5 px-2 pb-1 text-[12px] text-muted`,children:[(0,R.jsx)(It,{size:12}),` `,w(`This goes to {device}.`,{device:ie.name})]}),b.length>0&&(0,R.jsx)(`div`,{className:`mb-1 flex gap-2.5 overflow-x-auto px-1 pt-2.5 pb-1 pr-3`,role:`list`,"aria-label":w(`Attachments`),children:b.map(e=>(0,R.jsxs)(`div`,{role:`listitem`,className:i(`relative shrink-0 rounded-2xl border bg-surface-2`,e.error?`border-danger/60`:`border-border/70`),children:[e.preview?(0,R.jsx)(`img`,{src:e.preview,alt:e.file.name,className:`h-16 w-16 rounded-2xl object-cover`}):(0,R.jsxs)(`div`,{className:`flex h-16 w-40 items-center gap-2 px-2.5`,children:[(0,R.jsx)(`span`,{className:`rounded-xl bg-accent/12 p-1.5 text-accent`,children:Zm(e.file.name)===`data`?(0,R.jsx)(cn,{size:16}):(0,R.jsx)(mt,{size:16})}),(0,R.jsxs)(`span`,{className:`min-w-0`,children:[(0,R.jsx)(`span`,{className:`block truncate text-[12.5px] font-medium`,children:e.file.name}),(0,R.jsx)(`span`,{className:`block text-[11px] text-muted`,children:e.error?w(`Upload failed`):Xm(e.info?.size??e.file.size)})]})]}),!e.info&&!e.error&&(0,R.jsx)(`div`,{className:`absolute inset-0 flex items-center justify-center rounded-2xl bg-bg/50`,children:(0,R.jsx)(A,{size:18,className:`animate-spin text-accent`})}),(0,R.jsx)(`button`,{type:`button`,onClick:()=>D(e.key),"aria-label":w(`Remove`),className:`absolute -right-1.5 -top-1.5 flex h-6 w-6 items-center justify-center rounded-full border border-border bg-surface text-muted shadow-sm`,children:(0,R.jsx)(Fe,{size:13})})]},e.key))}),(0,R.jsxs)(`div`,{className:`flex items-end gap-2 rounded-[26px] border border-border bg-surface px-1.5 py-1.5 shadow-[0_2px_12px_-6px_rgba(0,0,0,0.12)] focus-within:border-fg/20`,children:[(0,R.jsx)(`input`,{ref:C,type:`file`,multiple:!0,accept:Qm,className:`hidden`,onChange:e=>{e.target.files&&T(e.target.files),e.target.value=``}}),(0,R.jsx)(`button`,{type:`button`,onClick:()=>C.current?.click(),"aria-label":w(`Attach a file`),className:`flex h-9 w-9 shrink-0 items-center justify-center rounded-full text-fg/70 transition hover:bg-surface-2 active:scale-95`,children:(0,R.jsx)(I,{size:22})}),(0,R.jsx)(`textarea`,{ref:S,value:u,onChange:e=>d(e.target.value),onPaste:e=>{let t=Array.from(e.clipboardData?.files??[]);t.length>0&&(e.preventDefault(),T(t))},onKeyDown:e=>{if(e.key===`Tab`&&j.length>0&&j[0]){e.preventDefault(),ne(j[0]);return}if(e.key===`Tab`&&N.length>0&&N[0]){e.preventDefault(),ae(N[0]);return}e.key===`Enter`&&!e.shiftKey&&!e.nativeEvent.isComposing&&(e.preventDefault(),oe())},rows:1,placeholder:n?w(`Answer {name}…`,{name:e}):b.length>0?w(`Say what to do with it…`):w(`Message`),className:`flex-1 resize-none bg-transparent px-1 py-2 text-[15px] leading-[1.4] outline-none placeholder:text-muted`}),g.supported&&(0,R.jsx)(Pp,{listening:g.listening,onClick:_}),(0,R.jsx)(`button`,{type:`submit`,disabled:!u.trim()&&k.length===0||O,"aria-label":w(`Send`),className:i(`flex h-9 w-9 shrink-0 items-center justify-center rounded-full transition active:scale-95`,u.trim()||k.length>0?`bg-accent text-accent-fg`:`bg-surface-2 text-muted`,`disabled:opacity-60`),children:(0,R.jsx)(Je,{size:19,strokeWidth:2.5})})]})]})}function oh({threads:e,active:t,onPick:n,onCleared:r,compact:a=!1,grouped:o=!1}){let{state:c,toast:l,dispatch:d}=E(),f=s(),[p,m]=(0,L.useState)(``),[h,g]=(0,L.useState)(!1),_=(0,L.useRef)(null),v=(c.hub?.devices??[]).filter(e=>!e.this&&e.kind!==`web`&&e.online),y=e=>c.hub?.devices.find(t=>t.id===e)?.kind??`phone`,b=async e=>{try{let t=await M.askDevice(e.id);d({type:`ws`,msg:{kind:`thread`,thread:t.thread}}),n(t.thread.id)}catch(e){l(e.message)}},x=async()=>{g(!0);try{let e=await M.createThread(p.trim()||f(`Side chat`));d({type:`ws`,msg:{kind:`thread`,thread:e}}),m(``),n(e.id)}catch(e){l(e.message)}finally{g(!1)}},S=async e=>{if(window.confirm(f(`Delete this side chat and its history?`)))try{await M.deleteThread(e),d({type:`ws`,msg:{kind:`thread_deleted`,thread:e}})}catch(e){l(e.message)}},C=async e=>{if(window.confirm(f(`Clear this conversation? Memory and goals are kept.`)))try{await M.clearThread(e),d({type:`ws`,msg:{kind:`thread_cleared`,thread:e}}),r?.()}catch(e){l(e.message)}},w=e=>(0,R.jsxs)(`li`,{className:i(`group flex items-center gap-2 px-3`,a?`py-2 rounded-xl hover:bg-surface-2/60`:`py-2.5`,e.id===t&&`bg-surface-2/60`),children:[(0,R.jsxs)(`button`,{type:`button`,onClick:()=>n(e.id),className:`flex-1 text-left min-w-0`,children:[(0,R.jsxs)(`div`,{className:i(`font-medium truncate flex items-center gap-2`,a?`text-[13.5px]`:`text-[15px]`),children:[e.device?(0,R.jsx)(`span`,{className:`text-accent`,children:y(e.device)===`computer`?(0,R.jsx)(Lt,{size:14}):(0,R.jsx)(tn,{size:14})}):e.remote_from?(0,R.jsx)(It,{size:14,className:`text-muted`}):null,(0,R.jsx)(`span`,{className:`truncate`,children:e.id===`main`?f(e.title):e.title}),e.busy&&(0,R.jsx)(`span`,{className:`h-1.5 w-1.5 shrink-0 rounded-full bg-amber-400 animate-pulse`})]}),(0,R.jsxs)(`div`,{className:i(`text-muted`,a?`text-[11.5px]`:`text-[12px]`),children:[f(`{n} events`,{n:e.events}),e.queued?` · ${f(`{n} queued`,{n:e.queued})}`:``,` · `,u(e.updated_at)]})]}),(0,R.jsx)(`button`,{type:`button`,"aria-label":f(`Clear`),onClick:()=>void C(e.id),className:i(`p-2 text-muted hover:text-fg`,a&&`opacity-0 group-hover:opacity-100 focus:opacity-100`),children:(0,R.jsx)(Fe,{size:16})}),e.id!==`main`&&(0,R.jsx)(`button`,{type:`button`,"aria-label":f(`Delete`),onClick:()=>void S(e.id),className:i(`p-2 text-muted hover:text-rose-500`,a&&`opacity-0 group-hover:opacity-100 focus:opacity-100`),children:(0,R.jsx)(fn,{size:16})})]},e.id),T=i(`divide-y divide-border overflow-hidden`,a?`rounded-xl`:`rounded-2xl border border-border`),D=`px-3 pb-1 pt-3 text-[11.5px] font-semibold uppercase tracking-wide text-muted`;return(0,R.jsxs)(`div`,{children:[o?(0,R.jsxs)(R.Fragment,{children:[(0,R.jsx)(`div`,{className:D,children:f(`Main chat`)}),(0,R.jsx)(`ul`,{className:T,children:e.filter(e=>e.id===`main`).map(w)}),(0,R.jsxs)(`div`,{className:i(D,`flex items-center justify-between pr-1`),children:[(0,R.jsx)(`span`,{children:f(`Side chats`)}),(0,R.jsx)(`button`,{type:`button`,"aria-label":f(`New side chat`),onClick:()=>_.current?.focus(),className:`flex h-6 w-6 items-center justify-center rounded-full text-muted hover:bg-surface-2 hover:text-fg`,children:(0,R.jsx)(I,{size:15})})]}),(0,R.jsx)(`ul`,{className:T,children:e.filter(e=>e.id!==`main`).map(w)}),e.every(e=>e.id===`main`)&&(0,R.jsx)(`p`,{className:`px-3 py-2 text-[12px] text-muted`,children:f(`A side chat keeps one topic apart from the rest.`)})]}):(0,R.jsx)(`ul`,{className:T,children:e.map(w)}),v.length>0&&(0,R.jsxs)(`div`,{className:`mt-4`,children:[(0,R.jsx)(`div`,{className:`mb-1.5 text-[12px] font-medium text-muted`,children:f(`Ask one of your devices`)}),(0,R.jsx)(`div`,{className:`flex flex-wrap gap-2`,children:v.map(e=>(0,R.jsxs)(`button`,{type:`button`,onClick:()=>void b(e),className:`flex items-center gap-1.5 rounded-full border border-border bg-surface px-3 py-1.5 text-[13px] font-medium hover:bg-surface-2`,children:[e.kind===`phone`?(0,R.jsx)(tn,{size:14,className:`text-accent`}):(0,R.jsx)(Lt,{size:14,className:`text-accent`}),e.name]},e.id))})]}),(0,R.jsxs)(`div`,{className:i(`flex gap-2`,a?`mt-3`:`mt-4`),children:[(0,R.jsx)(`input`,{ref:_,value:p,onChange:e=>m(e.target.value),onKeyDown:e=>{e.key===`Enter`&&!h&&x()},placeholder:f(a?`New side chat`:`New side chat, e.g. “Trip to Kyoto”`),className:i(`min-w-0 flex-1 bg-surface-2 outline-none focus:ring-2 focus:ring-accent/40`,a?`rounded-xl px-3 py-2 text-[13px]`:`rounded-2xl px-3.5 py-2.5 text-[14px]`)}),(0,R.jsxs)(`button`,{type:`button`,disabled:h,onClick:()=>void x(),"aria-label":f(`New`),className:i(`flex items-center gap-1.5 bg-accent text-accent-fg font-medium disabled:opacity-50`,a?`rounded-xl px-2.5`:`rounded-2xl px-3.5 py-2.5`),children:[(0,R.jsx)(jt,{size:18}),` `,!a&&f(`New`)]})]})]})}function sh(e){let t=[...e].reverse().find(e=>e.type===`user`),n=(((t?.type===`user`?t.text:``)||``).split(/\r?\n/).map(e=>e.trim()).find(e=>e.length>0)??``).replace(/\s+/g,` `);if(n.length<=36)return n;let r=n.slice(0,36),i=r.lastIndexOf(` `);return(i>16?r.slice(0,i):r).trimEnd()+`…`}function ch(e){let t=!1;for(let n=e.length-1;n>=0;n--){let r=e[n];if(r.type===`assistant`){if(!r.text||r.quiet)return!1;t=!0;continue}if(r.type===`user`)return t&&!r.via;if(r.type===`notice`)return!1}return!1}function lh(e){let t=Sn(),n=t?`Desktop app (${t.platform}, shell ${t.version})`:`Web app (${navigator.userAgent})`;return`https://github.com/nano-muse/nanoMuse/issues/new?${new URLSearchParams({template:`bug_report.yml`,version:e||``,os:n}).toString()}`}function uh(){let{state:e,setTab:t,openThread:n}=E(),r=s(),[a,o]=(0,L.useState)(!1),[c,l]=(0,L.useState)(!1),[u,d]=(0,L.useState)(``),f=(0,L.useRef)(null),p=$f(),{profile:m,status:h}=e,g=m?.name??`nanoMuse`,_=e.pendingApprovals.length,v=e.goals.filter(e=>e.proposal&&e.status!==`cancelled`).length,y=e.pendingApprovals.filter(t=>t.ts>e.feedSeenAt).length,b=(e.hub?.devices??[]).filter(e=>!e.this&&e.kind!==`web`&&e.online).length,x=_>0?_>1?r(`{n} approvals waiting for you`,{n:_}):r(`1 approval waiting for you`):h.state===`idle`?r(`Idle`):h.detail||(h.state===`waiting`?r(`Waiting for you`):r(`Working…`));(0,L.useEffect)(()=>{if(!c)return;let e=e=>{f.current?.contains(e.target)||l(!1)},t=e=>{e.key===`Escape`&&l(!1)};return document.addEventListener(`mousedown`,e),document.addEventListener(`keydown`,t),()=>{document.removeEventListener(`mousedown`,e),document.removeEventListener(`keydown`,t)}},[c]);let S=[{id:`chat`,label:`Chat`,icon:(0,R.jsx)(At,{size:21}),badge:_},{id:`feed`,label:`Feed`,icon:(0,R.jsx)(Bt,{size:21}),badge:y},{id:`ideas`,label:`Ideas`,icon:(0,R.jsx)(Ct,{size:21})},{id:`goals`,label:`Goals`,icon:(0,R.jsx)(rn,{size:21}),badge:v},{id:`library`,label:`Library`,icon:(0,R.jsx)(St,{size:21})},{id:`devices`,label:`Devices`,icon:(0,R.jsx)(It,{size:21}),dot:b>0},...p?[{id:`coding`,label:`Coding`,icon:(0,R.jsx)(on,{size:21})}]:[]],C=u.trim().toLowerCase(),w=C?e.threads.filter(e=>e.id===`main`||(e.id===`main`?r(e.title):e.title).toLowerCase().includes(C)||(e.device_name??``).toLowerCase().includes(C)):e.threads,T=e=>i(`relative flex w-[60px] flex-col items-center gap-[3px] rounded-xl py-1.5 text-[10.5px] font-medium leading-none transition`,e?`bg-surface-2 text-fg`:`text-fg/65 hover:bg-surface-2/60 hover:text-fg`);return(0,R.jsxs)(`div`,{className:`flex h-full shrink-0`,children:[(0,R.jsxs)(`aside`,{className:`relative flex h-full w-[76px] shrink-0 flex-col items-center border-r border-border bg-surface/70`,children:[(0,R.jsx)(`div`,{className:`titlebar-room`}),(0,R.jsxs)(`button`,{type:`button`,onClick:()=>o(!0),className:`relative mt-3 rounded-full transition hover:scale-[1.04]`,"aria-label":r(`Activity`),title:`${g} · ${x}`,children:[(0,R.jsx)(D,{profile:m,status:h,size:44}),_>0&&(0,R.jsx)(`span`,{className:`pointer-events-none absolute -right-1 -top-1 flex h-[18px] min-w-[18px] items-center justify-center rounded-full border-2 border-surface bg-rose-500 px-1 text-[10.5px] font-bold text-white`,children:_})]}),(0,R.jsx)(`span`,{className:`mt-1.5 max-w-[68px] truncate px-1 text-[11px] font-semibold leading-tight`,children:g}),(0,R.jsx)(`nav`,{className:`mt-3 flex w-full flex-1 flex-col items-center gap-0.5 overflow-y-auto overflow-x-hidden px-2`,children:S.map(n=>{let a=e.tab===n.id;return(0,R.jsxs)(`button`,{type:`button`,onClick:()=>t(n.id),"aria-current":a?`page`:void 0,className:T(a),children:[(0,R.jsx)(`span`,{className:i(a?`text-accent`:`text-fg/60`),children:n.icon}),(0,R.jsx)(`span`,{className:`max-w-full truncate`,children:r(n.label)}),n.badge?(0,R.jsx)(`span`,{className:`absolute right-1.5 top-1 flex h-[17px] min-w-[17px] items-center justify-center rounded-full bg-rose-500 px-1 text-[10px] font-bold text-white`,children:n.badge}):n.dot?(0,R.jsxs)(R.Fragment,{children:[(0,R.jsx)(`span`,{"aria-hidden":`true`,className:`absolute right-3 top-2 h-2 w-2 rounded-full border-2 border-surface bg-emerald-500`}),(0,R.jsx)(`span`,{className:`sr-only`,children:r(`{n} online`,{n:b})})]}):null]},n.id)})}),(0,R.jsxs)(`div`,{className:`flex w-full flex-col items-center gap-0.5 px-2 pb-3 pt-2`,children:[(0,R.jsxs)(`button`,{type:`button`,onClick:()=>t(`account`),"aria-current":e.tab===`account`?`page`:void 0,className:T(e.tab===`account`),title:e.hub?.account.signed_in?e.hub.account.hint:r(`Account`),children:[(0,R.jsx)(mn,{size:21,className:e.tab===`account`?`text-accent`:`text-fg/60`}),(0,R.jsx)(`span`,{className:`max-w-full truncate`,children:r(`Account`)})]}),(0,R.jsxs)(`button`,{type:`button`,onClick:()=>t(`you`),"aria-current":e.tab===`you`?`page`:void 0,className:T(e.tab===`you`),children:[(0,R.jsx)(en,{size:21,className:e.tab===`you`?`text-accent`:`text-fg/60`}),(0,R.jsx)(`span`,{className:`max-w-full truncate`,children:r(`Settings`)})]}),(0,R.jsxs)(`div`,{ref:f,className:`relative w-full`,children:[(0,R.jsxs)(`button`,{type:`button`,onClick:()=>l(e=>!e),"aria-expanded":c,"aria-haspopup":`menu`,className:i(T(c),`mx-auto`),children:[(0,R.jsx)(Ot,{size:21,className:`text-fg/60`}),(0,R.jsx)(`span`,{children:r(`More`)})]}),c&&(0,R.jsxs)(`div`,{role:`menu`,className:`absolute bottom-0 left-[68px] z-30 w-[232px] rounded-2xl border border-border bg-surface p-1.5 shadow-[0_12px_40px_-12px_rgba(0,0,0,0.3)]`,children:[(0,R.jsxs)(`a`,{role:`menuitem`,href:lh(e.version),target:`_blank`,rel:`noreferrer`,onClick:()=>l(!1),className:`flex items-center gap-2.5 rounded-xl px-2.5 py-2 text-[13px] font-medium hover:bg-surface-2`,children:[(0,R.jsx)(ue,{size:16,className:`text-fg/60`}),` `,r(`Report a bug`)]}),(0,R.jsxs)(`button`,{type:`button`,role:`menuitem`,onClick:()=>{l(!1),t(`you`),window.location.hash=`developer`},className:`flex w-full items-center gap-2.5 rounded-xl px-2.5 py-2 text-left text-[13px] font-medium hover:bg-surface-2`,children:[(0,R.jsx)(yn,{size:16,className:`text-fg/60`}),(0,R.jsx)(`span`,{className:`flex-1`,children:r(`Developer tools`)}),(0,R.jsx)(`span`,{className:`text-[11.5px] font-normal text-muted`,children:r(p?`On`:`Off`)})]}),e.version&&(0,R.jsxs)(`div`,{className:`px-2.5 pb-1 pt-1.5 text-[11.5px] text-muted`,children:[`nanoMuse `,e.version]})]})]})]}),(0,R.jsx)(am,{open:a,onClose:()=>o(!1)})]}),e.tab===`chat`&&(0,R.jsxs)(`section`,{className:`flex h-full w-[248px] shrink-0 flex-col border-r border-border bg-surface/40`,"aria-label":r(`Chats`),children:[(0,R.jsx)(`div`,{className:`titlebar-room`}),(0,R.jsxs)(`div`,{className:`px-3 pb-2 pt-4`,children:[(0,R.jsx)(`h2`,{className:`px-1 text-[15px] font-semibold tracking-tight`,children:r(`Chats`)}),(0,R.jsxs)(`label`,{className:`mt-2 flex items-center gap-2 rounded-xl bg-surface-2 px-2.5 py-1.5 text-muted focus-within:ring-2 focus-within:ring-accent/40`,children:[(0,R.jsx)(qt,{size:14,className:`shrink-0`}),(0,R.jsx)(`input`,{value:u,onChange:e=>d(e.target.value),placeholder:r(`Search`),"aria-label":r(`Search chats`),className:`min-w-0 flex-1 bg-transparent text-[13px] text-fg outline-none placeholder:text-muted`}),u&&(0,R.jsx)(`button`,{type:`button`,onClick:()=>d(``),"aria-label":r(`Clear`),className:`shrink-0 hover:text-fg`,children:(0,R.jsx)(Fe,{size:14})})]})]}),(0,R.jsx)(`div`,{className:`min-h-0 flex-1 overflow-y-auto px-2 pb-3`,children:(0,R.jsx)(oh,{threads:w,active:e.activeThread,onPick:e=>n(e),compact:!0,grouped:!0})})]})]})}function dh(){let{state:e,send:t,openThread:n,openFile:r,markFeedSeen:i,setTab:a,toast:o}=E(),[c,l]=(0,L.useState)(null),[u,p]=(0,L.useState)(null),[h,g]=(0,L.useState)(null),[_,v]=(0,L.useState)(null),b=e.profile?.name??`nanoMuse`,x=s(),S=y();(0,L.useEffect)(()=>{let e=!0;return M.feed(80).then(t=>e&&l(t)).catch(e=>o(e.message)),M.upcoming().then(t=>e&&g(t)).catch(()=>void 0),M.feedPosts().then(t=>e&&p(t)).catch(()=>void 0),()=>{e=!1}},[e.feedVersion,e.remindersVersion]),(0,L.useEffect)(()=>{let e=!0;return M.calendar().then(t=>e&&v(t)).catch(()=>void 0),()=>{e=!1}},[e.calendarVersion,e.connectionsVersion]),(0,L.useEffect)(()=>{c&&c.length&&c[0].ts>e.feedSeenAt&&i(c[0].ts)},[c,e.feedSeenAt,i]);let C=(0,L.useMemo)(()=>kh(c??[]),[c,S]),[w,T]=(0,L.useState)(!1),[D,O]=(0,L.useState)(null),[k,ee]=(0,L.useState)(()=>d(fh)===`1`),[j,ne]=(0,L.useState)(!1),re=()=>{f(fh,`1`),ee(!0)},N=async()=>{ne(!0);try{let e=await M.refreshFeedPosts();p(e),e.error&&o(x(`Could not write posts: {error}`,{error:e.error}))}catch(e){o(e.message)}finally{ne(!1)}},P=e=>{t(`main`,e.prompt||`${x(`About this post from my feed:`)}\n\n**${e.title}**\n\n${e.body.slice(0,1200)}`).catch(e=>o(e.message||x(`Could not send`))),n(`main`)},ie=(0,L.useMemo)(()=>mh(u?.posts??[]),[u]),ae=u!==null&&u.posts.length===0;return(0,R.jsxs)(`div`,{className:`flex h-full flex-col`,children:[(0,R.jsx)(Em,{title:``,trailing:(0,R.jsx)(te,{onClick:()=>T(!0),label:x(`Feed settings`),children:(0,R.jsx)(en,{size:22})})}),(0,R.jsxs)(`div`,{className:`flex-1 overflow-y-auto px-3.5 pb-7`,children:[ie.length===0&&(0,R.jsxs)(R.Fragment,{children:[(0,R.jsx)(gh,{text:hh(ph(),new Date)}),!k&&(0,R.jsx)(xh,{instructions:u?.instructions??``,onEdit:()=>T(!0),onAck:re}),ae&&(0,R.jsxs)(R.Fragment,{children:[(0,R.jsx)(Sh,{emoji:`🖼️`,title:x(`Nothing in the feed yet`),body:x(`As we get to know each other, new posts will show up here. Every day at {time} I read what I remember about you (your memory files, the last week of diary, your goals) and write a few short posts.`,{time:u?.time??`08:00`})}),(0,R.jsx)(Sh,{emoji:`📝`,title:x(`Steer it with one sentence`),body:x(`Tap the sliders at the top right to tell me what you want more of, switch the daily routine off, or have me write the first day now.`)}),e.settings&&!e.settings.llm_ready&&(0,R.jsx)(_h,{children:(0,R.jsxs)(`button`,{type:`button`,onClick:()=>a(`you`),className:`flex w-full items-center gap-2 p-4 text-left text-[14px] text-muted`,children:[(0,R.jsx)(F,{size:16,className:`shrink-0 text-accent`}),` `,x(`Add a model first; the feed is written by your agent.`)]})}),(0,R.jsx)(_h,{children:(0,R.jsx)(`div`,{className:`p-4`,children:j?(0,R.jsxs)(`div`,{className:`flex items-center justify-center gap-2.5 text-[15px]`,children:[(0,R.jsx)(A,{size:18,className:`animate-spin text-accent`}),` `,x(`Writing…`)]}):(0,R.jsx)(`button`,{type:`button`,onClick:()=>void N(),className:`h-[46px] w-full rounded-full bg-accent text-[15px] font-semibold text-accent-fg`,children:x(`Write it now`)})})})]})]}),ie.map(([e,t],n)=>(0,R.jsxs)(`section`,{children:[(0,R.jsx)(gh,{text:hh(e,new Date(t[0].ts))}),n===0&&!k&&(0,R.jsx)(xh,{instructions:u?.instructions??``,onEdit:()=>T(!0),onAck:re}),n===0&&j&&(0,R.jsx)(_h,{children:(0,R.jsxs)(`div`,{className:`flex items-center gap-2.5 p-4 text-[15px]`,children:[(0,R.jsx)(A,{size:18,className:`animate-spin text-accent`}),` `,x(`Writing…`)]})}),t.map(e=>(0,R.jsx)(bh,{post:e,onDiscuss:()=>P(e),onInfo:()=>O(e)},e.id))]},e)),(0,R.jsxs)(`div`,{className:`space-y-4 px-0.5 pt-3`,children:[h&&(0,R.jsx)(Th,{data:h,name:b,onSettings:()=>a(`you`),onGoals:()=>a(`goals`)}),_?.configured&&(0,R.jsx)(Eh,{data:_,onAsk:()=>n(`main`)}),c&&c.length===0&&(!u||u.posts.length===0)&&(0,R.jsxs)(`div`,{className:`py-10 text-center text-muted text-[14px] px-6`,children:[(0,R.jsx)(Rt,{size:28,className:`mx-auto mb-2 opacity-60`}),x(`Nothing yet. Once {name} works on a goal in the background or needs your approval, it shows up here.`,{name:b})]}),c&&c.length>0&&(0,R.jsx)(`div`,{className:`px-1 pt-1 text-[12px] font-semibold uppercase tracking-wide text-muted`,children:x(`While you were away`)}),C.map(([t,i])=>(0,R.jsxs)(`section`,{children:[(0,R.jsx)(`div`,{className:`px-1 mb-1.5 text-[12px] uppercase tracking-wide text-muted font-semibold`,children:t}),(0,R.jsx)(`ul`,{className:`space-y-2`,children:i.map(t=>(0,R.jsx)(`li`,{children:(0,R.jsx)(Oh,{item:t,unseen:t.ts>e.feedSeenAt,onOpen:()=>{t.kind===`artifact`&&t.path?r(t.path):n(t.thread)}})},t.id))})]},t))]})]}),(0,R.jsx)(wh,{open:w,onClose:()=>T(!1),data:u,writing:j,onChange:p,onWriteNow:()=>void N()}),(0,R.jsx)(Op,{open:D!==null,onClose:()=>O(null),title:D?.title,children:D&&(0,R.jsxs)(`div`,{className:`space-y-3 px-1 pb-2`,children:[(0,R.jsx)(Ch,{label:x(`Post type`),value:yh(D.area)}),(0,R.jsx)(Ch,{label:x(`Written`),value:new Date(D.ts).toLocaleString(m(),{dateStyle:`medium`,timeStyle:`short`})}),(0,R.jsx)(`button`,{type:`button`,onClick:async()=>{let e=D.id;O(null);try{await M.deleteFeedPost(e),p(t=>t&&{...t,posts:t.posts.filter(t=>t.id!==e)})}catch(e){o(e.message)}},className:`w-full rounded-full bg-surface-2 py-2.5 text-[15px] font-medium text-rose-500`,children:x(`Delete this post`)})]})})]})}var fh=`nanomuse.feed.introAck`;function ph(){let e=new Date;return`${e.getFullYear()}-${String(e.getMonth()+1).padStart(2,`0`)}-${String(e.getDate()).padStart(2,`0`)}`}function mh(e){let t=new Map;for(let n of e){let e=new Date(n.ts),r=`${e.getFullYear()}-${String(e.getMonth()+1).padStart(2,`0`)}-${String(e.getDate()).padStart(2,`0`)}`,i=t.get(r);i?i.push(n):t.set(r,[n])}return[...t.entries()]}function hh(e,t){let n=ph(),r=new Date;r.setDate(r.getDate()-1);let i=`${r.getFullYear()}-${String(r.getMonth()+1).padStart(2,`0`)}-${String(r.getDate()).padStart(2,`0`)}`,a=t.toLocaleDateString(m(),{weekday:`long`});if(e===n){let e=new Date().getHours(),t=_(e<12?`morning`:e<18?`afternoon`:`evening`);return _(`{weekday} {part}`,{weekday:a,part:t})}return e===i?_(`Yesterday`):`${a} · ${t.toLocaleDateString(m(),{month:`short`,day:`numeric`})}`}function gh({text:e}){return(0,R.jsx)(`h2`,{className:`px-1.5 pt-3.5 pb-2 text-[22px] font-bold leading-7`,children:e})}function _h({children:e,className:t}){return(0,R.jsx)(`div`,{className:i(`my-1.5 overflow-hidden rounded-[18px] bg-surface dark:border dark:border-border`,t),children:e})}var vh={planning:`🗓️`,research:`🔍`,goals:`🎯`,money:`💰`,health:`🌿`,home:`🏠`,learning:`📚`,people:`👥`,files:`📄`,fun:`🎈`};function yh(e){switch(e){case`planning`:return _(`Planning`);case`research`:return _(`Research`);case`goals`:return _(`Goals`);case`money`:return _(`Money`);case`health`:return _(`Health`);case`home`:return _(`Home`);case`learning`:return _(`Learning`);case`people`:return _(`People`);case`files`:return _(`Files`);case`fun`:return _(`Fun`);default:return _(`Note`)}}function bh({post:e,onDiscuss:t,onInfo:n}){let r=s();return(0,R.jsx)(_h,{children:(0,R.jsxs)(`article`,{className:`pl-3.5 pr-2.5 pt-3.5 pb-1.5`,children:[(0,R.jsxs)(`div`,{className:`flex items-start gap-3`,children:[(0,R.jsx)(`div`,{className:`flex h-11 w-11 shrink-0 items-center justify-center rounded-xl bg-surface-2 text-[22px] leading-none`,children:vh[e.area]??`📝`}),(0,R.jsxs)(`div`,{className:`min-w-0 flex-1`,children:[(0,R.jsx)(`h3`,{className:`text-[16px] font-semibold leading-[22px]`,children:e.title}),(0,R.jsx)(`div`,{className:`md mt-1 text-[15px] leading-[22px] text-fg/85`,children:(0,R.jsx)(hf,{text:e.body})})]})]}),(0,R.jsxs)(`div`,{className:`mt-1.5 flex items-center`,children:[(0,R.jsxs)(`button`,{type:`button`,onClick:t,className:`flex items-center gap-1.5 rounded-full px-2 py-2 text-[14px] hover:bg-surface-2`,children:[(0,R.jsx)(At,{size:22,strokeWidth:1.8}),` `,r(`Discuss`)]}),(0,R.jsx)(`button`,{type:`button`,onClick:n,"aria-label":r(`About this post`),className:`ml-auto rounded-full p-2 hover:bg-surface-2`,children:(0,R.jsx)(F,{size:22,strokeWidth:1.8})})]})]})})}function xh({instructions:e,onEdit:t,onAck:n}){let r=s();return(0,R.jsxs)(_h,{children:[(0,R.jsxs)(`div`,{className:`px-4 py-3.5`,children:[(0,R.jsx)(`div`,{className:`text-[17px] font-semibold`,children:r(`About the feed`)}),(0,R.jsx)(`p`,{className:`mt-1 text-[13px] leading-[18px] text-muted`,children:r(`Short posts your agent writes for you from what it remembers: your memory files, the last week of diary, your goals. The sentence below steers every post from now on; edit it any time.`)})]}),(0,R.jsxs)(`div`,{className:`border-t border-border/70 px-4 py-3.5`,children:[(0,R.jsx)(`p`,{className:`text-[15px] leading-[22px]`,children:e||r(`Build me a feed about what I care about. Keep it short and direct, easy to skim, no clickbait.`)}),(0,R.jsxs)(`div`,{className:`mt-3.5 flex justify-end gap-2.5`,children:[(0,R.jsx)(`button`,{type:`button`,onClick:t,className:`rounded-full bg-surface-2 px-6 py-2.5 text-[15px] font-medium`,children:r(`Edit`)}),(0,R.jsx)(`button`,{type:`button`,onClick:n,className:`rounded-full bg-accent px-6 py-2.5 text-[15px] font-semibold text-accent-fg`,children:r(`Got it`)})]})]})]})}function Sh({emoji:e,title:t,body:n}){return(0,R.jsx)(_h,{children:(0,R.jsxs)(`div`,{className:`flex items-start gap-3 p-3.5`,children:[(0,R.jsx)(`div`,{className:`flex h-11 w-11 shrink-0 items-center justify-center rounded-xl bg-surface-2 text-[22px] leading-none`,children:e}),(0,R.jsxs)(`div`,{className:`min-w-0 flex-1`,children:[(0,R.jsx)(`div`,{className:`text-[16px] font-semibold leading-[22px]`,children:t}),(0,R.jsx)(`p`,{className:`mt-1 text-[15px] leading-[22px] text-fg/85`,children:n})]})]})})}function Ch({label:e,value:t}){return(0,R.jsxs)(`div`,{className:`flex items-start gap-3 text-[14.5px]`,children:[(0,R.jsx)(`span`,{className:`w-14 shrink-0 text-muted`,children:e}),(0,R.jsx)(`span`,{className:`min-w-0 flex-1 break-words`,children:t})]})}function wh({open:e,onClose:t,data:n,writing:r,onChange:i,onWriteNow:a}){let{toast:o,state:c}=E(),l=s(),[u,d]=(0,L.useState)(``),[f,p]=(0,L.useState)(!1);(0,L.useEffect)(()=>{e&&d(n?.instructions??``)},[e,n]);let m=async()=>{p(!0);try{i(await M.setFeedInstructions({instructions:u})),t()}catch(e){o(e.message)}finally{p(!1)}},h=async e=>{try{i(await M.setFeedInstructions(e))}catch(e){o(e.message)}},g=c.settings?.llm_ready!==!1;return(0,R.jsx)(Op,{open:e,onClose:t,title:l(`Feed`),children:(0,R.jsxs)(`div`,{className:`space-y-3 px-1 pb-2`,children:[(0,R.jsx)(`p`,{className:`text-[13px] leading-[18px] text-muted`,children:l(`Your feed is driven by the instruction below. Any edit you make here applies to every post from now on.`)}),(0,R.jsx)(`textarea`,{value:u,onChange:e=>d(e.target.value),rows:4,maxLength:2e3,placeholder:l(`Build me a feed about what I care about. Keep it short and direct, easy to skim, no clickbait.`),className:`w-full resize-none rounded-2xl bg-surface-2 px-3.5 py-2.5 text-[15px] leading-snug outline-none focus:ring-2 focus:ring-accent/40`}),(0,R.jsxs)(`div`,{className:`space-y-2 rounded-2xl bg-surface-2 px-3.5 py-2.5`,children:[(0,R.jsx)(Pe,{label:l(`Write it every day`),hint:n?.daily===!1?void 0:l(`Daily at {time}`,{time:n?.time??`08:00`}),checked:n?.daily!==!1,onChange:e=>void h({daily:e}),disabled:!n}),n?.daily!==!1&&(0,R.jsxs)(`label`,{className:`flex items-center justify-between gap-3 text-[13px] text-muted`,children:[(0,R.jsx)(`span`,{children:l(`Time of day`)}),(0,R.jsx)(`input`,{type:`time`,value:n?.time??`08:00`,onChange:e=>e.target.value&&void h({time:e.target.value}),className:`rounded-lg bg-surface px-2 py-1 text-[13px] text-fg outline-none focus:ring-2 focus:ring-accent/40`})]}),!g&&(0,R.jsx)(`div`,{className:`text-[12.5px] text-muted`,children:l(`Add a model first; the feed is written by your agent.`)})]}),(0,R.jsxs)(`button`,{type:`button`,onClick:a,disabled:r||!n||!g,className:`flex w-full items-center justify-center gap-2 rounded-full bg-surface-2 py-2.5 text-[15px] font-medium disabled:opacity-60`,children:[r?(0,R.jsx)(A,{size:16,className:`animate-spin`}):(0,R.jsx)(nn,{size:16,className:`text-accent`}),l(r?`Writing…`:`Write it now`)]}),(0,R.jsx)(`button`,{type:`button`,onClick:()=>void m(),disabled:f,className:`h-[46px] w-full rounded-full bg-accent text-[15px] font-semibold text-accent-fg disabled:opacity-60`,children:l(`Save`)})]})})}function Th({data:t,name:n,onSettings:r,onGoals:i}){let a=s(),o=t.queue[0],c=t.reminders.filter(e=>e.status===`active`&&!!e.next_at),l=c[0],d=c.length;return(0,R.jsxs)(`div`,{className:`rounded-3xl border border-border/70 bg-surface shadow-sm px-4 py-3.5`,children:[(0,R.jsxs)(`div`,{className:`flex items-center gap-2 text-[12px] uppercase tracking-wide text-muted font-semibold`,children:[(0,R.jsx)(Xe,{size:13}),` `,a(`Next up`)]}),t.proactive?o?(0,R.jsxs)(`div`,{className:`mt-1.5 text-[14px] leading-snug`,children:[t.busy?a(`Working now`):t.quiet_until?a(`Quiet hours after {time}`,{time:u(t.quiet_until)}):t.next_pass_at?a(`Around {time}`,{time:u(t.next_pass_at)}):a(`Soon`),`: `,(0,R.jsx)(`span`,{className:`font-medium`,children:o.title}),o.next_step&&(0,R.jsxs)(`span`,{className:`text-muted`,children:[` · `,o.next_step]}),o.overdue&&(0,R.jsxs)(`span`,{className:`text-rose-500 font-medium`,children:[` · `,a(`overdue`)]}),t.queue.length>1&&(0,R.jsxs)(`span`,{className:`text-muted`,children:[` · `,a(`{n} more in line`,{n:t.queue.length-1})]})]}):(0,R.jsxs)(`div`,{className:`mt-1.5 text-[14px] leading-snug`,children:[a(`No goal has a next step to work on.`),` `,(0,R.jsx)(`button`,{type:`button`,onClick:i,className:`text-accent font-medium`,children:a(`Add one`)})]}):(0,R.jsxs)(`div`,{className:`mt-1.5 text-[14px] leading-snug`,children:[a(`Background work is off. {name} only acts when you ask.`,{name:n}),` `,(0,R.jsx)(`button`,{type:`button`,onClick:r,className:`text-accent font-medium`,children:a(`Turn it on`)})]}),t.check_ins[0]&&(0,R.jsxs)(`div`,{className:`mt-1.5 text-[12.5px] text-muted`,children:[a(`Check-in on`),` `,(0,R.jsx)(`span`,{className:`font-medium text-fg`,children:t.check_ins[0].title}),` `,e(t.check_ins[0].at),t.check_ins.length>1&&` · ${a(`{n} more`,{n:t.check_ins.length-1})}`]}),l&&(0,R.jsxs)(`div`,{className:`mt-1.5 text-[12.5px] text-muted`,children:[l.kind===`task`?a(`Routine`):a(`Reminder`),` `,(0,R.jsx)(`span`,{className:`font-medium text-fg`,children:l.text}),` `,e(l.next_at),d>1&&` · ${a(`{n} more`,{n:d-1})}`]})]})}function Eh({data:e,onAsk:t}){let n=s(),r=t=>t.start.slice(0,10)<=e.today,a=e.events.filter(r),o=e.events.filter(e=>!r(e)),c=new Date,l=e=>!e.all_day&&new Date(e.end)e.error),d=a.every(l)&&o.length>0,f=d?o:a;return(0,R.jsxs)(`div`,{className:`rounded-3xl border border-border/70 bg-surface shadow-sm px-4 py-3.5`,children:[(0,R.jsxs)(`div`,{className:`flex items-center gap-2 text-[12px] uppercase tracking-wide text-muted font-semibold`,children:[(0,R.jsx)(tt,{size:13}),` `,n(d?`Tomorrow`:`Today`),f.length>0&&(0,R.jsx)(`span`,{className:`ml-auto normal-case tracking-normal font-normal`,children:n(`{n} scheduled`,{n:f.length})})]}),f.length===0?(0,R.jsx)(`div`,{className:`mt-1.5 text-[14px] leading-snug text-muted`,children:n(`Nothing on the calendar today.`)}):(0,R.jsx)(`ul`,{className:`mt-1.5 space-y-1`,children:f.map(e=>(0,R.jsxs)(`li`,{className:i(`flex items-baseline gap-2.5 text-[14px] leading-snug`,!d&&l(e)&&`opacity-50`),children:[(0,R.jsx)(`span`,{className:`w-[86px] shrink-0 tabular-nums text-[12.5px] text-muted`,children:e.all_day?n(`all day`):`${e.start.slice(11,16)}–${e.end.slice(11,16)}`}),(0,R.jsxs)(`span`,{className:`min-w-0 flex-1`,children:[(0,R.jsx)(`span`,{className:`font-medium`,children:e.summary}),e.location&&(0,R.jsxs)(`span`,{className:`text-muted text-[12.5px]`,children:[` `,(0,R.jsx)(Dt,{size:11,className:`inline -mt-0.5`}),` `,e.location]})]})]},`${e.uid}-${e.start}`))}),u.length>0&&(0,R.jsx)(`div`,{className:`mt-1.5 text-[12px] text-rose-500`,children:n(`{name} could not be read`,{name:u.map(e=>e.name).join(`, `)})}),(0,R.jsx)(`button`,{type:`button`,onClick:t,className:`mt-2 text-[12.5px] text-accent font-medium`,children:n(`Ask about your week`)})]})}function Dh(e){return e.replace(/```[\s\S]*?```/g,` `).replace(/^#{1,6}\s+/gm,``).replace(/(\*\*|__|`)/g,``).replace(/^\s*[-*+]\s+/gm,`• `).replace(/\[([^\]]+)\]\([^)]*\)/g,`$1`).trim()}function Oh({item:n,unseen:r,onOpen:a}){let o=s(),c=n.kind===`approval`?(0,R.jsx)(Zt,{size:18}):n.kind===`question`?(0,R.jsx)(kt,{size:18}):n.kind===`artifact`?(0,R.jsx)(mt,{size:18}):n.quiet?(0,R.jsx)(Rt,{size:18}):n.title.startsWith(`New mail: `)?(0,R.jsx)(Et,{size:18}):n.title.startsWith(`Coming up: `)?(0,R.jsx)(et,{size:18}):n.title.startsWith(`Webhook: `)?(0,R.jsx)(_n,{size:18}):(0,R.jsx)(nn,{size:18}),l=n.kind===`approval`?`bg-amber-500/12 text-amber-600 dark:text-amber-300`:n.kind===`question`?`bg-accent/12 text-accent`:`bg-surface-2 text-muted`;return n.quiet?(0,R.jsxs)(`button`,{type:`button`,onClick:a,className:`w-full text-left px-2 py-1.5 flex items-center gap-2 text-[12.5px] text-muted`,children:[(0,R.jsx)(Rt,{size:13,className:`shrink-0`}),(0,R.jsxs)(`span`,{className:`truncate`,children:[o(`{label}: nothing new`,{label:t(n.title.replace(/^Working on your goal: /,``))}),n.text?`: ${n.text}`:``]}),(0,R.jsx)(`span`,{className:`ml-auto shrink-0`,children:e(n.ts)})]}):(0,R.jsx)(`button`,{type:`button`,onClick:a,className:i(`w-full text-left rounded-3xl border bg-surface shadow-sm px-4 py-3 active:scale-[0.99] transition`,r?`border-accent/40`:`border-border/70`),children:(0,R.jsxs)(`div`,{className:`flex items-start gap-3`,children:[(0,R.jsx)(`div`,{className:i(`rounded-2xl p-2 mt-0.5`,l),children:c}),(0,R.jsxs)(`div`,{className:`flex-1 min-w-0`,children:[(0,R.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,R.jsx)(`div`,{className:`font-semibold text-[14.5px] leading-snug truncate`,children:t(n.title)}),r&&(0,R.jsx)(`span`,{className:`h-2 w-2 rounded-full bg-accent shrink-0`})]}),n.text&&(0,R.jsx)(`div`,{className:`mt-0.5 text-[13.5px] text-muted leading-snug line-clamp-3 whitespace-pre-wrap`,children:Dh(n.text)}),(0,R.jsxs)(`div`,{className:`mt-1.5 flex items-center gap-2 text-[12px] text-muted`,children:[(0,R.jsx)(`span`,{children:e(n.ts)}),(0,R.jsx)(`span`,{children:`·`}),(0,R.jsx)(`span`,{className:`truncate`,children:n.thread===`main`?o(n.thread_title):n.thread_title}),(0,R.jsxs)(`span`,{className:`ml-auto flex items-center gap-1 text-accent font-medium`,children:[n.kind===`artifact`?o(`Open`):n.kind===`approval`||n.kind===`question`?o(`Answer`):o(`Open chat`),(0,R.jsx)(qe,{size:13})]})]})]})]})})}function kh(e){let t=new Date,n=new Date(t);n.setDate(t.getDate()-1);let r=e=>{let r=new Date(e);return r.toDateString()===t.toDateString()?_(`Today`):r.toDateString()===n.toDateString()?_(`Yesterday`):r.toLocaleDateString(m(),{weekday:`long`,month:`short`,day:`numeric`})},i=new Map;for(let t of e){let e=r(t.ts);i.set(e,[...i.get(e)??[],t])}return[...i.entries()]}function Ah({children:e,className:t}){return(0,R.jsx)(`div`,{className:i(`mx-4 overflow-hidden rounded-2xl bg-surface dark:border dark:border-border`,t),children:e})}function jh({inset:e=52}){return(0,R.jsx)(`div`,{className:i(`border-t border-border/60`,e===52?`ml-[52px]`:`ml-4`)})}function Mh({icon:e,label:t,value:n,onClick:r,external:a=!1,trailing:o,chevron:s=!0}){let c=(0,R.jsxs)(R.Fragment,{children:[e&&(0,R.jsx)(`span`,{className:`shrink-0 text-fg`,children:e}),(0,R.jsx)(`span`,{className:i(`min-w-0 truncate text-[16px] leading-[21px]`,n?`max-w-[60%] shrink-0`:`flex-1`),children:t}),n&&(0,R.jsx)(`span`,{className:`min-w-0 flex-1 truncate pl-3 text-right text-[14px] leading-[18px] text-muted`,children:n}),o??(s?a?(0,R.jsx)(Ae,{size:16,className:`shrink-0 text-muted/70`}):(0,R.jsx)(rt,{size:18,className:`shrink-0 text-muted/70`}):null)]}),l=`flex min-h-[54px] w-full items-center gap-3.5 px-4 py-2 text-left`;return r?(0,R.jsx)(`button`,{type:`button`,onClick:r,className:i(l,`hover:bg-surface-2/60`),children:c}):(0,R.jsx)(`div`,{className:l,children:c})}function Nh({icon:e,label:t,value:n,checked:r,disabled:a=!1,onChange:o}){return(0,R.jsxs)(`button`,{type:`button`,role:`switch`,"aria-checked":r,disabled:a,onClick:()=>o(!r),className:i(`flex min-h-[54px] w-full items-center gap-3.5 px-4 py-2 text-left`,a?`opacity-60`:`hover:bg-surface-2/60`),children:[e&&(0,R.jsx)(`span`,{className:`shrink-0 text-fg`,children:e}),(0,R.jsx)(`span`,{className:i(`min-w-0 truncate text-[16px] leading-[21px]`,n?`max-w-[60%] shrink-0`:`flex-1`),children:t}),n&&(0,R.jsx)(`span`,{className:`min-w-0 flex-1 truncate pl-3 text-right text-[14px] leading-[18px] text-muted`,children:n}),(0,R.jsx)(Ph,{checked:r})]})}function Ph({checked:e}){return(0,R.jsx)(`span`,{"aria-hidden":!0,className:i(`relative h-7 w-12 shrink-0 rounded-full transition`,e?`bg-accent`:`bg-surface-2 border border-border`),children:(0,R.jsx)(`span`,{className:i(`absolute top-0.5 h-6 w-6 rounded-full bg-white shadow transition`,e?`left-[22px]`:`left-0.5`)})})}function Fh({children:e,className:t}){return(0,R.jsx)(`p`,{className:i(`px-8 py-2 text-[13px] leading-[18px] text-muted`,t),children:e})}function Ih({children:e}){return(0,R.jsx)(`p`,{className:`px-8 pb-2 pt-[18px] text-[13px] leading-[18px] text-muted`,children:e})}var Lh=`https://nanomuse.cn/privacy/`;function Rh({me:e,onChanged:t,flush:n=!1}){let r=s(),{state:a,toast:o}=E(),c=!!a.hub?.account.signed_in,[l,u]=(0,L.useState)(null),[d,f]=(0,L.useState)(!1),p=e??l,m=async()=>{if(c&&!e)try{u(await M.cloudMe())}catch{}};(0,L.useEffect)(()=>{m()},[c,e]);let h=p?.contribute??{on:!1,samples:0},g=h.samples??0,_=h.privacy_url||`https://nanomuse.cn/privacy/`,v=async n=>{f(!0);try{await M.cloudContribute(n),o(r(n?`On. Turn it off here at any time.`:`Off. Nothing more is kept.`)),e?t?.():await m()}catch(e){o(e.message)}finally{f(!1)}},y=async()=>{if(window.confirm(r(`The kept conversations are removed from the server. This cannot be undone.`))){f(!0);try{let n=await M.cloudDeleteSamples();o(r(`{n} turns deleted`,{n:String(n.deleted)})),e?t?.():await m()}catch(e){o(e.message)}finally{f(!1)}}};return(0,R.jsxs)(`div`,{className:i(n&&`-mx-4`),children:[(0,R.jsx)(zh,{signedIn:c}),(0,R.jsx)(Ah,{children:(0,R.jsx)(Nh,{label:r(`Help improve nanoMuse's AI models`),checked:c&&h.on,disabled:d||!c||!p,onChange:e=>void v(e)})}),(0,R.jsxs)(Fh,{children:[r(`While this is on, the text of your chats with the nanoMuse Cloud models (what you wrote, what it answered and the tools it chose to call) is kept on the relay to train the community's own open model. Not your memory or SOUL (the system prompt), not what tools returned, not pictures, and never next to who you are. Your own API key never passes through the relay.`),` `,c?h.default_on!==void 0&&(h.default_on?r(`New accounts start with it on.`):r(`New accounts start with it off.`)):r(`Sign in to nanoMuse Cloud to use it.`),` `,c&&g>0&&r(`{n} turns kept so far.`,{n:String(g)}),` `,(0,R.jsx)(`a`,{href:_,target:`_blank`,rel:`noopener noreferrer`,className:`text-accent underline-offset-2 hover:underline`,children:r(`Privacy policy`)})]}),c&&g>0&&(0,R.jsxs)(Ah,{className:`mt-3`,children:[(0,R.jsx)(Mh,{icon:d?(0,R.jsx)(A,{size:22,className:`animate-spin`}):(0,R.jsx)(fn,{size:22}),label:r(`Delete the kept conversations`),value:r(`{n} turns`,{n:String(g)}),onClick:()=>void y(),chevron:!1}),(0,R.jsx)(jh,{inset:16}),(0,R.jsx)(Fh,{className:`px-4 pb-2.5 pt-2`,children:r(`Removes every turn kept from this account, whether the switch is on or off now. Turning the switch off keeps what was kept until you delete it here.`)})]})]})}function zh({signedIn:e}){let t=s(),{toast:n}=E(),[r,i]=(0,L.useState)(null),[a,o]=(0,L.useState)(!1),c=r?.relay?.counts??{conversations:0,messages:0},l=e&&(c.conversations>0||c.messages>0),u=async()=>{try{i(await M.syncState())}catch{}};(0,L.useEffect)(()=>{u()},[e]);let d=async(e,t)=>{o(!0);try{i(await e()),n(t)}catch(e){n(e.message),await u()}finally{o(!1)}},f=e=>{(e||!l||window.confirm(t(`Off deletes the synced conversations from nanoMuse Cloud. The chats on each device stay.`)))&&d(()=>M.syncSetState(e),t(e?`On. Your devices show the same conversations from now on.`:`Off. Nothing is kept on nanoMuse Cloud any more.`))},p=()=>{window.confirm(t(`The synced conversations are removed from nanoMuse Cloud. The chats on each device stay. This cannot be undone.`))&&d(()=>M.syncDelete(),t(`Synced conversations deleted.`))},m=e=>{d(()=>M.syncSetSideChats(e),t(e?`On. This device's side chats go to the account; the other devices' are on their way.`:`Off. Side chats stay on this device from now on.`))},h=e&&!!r?.enabled;return(0,R.jsxs)(`div`,{className:`mb-6`,children:[(0,R.jsx)(Ah,{children:(0,R.jsx)(Nh,{label:t(`Sync conversations between my devices`),checked:h,disabled:a||!e||!r,onChange:f})}),(0,R.jsxs)(Fh,{children:[t(`The text of your chats is kept on nanoMuse Cloud so every device shows the same conversations. Files and images stay on the device they were made on.`),` `,e?r?.paused?t(`Paused: sign in again to continue.`):l&&t(`{c} chats, {m} messages kept so far.`,{c:String(c.conversations),m:String(c.messages)}):t(`Sign in to nanoMuse Cloud to use it.`)]}),r&&`side_chats`in r&&(0,R.jsxs)(R.Fragment,{children:[(0,R.jsx)(Ah,{className:`mt-3`,children:(0,R.jsx)(Nh,{label:t(`Also sync side chats`),checked:h&&!!r.side_chats,disabled:a||!h,onChange:m})}),(0,R.jsx)(Fh,{children:t(`Off: side chats stay on this device. On: this device's side chats go to the account and the other devices' side chats come here.`)})]}),l&&(0,R.jsxs)(Ah,{className:`mt-3`,children:[(0,R.jsx)(Mh,{icon:a?(0,R.jsx)(A,{size:22,className:`animate-spin`}):(0,R.jsx)(fn,{size:22}),label:t(`Delete synced conversations`),value:t(`{n} chats`,{n:String(c.conversations)}),onClick:p,chevron:!1}),(0,R.jsx)(jh,{inset:16}),(0,R.jsx)(Fh,{className:`px-4 pb-2.5 pt-2`,children:t(`Removes what nanoMuse Cloud stores for this account; the chats on each device stay, and the switch stays on. Deleting a chat on one device deletes it on all of them.`)})]})]})}var Bh=`nm.invite`;function Vh(){try{let e=new URLSearchParams(window.location.search).get(`invite`);if(e){let t=Hh(e);t&&localStorage.setItem(Bh,t)}return localStorage.getItem(Bh)??``}catch{return``}}function Hh(e){return e.toUpperCase().replace(/[^A-Z0-9]/g,``).slice(0,8)}function Uh(e){return/^\s*[+\d]/.test(e)?`tel`:`email`}function Wh({onSignedIn:e,useAsModel:t=!1,cta:n,autoFocus:r=!0}){let a=s(),o=(0,L.useId)(),c=Ce(),[l,u]=(0,L.useState)(`code`),[d,f]=(0,L.useState)(``),[p,m]=(0,L.useState)(``),[h,g]=(0,L.useState)(``),[_,v]=(0,L.useState)(!1),[y,b]=(0,L.useState)(null),[x,S]=(0,L.useState)(null),[C,w]=(0,L.useState)(``),[T,E]=(0,L.useState)(!1);(0,L.useEffect)(()=>{let e=Vh();e&&(w(e),E(!0))},[]);let D=async()=>{if(t){b(`model`);try{await M.cloudUseAsModel()}catch{}}await e()},O=async()=>{let e=d.trim();if(e){b(`code`),S(null);try{await M.cloudCode(e),v(!0)}catch(e){S(a(e.message))}finally{b(null)}}},k=async()=>{let e=d.trim();if(!(!e||p.trim().length<4)){b(`verify`),S(null);try{(await M.cloudVerify(e,p.trim(),C.trim())).created&&Vf(),m(``),v(!1);try{localStorage.removeItem(Bh)}catch{}await D()}catch(e){S(a(e.message))}finally{b(null)}}},ee=async()=>{let e=d.trim();if(e&&h){b(`login`),S(null);try{await M.cloudLogin(e,h),g(``),await D()}catch(e){S(a(e.message))}finally{b(null)}}},te=()=>void(l===`password`?ee():_?k():O()),j=n??a(t?`Sign in and use its model`:`Sign in`);return(0,R.jsxs)(`form`,{className:`space-y-3`,onSubmit:e=>{e.preventDefault(),te()},children:[(0,R.jsxs)(`div`,{className:`grid grid-cols-2 gap-1 rounded-2xl bg-surface-2/70 p-1 text-[13px] font-medium`,children:[(0,R.jsx)(Gh,{active:l===`code`,onClick:()=>u(`code`),icon:(0,R.jsx)(Mt,{size:14}),label:a(`With a code`)}),(0,R.jsx)(Gh,{active:l===`password`,onClick:()=>u(`password`),icon:(0,R.jsx)(xt,{size:14}),label:a(`With a password`)})]}),(0,R.jsxs)(`div`,{children:[(0,R.jsx)(`label`,{htmlFor:`${o}-id`,className:`text-[12px] text-muted`,children:se()?a(`Mainland China phone number or e-mail`):a(`E-mail (or a mainland China phone number)`)}),(0,R.jsx)(`input`,{id:`${o}-id`,value:d,onChange:e=>{f(e.target.value),v(!1)},inputMode:Uh(d),autoComplete:`username`,autoFocus:r,placeholder:a(`138 0000 0000 or you@example.com`),className:i(Ie,`mt-1`)}),l===`code`&&!_&&(!se()||oe(d))&&(0,R.jsx)(`p`,{className:`mt-1.5 text-[12px] text-muted`,children:a(`Text-message codes reach mainland-China numbers only. Use an e-mail address instead.`)})]}),l===`password`?(0,R.jsxs)(`div`,{children:[(0,R.jsx)(`label`,{htmlFor:`${o}-password`,className:`text-[12px] text-muted`,children:a(`Password`)}),(0,R.jsx)(`input`,{id:`${o}-password`,type:`password`,value:h,onChange:e=>g(e.target.value),autoComplete:`current-password`,className:i(Ie,`mt-1`)}),(0,R.jsx)(`p`,{className:`mt-1.5 text-[12px] text-muted`,children:a(`No password yet? Use a code first; set one under Account.`)})]}):(0,R.jsxs)(R.Fragment,{children:[_&&(0,R.jsxs)(`div`,{children:[(0,R.jsx)(`label`,{htmlFor:`${o}-code`,className:`text-[12px] text-muted`,children:a(`The code you received`)}),(0,R.jsx)(`input`,{id:`${o}-code`,value:p,onChange:e=>m(e.target.value.replace(/\D/g,``).slice(0,8)),inputMode:`numeric`,autoComplete:`one-time-code`,placeholder:`123456`,autoFocus:!0,className:i(`w-full rounded-2xl bg-surface-2 px-3.5 py-2.5 text-[14.5px] outline-none focus:ring-2 focus:ring-accent/40`,`mt-1 tracking-[0.3em]`)})]}),T?(0,R.jsxs)(`div`,{children:[(0,R.jsx)(`label`,{htmlFor:`${o}-invite`,className:`text-[12px] text-muted`,children:a(`Invite code (optional)`)}),(0,R.jsx)(`input`,{id:`${o}-invite`,value:C,onChange:e=>w(Hh(e.target.value)),autoComplete:`off`,placeholder:`ABCD2345`,className:i(Ie,`mt-1 tracking-[0.2em] uppercase`)}),(0,R.jsx)(`p`,{className:`mt-1.5 text-[12px] text-muted`,children:a(`A friend's code counts for a new account: you both get ¥{invite} more allowance.`,{invite:(c.invite_bonus_cny??5).toFixed(0)})})]}):(0,R.jsx)(`button`,{type:`button`,onClick:()=>E(!0),className:`text-[12px] text-muted underline-offset-2 hover:underline`,children:a(`Have an invite code?`)})]}),x&&(0,R.jsx)(`div`,{className:`rounded-2xl bg-rose-500/12 px-3 py-2 text-[12.5px] text-rose-700 dark:text-rose-300`,children:x}),(0,R.jsx)(`div`,{className:`flex gap-2`,children:l===`code`&&_?(0,R.jsxs)(R.Fragment,{children:[(0,R.jsx)(`button`,{type:`button`,disabled:y!==null,onClick:()=>void O(),className:je,children:a(`Send again`)}),(0,R.jsxs)(`button`,{type:`submit`,disabled:y!==null||p.trim().length<4,className:i(Ne,`flex-1 py-3`),children:[y?(0,R.jsx)(A,{size:15,className:`animate-spin`}):null,` `,j]})]}):l===`code`?(0,R.jsxs)(`button`,{type:`submit`,disabled:y!==null||!d.trim(),className:i(Ne,`flex-1 py-3`),children:[y===`code`?(0,R.jsx)(A,{size:15,className:`animate-spin`}):null,` `,a(`Send me a code`)]}):(0,R.jsxs)(`button`,{type:`submit`,disabled:y!==null||!d.trim()||!h,className:i(Ne,`flex-1 py-3`),children:[y?(0,R.jsx)(A,{size:15,className:`animate-spin`}):null,` `,j]})})]})}function Gh({active:e,onClick:t,icon:n,label:r}){return(0,R.jsxs)(`button`,{type:`button`,onClick:t,"aria-pressed":e,className:i(`flex items-center justify-center gap-1.5 rounded-xl px-2 py-2 transition`,e?`bg-surface text-fg shadow-sm`:`text-muted hover:text-fg`),children:[n,` `,r]})}function Kh(){let{state:e,refreshSettings:t,refreshHub:n,toast:r,skipSignIn:i}=E(),a=s(),o=e.profile?.name??`nanoMuse`,c=(0,R.jsxs)(`ul`,{className:`grid grid-cols-2 gap-2 text-[12.5px] wide:grid-cols-1 wide:gap-1.5 wide:text-[13.5px]`,children:[(0,R.jsx)(qh,{icon:(0,R.jsx)(It,{size:15}),text:a(`Every device of yours, one nanoMuse`)}),(0,R.jsx)(qh,{icon:(0,R.jsx)(st,{size:15}),text:a(`A model with a free allowance, or your own key`)}),(0,R.jsx)(qh,{icon:(0,R.jsx)(vt,{size:15}),text:a(`It uses your phone and computers for you`)}),(0,R.jsx)(qh,{icon:(0,R.jsx)(Qt,{size:15}),text:a(`Keys in your vault; nothing you say is kept on the relay`)})]});return(0,R.jsxs)(`div`,{className:`relative mx-auto flex h-[100dvh] w-full max-w-[760px] flex-col overflow-hidden bg-bg sm:border-x sm:border-border wide:max-w-none wide:border-0`,children:[(0,R.jsx)(`div`,{className:`pointer-events-none absolute inset-x-0 top-0 h-[46vh] bg-[radial-gradient(ellipse_at_top,rgba(0,100,212,0.14),transparent_65%)] dark:bg-[radial-gradient(ellipse_at_top,rgba(23,147,255,0.2),transparent_65%)] wide:inset-y-0 wide:h-auto wide:bg-[radial-gradient(ellipse_at_left,rgba(0,100,212,0.12),transparent_60%)] wide:dark:bg-[radial-gradient(ellipse_at_left,rgba(23,147,255,0.16),transparent_60%)]`}),(0,R.jsx)(`div`,{className:`titlebar-room relative`}),(0,R.jsx)(`div`,{className:`relative flex-1 overflow-y-auto px-6 pb-8 wide:flex wide:items-center wide:px-12`,children:(0,R.jsxs)(`div`,{className:`mx-auto w-full wide:grid wide:max-w-[980px] wide:grid-cols-[1.1fr_1fr] wide:items-center wide:gap-16`,children:[(0,R.jsxs)(`div`,{className:`safe-top flex flex-col items-center pt-14 text-center wide:items-start wide:pt-0 wide:text-left`,children:[(0,R.jsx)(xn,{size:88,className:`drop-shadow-[0_20px_40px_rgba(0,100,212,0.28)]`}),(0,R.jsx)(`h1`,{className:`mt-6 text-[28px] font-bold tracking-tight wide:text-[34px]`,children:a(`Sign in to {name}`,{name:o})}),(0,R.jsx)(`p`,{className:`mt-2 max-w-sm text-[14.5px] leading-relaxed text-muted wide:max-w-md wide:text-[15.5px]`,children:a(`One free account. It is what lets your phone and computers work as one and brings a model to start with.`)}),(0,R.jsx)(`div`,{className:`mt-7 hidden w-full wide:block`,children:c}),(0,R.jsx)(Te,{compact:!0,className:`mt-6 hidden w-full wide:block`})]}),(0,R.jsxs)(`div`,{children:[(0,R.jsx)(`div`,{className:`mt-8 rounded-[28px] border border-border/70 bg-surface p-5 shadow-sm wide:mt-0 wide:p-7`,children:(0,R.jsx)(Wh,{onSignedIn:async()=>{r(a(`Signed in to nanoMuse Cloud.`)),await Promise.all([t(),n()])}})}),(0,R.jsx)(`button`,{type:`button`,onClick:i,className:`mt-4 w-full rounded-2xl border border-border/70 px-4 py-2.5 text-[13.5px] text-fg/80 hover:bg-surface-2`,"data-testid":`sign-in-skip`,children:a(`Use your own API key instead`)}),(0,R.jsx)(`p`,{className:`mt-2 text-center text-[11.5px] leading-relaxed text-muted`,children:a(`You can sign in later under Connections, for sync and your devices.`)}),(0,R.jsx)(`div`,{className:`mt-6 wide:hidden`,children:c}),(0,R.jsx)(Te,{compact:!0,className:`mt-6 wide:hidden`}),(0,R.jsxs)(`p`,{className:`mt-4 text-center text-[11.5px] leading-relaxed text-muted wide:mt-5`,children:[a(`The relay keeps an account id, a masked identifier, usage counts and your agent's name and look; what else, and what is yours to switch off, is in the`),` `,(0,R.jsx)(`a`,{href:Lh,target:`_blank`,rel:`noopener noreferrer`,className:`underline decoration-dotted underline-offset-2 hover:text-fg`,children:a(`privacy policy`)}),`.`]})]})]})})]})}function qh({icon:e,text:t}){return(0,R.jsxs)(`li`,{className:`flex items-start gap-2 rounded-2xl bg-surface-2/60 px-3 py-2.5 text-fg/80 wide:bg-transparent wide:px-0 wide:py-1`,children:[(0,R.jsx)(`span`,{className:`mt-0.5 text-accent`,children:e}),(0,R.jsx)(`span`,{className:`leading-snug`,children:t})]})}function Jh(e,t,n){return!e||!e.account.required||e.account.signed_in||t?.llm_ready?!1:!n}var Yh=`modulepreload`,Xh=function(e){return`/`+e},Zh={},Qh=function(e){return e.pathname.endsWith(`.css`)},$h=function(e,t,n){let r=Promise.resolve();if(t&&t.length>0){let e,i=document.querySelector(`meta[property=csp-nonce]`),a=i?.nonce||i?.getAttribute(`nonce`);function o(e){return Promise.all(e.map(e=>Promise.resolve(e).then(e=>({status:`fulfilled`,value:e}),e=>({status:`rejected`,reason:e}))))}function s(e){return import.meta.resolve?new URL(import.meta.resolve(e)):new URL(e,import.meta.url)}r=o(t.map(t=>{t=Xh(t,n);let r=s(t);if(r.href in Zh)return;Zh[r.href]=!0;let i=Qh(r);if(e===void 0){e={all:new Set,styles:new Set};let t=document.getElementsByTagName(`link`);for(let n=t.length-1;n>=0;n--){let r=t[n];e.all.add(r.href),r.rel===`stylesheet`&&e.styles.add(r.href)}}if((i?e.styles:e.all).has(r.href))return;let o=document.createElement(`link`);if(o.rel=i?`stylesheet`:Yh,i||(o.as=`script`),o.crossOrigin=``,o.href=r.href,a&&o.setAttribute(`nonce`,a),document.head.appendChild(o),i)return new Promise((e,t)=>{o.addEventListener(`load`,e),o.addEventListener(`error`,()=>t(Error(`Unable to preload CSS for ${r}`)))})}).filter(e=>e!==void 0))}function i(e){let t=new Event(`vite:preloadError`,{cancelable:!0});if(t.payload=e,window.dispatchEvent(t),!t.defaultPrevented)throw e}return r.then(t=>{for(let e of t||[])e.status===`rejected`&&i(e.reason);return e().catch(i)})},eg=(0,L.lazy)(()=>$h(()=>import(`./AccountScreen-DvBFnisI.js`).then(e=>({default:e.AccountScreen})),__vite__mapDeps([0,1,2,3,4,5,6,7,8]))),tg=(0,L.lazy)(()=>$h(()=>import(`./AvatarStudioScreen-C1Q0sV3j.js`).then(e=>({default:e.AvatarStudioScreen})),__vite__mapDeps([9,1,2,3,4,10,8,11]))),ng=(0,L.lazy)(()=>$h(()=>import(`./ChannelsScreen-Bt6eBqvc.js`).then(e=>({default:e.ChannelsScreen})),__vite__mapDeps([12,1,3,4,10,8]))),rg=(0,L.lazy)(()=>$h(()=>import(`./CodingScreen-CTT5Jjn2.js`).then(e=>({default:e.CodingScreen})),__vite__mapDeps([13,1,4,10,8]))),ig=(0,L.lazy)(()=>$h(()=>import(`./ConnectionsScreen-0U0bXAf7.js`).then(e=>({default:e.ConnectionsScreen})),__vite__mapDeps([14,1,2,3,4,5,7,15,10,8,16]))),ag=(0,L.lazy)(()=>$h(()=>import(`./DevicesScreen-P67eLmyB.js`).then(e=>({default:e.DevicesScreen})),__vite__mapDeps([17,1,3,4,10,8,16]))),og=(0,L.lazy)(()=>$h(()=>import(`./GoalsScreen-BGb02qG6.js`).then(e=>({default:e.GoalsScreen})),__vite__mapDeps([18,1,2,3,4]))),sg=(0,L.lazy)(()=>$h(()=>import(`./IdeasScreen-BVCFCRSV.js`).then(e=>({default:e.IdeasScreen})),__vite__mapDeps([19,1,10]))),cg=(0,L.lazy)(()=>$h(()=>import(`./LibraryScreen-U8NV3qaf.js`).then(e=>({default:e.LibraryScreen})),__vite__mapDeps([20,1]))),lg=(0,L.lazy)(()=>$h(()=>import(`./MemoryScreen-B5a6LPAu.js`).then(e=>({default:e.MemoryScreen})),__vite__mapDeps([21,1,8]))),ug=(0,L.lazy)(()=>$h(()=>import(`./Onboarding-rP8qAahh.js`).then(e=>({default:e.Onboarding})),__vite__mapDeps([22,1,2,3,4,23,11,14,5,7,15,10,8,16]))),dg=(0,L.lazy)(()=>$h(()=>import(`./SettingsScreen-DoXURXet.js`).then(e=>({default:e.SettingsScreen})),__vite__mapDeps([24,1,2,3,4,5,6,15,23,11,8]))),fg=(0,L.lazy)(()=>$h(()=>import(`./SkillsScreen-DZP-6db6.js`).then(e=>({default:e.SkillsScreen})),__vite__mapDeps([25,1,8])));function pg(){return(0,R.jsx)(`div`,{className:`flex h-full min-h-[40vh] items-center justify-center text-muted`,children:(0,R.jsx)(A,{className:`animate-spin`,size:20})})}var mg=e=>({size:26,strokeWidth:e?2:1.7,fill:e?`currentColor`:`none`,fillOpacity:e?.18:0}),hg=[{id:`chat`,label:`Chat`,icon:e=>(0,R.jsx)(At,{...mg(e)})},{id:`feed`,label:`Feed`,icon:e=>(0,R.jsx)(Bt,{...mg(e)})},{id:`ideas`,label:`Ideas`,icon:e=>(0,R.jsx)(Ct,{...mg(e)})},{id:`goals`,label:`Goals`,icon:e=>(0,R.jsx)(rn,{...mg(e)})},{id:`library`,label:`Library`,icon:e=>(0,R.jsx)(St,{...mg(e)})}];function gg(){let{state:e,setTab:t,openFile:n}=E(),r=Wf(),a=s();(0,L.useEffect)(()=>{let t=e.profile?.name?.trim();document.title=t&&t.toLowerCase()!==`nanomuse`?`${t} · nanoMuse`:`nanoMuse`},[e.profile?.name]),(0,L.useEffect)(()=>{let e=Sn()?.onQuickChat?.(()=>{t(`chat`),requestAnimationFrame(()=>window.dispatchEvent(new Event(`nanomuse:quick-chat`)))});return()=>{typeof e==`function`&&e()}},[t]),(0,L.useEffect)(()=>{let e=()=>{let e=window.location.hash.slice(1);(e&&hg.some(t=>t.id===e)||e===`devices`||e===`you`||e===`memory`||e===`connections`||e===`channels`||e===`skills`||e===`account`||e===`coding`||e===`avatar`)&&t(e)};return e(),window.addEventListener(`hashchange`,e),()=>window.removeEventListener(`hashchange`,e)},[t]);let o=r&&e.hub?.account.signed_in?(0,R.jsx)(Gf,{}):null,c=e.lite&&e.settings!==null&&!e.settings.onboarded;if((0,L.useEffect)(()=>{c&&M.onboarded(!0).catch(()=>void 0)},[c]),e.authError)return(0,R.jsx)(vg,{});if(!e.loaded)return(0,R.jsx)(_g,{error:e.error});if(Jh(e.hub,e.settings,e.signInSkipped))return(0,R.jsx)(Kh,{});if(!e.lite&&e.settings&&!e.settings.onboarded&&!e.onboardingDismissed&&!e.threads.some(e=>e.events>0))return(0,R.jsxs)(L.Suspense,{fallback:(0,R.jsx)(pg,{}),children:[(0,R.jsx)(ug,{}),o]});let l=e.pendingApprovals.length,u=e.goals.filter(e=>e.proposal&&e.status!==`cancelled`).length,d=e.pendingApprovals.filter(t=>t.ts>e.feedSeenAt).length;return(0,R.jsxs)(`div`,{className:i(`mx-auto flex h-[100dvh] max-w-[760px] flex-col bg-bg sm:border-x sm:border-border`,!e.lite&&`wide:max-w-none wide:flex-row wide:border-x-0`),children:[!e.lite&&(0,R.jsx)(`div`,{className:`hidden wide:block wide:h-full`,children:(0,R.jsx)(uh,{})}),(0,R.jsxs)(`div`,{className:`flex min-h-0 min-w-0 flex-1 flex-col`,children:[e.gone&&(0,R.jsxs)(`div`,{className:`flex items-center justify-center gap-2 bg-surface-2 text-muted text-[12.5px] py-1`,children:[(0,R.jsx)(vn,{size:14}),` `,a(e.lite?`This demo has ended.`:`This nanoMuse has stopped. Reload the page once it is running again.`)]}),!e.gone&&!e.connected&&e.loaded&&(0,R.jsxs)(`div`,{className:`flex items-center justify-center gap-2 bg-amber-500/15 text-amber-700 dark:text-amber-300 text-[12.5px] py-1`,children:[(0,R.jsx)(vn,{size:14}),` `,a(`Reconnecting to your nanoMuse…`)]}),!e.lite&&(0,R.jsx)(En,{}),(0,R.jsx)(`main`,{className:`mx-auto min-h-0 w-full flex-1 wide:max-w-[900px]`,children:(0,R.jsxs)(L.Suspense,{fallback:(0,R.jsx)(pg,{}),children:[e.tab===`chat`&&(0,R.jsx)(Wm,{}),e.tab===`feed`&&(0,R.jsx)(dh,{}),e.tab===`ideas`&&(0,R.jsx)(sg,{}),e.tab===`goals`&&(0,R.jsx)(og,{}),e.tab===`library`&&(0,R.jsx)(cg,{}),e.tab===`memory`&&(0,R.jsx)(lg,{}),e.tab===`skills`&&(0,R.jsx)(fg,{}),e.tab===`connections`&&(0,R.jsx)(ig,{}),e.tab===`channels`&&(0,R.jsx)(ng,{}),e.tab===`devices`&&(0,R.jsx)(ag,{}),e.tab===`you`&&(0,R.jsx)(dg,{}),e.tab===`account`&&(0,R.jsx)(eg,{}),e.tab===`coding`&&(0,R.jsx)(rg,{}),e.tab===`avatar`&&(0,R.jsx)(tg,{})]})}),(0,R.jsx)(`nav`,{className:i(`safe-bottom shrink-0 bg-bg`,!e.lite&&`wide:hidden`),children:(0,R.jsx)(`ul`,{className:`flex h-14 items-center justify-evenly`,children:hg.map(n=>{let r=e.tab===n.id,o=n.id===`chat`?l:n.id===`feed`?d:n.id===`goals`?u:0;return(0,R.jsx)(`li`,{children:(0,R.jsxs)(`button`,{type:`button`,onClick:()=>t(n.id),"aria-label":a(n.label),"aria-current":r?`page`:void 0,className:i(`relative flex h-12 w-12 items-center justify-center rounded-full transition`,r?`text-fg`:`text-fg/70 hover:text-fg`),children:[n.icon(r),o>0&&(0,R.jsx)(`span`,{className:`absolute right-1 top-1 flex h-[17px] min-w-[17px] items-center justify-center rounded-full bg-rose-500 px-1 text-[10px] font-bold text-white`,children:o})]})},n.id)})})})]}),(0,R.jsx)(kn,{}),(0,R.jsx)(gf,{path:e.viewer,onClose:()=>n(null)}),o,e.toast&&(0,R.jsx)(`div`,{className:`pointer-events-none fixed inset-x-0 bottom-24 z-[70] flex justify-center px-4`,children:(0,R.jsx)(`div`,{className:`rise rounded-2xl bg-fg text-bg px-4 py-2 text-[13.5px] shadow-lg max-w-sm text-center`,children:e.toast})})]})}function _g({error:e}){let t=s();return(0,R.jsxs)(`div`,{className:`mx-auto flex h-[100dvh] max-w-sm flex-col items-center justify-center px-6 text-center`,children:[(0,R.jsx)(xn,{size:72}),e?(0,R.jsxs)(R.Fragment,{children:[(0,R.jsx)(`p`,{className:`mt-6 text-[15px] font-medium`,children:t(`Could not reach your nanoMuse.`)}),(0,R.jsx)(`p`,{className:`mt-1.5 text-[13px] text-muted`,children:t(e)}),(0,R.jsx)(`button`,{type:`button`,onClick:()=>window.location.reload(),className:`mt-5 rounded-full bg-fg px-5 py-2 text-[14px] font-medium text-bg`,children:t(`Try again`)})]}):(0,R.jsxs)(`p`,{className:`mt-6 flex items-center gap-2 text-[14px] text-muted`,children:[(0,R.jsx)(A,{className:`animate-spin`,size:16}),` `,t(`Connecting to your nanoMuse…`)]})]})}function vg(){let[e,t]=(0,L.useState)(``),n=s();return(0,R.jsxs)(`div`,{className:`mx-auto flex h-[100dvh] max-w-md flex-col items-center justify-center px-6 text-center`,children:[(0,R.jsx)(xn,{size:88}),(0,R.jsx)(`h1`,{className:`mt-4 text-[22px] font-bold`,children:n(`Connect to your nanoMuse`)}),(0,R.jsxs)(`p`,{className:`mt-2 text-[14px] text-muted`,children:[n(`This app talks to the nanoMuse server you run yourself. Scan the QR code printed by`),` `,(0,R.jsx)(`code`,{className:`rounded bg-surface-2 px-1`,children:`nanomuse serve`}),n(`, or paste the access token below.`)]}),(0,R.jsxs)(`form`,{className:`mt-5 w-full flex gap-2`,onSubmit:t=>{t.preventDefault(),e.trim()&&(g(e.trim()),window.location.reload())},children:[(0,R.jsx)(`input`,{value:e,onChange:e=>t(e.target.value),"aria-label":n(`Access token`),placeholder:n(`Access token`),className:`flex-1 rounded-2xl bg-surface-2 px-4 py-2.5 text-[15px] outline-none focus:ring-2 focus:ring-accent/40`}),(0,R.jsx)(`button`,{type:`submit`,className:`rounded-2xl bg-accent text-accent-fg px-4 font-medium`,children:n(`Connect`)})]})]})}a(),ee(),wn(),bn.createRoot(document.getElementById(`root`)).render((0,R.jsx)(L.StrictMode,{children:(0,R.jsx)(T,{children:(0,R.jsx)(gg,{})})}));export{Ut as $,Ff as A,gn as B,Jp as C,Ze as Ct,rp as D,Ke as Dt,ip as E,qe as Et,hf as F,tn as G,sn as H,Mn as I,Xt as J,Qt as K,Sn as L,Nf as M,Pf as N,Zf as O,Af as P,Gt as Q,Cn as R,tm as S,Qe as St,op as T,Je as Tt,on as U,fn as V,nn as W,qt as X,Jt as Y,I as Z,nm as _,ct as _t,Ah as a,Nt as at,rm as b,rt as bt,Ih as c,Tt as ct,Um as d,F as dt,Ht as et,Em as f,vt as ft,Xp as g,ut as gt,Qp as h,pt as ht,Fh as i,It as it,jf as j,$f as k,Nh as l,wt as lt,Yp as m,mt,Rh as n,Rt as nt,jh as o,At as ot,Zp as p,gt as pt,Zt as q,Lh as r,Lt as rt,Mh as s,Et as st,Wh as t,Vt as tt,Vm as u,xt as ut,im as v,st as vt,Op as w,Xe as wt,$p as x,tt as xt,em as y,at as yt,yn as z}; \ No newline at end of file +`).replace(/\\([,;\\])/g,`$1`),a=(e,t)=>{if(/VALUE=DATE(?![-])/i.test(t)||/^\d{8}$/.test(e)){let t=/^(\d{4})(\d{2})(\d{2})/.exec(e);return{at:t?new Date(+t[1],t[2]-1,+t[3]):null,allDay:!0}}let n=/^(\d{4})(\d{2})(\d{2})T(\d{2})(\d{2})(\d{2})?(Z?)$/.exec(e);if(!n)return{at:null,allDay:!1};let r=[+n[1],n[2]-1,+n[3],+n[4],+n[5],+(n[6]??0)];return{at:n[7]?new Date(Date.UTC(...r)):new Date(...r),allDay:!1}};for(let e of t)if(e===`BEGIN:VEVENT`)r={summary:``,location:``,description:``,start:null,end:null,allDay:!1};else if(e===`END:VEVENT`&&r)n.push(r),r=null;else if(r){let t=e.indexOf(`:`);if(t<0)continue;let[n,...o]=e.slice(0,t).split(`;`),s=e.slice(t+1),c=o.join(`;`);if(n===`SUMMARY`)r.summary=i(s);else if(n===`LOCATION`)r.location=i(s);else if(n===`DESCRIPTION`)r.description=i(s);else if(n===`DTSTART`){let e=a(s,c);r.start=e.at,r.allDay=e.allDay}else n===`DTEND`&&(r.end=a(s,c).at)}return n}function Sf(e){if(!e.start)return``;let t=m(),n=e=>e.toLocaleDateString(t,{weekday:`short`,year:`numeric`,month:`short`,day:`numeric`}),r=e=>e.toLocaleTimeString(t,{hour:`numeric`,minute:`2-digit`});if(e.allDay){let t=e.end?new Date(e.end.getTime()-864e5):e.start;return t>e.start?`${n(e.start)} – ${n(t)}`:`${n(e.start)} · ${_(`all day`)}`}return e.end?e.start.toDateString()===e.end.toDateString()?`${n(e.start)} ${r(e.start)}–${r(e.end)}`:`${n(e.start)} ${r(e.start)} – ${n(e.end)} ${r(e.end)}`:`${n(e.start)} ${r(e.start)}`}function Cf({path:e,kind:t}){let{text:n,error:r}=vf(e);return r?(0,R.jsx)(Ef,{error:r}):n===null?(0,R.jsx)(Tf,{}):t===`text`&&/\.md$/i.test(e)?(0,R.jsx)(`div`,{className:`mx-auto max-w-[720px] px-5 py-4`,children:(0,R.jsx)(hf,{text:n})}):t===`data`&&/\.csv$/i.test(e)?(0,R.jsx)(wf,{text:n}):(0,R.jsx)(`pre`,{className:`whitespace-pre-wrap break-words px-4 py-3 font-mono text-[12.5px] leading-relaxed`,children:n})}function wf({text:e}){let t=s(),n=e.split(/\r?\n/).filter(e=>e.trim()).slice(0,500).map(e=>e.split(`,`));if(!n.length)return(0,R.jsx)(`div`,{className:`p-6 text-muted text-center`,children:t(`Empty file.`)});let[r,...i]=n;return(0,R.jsx)(`div`,{className:`overflow-auto p-3`,children:(0,R.jsxs)(`table`,{className:`min-w-full text-[13px] border-separate border-spacing-0`,children:[(0,R.jsx)(`thead`,{children:(0,R.jsx)(`tr`,{children:r.map((e,t)=>(0,R.jsx)(`th`,{className:`sticky top-0 bg-surface-2 text-left font-semibold px-3 py-2 border-b border-border whitespace-nowrap`,children:e},t))})}),(0,R.jsx)(`tbody`,{children:i.map((e,t)=>(0,R.jsx)(`tr`,{className:`odd:bg-surface`,children:e.map((e,t)=>(0,R.jsx)(`td`,{className:`px-3 py-1.5 border-b border-border/60 whitespace-nowrap`,children:e},t))},t))})]})})}function Tf(){return(0,R.jsx)(`div`,{className:`flex h-full items-center justify-center text-muted`,children:(0,R.jsx)(A,{className:`animate-spin`,size:22})})}function Ef({error:e}){let t=s();return(0,R.jsx)(`div`,{className:`p-8 text-center text-rose-600 dark:text-rose-300 text-[14px]`,children:t(`Could not load the file: {error}`,{error:e})})}var Df=`OpenAI's terms cover using a ChatGPT plan inside OpenAI's own Codex; other apps have had this access cut off before (OpenCode, January 2026). If it stops working, an API key does.`,Of=2e3,kf=6e5;function Af({compact:e,onChanged:t}){let n=s(),{toast:r}=E(),[a,o]=(0,L.useState)(null),[c,l]=(0,L.useState)(`unknown`),[u,d]=(0,L.useState)(null),[f,p]=(0,L.useState)(null),[m,h]=(0,L.useState)(!0),[g,_]=(0,L.useState)(``),[v,y]=(0,L.useState)(null),b=(0,L.useRef)(0),x=(0,L.useCallback)(async()=>{try{let e=await M.chatgptStatus();return o(e),l(`yes`),e}catch(e){return/not found/i.test(e.message)?l(`no`):y(e.message),null}},[]);(0,L.useEffect)(()=>{x().then(e=>{e?.pending&&e.url&&(b.current=Date.now(),h(e.port_bound!==!1),p(e.url))})},[x]),(0,L.useEffect)(()=>{if(!f)return;let e=setInterval(()=>{x().then(e=>{e?.signed_in?(p(null),Ee(),r(n(`Signed in with {label}.`,{label:e.label||`ChatGPT`})),t?.()):e&&e.pending===!1&&e.error?(p(null),y(n(e.error))):Date.now()-b.current>kf&&(p(null),y(n(`The sign-in did not finish in ten minutes. Try again.`)))})},Of);return()=>clearInterval(e)},[f,x,t,r,n]);let S=async()=>{d(`login`),y(null);try{let e=await M.chatgptLogin();b.current=Date.now(),h(e.port_bound!==!1),_(``),p(e.url),window.open(e.url,`_blank`,`noopener`)}catch(e){/not found/i.test(e.message)?l(`no`):y(e.message)}finally{d(null)}},C=async()=>{let e=g.trim();if(e){d(`paste`),y(null);try{await M.chatgptCallback(e),_(``)}catch(e){let t=e.message;/state/i.test(t)?y(n(`That address belongs to another sign-in attempt. Open the page again and paste the address it ends on.`)):/no sign-in|409/i.test(t)?(p(null),y(n(`The sign-in did not finish in ten minutes. Try again.`))):y(t)}finally{d(null)}}},w=async()=>{d(`use`),y(null);try{await M.setLLM({provider:`chatgpt`,model:a?.models?.[0]??``,base_url:``,api_key:``}),Ee(),r(n(`ChatGPT answers the chat now.`)),t?.()}catch(e){y(e.message)}finally{d(null)}},T=async()=>{d(`logout`),y(null);try{await M.chatgptLogout(),Ee(),await x(),t?.()}catch(e){y(e.message)}finally{d(null)}},D=n(`Covers chat and the hands. Pictures and clips are not part of it; those need a provider with image or video models.`);return(0,R.jsxs)(`div`,{className:i(`space-y-2`,!e&&`rounded-2xl bg-surface-2/60 p-3`),children:[!e&&(0,R.jsxs)(`div`,{className:`flex items-center gap-2 text-[13px] font-medium`,children:[(0,R.jsx)(Mt,{size:15,className:`text-accent`}),` `,n(`Sign in with ChatGPT`)]}),c===`no`?(0,R.jsxs)(`p`,{className:`text-[12.5px] text-muted`,children:[n(`This nanoMuse has no sign-in route yet. In a terminal on this computer, run`),` `,(0,R.jsx)(`code`,{className:`rounded bg-surface-2 px-1 py-0.5 text-[12px]`,children:`nanomuse chatgpt login`}),` `,n(`and reload this page.`)]}):a?.signed_in?(0,R.jsxs)(`div`,{className:`space-y-2`,children:[(0,R.jsxs)(`p`,{className:`text-[12.5px]`,children:[(0,R.jsx)(`span`,{className:`font-medium`,children:n(`Signed in with {label}.`,{label:a.label||`ChatGPT`})}),` `,(0,R.jsx)(`span`,{className:`text-muted`,children:D})]}),(0,R.jsxs)(`div`,{className:`flex flex-wrap gap-2`,children:[(0,R.jsxs)(`button`,{type:`button`,disabled:u!==null,onClick:()=>void w(),className:i(Ne,`inline-flex items-center gap-1.5 py-2`),children:[u===`use`?(0,R.jsx)(A,{size:14,className:`animate-spin`}):(0,R.jsx)(Mt,{size:14}),` `,n(`Use it for the chat`)]}),(0,R.jsxs)(`button`,{type:`button`,disabled:u!==null,onClick:()=>void T(),className:i(je,`inline-flex items-center gap-1.5`),children:[u===`logout`?(0,R.jsx)(A,{size:14,className:`animate-spin`}):(0,R.jsx)(Tt,{size:14}),` `,n(`Sign out of ChatGPT`)]})]})]}):f?(0,R.jsxs)(`div`,{className:`space-y-2`,children:[(0,R.jsxs)(`p`,{className:`flex items-start gap-2 text-[12.5px] text-muted`,children:[(0,R.jsx)(A,{size:14,className:`mt-0.5 shrink-0 animate-spin`}),(0,R.jsx)(`span`,{children:n(m?`A page from OpenAI opened in a new tab. Sign in there; this card follows on its own.`:`A page from OpenAI opened in a new tab. Sign in there; when the browser ends on an address that will not load, paste that address below.`)})]}),(0,R.jsxs)(`div`,{className:`flex flex-wrap gap-2`,children:[(0,R.jsxs)(`a`,{href:f,target:`_blank`,rel:`noopener noreferrer`,className:i(je,`inline-flex items-center gap-1.5`),children:[(0,R.jsx)(Ae,{size:14}),` `,n(`Open the page again`)]}),(0,R.jsx)(`button`,{type:`button`,onClick:()=>p(null),className:je,children:n(`Cancel`)})]}),(0,R.jsxs)(`form`,{className:`flex flex-wrap items-center gap-2`,onSubmit:e=>{e.preventDefault(),C()},children:[(0,R.jsx)(`input`,{type:`url`,value:g,onChange:e=>_(e.target.value),placeholder:`http://localhost:1455/auth/callback?code=…`,"aria-label":n(`The address the browser ended on`),className:`min-w-0 flex-1 rounded-lg border border-border bg-surface px-2 py-1.5 text-[12.5px]`}),(0,R.jsxs)(`button`,{type:`submit`,disabled:u!==null||!g.trim(),className:i(je,`inline-flex items-center gap-1.5`),children:[u===`paste`?(0,R.jsx)(A,{size:14,className:`animate-spin`}):null,` `,n(`Use this address`)]})]}),!m&&(0,R.jsx)(`p`,{className:`text-[11.5px] text-muted`,children:n(`This nanoMuse runs where the browser cannot reach port 1455, so it cannot pick the sign-in up by itself.`)})]}):(0,R.jsxs)(`div`,{className:`space-y-2`,children:[(0,R.jsx)(`p`,{className:`text-[12.5px] text-muted`,children:D}),(0,R.jsxs)(`button`,{type:`button`,disabled:u!==null||c===`unknown`,onClick:()=>void S(),className:i(Ne,`inline-flex items-center gap-1.5 py-2`),children:[u===`login`?(0,R.jsx)(A,{size:14,className:`animate-spin`}):(0,R.jsx)(wt,{size:14}),` `,n(`Sign in with ChatGPT`)]})]}),(0,R.jsx)(`p`,{className:`text-[11.5px] leading-snug text-muted`,children:n(Df)}),v&&(0,R.jsx)(`p`,{className:`text-[12px] text-rose-600 dark:text-rose-300`,children:v})]})}var jf=xe,Mf=`nm.connections.preset`;function Nf(e,t=_e().preset){try{sessionStorage.setItem(Mf,t)}catch{}e(`connections`)}function Pf(){try{let e=sessionStorage.getItem(Mf);return e&&sessionStorage.removeItem(Mf),e}catch{return null}}function Ff({info:e,exhausted:t,compact:n}){let r=s(),{toast:a,setTab:o,state:l}=E(),u=l.hub?.account,d=_e(u),f=ae(u),p=c(),m=e.invite_bonus_cny??5,h=e.own_key_docs||e.guidance?.docs||jf,g=e.invite_url||``,[_,v]=(0,L.useState)(!1),[y,b]=(0,L.useState)(!1),x=(e.guidance?.providers??de(f)).filter(e=>e.id!==d.id).map(e=>({id:e.id,name:De(e,p),keyUrl:e.key_url,covers:`covers`in e?e.covers:e.capabilities})),S=Oe().map(e=>e.name),C=async e=>{try{await navigator.clipboard.writeText(e),a(r(`Copied`))}catch{a(e)}},w=async()=>{let e=r(`Try nanoMuse with me, a fully open-source personal agent, free to use. Sign up with my link: {link}`,{link:g}),t=navigator;if(t.share)try{await t.share({text:e});return}catch{}await C(e)},T=Ce(),[D,O]=me(`exhausted`,t),k=ve(be(r,`exhausted`)),ee=t?r(`The free allowance is used up.`):r(`Nearly used up: ¥{left} of ¥{grant} left.`,{left:(e.left??0).toFixed(2),grant:(e.grant??0).toFixed(0)});return(0,R.jsxs)(`div`,{className:i(`space-y-2.5`,!n&&`pt-1`),children:[(0,R.jsxs)(`div`,{children:[(0,R.jsx)(`div`,{className:i(`font-semibold`,n?`text-[13.5px]`:`text-[15px]`),children:ee}),(0,R.jsx)(`div`,{className:`mt-0.5 text-[12.5px] text-muted`,children:r(`Three ways on; your sign-in and your devices keep working whichever you pick.`)})]}),(0,R.jsxs)(If,{icon:(0,R.jsx)(xt,{size:16}),tone:`bg-accent/12 text-accent`,title:r(`Use your own model key`),children:[(0,R.jsx)(`p`,{className:`text-[12.5px] text-muted`,children:ie(r,u)}),(0,R.jsxs)(`div`,{className:`flex flex-wrap gap-2`,children:[(0,R.jsxs)(`button`,{type:`button`,onClick:()=>Nf(o,d.preset),className:i(Ne,`inline-flex items-center gap-1.5 py-2`),children:[(0,R.jsx)(xt,{size:14}),` `,r(`Set it up`)]}),(0,R.jsxs)(`a`,{href:d.keyUrl,target:`_blank`,rel:`noopener noreferrer`,className:i(je,`inline-flex items-center gap-1.5`),children:[(0,R.jsx)(Ae,{size:14}),` `,r(`Get a key from {vendor}`,{vendor:d.label})]}),(0,R.jsxs)(`a`,{href:h,target:`_blank`,rel:`noopener noreferrer`,className:i(je,`inline-flex items-center gap-1.5`),children:[(0,R.jsx)(Ae,{size:14}),` `,r(`Step-by-step guide`)]})]}),x.length>0&&(0,R.jsxs)(`div`,{children:[(0,R.jsxs)(`button`,{type:`button`,onClick:()=>v(!_),className:`inline-flex items-center gap-1 text-[12px] text-muted`,children:[_?(0,R.jsx)(Le,{size:13}):(0,R.jsx)(Me,{size:13}),` `,r(`Other providers and what each key covers`)]}),_&&(0,R.jsx)(`ul`,{className:`mt-1.5 space-y-1 text-[12.5px]`,children:x.map(e=>(0,R.jsxs)(`li`,{className:`flex flex-wrap items-baseline justify-between gap-x-3`,children:[(0,R.jsxs)(`span`,{children:[(0,R.jsx)(`span`,{className:`font-medium`,children:e.name}),` `,(0,R.jsxs)(`span`,{className:`text-muted`,children:[`· `,he(r,e.covers)]})]}),(0,R.jsxs)(`span`,{className:`flex gap-2`,children:[(0,R.jsx)(`button`,{type:`button`,onClick:()=>Nf(o,pe(e.id)),className:`text-accent`,children:r(`Set it up`)}),(0,R.jsxs)(`a`,{href:e.keyUrl,target:`_blank`,rel:`noopener noreferrer`,className:`inline-flex items-center gap-0.5 text-accent`,children:[r(`Get a key`),` `,(0,R.jsx)(Ae,{size:11})]})]})]},e.id))})]})]}),(0,R.jsxs)(If,{icon:(0,R.jsx)(wt,{size:16}),tone:`bg-emerald-500/12 text-emerald-600 dark:text-emerald-300`,title:r(`Sign in with a plan you already pay for`),children:[(0,R.jsx)(`p`,{className:`text-[12.5px] text-muted`,children:r(`{plans}: the plan's models answer here, no key to make. ChatGPT works on every device, the others on the phones. A ChatGPT sign-in covers chat and the hands; pictures and clips still want a key.`,{plans:S.join(r(`, `))})}),y?(0,R.jsx)(Af,{compact:!0,onChanged:()=>b(!1)}):(0,R.jsxs)(`button`,{type:`button`,onClick:()=>b(!0),className:i(je,`inline-flex items-center gap-1.5`),children:[(0,R.jsx)(wt,{size:14}),` `,r(`Sign in with ChatGPT`)]})]}),(0,R.jsx)(If,{icon:(0,R.jsx)(hn,{size:16}),tone:`bg-violet-500/12 text-violet-600 dark:text-violet-300`,title:r(`Invite a friend: +¥{bonus} for you and +¥{bonus} for them, for each new person who signs up with your link.`,{bonus:m.toFixed(0)}),children:g?(0,R.jsxs)(`div`,{className:`flex flex-wrap gap-2`,children:[(0,R.jsxs)(`button`,{type:`button`,onClick:()=>void w(),className:i(je,`inline-flex items-center gap-1.5`),children:[(0,R.jsx)(Xt,{size:14}),` `,r(`Share the link`)]}),(0,R.jsxs)(`button`,{type:`button`,onClick:()=>void C(g),className:i(je,`inline-flex items-center gap-1.5`),children:[(0,R.jsx)(ut,{size:14}),` `,r(`Copy the link`)]})]}):(0,R.jsxs)(`button`,{type:`button`,onClick:()=>o(`account`),className:i(je,`inline-flex items-center gap-1.5`),children:[(0,R.jsx)(Xt,{size:14}),` `,r(`Your invite link is under Account`)]})}),t&&D&&(0,R.jsxs)(If,{icon:(0,R.jsx)(ce,{size:16}),tone:`bg-amber-400/15 text-amber-600 dark:text-amber-300`,title:k,children:[(0,R.jsxs)(`button`,{type:`button`,onClick:()=>fe(T.repo_url),className:i(`flex items-center justify-center gap-1.5 rounded-2xl border border-border px-4 py-2.5 text-[14px] font-medium text-muted disabled:opacity-40`,`inline-flex items-center gap-1.5`),children:[(0,R.jsx)(ce,{size:14}),` `,r(`Star on GitHub`)]}),(0,R.jsx)(`button`,{type:`button`,onClick:()=>{ge(),O(!1)},className:i(`flex items-center justify-center gap-1.5 rounded-2xl border border-border px-4 py-2.5 text-[14px] font-medium text-muted disabled:opacity-40`,`inline-flex items-center gap-1.5`),children:r(`I already starred`)})]})]})}function If({icon:e,tone:t,title:n,children:r}){return(0,R.jsxs)(`div`,{className:`flex gap-3 rounded-2xl bg-surface-2/60 p-3`,children:[(0,R.jsx)(`span`,{className:i(`flex h-8 w-8 shrink-0 items-center justify-center rounded-xl`,t),children:e}),(0,R.jsxs)(`div`,{className:`min-w-0 flex-1 space-y-2`,children:[(0,R.jsx)(`div`,{className:`text-[13px] font-medium leading-snug`,children:n}),r]})]})}var Lf=`nm.cloud.warned_grant`;function Rf(){let e=s(),{state:t,setTab:n}=E(),[r,i]=(0,L.useState)(null),a=(0,L.useRef)(0),o=t.hub?.account,c=!!o?.signed_in&&!!o.is_model,l=t.finishedAt;if((0,L.useEffect)(()=>{if(!c||!l||r||Date.now()-a.current<6e4)return;a.current=Date.now();let e=!1;return M.cloudMe().then(t=>{if(e)return;let n=t.spend,r=n.grant??n.allowance_cny??0,a=n.left??null;if(n.unlimited||!n.warn||a===null||a<=0)return;let o=null;try{o=localStorage.getItem(Lf)}catch{}o!==String(r)&&i({left:a,grant:r,invite_url:t.invite?.url,invite_bonus_cny:n.invite_bonus_cny,invitee_bonus_cny:n.invitee_bonus_cny,own_key_docs:n.own_key_docs,guidance:n.guidance})}).catch(()=>{}),()=>{e=!0}},[c,l,r]),!r)return null;let u=()=>{try{localStorage.setItem(Lf,String(r.grant??0))}catch{}i(null)};return(0,R.jsxs)(`div`,{className:`rise mx-3 mb-1.5 flex items-start gap-2 rounded-2xl bg-amber-500/12 px-3 py-2 text-[12.5px] leading-snug text-amber-800 dark:text-amber-200`,children:[(0,R.jsx)(nn,{size:14,className:`mt-0.5 shrink-0`}),(0,R.jsxs)(`div`,{className:`min-w-0 flex-1`,children:[e(`Nearly used up: ¥{left} of ¥{grant} left.`,{left:(r.left??0).toFixed(2),grant:(r.grant??0).toFixed(0)}),` `,e(`Invite a friend (+¥{invite} for each of you) or bring your own key; your sign-in keeps working either way.`,{invite:(r.invite_bonus_cny??5).toFixed(0)}),` `,(0,R.jsx)(`button`,{type:`button`,onClick:()=>{u(),n(`account`)},className:`font-semibold underline decoration-dotted underline-offset-2`,children:e(`See the ways`)})]}),(0,R.jsx)(`button`,{type:`button`,onClick:u,"aria-label":e(`Dismiss`),className:`shrink-0 rounded-full p-0.5 opacity-70 hover:opacity-100`,children:(0,R.jsx)(Fe,{size:14})})]})}var zf=`nm.cloud.first_sign_in`,Bf=`nm:first-sign-in`;function Vf(){try{sessionStorage.setItem(zf,`1`)}catch{}window.dispatchEvent(new Event(Bf))}function Hf(){try{sessionStorage.removeItem(zf)}catch{}window.dispatchEvent(new Event(Bf))}function Uf(){try{return sessionStorage.getItem(zf)===`1`}catch{return!1}}function Wf(){let[e,t]=(0,L.useState)(Uf);return(0,L.useEffect)(()=>{let e=()=>t(Uf());return window.addEventListener(Bf,e),()=>window.removeEventListener(Bf,e)},[]),e}function Gf(){let e=s(),{toast:t,refreshHub:n,setTab:r,state:a}=E(),o=_e(a.hub?.account),[c,l]=(0,L.useState)(`password`),[u,d]=(0,L.useState)(``),[f,p]=(0,L.useState)(``),[m,h]=(0,L.useState)(!1),[g,_]=(0,L.useState)(null),v=async()=>{Hf(),await n().catch(()=>void 0)},y=async()=>{if(!(u.length<8||u!==f)){h(!0),_(null);try{await M.cloudPassword(u),t(e(`Password set.`)),d(``),p(``),l(`source`)}catch(t){_(e(t.message))}finally{h(!1)}}},b=async()=>{await v(),Nf(r,o.preset)},x=(0,L.useRef)(null);On(x,!0);let S=f.length>0&&f!==u;return(0,R.jsx)(`div`,{className:`fixed inset-0 z-50 flex items-end justify-center bg-black/40 backdrop-blur-[2px] sm:items-center`,role:`dialog`,"aria-modal":`true`,children:(0,R.jsxs)(`div`,{ref:x,className:`safe-bottom w-full max-w-[520px] rounded-t-[28px] bg-bg p-6 shadow-2xl sm:rounded-[28px]`,children:[(0,R.jsxs)(`div`,{className:`mb-4 flex gap-1`,children:[(0,R.jsx)(`span`,{className:i(`h-1.5 w-5 rounded-full bg-accent`)}),(0,R.jsx)(`span`,{className:i(`h-1.5 rounded-full transition-all`,c===`source`?`w-5 bg-accent`:`w-1.5 bg-border`)})]}),c===`password`?(0,R.jsxs)(`form`,{className:`space-y-4`,onSubmit:e=>{e.preventDefault(),y()},children:[(0,R.jsxs)(`div`,{className:`flex items-start gap-3`,children:[(0,R.jsx)(`span`,{className:`flex h-11 w-11 shrink-0 items-center justify-center rounded-2xl bg-accent/12 text-accent`,children:(0,R.jsx)(xt,{size:20})}),(0,R.jsxs)(`div`,{children:[(0,R.jsx)(`h2`,{className:`text-[20px] font-bold tracking-tight`,children:e(`Set a password`)}),(0,R.jsx)(`p`,{className:`mt-1 text-[13.5px] leading-relaxed text-muted`,children:e(`Your account is in. With a password, your phone and your other computers sign in at once, without waiting for a code. Optional; you can set one later under Account.`)})]})]}),(0,R.jsxs)(`div`,{className:`space-y-2`,children:[(0,R.jsx)(`input`,{type:`password`,value:u,onChange:e=>d(e.target.value),autoComplete:`new-password`,autoFocus:!0,placeholder:e(`At least 8 characters`),className:Ie}),(0,R.jsx)(`input`,{type:`password`,value:f,onChange:e=>p(e.target.value),autoComplete:`new-password`,placeholder:e(`Once more`),className:i(Ie,S&&`border-rose-400`)}),S&&(0,R.jsx)(`p`,{className:`text-[12px] text-rose-600 dark:text-rose-300`,children:e(`The two do not match.`)})]}),g&&(0,R.jsx)(`div`,{className:`rounded-2xl bg-rose-500/12 px-3 py-2 text-[12.5px] text-rose-700 dark:text-rose-300`,children:g}),(0,R.jsxs)(`div`,{className:`flex gap-2`,children:[(0,R.jsx)(`button`,{type:`button`,disabled:m,onClick:()=>l(`source`),className:je,children:e(`Skip`)}),(0,R.jsxs)(`button`,{type:`submit`,disabled:m||u.length<8||u!==f,className:i(Ne,`flex-1 py-3`),children:[m?(0,R.jsx)(A,{size:15,className:`animate-spin`}):null,` `,e(`Set the password`),` `,(0,R.jsx)(qe,{size:16})]})]})]}):(0,R.jsxs)(`div`,{className:`space-y-4`,children:[(0,R.jsxs)(`div`,{className:`flex items-start gap-3`,children:[(0,R.jsx)(`span`,{className:`flex h-11 w-11 shrink-0 items-center justify-center rounded-2xl bg-accent/12 text-accent`,children:(0,R.jsx)(ot,{size:20})}),(0,R.jsxs)(`div`,{children:[(0,R.jsx)(`h2`,{className:`text-[20px] font-bold tracking-tight`,children:e(`Which model answers?`)}),(0,R.jsx)(`p`,{className:`mt-1 text-[13.5px] leading-relaxed text-muted`,children:e(`Your account already brings one. You can add your own API key as well and switch at any time.`)})]})]}),(0,R.jsxs)(`ul`,{className:`space-y-2 text-[13px] leading-snug`,children:[(0,R.jsxs)(`li`,{className:`flex items-start gap-2.5 rounded-2xl bg-surface-2 px-3 py-2.5`,children:[(0,R.jsx)(ot,{size:16,className:`mt-0.5 shrink-0 text-accent`}),(0,R.jsxs)(`span`,{children:[(0,R.jsx)(`span`,{className:`font-medium`,children:e(`Use the nanoMuse Cloud model`)}),(0,R.jsx)(`span`,{className:`block text-muted`,children:e(`DeepSeek for the chat and Qwen for the hands, with a free allowance per account paid by the developer. Nothing to configure.`)})]})]}),(0,R.jsxs)(`li`,{className:`flex items-start gap-2.5 rounded-2xl bg-surface-2 px-3 py-2.5`,children:[(0,R.jsx)(xt,{size:16,className:`mt-0.5 shrink-0 text-accent`}),(0,R.jsxs)(`span`,{children:[(0,R.jsx)(`span`,{className:`font-medium`,children:e(`I have my own API key`)}),(0,R.jsx)(`span`,{className:`block text-muted`,children:o.preset===`qwen`?e(`Alibaba Cloud Bailian first (one key covers chat, the hands, pictures and clips), then DeepSeek, Kimi, Zhipu, OpenAI, OpenRouter and any OpenAI-compatible endpoint. The key stays on this device.`):e(`OpenRouter first (one account, one key, pay as you go), then OpenAI, Anthropic, Gemini, DeepSeek and any OpenAI-compatible endpoint. The key stays on this device.`)})]})]}),(0,R.jsxs)(`li`,{className:`flex items-start gap-2.5 rounded-2xl bg-surface-2 px-3 py-2.5`,children:[(0,R.jsx)(wt,{size:16,className:`mt-0.5 shrink-0 text-accent`}),(0,R.jsxs)(`span`,{children:[(0,R.jsx)(`span`,{className:`font-medium`,children:e(`Sign in with a plan you already pay for`)}),(0,R.jsx)(`span`,{className:`block text-muted`,children:e(`A ChatGPT plan signs in from Connections and answers the chat and the hands. Pictures and clips still want a key.`)})]})]})]}),(0,R.jsxs)(`div`,{className:`flex gap-2`,children:[(0,R.jsx)(`button`,{type:`button`,disabled:m,onClick:()=>void b(),className:je,children:e(`I have my own API key`)}),(0,R.jsxs)(`button`,{type:`button`,disabled:m,onClick:()=>void v(),className:i(Ne,`flex-1 py-3`),children:[e(`Use the nanoMuse Cloud model`),` `,(0,R.jsx)(qe,{size:16})]})]})]})]})})}var Kf=`nanomuse_devtools`;function qf(){try{return localStorage.getItem(Kf)===`1`}catch{return!1}}var Jf=qf(),Yf=new Set;function Xf(){return Jf}function Zf(e){Jf=e;try{localStorage.setItem(Kf,e?`1`:`0`)}catch{}Yf.forEach(e=>e())}function Qf(e){return Yf.add(e),()=>Yf.delete(e)}function $f(){return(0,L.useSyncExternalStore)(Qf,Xf,Xf)}function ep(e,t,n){if(!n.signedIn||n.chatOnCloud||n.deviceChat)return;let r=e[t];if(r?.type===`notice`&&r.level===`error`&&r.code&&r.code!==`allowance`&&!r.model_used)for(let n=t-1;n>=0;n--){let t=e[n];if(t?.type===`user`){let e=(t.files??[]).map(e=>e.path);return t.text||e.length>0?{text:t.text,files:e}:void 0}}}var tp=[`idle`,`working`,`waiting`,`happy`,`error`];function np({event:e,name:t=`nanoMuse`}){let n=s(),{toast:r}=E(),[a,o]=(0,L.useState)(null),c=e.cost??{},l=e.candidates??[null,null,null,null],u=e.moods??{},d=e.clips??{},f=async(e,t)=>{o(e);try{await t()}catch(e){r(e.message)}finally{o(null)}},p=e.stage===`estimate`||e.stage===`drawing`||e.stage===`choose`||e.stage===`posing`||e.stage===`animating`,m=c.clips?n(`{n} pictures and {c} clips`,{n:c.pictures??8,c:c.clips}):n(`{n} pictures`,{n:c.pictures??8}),g=(()=>{if(c.cloud===!1)return n(`{what}, made with your own key at your provider's prices.`,{what:m});if(c.error)return n(`The cost could not be checked: {error}`,{error:c.error});if(typeof c.cny!=`number`)return n(`Checking the cost…`);if(c.unlimited)return n(`About ¥{cny} for {what}; your account has no limit.`,{cny:c.cny.toFixed(2),what:m});let e=typeof c.left_cny==`number`?c.left_cny.toFixed(2):`?`;return c.affordable===!1?n(`About ¥{cny} for {what}, more than the ¥{left} left in your allowance.`,{cny:c.cny.toFixed(2),what:m,left:e}):n(`About ¥{cny} for {what}; ¥{left} left in your allowance.`,{cny:c.cny.toFixed(2),what:m,left:e})})();return(0,R.jsx)(`div`,{className:`rise flex justify-start pr-8`,children:(0,R.jsxs)(`div`,{className:i(`w-full max-w-[360px] overflow-hidden rounded-3xl rounded-tl-lg border bg-surface shadow-sm`,p?`border-accent/50`:`border-border/70`),children:[(0,R.jsxs)(`div`,{className:`flex items-start gap-3 px-4 pt-3.5 pb-2`,children:[(0,R.jsx)(`div`,{className:i(`mt-0.5 rounded-full p-2`,p?`bg-accent/12 text-accent`:`bg-surface-2 text-fg/80`),children:(0,R.jsx)(nn,{size:18})}),(0,R.jsxs)(`div`,{className:`min-w-0 flex-1`,children:[(0,R.jsxs)(`div`,{className:`text-[12.5px] font-medium text-muted`,children:[e.stage===`estimate`&&n(`A new look for {name}`,{name:t}),e.stage===`drawing`&&n(`Drawing four to choose from…`),e.stage===`choose`&&n(`Pick one: tap it, or say which`),e.stage===`posing`&&n(`Drawing the poses…`),e.stage===`animating`&&n(`The new look is on; making the clips…`),e.stage===`done`&&n(`The new look is on`),e.stage===`cancelled`&&n(`Not this time`),e.stage===`failed`&&n(`That did not work`)]}),(0,R.jsx)(`div`,{className:`mt-0.5 text-[14px] leading-snug`,children:e.description}),e.reference&&(0,R.jsxs)(`div`,{className:`mt-1.5 flex items-center gap-2 text-[12px] text-muted`,children:[(0,R.jsx)(`img`,{src:h(e.reference),alt:``,draggable:!1,className:`h-9 w-9 rounded-lg object-cover`}),n(`drawn from the picture you attached`)]})]})]}),e.stage===`estimate`&&(0,R.jsxs)(`div`,{className:`px-4 pb-3.5 space-y-2.5`,children:[(0,R.jsx)(`p`,{className:`text-[12.5px] text-muted`,children:g}),(0,R.jsxs)(`div`,{className:`flex gap-2`,children:[(0,R.jsxs)(`button`,{type:`button`,disabled:a!==null||c.cloud!==!1&&typeof c.cny!=`number`&&!c.error,onClick:()=>f(`start`,()=>M.avatarStart(e.session)),className:i(`flex items-center justify-center gap-1.5 rounded-2xl bg-accent text-accent-fg px-4 py-2.5 text-[14px] font-medium disabled:opacity-40`,`inline-flex items-center gap-1.5 py-2`),children:[a===`start`?(0,R.jsx)(A,{size:14,className:`animate-spin`}):(0,R.jsx)(nn,{size:14}),` `,n(`Draw`)]}),(0,R.jsxs)(`button`,{type:`button`,disabled:a!==null,onClick:()=>f(`cancel`,()=>M.avatarCancel(e.session)),className:i(`flex items-center justify-center gap-1.5 rounded-2xl border border-border px-4 py-2.5 text-[14px] font-medium text-muted disabled:opacity-40`,`inline-flex items-center gap-1.5`),children:[(0,R.jsx)(Fe,{size:14}),` `,n(`Not now`)]})]})]}),(e.stage===`drawing`||e.stage===`choose`)&&(0,R.jsxs)(`div`,{className:`px-4 pb-3.5 space-y-2.5`,children:[(0,R.jsx)(`div`,{className:`grid grid-cols-2 gap-2`,children:l.map((t,r)=>(0,R.jsxs)(`button`,{type:`button`,disabled:!t||e.stage!==`choose`||a!==null,onClick:()=>f(`pick${r}`,()=>M.avatarChoose(e.session,r)),"aria-label":n(`Candidate {n}`,{n:r+1}),className:i(`relative aspect-square overflow-hidden rounded-2xl bg-[#f1efeb] transition`,t&&e.stage===`choose`?`hover:ring-2 hover:ring-accent`:``),children:[t?(0,R.jsx)(`img`,{src:h(t),alt:``,draggable:!1,className:`h-full w-full object-cover`}):(0,R.jsx)(`span`,{className:`absolute inset-0 flex items-center justify-center text-muted`,children:e.stage===`drawing`?(0,R.jsx)(A,{size:20,className:`animate-spin`}):(0,R.jsx)(Fe,{size:18,className:`opacity-50`})}),a===`pick${r}`&&(0,R.jsx)(`span`,{className:`absolute inset-0 flex items-center justify-center bg-bg/60`,children:(0,R.jsx)(A,{size:20,className:`animate-spin`})}),(0,R.jsx)(`span`,{className:`absolute left-1.5 top-1.5 rounded-full bg-bg/80 px-1.5 text-[10.5px] font-semibold text-fg/80`,children:r+1})]},r))}),e.errors&&e.errors.length>0&&(0,R.jsx)(`p`,{className:`text-[12px] text-rose-600 dark:text-rose-300`,children:n(e.errors[0])}),e.stage===`choose`&&(0,R.jsxs)(`div`,{className:`flex gap-2`,children:[(0,R.jsxs)(`button`,{type:`button`,disabled:a!==null,onClick:()=>f(`redraw`,()=>M.avatarStart(e.session)),className:i(`flex items-center justify-center gap-1.5 rounded-2xl border border-border px-4 py-2.5 text-[14px] font-medium text-muted disabled:opacity-40`,`inline-flex items-center gap-1.5`),children:[a===`redraw`?(0,R.jsx)(A,{size:14,className:`animate-spin`}):(0,R.jsx)(Re,{size:14}),` `,n(`Redraw`)]}),(0,R.jsxs)(`button`,{type:`button`,disabled:a!==null,onClick:()=>f(`cancel`,()=>M.avatarCancel(e.session)),className:i(`flex items-center justify-center gap-1.5 rounded-2xl border border-border px-4 py-2.5 text-[14px] font-medium text-muted disabled:opacity-40`,`inline-flex items-center gap-1.5`),children:[(0,R.jsx)(Fe,{size:14}),` `,n(`Not now`)]})]})]}),(e.stage===`posing`||e.stage===`animating`||e.stage===`done`)&&(0,R.jsxs)(`div`,{className:`px-4 pb-3.5 space-y-2`,children:[(0,R.jsx)(`div`,{className:`flex gap-1.5`,children:tp.map(t=>(0,R.jsxs)(`div`,{className:`relative aspect-square flex-1 overflow-hidden rounded-xl bg-[#f1efeb]`,children:[d[t]?(0,R.jsx)(`video`,{src:h(d[t]),poster:u[t]?h(u[t]):void 0,autoPlay:!0,loop:!0,muted:!0,playsInline:!0,disablePictureInPicture:!0,className:`h-full w-full object-cover`},d[t]):u[t]?(0,R.jsx)(`img`,{src:h(u[t]),alt:``,draggable:!1,className:`h-full w-full object-cover`}):(0,R.jsx)(`span`,{className:`absolute inset-0 flex items-center justify-center text-muted`,children:(0,R.jsx)(A,{size:14,className:`animate-spin`})}),e.stage===`animating`&&u[t]&&!d[t]&&t!==`error`&&(0,R.jsx)(`span`,{className:`absolute bottom-1 right-1 rounded-full bg-white/80 p-0.5 text-muted`,children:(0,R.jsx)(A,{size:10,className:`animate-spin`})})]},t))}),e.stage===`done`?(0,R.jsxs)(`p`,{className:`flex items-center gap-1.5 text-[12.5px] text-muted`,children:[(0,R.jsx)(ke,{size:14,className:`text-emerald-600`}),` `,n(`Idle, working, waiting, happy, sorry: the face follows what {name} is doing.`,{name:t})]}):e.stage===`animating`?(0,R.jsx)(`p`,{className:`text-[12.5px] text-muted`,children:n(`The face is already on; four short clips are being made from the poses, a few minutes.`)}):(0,R.jsx)(`p`,{className:`text-[12.5px] text-muted`,children:n(`Four more pictures from the one you picked; this takes a minute or two.`)}),e.errors&&e.errors.length>0&&e.stage===`done`&&(0,R.jsxs)(`p`,{className:`text-[12px] text-muted`,children:[e.errors.some(e=>!e.includes(` clip:`))&&n(`Some poses could not be drawn and show the idle picture instead.`),` `,e.errors.some(e=>e.includes(` clip:`))&&n(`Some clips could not be made; those moods stay still.`)]})]}),(e.stage===`failed`||e.stage===`cancelled`)&&e.message&&(0,R.jsx)(`p`,{className:`px-4 pb-3.5 text-[12.5px] text-muted`,children:n(e.message)})]})})}function rp(){let e=ip();if(!e||typeof e.keepRunning!=`function`)return null;try{return JSON.parse(e.keepRunning())}catch{return null}}function ip(){return window.NanoMuseAndroid??null}function ap(){let e=ip();return!!e&&typeof e.takeOverBrowser==`function`&&(typeof e.hasBrowser!=`function`||e.hasBrowser())}function op(){let e=ip();if(!e||typeof e.accessibilityState!=`function`)return null;let t=e.accessibilityState();return t===`on`||t===`off`||t===`unsupported`?t:null}function sp(e,t=15){switch(e){case`web_search`:return(0,R.jsx)(qt,{size:t});case`web_fetch`:case`browser`:return(0,R.jsx)(gt,{size:t});case`files`:return(0,R.jsx)(mt,{size:t});case`shell`:return(0,R.jsx)(dn,{size:t});case`python_execute`:return(0,R.jsx)(ct,{size:t});case`read_emails`:case`send_email`:return(0,R.jsx)(Et,{size:t});case`goals`:return(0,R.jsx)(un,{size:t});case`remember`:case`recall`:case`forget`:return(0,R.jsx)(Qe,{size:t});case`ask_user`:return(0,R.jsx)(kt,{size:t});case`devices`:return(0,R.jsx)(It,{size:t});case`device_shell`:return(0,R.jsx)(dn,{size:t});case`device_files`:case`device_get`:case`device_put`:return(0,R.jsx)(mt,{size:t});case`device_open`:return(0,R.jsx)(Ae,{size:t});case`device_screen`:return(0,R.jsx)(Lt,{size:t});case`device_notify`:return(0,R.jsx)(Xe,{size:t});case`delegate`:return(0,R.jsx)(Jt,{size:t});case`computer_screen`:return(0,R.jsx)(Lt,{size:t});case`computer_act`:return(0,R.jsx)(zt,{size:t});case`computer_task`:case`computer_app`:return(0,R.jsx)(vt,{size:t});case`phone_screen`:case`phone_act`:case`phone_task`:return(0,R.jsx)(tn,{size:t});default:return(0,R.jsx)(Ze,{size:t})}}function cp({device:e,className:t}){let n=s();return(0,R.jsxs)(`span`,{className:i(`inline-flex max-w-full items-center gap-1 rounded-full bg-accent/12 px-2 py-0.5 text-[11px] font-medium text-accent`,t),children:[(0,R.jsx)(It,{size:11,className:`shrink-0`}),` `,(0,R.jsx)(`span`,{className:`truncate`,children:n(`on {device}`,{device:e})})]})}var lp={safe:`bg-emerald-500/15 text-emerald-700 dark:text-emerald-300`,moderate:`bg-amber-500/15 text-amber-700 dark:text-amber-300`,sensitive:`bg-rose-500/15 text-rose-700 dark:text-rose-300`};function up({risk:e}){return(0,R.jsx)(`span`,{className:i(`px-2 py-0.5 rounded-full text-[11px] font-semibold uppercase tracking-wide`,lp[e]),children:_(e)})}function dp({args:e}){let t=Object.entries(e??{}).filter(([,e])=>e!=null&&e!==``);return t.length?(0,R.jsx)(`dl`,{className:`mt-2 grid grid-cols-[auto_1fr] gap-x-3 gap-y-1 text-[13px]`,children:t.map(([e,t])=>(0,R.jsxs)(`div`,{className:`contents`,children:[(0,R.jsx)(`dt`,{className:`text-muted`,children:e}),(0,R.jsx)(`dd`,{className:`break-words whitespace-pre-wrap font-mono text-[12.5px] leading-snug`,children:String(t)})]},e))}):null}function fp({event:e}){let[t,n]=(0,L.useState)(!1),r=e.status===`running`?(0,R.jsx)(A,{size:14,className:`animate-spin text-accent`}):e.status===`ok`?(0,R.jsx)(ke,{size:14,className:`text-emerald-500`}):e.status===`blocked`?(0,R.jsx)(Ye,{size:14,className:`text-rose-500`}):(0,R.jsx)(Fe,{size:14,className:`text-rose-500`});return(0,R.jsx)(`div`,{className:`rise flex justify-start pr-8`,children:(0,R.jsxs)(`button`,{type:`button`,onClick:()=>n(e=>!e),className:`max-w-full text-left rounded-2xl bg-surface-2/80 border border-border/60 px-3 py-1.5 text-[13px] text-muted hover:text-fg transition`,children:[(0,R.jsxs)(`span`,{className:`flex items-center gap-2`,children:[(0,R.jsx)(`span`,{className:`text-muted`,children:sp(e.tool)}),(0,R.jsx)(`span`,{className:`truncate flex-1`,children:e.title||e.summary||e.tool}),e.device&&(0,R.jsx)(cp,{device:e.device}),r,e.output?t?(0,R.jsx)(Me,{size:13}):(0,R.jsx)(rt,{size:13}):null]}),t&&(0,R.jsxs)(`div`,{className:`mt-2 text-fg`,children:[(0,R.jsx)(dp,{args:e.args}),e.output&&(0,R.jsx)(`pre`,{className:`mt-2 max-h-52 overflow-auto whitespace-pre-wrap break-words rounded-xl bg-bg p-2 text-[12px] leading-snug`,children:e.output})]})]})})}function pp(e,t,n){if(!t)return e.replace(/_/g,` `);switch(e){case`shell`:return _(`{what} commands`,{what:t.split(`,`).join(`, `)});case`send_email`:return _(`email to {who}`,{who:t.split(`,`).join(`, `)});case`remote_control`:return _(`the device {name}`,{name:typeof n?.device==`string`&&n.device?n.device:t});case`computer_app`:return _(`the hands in {app}`,{app:typeof n?.name==`string`&&n.name?n.name:t});default:return t}}function mp(e,t,n,r){switch(e){case`once`:return _(`Once`);case`conversation`:return _(`For this conversation`);case`session`:return _(`Until restart`);case`24h`:return _(`For 24 hours`);case`always`:return _(`Always for {subject}`,{subject:pp(t,n,r)});default:return e}}function hp({event:e,name:t=`nanoMuse`,onDecide:n}){let[r,a]=(0,L.useState)(!1),[o,c]=(0,L.useState)(!1),[l,d]=(0,L.useState)(!1),[f,p]=(0,L.useState)(!1),m=(e,t)=>{f||(p(!0),Promise.resolve(n(e,t)).finally(()=>p(!1)))},h=(0,L.useRef)(null),g=(0,L.useRef)(null),_=s(),y=e.status===`pending`,b=e.risk===`sensitive`,x=(e.grant_options??[`once`]).filter(e=>e!==`once`),S=e.egress_target||([`web_fetch`,`browser`,`web_search`].includes(e.tool)?e.target:null),C=e.tool===`send_email`?e.target:null,w=Object.values(e.args??{}).some(e=>e!=null&&e!==``);return(0,L.useEffect)(()=>{let e=g.current;e&&!r&&d(e.scrollHeight>e.clientHeight+2)},[e.args,r]),(0,L.useEffect)(()=>{(r||o)&&h.current?.scrollIntoView({block:`end`,behavior:`smooth`})},[r,o]),(0,R.jsx)(`div`,{className:`rise flex justify-start`,ref:h,children:(0,R.jsxs)(`div`,{className:i(`w-full max-w-[600px] overflow-hidden rounded-[22px] bg-surface shadow-[0_2px_12px_rgba(0,0,0,0.12)] dark:border dark:border-border dark:shadow-none`,y&&b&&`border border-rose-400/60`),children:[(0,R.jsxs)(`div`,{className:`flex items-start gap-3 px-4 pt-4 pb-2`,children:[(0,R.jsx)(`div`,{className:i(`flex h-10 w-10 shrink-0 items-center justify-center rounded-full`,b?`bg-rose-500/12 text-rose-500`:`bg-surface-2 text-fg`),children:b?(0,R.jsx)(Zt,{size:22}):sp(e.tool,22)}),(0,R.jsxs)(`div`,{className:`min-w-0 flex-1`,children:[(0,R.jsxs)(`div`,{className:`flex flex-wrap items-center gap-1.5 text-[12.5px] font-medium text-muted`,children:[(0,R.jsx)(`span`,{children:e.remote?_(`{name} on {device} wants to`,{name:t,device:e.remote.name}):_(`{name} wants to`,{name:t})}),e.remote&&(0,R.jsx)(cp,{device:e.remote.name})]}),(0,R.jsx)(`div`,{className:`mt-0.5 break-words text-[17px] font-semibold leading-[22px]`,children:e.summary}),S?(0,R.jsxs)(`div`,{className:`mt-1 flex items-center gap-1 text-[13px] text-muted`,children:[(0,R.jsx)(gt,{size:12}),` `,(0,R.jsx)(`span`,{className:`truncate`,children:_(`at {host}`,{host:S})})]}):C?(0,R.jsxs)(`div`,{className:`mt-1 flex items-center gap-1 text-[13px] text-muted`,children:[(0,R.jsx)(Et,{size:12}),` `,(0,R.jsx)(`span`,{className:`truncate`,children:_(`to {recipient}`,{recipient:C})})]}):null,e.purpose&&(0,R.jsx)(`div`,{className:`mt-1.5 break-words text-[13px] leading-snug text-muted line-clamp-2`,children:e.purpose}),b&&(0,R.jsx)(`div`,{className:`mt-1.5`,children:(0,R.jsx)(up,{risk:e.risk})})]})]}),e.warnings?.length>0&&(0,R.jsx)(`div`,{className:`space-y-1 px-4 pb-2`,children:e.warnings.map(e=>(0,R.jsxs)(`div`,{className:`flex items-start gap-1.5 text-[12.5px] text-rose-600 dark:text-rose-300`,children:[(0,R.jsx)(pn,{size:13,className:`mt-0.5 shrink-0`}),` `,(0,R.jsx)(`span`,{children:_(e)})]},e))}),(w||e.reasons?.length>0)&&(0,R.jsx)(`div`,{className:`px-4 pb-2`,children:(0,R.jsxs)(`div`,{className:`rounded-xl bg-surface-2 px-3 py-2.5`,children:[(0,R.jsx)(`div`,{className:`text-[11px] font-medium text-muted`,children:_(`Exactly what will run`)}),(0,R.jsxs)(`div`,{ref:g,className:i(`-mt-1`,!r&&`max-h-40 overflow-hidden`),children:[(0,R.jsx)(dp,{args:e.args}),e.reasons?.length>0&&(0,R.jsx)(`div`,{className:`mt-1.5 text-[12px] text-muted`,children:_(`Why it asks: {reasons}`,{reasons:e.reasons.map(v).join(` · `)})})]}),(l||r)&&(0,R.jsxs)(`button`,{type:`button`,className:`mt-1 flex items-center gap-1 text-[12.5px] text-accent`,onClick:()=>a(e=>!e),children:[r?(0,R.jsx)(Me,{size:13}):(0,R.jsx)(rt,{size:13}),` `,_(r?`Fewer options`:`Show all`)]})]})}),y?(0,R.jsxs)(`div`,{className:`flex flex-col gap-2 px-4 pb-4 pt-2`,children:[(0,R.jsx)(`button`,{type:`button`,onClick:()=>m(!0,`once`),disabled:f,className:`h-[46px] w-full rounded-full bg-accent text-[15px] font-semibold text-accent-fg transition active:scale-[0.98] disabled:opacity-60`,children:_(`Allow once`)}),x.filter(e=>o||e===`conversation`||e===`always`).map(t=>(0,R.jsx)(`button`,{type:`button`,onClick:()=>m(!0,t),disabled:f,className:`h-11 w-full truncate rounded-full bg-surface-2 px-4 text-[15px] font-medium transition active:scale-[0.98] disabled:opacity-60`,children:mp(t,e.tool,e.target,e.args)},t)),(0,R.jsx)(`button`,{type:`button`,onClick:()=>m(!1,`once`),disabled:f,className:`h-11 w-full rounded-full bg-surface-2 text-[15px] font-medium transition active:scale-[0.98] disabled:opacity-60`,children:_(`Deny`)}),x.length===0?(0,R.jsx)(`div`,{className:`text-center text-[12px] text-muted`,children:_(`This kind of action is approved one at a time.`)}):!o&&x.some(e=>e!==`conversation`&&e!==`always`)&&(0,R.jsx)(`button`,{type:`button`,className:`self-center text-[12.5px] text-muted`,onClick:()=>c(!0),children:_(`Allow {subject} for longer…`,{subject:pp(e.tool,e.target,e.args)})})]}):(0,R.jsxs)(`div`,{className:i(`flex items-center gap-1.5 border-t border-border px-4 py-2.5 text-[13px] font-medium`,e.status===`approved`?`text-emerald-600 dark:text-emerald-300`:`text-muted`),children:[e.status===`approved`?(0,R.jsx)(ke,{size:15}):(0,R.jsx)(Fe,{size:15}),e.status===`approved`?`${_(`Approved`)}${e.scope&&e.scope!==`once`?` · ${mp(e.scope,e.tool,e.target).toLowerCase()}`:``}`:e.status===`denied`?_(`Denied`):_(`Expired without an answer`),(0,R.jsx)(`span`,{className:`ml-auto font-normal`,children:u(e.updated_ts??e.ts)})]})]})})}function gp({event:e,name:t}){let n=s();return(0,R.jsx)(`div`,{className:`rise flex justify-start pr-8`,children:(0,R.jsxs)(`div`,{className:`max-w-full rounded-[20px] rounded-bl-md border border-accent/30 bg-surface px-4 py-3`,children:[(0,R.jsxs)(`div`,{className:`flex items-center gap-1.5 text-[12.5px] font-medium text-accent`,children:[(0,R.jsx)(kt,{size:14}),` `,n(`{name} asks`,{name:t})]}),(0,R.jsx)(`div`,{className:`mt-1 text-[15px] leading-snug whitespace-pre-wrap break-words`,children:e.text}),e.status===`pending`&&(0,R.jsx)(`div`,{className:`mt-1.5 text-[12.5px] text-muted`,children:n(`Reply below to continue.`)}),e.status===`answered`&&e.answer&&(0,R.jsxs)(`div`,{className:`mt-2 text-[13px] text-muted border-t border-border pt-2`,children:[n(`You:`),` `,(0,R.jsx)(`span`,{className:`text-fg`,children:e.answer})]})]})})}function _p(e){return e.source===`reminder`||e.source===`memory`?t(e.text):_(e.text,e.vars)}function vp({event:e,onCloudRetry:t}){let n=s(),[r,a]=(0,L.useState)(!1),[o,c]=(0,L.useState)(!1),[l,u]=(0,L.useState)(null),d=e.detail&&e.detail!==e.text?e.detail:null;return e.code===`allowance`&&e.allowance?(0,R.jsxs)(`div`,{className:`rise flex flex-col items-center gap-2 px-6`,children:[(0,R.jsx)(`div`,{className:`max-w-full rounded-2xl bg-amber-500/12 px-3 py-1.5 text-center text-[12.5px] leading-snug text-amber-700 dark:text-amber-300`,children:n(e.text)}),(0,R.jsx)(`div`,{className:`w-full max-w-[520px]`,children:(0,R.jsx)(Ff,{info:e.allowance,exhausted:!0,compact:!0})})]}):(0,R.jsx)(`div`,{className:`rise flex justify-center px-6`,children:(0,R.jsxs)(`div`,{className:i(`max-w-full rounded-2xl px-3 py-1.5 text-center text-[12.5px] leading-snug`,e.level===`info`&&`bg-surface-2/70 text-muted`,e.level===`warn`&&`bg-amber-500/12 text-amber-700 dark:text-amber-300`,e.level===`error`&&`bg-rose-500/12 text-rose-700 dark:text-rose-300`),children:[_p(e),d&&(0,R.jsxs)(R.Fragment,{children:[` `,(0,R.jsx)(`button`,{type:`button`,onClick:()=>a(e=>!e),className:`underline decoration-dotted underline-offset-2 opacity-70 hover:opacity-100`,children:n(r?`Hide details`:`Details`)}),r&&(0,R.jsx)(`div`,{className:`mt-1.5 break-all text-left font-mono text-[11px] opacity-80`,children:d})]}),t&&(0,R.jsxs)(`div`,{className:`mt-1.5 flex flex-col items-center gap-1`,children:[(0,R.jsx)(`button`,{type:`button`,disabled:o,onClick:()=>{t&&(c(!0),u(null),t().catch(e=>u(n(e.message||`Could not send`))).finally(()=>c(!1)))},className:`rounded-full bg-accent/12 px-3 py-1 text-[12px] font-medium text-accent disabled:opacity-50`,children:n(`Use nanoMuse Cloud this time`)}),l&&(0,R.jsx)(`div`,{className:`text-[12px] text-rose-700 dark:text-rose-300`,children:l})]})]})})}function yp({event:e,onOpen:t}){let[r,i]=(0,L.useState)(!1),a=s(),o=e.status===`live`,c=e.url;try{c=new URL(e.url).host}catch{}return(0,R.jsx)(`div`,{className:`rise flex justify-start pr-8`,children:(0,R.jsxs)(`button`,{type:`button`,onClick:()=>t(e.id),"aria-label":a(`Browser: {title}`,{title:e.title||c}),className:`w-full max-w-[340px] overflow-hidden rounded-3xl rounded-tl-lg border border-border bg-surface shadow-sm hover:bg-surface-2 transition text-left`,children:[(0,R.jsxs)(`div`,{className:`relative aspect-[16/10] bg-surface-2`,children:[r?(0,R.jsxs)(`div`,{className:`absolute inset-0 flex flex-col items-center justify-center gap-1 text-muted`,children:[(0,R.jsx)(gt,{size:22}),(0,R.jsx)(`span`,{className:`text-[12px]`,children:a(`Frame no longer available`)})]}):(0,R.jsx)(`img`,{src:n(e.thread,e.frame),alt:e.title||c,onError:()=>i(!0),className:`absolute inset-0 h-full w-full object-cover object-top`},e.frame),(0,R.jsx)(`div`,{className:`absolute left-2.5 top-2.5 flex items-center gap-1.5 rounded-full bg-black/60 px-2 py-0.5 text-[10.5px] font-semibold text-white`,children:o?(0,R.jsxs)(R.Fragment,{children:[(0,R.jsx)(`span`,{className:`h-1.5 w-1.5 rounded-full bg-rose-400 animate-pulse`}),` `,a(`LIVE`)]}):(0,R.jsxs)(R.Fragment,{children:[(0,R.jsx)(gt,{size:11}),` `,a(`BROWSER`)]})})]}),(0,R.jsxs)(`div`,{className:`flex items-center gap-2 px-3.5 py-2.5`,children:[(0,R.jsxs)(`div`,{className:`min-w-0 flex-1`,children:[(0,R.jsx)(`div`,{className:`text-[13.5px] font-medium truncate`,children:e.title||c}),(0,R.jsxs)(`div`,{className:`text-[12px] text-muted truncate`,children:[e.by_user&&e.action.startsWith(`You`)?a(`You`)+e.action.slice(3):e.action,` · `,c]})]}),(0,R.jsx)(rt,{size:16,className:`text-muted shrink-0`})]})]})})}function bp({event:e,name:t=`nanoMuse`}){let n=s(),{state:r,toast:a}=E(),[o,c]=(0,L.useState)(!1),[l,d]=(0,L.useState)(!1),f=e.status===`live`,p=e.last,m=[e.app,e.title].filter(Boolean).join(` · `),h=r.holds.find(t=>t.thread===e.thread&&t.tool===`computer`),g=async()=>{c(!0);try{await M.stopHands()}catch{}finally{c(!1)}},_=async()=>{d(!0);try{await M.openHold(e.thread,`computer`)}catch(e){a(e.message)}finally{d(!1)}};return(0,R.jsx)(`div`,{className:`rise flex justify-start pr-8`,children:(0,R.jsxs)(`div`,{className:i(`w-full max-w-[360px] overflow-hidden rounded-3xl rounded-tl-lg border bg-surface shadow-sm`,f?`border-accent/50`:`border-border/70`),children:[(0,R.jsxs)(`div`,{className:`flex items-start gap-3 px-4 pt-3.5 pb-2`,children:[(0,R.jsx)(`div`,{className:i(`mt-0.5 rounded-full p-2`,f?`bg-accent/12 text-accent`:`bg-surface-2 text-fg/80`),children:(0,R.jsx)(vt,{size:18})}),(0,R.jsxs)(`div`,{className:`min-w-0 flex-1`,children:[(0,R.jsxs)(`div`,{className:`flex items-center gap-2 text-[12.5px] font-medium text-muted`,children:[(0,R.jsx)(`span`,{children:f?n(`{name} is using this computer`,{name:t}):e.status===`stopped`?n(`Hands stopped`):n(`Hands done`)}),f&&(0,R.jsxs)(`span`,{className:`flex items-center gap-1 rounded-full bg-accent/12 px-2 py-0.5 text-[10.5px] font-semibold text-accent`,children:[(0,R.jsx)(`span`,{className:`h-1.5 w-1.5 animate-pulse rounded-full bg-accent`}),` `,n(`LIVE`)]})]}),e.text&&(0,R.jsx)(`div`,{className:`mt-0.5 break-words text-[15px] font-semibold leading-snug`,children:e.text}),p?.action&&(0,R.jsxs)(`div`,{className:`mt-1.5 flex items-center gap-1.5 text-[13px] text-fg/90`,children:[(0,R.jsx)(zt,{size:13,className:`shrink-0 text-muted`}),(0,R.jsx)(`span`,{className:`truncate`,children:Tp(p,n)})]}),m&&(0,R.jsx)(`div`,{className:`mt-1 truncate text-[12px] text-muted`,children:m}),e.notice&&(0,R.jsx)(`div`,{className:`mt-1.5 rounded-2xl bg-amber-500/12 px-3 py-1.5 text-[12.5px] text-amber-700 dark:text-amber-300`,children:e.notice}),f&&h&&(0,R.jsx)(xp,{hold:h})]})]}),(0,R.jsxs)(`div`,{className:`flex items-center gap-2 border-t border-border/70 px-4 py-2 text-[12px] text-muted`,children:[(0,R.jsx)(`span`,{children:n(`{n} steps`,{n:e.steps})}),(0,R.jsx)(`span`,{className:`ml-auto`,children:u(e.updated_ts??e.ts)}),f&&!h&&(0,R.jsxs)(`button`,{type:`button`,onClick:()=>void _(),disabled:l,className:`ml-1 inline-flex items-center gap-1.5 rounded-full bg-accent/12 px-3 py-1 text-[12.5px] font-semibold text-accent transition active:scale-95 disabled:opacity-60`,children:[(0,R.jsx)(vt,{size:11}),` `,n(`Take over`)]}),f&&(0,R.jsxs)(`button`,{type:`button`,onClick:()=>void g(),disabled:o,className:`ml-1 inline-flex items-center gap-1.5 rounded-full bg-fg px-3 py-1 text-[12.5px] font-semibold text-bg transition active:scale-95 disabled:opacity-60`,children:[(0,R.jsx)(sn,{size:10,fill:`currentColor`}),` `,n(`Stop`)]})]})]})})}function xp({hold:e,compact:t}){let n=s(),[r,a]=(0,L.useState)(!1),o=async()=>{a(!0);try{await M.doneHold(e.id)}catch{}finally{a(!1)}};return(0,R.jsxs)(`div`,{className:i(`flex items-center gap-2 rounded-2xl bg-amber-500/12 px-3 text-amber-800 dark:text-amber-200`,t?`py-1.5 text-[12.5px]`:`mt-1.5 py-2 text-[13px]`),children:[(0,R.jsx)(vt,{size:14,className:`shrink-0`}),(0,R.jsx)(`span`,{className:`min-w-0 flex-1 leading-snug`,children:Cp(e,n)}),(0,R.jsx)(`button`,{type:`button`,onClick:()=>void o(),disabled:r,className:`shrink-0 rounded-full bg-fg px-3 py-1 text-[12.5px] font-semibold text-bg transition active:scale-95 disabled:opacity-60`,children:r?(0,R.jsx)(A,{size:13,className:`animate-spin`}):n(`Done`)})]})}function Sp(e,t){return t(e===`browser`?`the browser`:e===`phone`?`the phone`:`this computer`)}function Cp(e,t){return e.by===`agent`?e.reason?t(`Your turn: {reason}`,{reason:e.reason}):t(`Your turn`):t(`You took over {thing}`,{thing:Sp(e.tool,t)})}function wp({event:e,name:t=`nanoMuse`}){let n=s(),[r,a]=(0,L.useState)(!1),o=e.status===`on`,c=Sp(e.tool,n),l=async()=>{a(!0);try{await M.doneHold(e.id)}catch{}finally{a(!1)}},d=e.timed_out?n(`{name} waited ten minutes and went on without you.`,{name:t}):e.stale?n(`Ended when the runtime restarted.`):e.by===`agent`?n(`You did it; {name} carried on.`,{name:t}):n(`Handed back; {name} carried on.`,{name:t});return(0,R.jsx)(`div`,{className:`rise flex justify-start pr-8`,children:(0,R.jsxs)(`div`,{className:i(`w-full max-w-[360px] overflow-hidden rounded-3xl rounded-tl-lg border bg-surface shadow-sm`,o?`border-amber-500/50`:`border-border/70 opacity-70`),children:[(0,R.jsxs)(`div`,{className:`flex items-start gap-3 px-4 pt-3.5 pb-3`,children:[(0,R.jsx)(`div`,{className:i(`mt-0.5 rounded-full p-2`,o?`bg-amber-500/15 text-amber-700 dark:text-amber-300`:`bg-surface-2 text-fg/70`),children:(0,R.jsx)(vt,{size:18})}),(0,R.jsxs)(`div`,{className:`min-w-0 flex-1`,children:[(0,R.jsx)(`div`,{className:`text-[12.5px] font-medium text-muted`,children:e.tool===`browser`?n(`The browser`):e.tool===`phone`?n(`The phone`):n(`This computer`)}),(0,R.jsx)(`div`,{className:`mt-0.5 break-words text-[15px] font-semibold leading-snug`,children:e.by===`agent`?n(`Your turn`):n(`You took over {thing}`,{thing:c})}),e.by===`agent`&&e.reason&&(0,R.jsx)(`div`,{className:`mt-1 break-words text-[13.5px] leading-snug text-fg/90`,children:e.reason}),(0,R.jsx)(`div`,{className:`mt-1.5 text-[12.5px] leading-snug text-muted`,children:o?e.by===`agent`?n(`Do this part yourself, then press Done. {name} looks again and carries on from there.`,{name:t}):n(`{name} waits. Press Done when you are finished and it looks again.`,{name:t}):d})]})]}),(0,R.jsxs)(`div`,{className:`flex items-center gap-2 border-t border-border/70 px-4 py-2 text-[12px] text-muted`,children:[(0,R.jsx)(`span`,{children:u(e.ts)}),o&&(0,R.jsxs)(`button`,{type:`button`,onClick:()=>void l(),disabled:r,className:`ml-auto inline-flex items-center gap-1.5 rounded-full bg-fg px-3.5 py-1 text-[12.5px] font-semibold text-bg transition active:scale-95 disabled:opacity-60`,children:[r?(0,R.jsx)(A,{size:13,className:`animate-spin`}):(0,R.jsx)(ke,{size:12}),` `,n(`Done`)]})]})]})})}function Tp(e,t){let n=e.label?`“${e.label}”`:``;switch(e.action){case`click`:return n?t(`Clicked {label}`,{label:n}):t(`Clicked`);case`double_click`:return n?t(`Double-clicked {label}`,{label:n}):t(`Double-clicked`);case`right_click`:case`middle_click`:return n?t(`Right-clicked {label}`,{label:n}):t(`Right-clicked`);case`move`:return n?t(`Pointed at {label}`,{label:n}):t(`Moved the mouse`);case`type`:return t(`Typed {n} characters`,{n:(e.text??``).length});case`key`:return t(`Pressed {keys}`,{keys:(e.keys??[]).join(`+`)});case`scroll`:return t(`Scrolled`);case`drag`:return t(`Dragged`);case`open_app`:return n?t(`Opened {label}`,{label:n}):t(`Opened an application`);case`wait`:return t(`Waited`);default:return e.action??``}}function Ep({event:e,onOpen:t}){let n=s(),a=r(e.name),o=n(a===`html`?`Page`:a===`image`?`Image`:a===`data`?`Data`:a===`code`?`Code`:a===`event`?`Event`:`Document`),c=e.action===`update`?`${o} · ${n(`updated`)}`:o,l=a===`html`||a===`image`;return(0,R.jsx)(`div`,{className:`rise flex justify-start pr-8`,children:(0,R.jsxs)(`button`,{type:`button`,onClick:()=>t(e.path),className:i(`max-w-full overflow-hidden rounded-[20px] border border-border bg-surface text-left shadow-[0_4px_20px_-12px_rgba(0,0,0,0.2)] transition hover:bg-surface-2`,l?`w-[300px]`:``),children:[l&&(0,R.jsx)(Dp,{path:e.path,kind:a}),(0,R.jsxs)(`div`,{className:`flex items-center gap-3 px-4 py-3`,children:[!l&&(0,R.jsx)(`div`,{className:`rounded-2xl bg-accent/12 p-2.5 text-accent`,children:a===`code`?(0,R.jsx)(ct,{size:20}):a===`event`?(0,R.jsx)(tt,{size:20}):(0,R.jsx)(mt,{size:20})}),(0,R.jsxs)(`div`,{className:`min-w-0 flex-1`,children:[(0,R.jsx)(`div`,{className:`text-[11px] font-semibold uppercase tracking-wide text-muted`,children:c}),(0,R.jsx)(`div`,{className:`truncate text-[14.5px] font-medium`,children:e.name}),(0,R.jsx)(`div`,{className:`truncate text-[12px] text-muted`,children:e.path})]}),(0,R.jsx)(rt,{size:16,className:`ml-1 shrink-0 text-muted`})]})]})})}function Dp({path:e,kind:t}){return t===`image`?(0,R.jsx)(`img`,{src:h(e),alt:``,loading:`lazy`,className:`h-40 w-full object-cover`}):(0,R.jsx)(`div`,{className:`pointer-events-none relative h-40 w-full overflow-hidden bg-white`,children:(0,R.jsx)(`iframe`,{title:e,src:h(e),sandbox:``,tabIndex:-1,loading:`lazy`,scrolling:`no`,className:`absolute left-0 top-0 h-[480px] w-[900px] origin-top-left scale-[0.3333] border-0`})})}function Op({open:e,onClose:t,title:n,children:r,footer:i}){let a=s(),o=(0,L.useRef)(null);return On(o,e),(0,L.useEffect)(()=>{if(!e)return;let n=e=>e.key===`Escape`&&t();return window.addEventListener(`keydown`,n),()=>window.removeEventListener(`keydown`,n)},[e,t]),e?(0,R.jsxs)(`div`,{className:`fixed inset-0 z-50 flex items-end sm:items-center sm:justify-center`,children:[(0,R.jsx)(`div`,{className:`absolute inset-0 bg-black/45 backdrop-blur-[2px]`,onClick:t}),(0,R.jsxs)(`div`,{ref:o,role:`dialog`,"aria-modal":`true`,className:`sheet-in relative w-full sm:max-w-lg max-h-[92dvh] flex flex-col bg-surface rounded-t-3xl sm:rounded-3xl shadow-2xl border border-border`,children:[(0,R.jsxs)(`div`,{className:`flex items-center gap-3 px-5 pt-4 pb-2`,children:[(0,R.jsx)(`div`,{className:`sm:hidden absolute left-1/2 -translate-x-1/2 top-2 h-1 w-10 rounded-full bg-border`}),(0,R.jsx)(`div`,{className:`flex-1 font-semibold text-[17px] mt-1`,children:n}),(0,R.jsx)(`button`,{type:`button`,onClick:t,"aria-label":a(`Close`),className:`p-2 -mr-2 rounded-full text-muted hover:bg-surface-2`,children:(0,R.jsx)(Fe,{size:20})})]}),(0,R.jsx)(`div`,{className:`flex-1 overflow-y-auto px-5 pb-4`,children:r}),i&&(0,R.jsx)(`div`,{className:`px-5 pt-2 pb-4 safe-bottom border-t border-border`,children:i})]})]}):null}var kp=1e3;function Ap({thread:e,eventId:t,onClose:r}){let{state:a,toast:o}=E(),c=s(),l=(a.events[e]??[]).find(e=>e.id===t),u=a.holds.find(t=>t.thread===e&&t.tool===`browser`),[d,f]=(0,L.useState)(null),[p,m]=(0,L.useState)(null),[h,g]=(0,L.useState)(``),[_,v]=(0,L.useState)(``),[y,b]=(0,L.useState)(!1),x=(0,L.useRef)(null),S=d?d===`on`:!!u;(0,L.useEffect)(()=>b(!1),[l?.frame]),(0,L.useEffect)(()=>f(null),[u?.id,u?.status]);let C=l?.backend===`device`&&ap();(0,L.useEffect)(()=>{if(!C)return;let t=t=>{let n=t.detail;n?.thread&&n.thread!==e||M.browserControl(e,{action:`handed_back`}).catch(e=>o(e.message))};return window.addEventListener(`nanomuse:browser-handed-back`,t),()=>window.removeEventListener(`nanomuse:browser-handed-back`,t)},[C,e,o]);let w=(0,L.useCallback)(async t=>{m(t.action);try{await M.browserControl(e,t)}catch(e){o(e.message)}finally{m(null)}},[e,o]),T=()=>{if(C){ip()?.takeOverBrowser?.(e),M.browserControl(e,{action:`take_over`}).catch(()=>void 0);return}f(`on`),w({action:`take_over`})},D=()=>{f(`off`),w({action:`handed_back`})};(0,L.useEffect)(()=>{if(!S||C||!l||l.status!==`live`)return;let t=window.setInterval(()=>{document.hidden||M.browserControl(e,{action:`look`}).catch(()=>void 0)},kp);return()=>window.clearInterval(t)},[S,C,e,l]);let O=e=>{if(!S||p)return;let t=e.currentTarget.getBoundingClientRect(),n=(e.clientX-t.left)/t.width,r=(e.clientY-t.top)/t.height;w({action:`click`,x:Math.min(Math.max(n,0),1),y:Math.min(Math.max(r,0),1)})},k=e=>{!S||p||Math.abs(e.deltaY)<8||w({action:`scroll`,dy:Math.max(-2e3,Math.min(2e3,Math.round(e.deltaY*2)))})};if(!l)return null;let ee=l.url;try{ee=new URL(l.url).host}catch{}let te=l.status===`live`,j=a.profile?.name??`nanoMuse`,ne=u?c(`{name} is waiting for you`,{name:j}):a.status.state!==`idle`&&a.status.thread===e?c(`{name} is working`,{name:j}):l.action;return(0,R.jsxs)(Op,{open:!0,onClose:r,title:(0,R.jsxs)(`div`,{className:`flex items-center gap-2 min-w-0`,children:[(0,R.jsx)(gt,{size:17,className:`text-accent shrink-0`}),(0,R.jsx)(`span`,{className:`truncate`,children:l.title||ee}),te&&(0,R.jsxs)(`span`,{className:`ml-1 flex items-center gap-1 rounded-full bg-rose-500/12 px-2 py-0.5 text-[10.5px] font-semibold text-rose-500`,children:[(0,R.jsx)(`span`,{className:`h-1.5 w-1.5 rounded-full bg-rose-500 animate-pulse`}),` `,c(`LIVE`)]})]}),footer:S?(0,R.jsxs)(`div`,{className:`space-y-2`,children:[(0,R.jsxs)(`form`,{className:`flex items-center gap-2`,onSubmit:e=>{e.preventDefault(),h&&w({action:`type`,text:h}).then(()=>g(``))},children:[(0,R.jsx)(`input`,{value:h,onChange:e=>g(e.target.value),placeholder:c(`Type into the focused field…`),className:`flex-1 rounded-2xl bg-surface-2 px-3.5 py-2.5 text-[14px] outline-none`,autoComplete:`off`,autoCapitalize:`off`}),(0,R.jsx)(`button`,{type:`submit`,disabled:!h||!!p,"aria-label":c(`Type`),className:`rounded-full bg-accent p-2.5 text-white disabled:opacity-40`,children:p===`type`?(0,R.jsx)(A,{size:16,className:`animate-spin`}):(0,R.jsx)(qe,{size:16})}),(0,R.jsx)(`button`,{type:`button`,onClick:()=>void w({action:`key`,key:`Enter`}),disabled:!!p,"aria-label":c(`Press Enter`),className:`rounded-full bg-surface-2 p-2.5 text-fg disabled:opacity-40`,children:(0,R.jsx)(dt,{size:16})})]}),(0,R.jsxs)(`form`,{className:`flex items-center gap-2`,onSubmit:e=>{e.preventDefault(),_&&w({action:`navigate`,url:_}).then(()=>v(``))},children:[(0,R.jsx)(`button`,{type:`button`,onClick:()=>void w({action:`back`}),disabled:!!p,"aria-label":c(`Back`),className:`rounded-full bg-surface-2 p-2 text-fg disabled:opacity-40`,children:(0,R.jsx)(Ke,{size:15})}),(0,R.jsx)(`input`,{value:_,onChange:e=>v(e.target.value),placeholder:c(`Open a URL…`),inputMode:`url`,autoCapitalize:`off`,className:`flex-1 min-w-0 rounded-2xl bg-surface-2 px-3.5 py-2 text-[13px] outline-none`}),(0,R.jsx)(`button`,{type:`submit`,disabled:!_||!!p,className:`rounded-2xl bg-surface-2 px-3 py-2 text-[13px] font-medium disabled:opacity-40`,children:c(`Go`)}),(0,R.jsx)(`button`,{type:`button`,onClick:()=>void w({action:`scroll`,dy:-600}),disabled:!!p,"aria-label":c(`Scroll up`),className:`rounded-full bg-surface-2 p-2 text-fg disabled:opacity-40`,children:(0,R.jsx)(Je,{size:15})}),(0,R.jsx)(`button`,{type:`button`,onClick:()=>void w({action:`scroll`,dy:600}),disabled:!!p,"aria-label":c(`Scroll down`),className:`rounded-full bg-surface-2 p-2 text-fg disabled:opacity-40`,children:(0,R.jsx)(Ge,{size:15})})]}),(0,R.jsxs)(`div`,{className:`flex items-center justify-between gap-2`,children:[(0,R.jsx)(`span`,{className:`min-w-0 truncate text-[12px] text-muted`,children:c(`Tap the page to click. If the browser was closed, open a URL first.`)}),(0,R.jsxs)(`button`,{type:`button`,onClick:D,disabled:p===`handed_back`,className:`flex shrink-0 items-center gap-1.5 whitespace-nowrap rounded-full bg-fg px-3.5 py-1.5 text-[13px] font-semibold text-bg disabled:opacity-60`,children:[p===`handed_back`?(0,R.jsx)(A,{size:14,className:`animate-spin`}):(0,R.jsx)(ke,{size:14}),` `,c(`Done`)]})]})]}):(0,R.jsxs)(`div`,{className:`flex items-center justify-between gap-2`,children:[(0,R.jsxs)(`div`,{className:`min-w-0 text-[12.5px] text-muted truncate`,children:[ne,` · `,ee]}),(0,R.jsxs)(`div`,{className:`flex items-center gap-2 shrink-0`,children:[(0,R.jsx)(`button`,{type:`button`,onClick:()=>void w({action:`look`}),disabled:!!p,"aria-label":c(`Refresh`),className:`rounded-full bg-surface-2 p-2 text-muted disabled:opacity-40`,children:p===`look`?(0,R.jsx)(A,{size:15,className:`animate-spin`}):(0,R.jsx)(Re,{size:15})}),(0,R.jsxs)(`button`,{type:`button`,onClick:T,disabled:d===`on`,className:`flex items-center gap-1.5 rounded-full bg-accent px-3.5 py-2 text-[13px] font-semibold text-white disabled:opacity-60`,children:[(0,R.jsx)(vt,{size:14}),` `,c(`Take over`)]})]})]}),children:[u&&u.by===`agent`&&(0,R.jsx)(`div`,{className:`mb-2`,children:(0,R.jsx)(xp,{hold:u,compact:!0})}),(0,R.jsxs)(`div`,{className:i(`relative overflow-hidden rounded-2xl border border-border bg-surface-2`,S&&`ring-2 ring-accent`),children:[y?(0,R.jsxs)(`div`,{className:`flex aspect-[16/10] flex-col items-center justify-center gap-1 text-muted`,children:[(0,R.jsx)(gt,{size:24}),(0,R.jsx)(`span`,{className:`text-[12.5px]`,children:c(`This frame is no longer available.`)}),(0,R.jsx)(`button`,{type:`button`,onClick:()=>void w({action:`look`}),className:`text-accent text-[13px] font-medium`,children:c(`Look again`)})]}):(0,R.jsx)(`img`,{ref:x,src:n(e,l.frame),alt:l.title||ee,onError:()=>b(!0),onClick:O,onWheel:k,draggable:!1,className:i(`block w-full select-none`,S?`cursor-crosshair`:``)},l.frame),p&&p!==`look`&&(0,R.jsx)(`div`,{className:`absolute inset-0 flex items-center justify-center bg-black/20`,children:(0,R.jsx)(A,{size:26,className:`animate-spin text-white`})})]}),(0,R.jsxs)(`div`,{className:`mt-2 flex items-center justify-between text-[12px] text-muted`,children:[(0,R.jsx)(`span`,{className:`truncate`,children:l.url}),(0,R.jsx)(`span`,{className:`shrink-0 ml-2`,children:l.frames===1?c(`1 frame`):c(`{n} frames`,{n:l.frames})})]}),S&&(0,R.jsxs)(`div`,{className:`mt-3 rounded-2xl bg-accent/8 px-3.5 py-2.5 text-[13px] leading-snug`,children:[(0,R.jsx)(`div`,{className:`font-medium`,children:u&&u.by===`agent`?Cp(u,c):c(`You have the page. Press Done when you are finished.`)}),(0,R.jsx)(`div`,{className:`mt-1 text-muted`,children:c(`{name} waits meanwhile, then looks at the page as you left it and carries on. Passwords you type here go to the website, never to the model.`,{name:j})})]})]})}function jp(){if(typeof window>`u`)return null;let e=window;return e.SpeechRecognition??e.webkitSpeechRecognition??null}function Mp(){return jp()!==null}function Np(e,t){let[n,r]=(0,L.useState)(!1),i=(0,L.useRef)(null),a=(0,L.useRef)(``),o=s(),c=(0,L.useCallback)(()=>{i.current?.stop()},[]),l=(0,L.useCallback)(()=>{let n=jp();if(!n)return;let s=new n;s.lang=navigator.language||`en-US`,s.continuous=!0,s.interimResults=!0,a.current=``,s.onresult=t=>{let n=``;for(let e=t.resultIndex;e{let n=e.error||``;n!==`aborted`&&n!==`no-speech`&&t?.(n===`not-allowed`||n===`service-not-allowed`?o(`The microphone is not allowed. Allow it in the browser and try again.`):o(`Voice input stopped ({code}).`,{code:n}))},s.onend=()=>{i.current=null,r(!1)},i.current=s;try{s.start(),r(!0)}catch{i.current=null,r(!1)}},[e,t,o]),u=(0,L.useCallback)(()=>{i.current?c():l()},[l,c]);return(0,L.useEffect)(()=>()=>i.current?.abort(),[]),{supported:Mp(),listening:n,toggle:u,stop:c}}function Pp({listening:e,onClick:t,className:n}){let r=s();return(0,R.jsx)(`button`,{type:`button`,onClick:t,"aria-label":r(e?`Stop voice input`:`Voice input`),"aria-pressed":e,className:i(`flex h-9 w-9 shrink-0 items-center justify-center rounded-full transition active:scale-95`,e?`bg-accent/15 text-accent animate-pulse`:`text-fg/70 hover:bg-surface-2`,n),children:e?(0,R.jsx)(Pt,{size:19}):(0,R.jsx)(Ft,{size:19})})}function Fp({lines:e}){return(0,R.jsx)(`div`,{className:`flex items-end gap-2 pr-10`,children:(0,R.jsx)(`div`,{className:`min-w-0 max-w-full`,children:e.map((e,t)=>(0,R.jsx)(`div`,{className:`my-1 max-w-[340px] rounded-[20px] bg-surface-2 px-3.5 py-2.5 text-[14.5px] leading-snug whitespace-pre-wrap break-words wide:max-w-[600px]`,children:e},t))})})}function Ip({chips:e,chosen:t,busy:n,onPick:r,onElse:a}){let o=s();return e.length===0&&!t?null:(0,R.jsxs)(`section`,{className:`rise mx-1 my-2 rounded-[22px] border border-border/70 bg-surface p-3.5`,children:[(0,R.jsxs)(`div`,{className:`flex items-center gap-2 text-[13px] font-medium text-fg`,children:[(0,R.jsx)(nn,{size:14,className:`text-accent`}),` `,o(`Pick a name for me, or type one`)]}),(0,R.jsxs)(`div`,{className:`mt-2.5 flex flex-wrap gap-2`,children:[e.map(e=>{let a=t===e;return(0,R.jsxs)(`button`,{type:`button`,disabled:n||!!t,onClick:()=>r(e),className:i(`inline-flex items-center gap-1.5 rounded-full px-3.5 py-1.5 text-[13.5px] font-medium transition-colors disabled:opacity-60`,a?`bg-accent text-accent-fg`:`bg-surface-2 hover:bg-border/60`),children:[a&&(0,R.jsx)(ke,{size:13,strokeWidth:3}),e]},e)}),!t&&(0,R.jsx)(`button`,{type:`button`,disabled:n,onClick:a,className:`rounded-full border border-border px-3.5 py-1.5 text-[13.5px] text-muted hover:bg-surface-2 disabled:opacity-60`,children:o(`Something else`)})]})]})}var Lp=[{id:`pink`,background:`#F9D9E3`,accent:`#B5476A`,mood:`idle`},{id:`blue`,background:`#D6E6FA`,accent:`#2F5FA8`,mood:`working`},{id:`yellow`,background:`#FBEFC7`,accent:`#9A6B12`,mood:`waiting`},{id:`purple`,background:`#E4DDF7`,accent:`#5D44A6`,mood:`happy`},{id:`green`,background:`#D9F0DF`,accent:`#2E7D4F`,mood:`error`}],Rp=`github.com/nano-muse/nanoMuse`,zp=540,Bp=720;function Vp(e,t){return!e||w(e.avatar)?j(t):e.avatar?re(e.avatar,t):null}function Hp(e){return new Promise(t=>{let n=new Image;n.crossOrigin=`anonymous`,n.onload=()=>t(n),n.onerror=()=>t(null),n.src=e})}function Up(e,t,n){let r=t.includes(` `)?t.split(` `):Array.from(t),i=t.includes(` `)?` `:``,a=[],o=``;for(let t of r){let r=o?o+i+t:t;e.measureText(r).width>n&&o?(a.push(o),o=t):o=r}return o&&a.push(o),a}function Wp(e,t,n,r,i,a){e.beginPath(),e.moveTo(t+a,n),e.arcTo(t+r,n,t+r,n+i,a),e.arcTo(t+r,n+i,t,n+i,a),e.arcTo(t,n+i,t,n,a),e.arcTo(t,n,t+r,n,a),e.closePath()}async function Gp(e,t,n,r,i,a=2){let o=document.createElement(`canvas`);o.width=zp*a,o.height=Bp*a;let s=o.getContext(`2d`);if(!s)return o;s.scale(a,a),s.fillStyle=e.background,Wp(s,0,0,zp,Bp,36),s.fill(),s.font=`600 22px system-ui, -apple-system, 'Segoe UI', sans-serif`;let c=Up(s,r,400),l=Math.max(...c.map(e=>s.measureText(e).width))+48,u=c.length*30+36,d=(zp-l)/2;s.fillStyle=`#ffffff`,Wp(s,d,56,l,u,24),s.fill(),s.beginPath(),s.moveTo(zp/2-14,56+u-1),s.lineTo(zp/2,56+u+18),s.lineTo(284,56+u-1),s.closePath(),s.fill(),s.fillStyle=e.accent,s.textAlign=`center`,s.textBaseline=`top`,c.forEach((e,t)=>s.fillText(e,zp/2,74+t*30+3));let f=56+u+54;s.fillStyle=`#ffffff`,s.beginPath(),s.arc(zp/2,f+150,158,0,Math.PI*2),s.fill();let p=Vp(t,e.mood),m=p?await Hp(p):null;return s.save(),s.beginPath(),s.arc(zp/2,f+150,150,0,Math.PI*2),s.clip(),m?(s.fillStyle=`#f1efeb`,s.fillRect(120,f,300,300),s.drawImage(m,120,f,300,300)):(s.fillStyle=t?.color??`#0064d4`,s.fillRect(120,f,300,300),s.font=`150px system-ui, 'Apple Color Emoji', 'Segoe UI Emoji', sans-serif`,s.textAlign=`center`,s.textBaseline=`middle`,s.fillStyle=`#ffffff`,s.fillText(t?.emoji??`✨`,zp/2,f+150+6)),s.restore(),s.fillStyle=e.accent,s.textAlign=`center`,s.textBaseline=`top`,s.font=`700 30px system-ui, -apple-system, 'Segoe UI', sans-serif`,s.fillText(n,zp/2,f+300+34),s.font=`500 15px system-ui, -apple-system, 'Segoe UI', sans-serif`,s.globalAlpha=.8,Up(s,i,460).forEach((e,t)=>s.fillText(e,zp/2,644+t*22)),s.globalAlpha=1,o}function Kp(e){return new Promise(t=>e.toBlob(t,`image/png`))}function qp({open:e,onClose:t}){let{state:n,toast:r}=E(),a=s(),o=n.profile,c=o?.name??`nanoMuse`,[l,u]=(0,L.useState)(0),[d,f]=(0,L.useState)([]),[p,m]=(0,L.useState)(!1),h=(0,L.useRef)(!0),g=a(`Hi, I'm {name}, a personal AI agent. Meet nanoMuse: open source, runs on your phone.`,{name:c}),_=a(`Your personal AI agent, open source · {repo}`,{repo:Rp});(0,L.useEffect)(()=>{if(h.current=!0,e)return u(0),(async()=>{let e=[];for(let t of Lp){let n=await Gp(t,o,c,g,_,1);e.push(n.toDataURL(`image/png`))}h.current&&f(e)})(),()=>{h.current=!1}},[e,o?.avatar,o?.emoji,o?.color,c]);let v=async()=>{m(!0);try{let e=await Kp(await Gp(Lp[l]??Lp[0],o,c,g,_,2));if(!e)throw Error(a(`The card could not be drawn.`));let n=new File([e],`${c}-nanomuse.png`,{type:`image/png`}),i=`${g}\nhttps://${Rp}`,s=navigator;if(typeof s.share==`function`&&(!s.canShare||s.canShare({files:[n]})))try{await s.share({files:[n],text:i,title:c}),t();return}catch(e){if(e.name===`AbortError`)return}let u=document.createElement(`a`);u.href=URL.createObjectURL(e),u.download=n.name,u.click(),window.setTimeout(()=>URL.revokeObjectURL(u.href),2e3),r(a(`Saved the card as a picture.`))}catch(e){r(e.message)}finally{m(!1)}};return(0,R.jsxs)(Op,{open:e,onClose:t,title:a(`Share my avatar`),children:[(0,R.jsx)(`p`,{className:`mb-3 text-[13px] text-muted`,children:a(`Pick a card. It goes out through the system share sheet, or saves as a picture where there is none.`)}),(0,R.jsx)(`div`,{className:`grid grid-cols-3 gap-2.5 sm:grid-cols-5`,children:Lp.map((e,t)=>(0,R.jsx)(`button`,{type:`button`,"aria-label":e.id,"aria-pressed":l===t,onClick:()=>u(t),className:i(`overflow-hidden rounded-2xl border-2 transition`,l===t?`border-accent`:`border-transparent`),style:{background:e.background,aspectRatio:`${zp} / ${Bp}`},children:d[t]?(0,R.jsx)(`img`,{src:d[t],alt:``,className:`h-full w-full object-cover`}):(0,R.jsx)(A,{size:18,className:`mx-auto my-8 animate-spin text-muted`})},e.id))}),d[l]&&(0,R.jsx)(`img`,{src:d[l],alt:``,className:`mx-auto mt-4 w-[260px] rounded-[20px] shadow-md`}),(0,R.jsxs)(`div`,{className:`mt-4 flex justify-end gap-2`,children:[(0,R.jsx)(`button`,{type:`button`,onClick:t,className:je,children:a(`Later`)}),(0,R.jsxs)(`button`,{type:`button`,disabled:p||!d.length,onClick:()=>void v(),className:Ne,children:[p?(0,R.jsx)(A,{size:15,className:`animate-spin`}):typeof navigator.share==`function`?(0,R.jsx)(Xt,{size:15}):(0,R.jsx)(ft,{size:15}),` `,typeof navigator.share==`function`?a(`Share`):a(`Save picture`)]})]})]})}function Jp({message:e,onRetry:t}){let n=s();return(0,R.jsxs)(`div`,{className:`flex flex-col items-center gap-3 px-8 py-10 text-center`,children:[(0,R.jsx)(`p`,{className:`text-[14px] text-rose-600 dark:text-rose-300`,children:n(e)||n(`Could not load.`)}),(0,R.jsxs)(`button`,{type:`button`,onClick:t,className:`flex h-10 items-center gap-1.5 rounded-full bg-surface px-4 text-[13.5px] font-medium shadow-[0_1px_4px_rgba(0,0,0,0.14)] dark:border dark:border-border dark:shadow-none`,children:[(0,R.jsx)(Re,{size:14}),` `,n(`Try again`)]})]})}var Yp=[{id:`health`,label:`Health`,icon:e=>(0,R.jsx)(yt,{...e}),tone:`bg-rose-500/12 text-rose-600 dark:text-rose-300`},{id:`finance`,label:`Finance`,icon:e=>(0,R.jsx)(Wt,{...e}),tone:`bg-emerald-500/12 text-emerald-600 dark:text-emerald-300`},{id:`career`,label:`Career`,icon:e=>(0,R.jsx)($e,{...e}),tone:`bg-sky-500/12 text-sky-600 dark:text-sky-300`},{id:`learning`,label:`Learning`,icon:e=>(0,R.jsx)(_t,{...e}),tone:`bg-violet-500/12 text-violet-600 dark:text-violet-300`},{id:`relationships`,label:`Relationships`,icon:e=>(0,R.jsx)(le,{...e}),tone:`bg-pink-500/12 text-pink-600 dark:text-pink-300`},{id:`family`,label:`Family`,icon:e=>(0,R.jsx)(hn,{...e}),tone:`bg-amber-500/12 text-amber-600 dark:text-amber-300`},{id:`home`,label:`Home`,icon:e=>(0,R.jsx)(bt,{...e}),tone:`bg-orange-500/12 text-orange-600 dark:text-orange-300`},{id:`travel`,label:`Travel`,icon:e=>(0,R.jsx)(lt,{...e}),tone:`bg-cyan-500/12 text-cyan-600 dark:text-cyan-300`},{id:`creative`,label:`Creative`,icon:e=>(0,R.jsx)(Vt,{...e}),tone:`bg-fuchsia-500/12 text-fuchsia-600 dark:text-fuchsia-300`},{id:`other`,label:`Other`,icon:e=>(0,R.jsx)(ln,{...e}),tone:`bg-surface-2 text-muted`}];function Xp(e){return Yp.find(t=>t.id===e)??null}var Zp=[{id:``,label:`No reminders`},{id:`daily`,label:`Every day`},{id:`weekdays`,label:`Weekdays`},{id:`weekly`,label:`Once a week`},{id:`monthly`,label:`Once a month`}],Qp=[`mon`,`tue`,`wed`,`thu`,`fri`,`sat`,`sun`];function $p(e){let t=/^(daily|weekdays|weekly|monthly)(?:\s+(\S+?))?(?:\s+(\d{1,2}:\d{2}))?$/.exec(e.trim());if(!t)return{cadence:``,anchor:``,time:`09:00`};let n=t[2]??``,r=t[3]??`09:00`;return n&&/^\d{1,2}:\d{2}$/.test(n)&&(r=n,n=``),{cadence:t[1],anchor:n,time:r.padStart(5,`0`)}}function em(e,t,n){return e?[e,t,n].filter(Boolean).join(` `):``}function tm(e){let t=Qp.indexOf(e);return t<0?e:new Date(2024,0,1+t).toLocaleDateString(m(),{weekday:`long`})}function nm(e){let{cadence:t,anchor:n,time:r}=$p(e);switch(t){case`daily`:return _(`Daily at {time}`,{time:r});case`weekdays`:return _(`Weekdays at {time}`,{time:r});case`weekly`:return n&&Qp.includes(n)?_(`{day}s at {time}`,{day:tm(n),time:r}):_(`Weekly at {time}`,{time:r});case`monthly`:return _(`Monthly on the {day} at {time}`,{day:rm(Number(n||1)),time:r});default:return``}}function rm(e){if(c()!==`en`)return String(e);let t=[`th`,`st`,`nd`,`rd`],n=e%100;return`${e}${t[(n-20)%10]??t[n]??t[0]}`}function im(e,t){if(!e)return``;let n=new Date(`${e}T00:00:00`),r=n.toLocaleDateString(m(),{month:`short`,day:`numeric`,year:n.getFullYear()===new Date().getFullYear()?void 0:`numeric`});if(t)return _(`Was due {date}`,{date:r});let i=Math.ceil((n.getTime()-Date.now())/864e5);return i<=0?_(`Due today`):i===1?_(`Due tomorrow`):i<=14?_(`Due in {n} days`,{n:i}):_(`By {date}`,{date:r})}function am({open:e,onClose:t}){let{state:n,setTab:r,draft:a,toast:o}=E(),[c,l]=(0,L.useState)(0),[u,d]=(0,L.useState)(!1),[f,p]=(0,L.useState)(!1),[m,h]=(0,L.useState)(!1),g=n.profile?.name??`nanoMuse`,_=n.pendingApprovals.length,v=s();(0,L.useEffect)(()=>{e&&(l(+(_>0)),d(!1),p(!1))},[e]);let y=(e,n)=>{t(),n&&history.replaceState(null,``,`${window.location.pathname}${window.location.search}#${n}`),r(e)},b=n.status.state===`working`,x=_>0?_>1?v(`{n} approvals waiting for you`,{n:_}):v(`1 approval waiting for you`):b?n.status.detail||v(`On it`):n.status.state===`waiting`?v(`Waiting for you`):v(`online`),S=async()=>{h(!0);try{(await M.stopThread(n.status.thread||`main`)).ok||o(v(`Nothing to stop`))}catch(e){o(e.message)}finally{h(!1)}},C=[{icon:(0,R.jsx)(it,{size:22}),label:v(`Activity`)},{icon:(0,R.jsx)(Qt,{size:22}),label:v(`Approvals`),badge:_},{icon:(0,R.jsx)(at,{size:22}),label:v(`Daily`)},{icon:(0,R.jsx)(ht,{size:22}),label:v(`Soul & memory`)}];return(0,R.jsxs)(Op,{open:e,onClose:t,children:[(0,R.jsxs)(`div`,{className:`relative flex flex-col items-center px-1 pb-3 text-center`,children:[(0,R.jsx)(`button`,{type:`button`,"aria-label":v(`Share avatar`),title:v(`Share avatar`),onClick:()=>p(!0),className:`absolute right-0 top-0 flex h-9 w-9 items-center justify-center rounded-full bg-surface-2/70 text-fg hover:bg-surface-2`,children:(0,R.jsx)(Xt,{size:16})}),(0,R.jsxs)(`div`,{className:`relative`,children:[(0,R.jsx)(D,{profile:n.profile,status:n.status,size:72}),(0,R.jsx)(`button`,{type:`button`,"aria-label":v(`Edit`),"aria-expanded":u,onClick:()=>d(e=>!e),className:`absolute -bottom-0.5 -right-0.5 flex h-6 w-6 items-center justify-center rounded-full bg-surface text-fg shadow-[0_1px_4px_rgba(0,0,0,0.18)] hover:bg-surface-2 dark:border dark:border-border`,children:(0,R.jsx)(Ht,{size:13})}),u&&(0,R.jsxs)(`div`,{className:`absolute left-1/2 top-full z-20 mt-2 w-56 -translate-x-1/2 overflow-hidden rounded-2xl border border-border/70 bg-surface py-1 text-left text-[14px] shadow-lg`,children:[(0,R.jsx)(`button`,{type:`button`,onClick:()=>{a(v(`Change your avatar to `)),t(),r(`chat`)},className:`block w-full px-4 py-2.5 text-left hover:bg-surface-2`,children:v(`Change avatar`)}),(0,R.jsx)(`button`,{type:`button`,onClick:()=>y(`you`,`who`),className:`block w-full px-4 py-2.5 text-left hover:bg-surface-2`,children:v(`Edit name`)}),(0,R.jsx)(`button`,{type:`button`,onClick:()=>y(`avatar`),className:`block w-full px-4 py-2.5 text-left text-muted hover:bg-surface-2`,children:v(`Avatar studio…`)})]})]}),(0,R.jsx)(`div`,{className:`mt-2.5 text-[21px] font-semibold leading-[26px]`,children:g}),(0,R.jsxs)(`div`,{className:i(`mt-0.5 flex items-center gap-1.5 text-[14px]`,b||_>0?`text-fg`:`text-muted`),children:[b&&(0,R.jsx)(A,{size:13,className:`animate-spin text-accent`}),(0,R.jsx)(`span`,{className:`line-clamp-2`,children:x})]}),(b||n.status.state===`waiting`)&&(0,R.jsxs)(`button`,{type:`button`,onClick:()=>void S(),disabled:m,className:`mt-2.5 inline-flex items-center gap-1.5 rounded-full bg-fg px-4 py-1.5 text-[13.5px] font-semibold text-bg transition active:scale-95 disabled:opacity-60`,children:[(0,R.jsx)(sn,{size:12,fill:`currentColor`}),` `,v(`Stop`)]})]}),(0,R.jsx)(`div`,{role:`tablist`,className:`mb-5 flex rounded-2xl bg-surface-2/60 p-1`,children:C.map((e,t)=>(0,R.jsxs)(`button`,{type:`button`,role:`tab`,"aria-selected":c===t,"aria-label":e.label,title:e.label,onClick:()=>l(t),className:i(`relative flex h-11 flex-1 items-center justify-center rounded-[13px] text-fg transition`,c===t&&`bg-surface shadow-sm`),children:[e.icon,e.badge?(0,R.jsx)(`span`,{className:`absolute right-1.5 top-1 flex h-[17px] min-w-[17px] items-center justify-center rounded-full bg-rose-500 px-1 text-[10px] font-bold text-white`,children:e.badge}):null]},e.label))}),c===0&&(0,R.jsx)(ym,{open:e}),c===1&&(0,R.jsxs)(R.Fragment,{children:[_>0&&(0,R.jsx)(cm,{onDone:()=>void 0}),(0,R.jsx)(bm,{open:e})]}),c===2&&(0,R.jsx)(lm,{onSettings:()=>y(`you`,`proactivity`)}),c===3&&(0,R.jsx)(om,{name:g,onEdit:()=>y(`you`,`who`),onMemory:()=>y(`memory`)}),(0,R.jsx)(qp,{open:f,onClose:()=>p(!1)})]})}function om({name:e,onEdit:t,onMemory:n}){let{state:r}=E(),i=s(),a=r.profile?.tagline?.trim()??``;return(0,R.jsxs)(`div`,{className:`pb-2`,children:[(0,R.jsx)(`div`,{className:`px-1 text-[15px]`,children:e}),(0,R.jsxs)(`button`,{type:`button`,onClick:t,className:`mt-2 flex h-[50px] w-full items-center justify-center gap-2 rounded-2xl bg-surface-2/70 text-[15px] font-medium hover:bg-surface-2`,children:[(0,R.jsx)(Ht,{size:18}),` `,i(`Edit`)]}),(0,R.jsxs)(`div`,{className:`mt-4 grid grid-cols-2 gap-3`,children:[(0,R.jsx)(sm,{title:`SOUL`,caption:i(`Handle with care`),foot:a,colors:`from-[#7d6bc7] to-[#574494]`,onClick:t}),(0,R.jsx)(sm,{title:i(`Memory`),caption:i(`Handle with care`),foot:r.settings?.memory_enabled===!1?i(`Off`):``,colors:`from-[#b0413e] to-[#7a1f1f]`,onClick:n})]})]})}function sm({title:e,caption:t,foot:n,colors:r,onClick:a}){return(0,R.jsxs)(`button`,{type:`button`,onClick:a,className:i(`flex h-[130px] flex-col items-start rounded-[18px] bg-gradient-to-b p-3.5 text-left text-white transition active:scale-[0.98]`,r),children:[(0,R.jsx)(`span`,{className:`text-[17px] font-semibold`,children:e}),(0,R.jsx)(`span`,{className:`mt-0.5 text-[11px] text-white/85`,children:t}),(0,R.jsx)(`span`,{className:`mt-auto text-[12px] text-white/90`,children:n})]})}function cm({onDone:e}){let{state:t,decide:n,openThread:r,toast:i}=E(),a=t.profile?.name??`nanoMuse`,o=s(),c=[...t.pendingApprovals].sort((e,t)=>e.ts.localeCompare(t.ts)),l=e=>{let n=t.threads.find(t=>t.id===e);return n?n.id===`main`?o(n.title):n.title:e};return(0,L.useEffect)(()=>{if(c.length===0){let t=window.setTimeout(e,600);return()=>window.clearTimeout(t)}},[c.length,e]),c.length===0?(0,R.jsxs)(`div`,{className:`py-10 text-center text-muted text-[14px]`,children:[(0,R.jsx)(ke,{size:26,className:`mx-auto mb-2 text-emerald-500`}),o(`Nothing is waiting for you.`)]}):(0,R.jsxs)(`div`,{className:`space-y-4 pb-2`,children:[(0,R.jsx)(`p`,{className:`text-[12.5px] text-muted`,children:o(`Actions {name} wants to take but cannot without you. Each one shows what will run and why; a permission you grant is bound to that exact tool and target.`,{name:a})}),c.map(e=>(0,R.jsxs)(`div`,{children:[(0,R.jsxs)(`button`,{type:`button`,onClick:()=>r(e.thread),className:`mb-1 px-1 text-[12px] font-semibold uppercase tracking-wide text-muted hover:text-accent`,children:[l(e.thread),` · `,u(e.ts)]}),(0,R.jsx)(`div`,{className:`rounded-[22px] border border-border/70`,children:(0,R.jsx)(hp,{event:e,onDecide:(t,r)=>n(e.id,t,r).catch(e=>i(e.message))})})]},e.id))]})}function lm({onSettings:t}){let{state:n,refreshSettings:r,toast:a}=E(),[o,c]=(0,L.useState)(null),[l,d]=(0,L.useState)(null),[f,p]=(0,L.useState)(null),m=n.profile?.name??`nanoMuse`,h=s(),g=()=>M.upcoming().then(e=>{c(e),d(null)}).catch(e=>o===null?d(e.message):a(e.message));(0,L.useEffect)(()=>{g()},[n.goalsVersion,n.remindersVersion,n.profile?.proactive,n.profile?.goal_interval_minutes]);let _=async()=>{try{await M.updateSettings({profile:{proactive:!n.profile?.proactive}}),await r()}catch(e){a(e.message)}},v=async e=>{p(e);try{await M.advanceGoal(e),a(h(`{name} is working on it in the main chat`,{name:m}))}catch(e){a(e.message)}finally{p(null)}};return o?(0,R.jsxs)(`div`,{className:`space-y-4 pb-2`,children:[(0,R.jsxs)(`div`,{className:`rounded-2xl border border-border p-3.5`,children:[(0,R.jsxs)(`div`,{className:`flex items-center justify-between gap-3`,children:[(0,R.jsxs)(`div`,{children:[(0,R.jsx)(`div`,{className:`font-medium`,children:h(`Background work`)}),(0,R.jsx)(`div`,{className:`text-[12.5px] text-muted`,children:o.proactive?`${h(o.proactivity[0].toUpperCase()+o.proactivity.slice(1))} · ${h(`every {n} min {name} picks one active goal and works on its next step.`,{n:o.effective_interval_minutes,name:m})}${o.quiet_until?` ${h(`Quiet hours until {time}.`,{time:u(o.quiet_until)})}`:o.next_pass_at?` ${h(`Next around {time}.`,{time:u(o.next_pass_at)})}`:``}`:h(`Off. {name} only works when you ask.`,{name:m})})]}),(0,R.jsx)(`button`,{type:`button`,role:`switch`,"aria-checked":o.proactive,onClick:()=>void _(),className:i(`relative h-7 w-12 shrink-0 rounded-full transition`,o.proactive?`bg-accent`:`bg-border`),children:(0,R.jsx)(`span`,{className:i(`absolute top-0.5 h-6 w-6 rounded-full bg-white shadow transition`,o.proactive?`left-[26px]`:`left-0.5`)})})]}),(0,R.jsx)(`button`,{type:`button`,onClick:t,className:`mt-2 text-[12.5px] text-accent font-medium`,children:h(`Level, interval and quiet hours in Settings`)})]}),(0,R.jsxs)(`div`,{children:[(0,R.jsx)(`div`,{className:`text-[12px] uppercase tracking-wide text-muted font-semibold mb-1.5`,children:h(`In line`)}),o.queue.length===0?(0,R.jsx)(`div`,{className:`text-[13px] text-muted`,children:h(`No active goal has a next step. Add one in Goals and {name} will pick it up.`,{name:m})}):(0,R.jsx)(`ul`,{className:`space-y-1.5`,children:o.queue.map((e,t)=>(0,R.jsxs)(`li`,{className:`flex items-center gap-2.5 rounded-2xl bg-surface-2/60 px-3 py-2`,children:[(0,R.jsx)(`span`,{className:`w-5 text-center text-[12px] font-semibold text-muted`,children:t+1}),(0,R.jsxs)(`div`,{className:`min-w-0 flex-1`,children:[(0,R.jsx)(`div`,{className:`text-[13.5px] font-medium truncate`,children:e.title}),(0,R.jsxs)(`div`,{className:`text-[11.5px] text-muted truncate`,children:[e.next_step??`—`,` · `,h(`{done}/{total} done`,{done:e.progress.done,total:e.progress.total})]})]}),(0,R.jsx)(`button`,{type:`button`,onClick:()=>void v(e.goal_id),disabled:f!==null||o.busy,"aria-label":h(`Work on {title} now`,{title:e.title}),className:`rounded-full bg-accent/12 p-2 text-accent disabled:opacity-50`,children:f===e.goal_id?(0,R.jsx)(A,{size:15,className:`animate-spin`}):(0,R.jsx)(Gt,{size:15})})]},e.goal_id))})]}),o.check_ins.length>0&&(0,R.jsxs)(`div`,{children:[(0,R.jsx)(`div`,{className:`text-[12px] uppercase tracking-wide text-muted font-semibold mb-1.5`,children:h(`Check-ins`)}),(0,R.jsx)(`ul`,{className:`space-y-1.5`,children:o.check_ins.map(t=>(0,R.jsxs)(`li`,{className:`flex items-center gap-2.5 rounded-2xl bg-surface-2/60 px-3 py-2`,children:[(0,R.jsx)(Xe,{size:15,className:`text-muted shrink-0`}),(0,R.jsxs)(`div`,{className:`min-w-0 flex-1`,children:[(0,R.jsx)(`div`,{className:`text-[13.5px] font-medium truncate`,children:t.title}),(0,R.jsxs)(`div`,{className:`text-[11.5px] text-muted truncate`,children:[e(t.at),` · `,u(t.at),` · `,nm(t.cadence).toLowerCase()]})]})]},t.goal_id))}),(0,R.jsx)(`div`,{className:`mt-1.5 text-[12px] text-muted`,children:h(`Goal nudges you asked for; they arrive whatever the proactivity level, but wait out quiet hours.`)})]}),(0,R.jsx)(um,{items:o.reminders,name:m,onChange:()=>void g()}),(0,R.jsx)(mm,{data:o.triggers,name:m,onChange:()=>void g()})]}):l?(0,R.jsx)(Jp,{message:l,onRetry:()=>void g()}):(0,R.jsx)(`div`,{className:`py-10 flex justify-center text-muted`,children:(0,R.jsx)(A,{className:`animate-spin`,size:20})})}function um({items:t,name:n,onChange:r}){let{toast:i}=E(),a=s(),[o,c]=(0,L.useState)(null),[l,d]=(0,L.useState)(!1),f=t.filter(e=>e.status===`active`),p=t.filter(e=>e.status!==`active`),m=async e=>{c(e.id);try{await M.cancelReminder(e.id),r()}catch(e){i(e.message)}finally{c(null)}},h=async e=>{c(e.id);try{await M.fireReminder(e.id),i(e.kind===`task`?a(`{name} is on it`,{name:n}):a(`{name} will say it now`,{name:n})),r()}catch(e){i(e.message)}finally{c(null)}};return(0,R.jsxs)(`div`,{children:[(0,R.jsxs)(`div`,{className:`flex items-center justify-between mb-1.5`,children:[(0,R.jsx)(`div`,{className:`text-[12px] uppercase tracking-wide text-muted font-semibold`,children:a(`Reminders & routines`)}),!l&&(0,R.jsx)(`button`,{type:`button`,onClick:()=>d(!0),className:`text-[12.5px] text-accent font-medium`,children:a(`+ Add`)})]}),l&&(0,R.jsx)(dm,{onDone:()=>{d(!1),r()},onCancel:()=>d(!1)}),f.length===0&&!l?(0,R.jsx)(`div`,{className:`text-[13px] text-muted`,children:a(`Nothing scheduled. Tell {name} “remind me at six to call mum” or “every weekday morning, summarise my unread email”.`,{name:n})}):(0,R.jsx)(`ul`,{className:`space-y-1.5`,children:f.map(t=>(0,R.jsxs)(`li`,{className:`flex items-center gap-2.5 rounded-2xl bg-surface-2/60 px-3 py-2`,children:[t.kind===`task`?(0,R.jsx)(Kt,{size:15,className:`text-muted shrink-0`}):(0,R.jsx)(We,{size:15,className:`text-muted shrink-0`}),(0,R.jsxs)(`div`,{className:`min-w-0 flex-1`,children:[(0,R.jsx)(`div`,{className:`text-[13.5px] font-medium truncate`,children:t.text}),(0,R.jsxs)(`div`,{className:`text-[11.5px] text-muted truncate`,children:[t.next_at?`${e(t.next_at)} · ${u(t.next_at)}`:`—`,t.repeat&&` · ${nm(t.repeat).toLowerCase()}`,t.kind===`task`&&` · ${a(`does the work`)}`]})]}),(0,R.jsx)(`button`,{type:`button`,onClick:()=>void h(t),disabled:o!==null,"aria-label":t.kind===`task`?a(`Do “{text}” now`,{text:t.text}):a(`Remind me now: {text}`,{text:t.text}),className:`rounded-full bg-accent/12 p-2 text-accent disabled:opacity-50`,children:o===t.id?(0,R.jsx)(A,{size:15,className:`animate-spin`}):(0,R.jsx)(Gt,{size:15})}),(0,R.jsx)(`button`,{type:`button`,onClick:()=>void m(t),disabled:o!==null,"aria-label":a(`Cancel: {text}`,{text:t.text}),className:`rounded-full p-2 text-muted hover:text-fg disabled:opacity-50`,children:(0,R.jsx)(Fe,{size:15})})]},t.id))}),p.length>0&&(0,R.jsxs)(`details`,{className:`mt-2`,children:[(0,R.jsx)(`summary`,{className:`text-[12px] text-muted cursor-pointer select-none`,children:a(`{n} finished recently`,{n:p.length})}),(0,R.jsx)(`ul`,{className:`mt-1.5 space-y-1`,children:p.map(t=>(0,R.jsxs)(`li`,{className:`flex items-center gap-2 px-3 text-[12.5px] text-muted`,children:[(0,R.jsx)(`span`,{className:`min-w-0 flex-1 truncate line-through decoration-border`,children:t.text}),(0,R.jsx)(`span`,{className:`shrink-0`,children:t.status===`done`?t.last_fired_at?e(t.last_fired_at):a(`done`):a(`cancelled`)})]},t.id))})]}),(0,R.jsx)(`div`,{className:`mt-1.5 text-[12px] text-muted`,children:a(`A time you named is kept whatever the level or the quiet hours. Reminders just say it; routines do the work and report.`)})]})}function dm({onDone:e,onCancel:t}){let{toast:n}=E(),r=s(),[a,o]=(0,L.useState)(``),[c,l]=(0,L.useState)(`remind`),[u,d]=(0,L.useState)(`once`),[f,p]=(0,L.useState)(()=>_m()),[h,g]=(0,L.useState)(`daily`),[_,v]=(0,L.useState)(`09:00`),[y,b]=(0,L.useState)(`mon`),[x,S]=(0,L.useState)(`1`),[C,w]=(0,L.useState)(!1),T=h===`weekly`?`weekly ${y} ${_}`:h===`monthly`?`monthly ${x} ${_}`:`${h} ${_}`,D=async()=>{if(a.trim()){w(!0);try{await M.createReminder(u===`once`?{text:a.trim(),kind:c,at:f.replace(`T`,` `)}:{text:a.trim(),kind:c,repeat:T}),e()}catch(e){n(e.message)}finally{w(!1)}}},O=`h-9 rounded-xl bg-surface border border-border px-3 text-[13px] outline-none focus:border-accent`;return(0,R.jsxs)(`div`,{className:`mb-2 rounded-2xl border border-border p-3 space-y-2`,children:[(0,R.jsx)(`input`,{autoFocus:!0,value:a,onChange:e=>o(e.target.value),placeholder:r(c===`task`?`What should be done…`:`What to remind you of…`),className:i(O,`w-full h-10 text-[14px]`)}),(0,R.jsxs)(`div`,{className:`flex gap-1.5 text-[12.5px]`,children:[(0,R.jsx)(gm,{options:[[`remind`,r(`Remind me`)],[`task`,r(`Do it for me`)]],value:c,onChange:e=>l(e)}),(0,R.jsx)(gm,{options:[[`once`,r(`Once`)],[`repeat`,r(`Repeat`)]],value:u,onChange:e=>d(e)})]}),u===`once`?(0,R.jsx)(`input`,{type:`datetime-local`,value:f,onChange:e=>p(e.target.value),className:i(O,`w-full`)}):(0,R.jsxs)(`div`,{className:`flex flex-wrap gap-1.5`,children:[(0,R.jsxs)(`select`,{value:h,onChange:e=>g(e.target.value),className:O,children:[(0,R.jsx)(`option`,{value:`daily`,children:r(`Every day`)}),(0,R.jsx)(`option`,{value:`weekdays`,children:r(`Weekdays`)}),(0,R.jsx)(`option`,{value:`weekly`,children:r(`Weekly`)}),(0,R.jsx)(`option`,{value:`monthly`,children:r(`Monthly`)})]}),h===`weekly`&&(0,R.jsx)(`select`,{value:y,onChange:e=>b(e.target.value),className:O,children:[`mon`,`tue`,`wed`,`thu`,`fri`,`sat`,`sun`].map((e,t)=>(0,R.jsx)(`option`,{value:e,children:new Date(2024,0,1+t).toLocaleDateString(m(),{weekday:`long`})},e))}),h===`monthly`&&(0,R.jsx)(`select`,{value:x,onChange:e=>S(e.target.value),className:O,children:Array.from({length:28},(e,t)=>String(t+1)).map(e=>(0,R.jsx)(`option`,{value:e,children:r(`Day {d}`,{d:e})},e))}),(0,R.jsx)(`input`,{type:`time`,value:_,onChange:e=>v(e.target.value),className:O})]}),(0,R.jsxs)(`div`,{className:`flex justify-end gap-2 pt-0.5`,children:[(0,R.jsx)(`button`,{type:`button`,onClick:t,className:`rounded-full px-3 py-1.5 text-[13px] text-muted`,children:r(`Cancel`)}),(0,R.jsx)(`button`,{type:`button`,onClick:()=>void D(),disabled:C||!a.trim(),className:`rounded-full bg-accent px-3.5 py-1.5 text-[13px] font-medium text-accent-fg disabled:opacity-50`,children:r(C?`Saving…`:u===`once`?`Set reminder`:`Set routine`)})]})]})}var fm={mail:Et,event:et,hook:_n};function pm(e,t){if(e.kind===`mail`)return e.match?t(`mail matching “{match}”`,{match:e.match}):t(`any new mail`);if(e.kind===`event`){let n=e.match?t(`events matching “{match}”`,{match:e.match}):t(`any event`);return t(`{n} min before {what}`,{n:e.lead_minutes,what:n})}return e.match?t(`webhook “{match}”`,{match:e.match}):t(`webhook`)}function mm({data:t,name:n,onChange:r}){let{toast:a}=E(),o=s(),[c,l]=(0,L.useState)(null),[u,d]=(0,L.useState)(!1),f=t.items.filter(e=>e.status===`active`),p=f.some(e=>e.kind===`mail`),m=async e=>{l(e.id);try{await M.cancelTrigger(e.id),r()}catch(e){a(e.message)}finally{l(null)}},h=async e=>{l(e.id);try{await M.fireTrigger(e.id),a(o(`{name} is on it`,{name:n})),r()}catch(e){a(e.message)}finally{l(null)}},g=async e=>{if(e.url)try{await navigator.clipboard.writeText(e.url),a(o(`Webhook URL copied`))}catch{a(e.url)}};return(0,R.jsxs)(`div`,{children:[(0,R.jsxs)(`div`,{className:`flex items-center justify-between mb-1.5`,children:[(0,R.jsx)(`div`,{className:`text-[12px] uppercase tracking-wide text-muted font-semibold`,children:o(`When something happens`)}),!u&&(0,R.jsx)(`button`,{type:`button`,onClick:()=>d(!0),className:`text-[12.5px] text-accent font-medium`,children:o(`+ Add`)})]}),u&&(0,R.jsx)(hm,{available:t.available,onDone:()=>{d(!1),r()},onCancel:()=>d(!1)}),f.length===0&&!u?(0,R.jsx)(`div`,{className:`text-[13px] text-muted`,children:o(`Nothing yet. Tell {name} “when the landlord writes back, summarise it and draft a reply” or “half an hour before any review, brief me”.`,{name:n})}):(0,R.jsx)(`ul`,{className:`space-y-1.5`,children:f.map(t=>{let n=fm[t.kind];return(0,R.jsxs)(`li`,{className:`flex items-start gap-2.5 rounded-2xl bg-surface-2/60 px-3 py-2`,children:[(0,R.jsx)(n,{size:15,className:`text-muted shrink-0 mt-[3px]`}),(0,R.jsxs)(`div`,{className:`min-w-0 flex-1`,children:[(0,R.jsx)(`div`,{className:`text-[13.5px] font-medium`,children:pm(t,o)}),(0,R.jsx)(`div`,{className:`text-[12px] leading-snug text-fg/80 line-clamp-2`,children:t.text}),(0,R.jsxs)(`div`,{className:`text-[11.5px] text-muted flex flex-wrap items-center gap-x-1.5`,children:[t.fired>0?(0,R.jsxs)(`span`,{children:[o(`fired {n}×`,{n:t.fired}),t.last_fired_at&&` · ${e(t.last_fired_at)}`]}):(0,R.jsx)(`span`,{children:o(`not fired yet`)}),t.kind===`hook`&&t.url&&(0,R.jsxs)(`button`,{type:`button`,onClick:()=>void g(t),className:`inline-flex items-center gap-1 text-accent font-medium`,children:[(0,R.jsx)(ut,{size:11}),` `,o(`Copy URL`)]})]})]}),(0,R.jsx)(`button`,{type:`button`,onClick:()=>void h(t),disabled:c!==null,"aria-label":o(`Run now: {text}`,{text:t.text}),className:`rounded-full bg-accent/12 p-2 text-accent disabled:opacity-50`,children:c===t.id?(0,R.jsx)(A,{size:15,className:`animate-spin`}):(0,R.jsx)(Gt,{size:15})}),(0,R.jsx)(`button`,{type:`button`,onClick:()=>void m(t),disabled:c!==null,"aria-label":o(`Cancel: {text}`,{text:t.text}),className:`rounded-full p-2 text-muted hover:text-fg disabled:opacity-50`,children:(0,R.jsx)(Fe,{size:15})})]},t.id)})}),p&&(0,R.jsx)(`div`,{className:i(`mt-1.5 text-[12px]`,t.mail_error?`text-rose-500`:`text-muted`),children:t.mail_error?o(`The inbox could not be read: {error}`,{error:t.mail_error}):t.mail_checked_at?o(`Inbox checked {when}; {name} looks every {n} min.`,{when:e(t.mail_checked_at),name:n,n:t.mail_poll_minutes}):o(`{name} will look at the inbox shortly, then every {n} min.`,{name:n,n:t.mail_poll_minutes})}),(0,R.jsx)(`div`,{className:`mt-1.5 text-[12px] text-muted`,children:o(`Each time it happens {name} does the work in the chat it was set from and reports in the Feed. A mail or a request is treated as data, never as instructions.`,{name:n})})]})}function hm({available:e,onDone:t,onCancel:n}){let{toast:r}=E(),a=s(),o=[`mail`,`event`,`hook`].find(t=>e[t])??`hook`,[c,l]=(0,L.useState)(o),[u,d]=(0,L.useState)(``),[f,p]=(0,L.useState)(`30`),[m,h]=(0,L.useState)(``),[g,_]=(0,L.useState)(!1),[v,y]=(0,L.useState)(null),b=async()=>{if(m.trim()){_(!0);try{let e=await M.createTrigger({kind:c,text:m.trim(),match:u.trim(),lead_minutes:Number(f)||30});e.kind===`hook`&&e.url?y(e):t()}catch(e){r(e.message)}finally{_(!1)}}},x=`h-9 rounded-xl bg-surface border border-border px-3 text-[13px] outline-none focus:border-accent`;if(v)return(0,R.jsxs)(`div`,{className:`mb-2 rounded-2xl border border-border p-3 space-y-2`,children:[(0,R.jsx)(`div`,{className:`text-[13.5px] font-medium`,children:a(`Webhook ready`)}),(0,R.jsx)(`div`,{className:`text-[12.5px] text-muted`,children:a(`POST anything to this URL and the work starts. The key is in the URL; share it only with the program that will call it.`)}),(0,R.jsx)(`code`,{className:`block break-all rounded-xl bg-surface-2 px-3 py-2 text-[12px]`,children:v.url}),(0,R.jsxs)(`div`,{className:`flex justify-end gap-2 pt-0.5`,children:[(0,R.jsx)(`button`,{type:`button`,onClick:()=>void navigator.clipboard.writeText(v.url??``).then(()=>r(a(`Webhook URL copied`)),()=>r(v.url??``)),className:`rounded-full px-3 py-1.5 text-[13px] text-accent font-medium`,children:a(`Copy`)}),(0,R.jsx)(`button`,{type:`button`,onClick:t,className:`rounded-full bg-accent px-3.5 py-1.5 text-[13px] font-medium text-accent-fg`,children:a(`Done`)})]})]});let S=[[`mail`,a(`New mail`)],[`event`,a(`Before an event`)],[`hook`,a(`Webhook`)]];return(0,R.jsxs)(`div`,{className:`mb-2 rounded-2xl border border-border p-3 space-y-2`,children:[(0,R.jsx)(gm,{options:S,value:c,onChange:e=>l(e)}),!e[c]&&(0,R.jsx)(`div`,{className:`text-[12.5px] text-rose-500`,children:a(c===`mail`?`Connect a mailbox under Connections first.`:`Add a calendar under Connections first.`)}),(0,R.jsxs)(`div`,{className:`flex gap-1.5`,children:[(0,R.jsx)(`input`,{value:u,onChange:e=>d(e.target.value),placeholder:a(c===`mail`?`Words in the sender or subject (empty: any mail)`:c===`event`?`Words in the title or place (empty: any event)`:`A name for this hook`),className:i(x,`min-w-0 flex-1`)}),c===`event`&&(0,R.jsxs)(`label`,{className:`flex items-center gap-1 text-[12.5px] text-muted`,children:[(0,R.jsx)(`input`,{type:`number`,min:0,max:1440,value:f,onChange:e=>p(e.target.value),className:i(x,`w-[64px] px-2`),"aria-label":a(`Minutes before`)}),a(`min before`)]})]}),(0,R.jsx)(`input`,{value:m,onChange:e=>h(e.target.value),placeholder:a(`What should be done each time…`),className:i(x,`w-full h-10 text-[14px]`)}),(0,R.jsx)(`div`,{className:`text-[12px] text-muted`,children:a(`When {condition}`,{condition:pm({kind:c,match:u.trim(),lead_minutes:Number(f)||30},a)})}),(0,R.jsxs)(`div`,{className:`flex justify-end gap-2 pt-0.5`,children:[(0,R.jsx)(`button`,{type:`button`,onClick:n,className:`rounded-full px-3 py-1.5 text-[13px] text-muted`,children:a(`Cancel`)}),(0,R.jsx)(`button`,{type:`button`,onClick:()=>void b(),disabled:g||!m.trim()||!e[c],className:`rounded-full bg-accent px-3.5 py-1.5 text-[13px] font-medium text-accent-fg disabled:opacity-50`,children:a(g?`Saving…`:`Set trigger`)})]})]})}function gm({options:e,value:t,onChange:n}){return(0,R.jsx)(`div`,{className:`flex rounded-full bg-surface-2 p-0.5`,children:e.map(([e,r])=>(0,R.jsx)(`button`,{type:`button`,onClick:()=>n(e),className:i(`rounded-full px-2.5 py-1 transition`,t===e?`bg-surface shadow-sm font-medium`:`text-muted`),children:r},e))})}function _m(){let e=new Date(Date.now()+36e5);e.setMinutes(0,0,0);let t=e=>String(e).padStart(2,`0`);return`${e.getFullYear()}-${t(e.getMonth()+1)}-${t(e.getDate())}T${t(e.getHours())}:${t(e.getMinutes())}`}function vm(e){let[t,n]=(0,L.useState)(null),[r,i]=(0,L.useState)(null),a=async()=>{try{n(await M.activity(150)),i(null)}catch(e){i(e.message||`Could not load.`)}};return(0,L.useEffect)(()=>{if(!e)return;a();let t=window.setInterval(()=>void a(),4e3);return()=>window.clearInterval(t)},[e]),[t,a,r]}function ym({open:e}){let[t,n,r]=vm(e),{state:i}=E(),a=s(),o=i.profile?.name??`nanoMuse`,c=(t?.audit??[]).filter(e=>e.event===`tool_call`).reverse(),l=c.filter(e=>e.channel===`gui`).length;return(0,R.jsxs)(`div`,{className:`pb-2`,children:[(0,R.jsx)(`p`,{className:`text-[12.5px] text-muted mb-2`,children:a(`Every tool call goes through the Sentinel and is written to the audit log, including the ones it refused.`)}),l>0&&(0,R.jsx)(`p`,{className:`text-[12.5px] text-muted mb-2`,children:a(`On the phone's screen: {gui} of {total} steps ({pct}%). The screen is the last resort; a skill, a fetch or the browser comes first.`,{gui:String(l),total:String(c.length),pct:String(Math.round(l/c.length*100))})}),!t&&r&&(0,R.jsx)(Jp,{message:r,onRetry:()=>void n()}),!t&&!r&&(0,R.jsx)(`div`,{className:`py-10 flex justify-center text-muted`,children:(0,R.jsx)(A,{className:`animate-spin`,size:20})}),t&&c.length===0&&(0,R.jsx)(`div`,{className:`py-8 text-center text-muted text-[14px]`,children:a(`Nothing yet today. What you ask for and what {name} does about it shows up here.`,{name:o})}),(0,R.jsx)(`ul`,{className:`space-y-1.5`,children:c.map((e,t)=>(0,R.jsx)(Tm,{entry:e},`${e.ts}-${t}`))})]})}function bm({open:e}){let{state:t,toast:n}=E(),r=s(),[i,a]=vm(e),o=async()=>{if(window.confirm(r(`Forget every permission you granted? {name} will ask again next time.`,{name:t.profile?.name??`nanoMuse`})))try{await M.resetApprovals(),await a(),n(r(`Permissions reset`))}catch(e){n(e.message)}},c=async e=>{try{await M.revokeGrant(e.key),await a(),n(r(`Revoked: {subject}`,{subject:pp(e.tool,e.target)}))}catch(e){n(e.message)}},l=t.settings?.sentinel.mode;return(0,R.jsxs)(`div`,{className:`space-y-4 pb-2`,children:[(0,R.jsxs)(`div`,{className:`rounded-2xl border border-border p-3.5`,children:[(0,R.jsxs)(`div`,{className:`flex items-center gap-2 font-medium`,children:[(0,R.jsx)(Qt,{size:18,className:`text-accent`}),` `,r(`Sentinel mode:`),` `,(0,R.jsx)(`span`,{className:`capitalize`,children:l===`ask`?r(`balanced`):l===`strict`?r(`cautious`):l===`auto`?r(`hands-off`):l})]}),(0,R.jsxs)(`p`,{className:`mt-1 text-[12.5px] text-muted`,children:[l===`ask`&&r(`Safe and moderate actions run freely; anything sensitive (email, shell, purchases) waits for you.`),l===`strict`&&r(`Moderate and sensitive actions both wait for your approval.`),l===`auto`&&r(`Everything is approved automatically except explicit deny rules. Use with care.`)]}),i?.tainted&&(0,R.jsxs)(`p`,{className:`mt-2 text-[12.5px] text-amber-600 dark:text-amber-300 flex items-center gap-1.5`,children:[(0,R.jsx)($t,{size:14}),` `,r(`Private data was read this session: network calls to new destinations need approval.`)]})]}),(0,R.jsx)(Cm,{grants:i?.grants??[],onRevoke:c}),(0,R.jsx)(wm,{title:r(`Always ask (from config)`),tools:t.settings?.sentinel.always_ask_tools??[],muted:!0}),(i?.grants.length??0)>0&&(0,R.jsx)(`button`,{type:`button`,onClick:()=>void o(),className:`w-full rounded-2xl border border-border py-2.5 text-[14px] font-medium`,children:r(`Reset all granted permissions`)})]})}function xm(e,t){switch(e.scope){case`conversation`:return t(`for this conversation`);case`session`:return t(`until restart`);case`24h`:return e.expires_at?t(`until {time}`,{time:u(e.expires_at)}):t(`for 24 hours`);case`always`:return t(`always`);default:return e.scope}}var Sm=[`sensitive`,`moderate`,`low`,`safe`];function Cm({grants:e,onRevoke:t}){let n=s(),{state:r}=E(),i=e=>r.settings?.tools.find(t=>t.name===e)?.risk??`moderate`,a=Sm.map(t=>({risk:t,rows:e.filter(e=>i(e.tool)===t)})).filter(e=>e.rows.length>0);return(0,R.jsx)(`div`,{className:`space-y-3`,children:e.length===0?(0,R.jsxs)(`div`,{children:[(0,R.jsx)(`div`,{className:`text-[12px] uppercase tracking-wide text-muted font-semibold mb-1.5`,children:n(`Permissions you granted`)}),(0,R.jsx)(`div`,{className:`text-[13px] text-muted`,children:n(`No standing approvals. When you answer “always allow” to a risky step, it is listed here and can be revoked; approvals you give once are not kept.`)})]}):a.map((e,r)=>(0,R.jsxs)(`div`,{children:[(0,R.jsxs)(`div`,{className:`text-[12px] uppercase tracking-wide text-muted font-semibold mb-1.5`,children:[r===0?`${n(`Permissions you granted`)} · `:``,n(e.risk)]}),(0,R.jsx)(`ul`,{className:`space-y-1.5`,children:e.rows.map(e=>(0,R.jsxs)(`li`,{className:`flex items-center gap-2.5 rounded-2xl bg-surface-2/60 px-3 py-2`,children:[(0,R.jsx)(`span`,{className:`text-accent`,children:sp(e.tool,15)}),(0,R.jsxs)(`div`,{className:`min-w-0 flex-1`,children:[(0,R.jsx)(`div`,{className:`text-[13.5px] font-medium truncate`,children:pp(e.tool,e.target)}),(0,R.jsxs)(`div`,{className:`text-[11.5px] text-muted`,children:[e.tool,` · `,xm(e,n),` · `,n(`granted {time}`,{time:u(e.granted_at)})]})]}),(0,R.jsx)(`button`,{type:`button`,"aria-label":n(`Revoke {what}`,{what:mp(e.scope,e.tool,e.target)}),onClick:()=>t(e),className:`rounded-full p-1.5 text-muted hover:bg-surface active:scale-95`,children:(0,R.jsx)(Fe,{size:15})})]},e.key))})]},e.risk))})}function wm({title:e,tools:t,muted:n}){let r=s();return(0,R.jsxs)(`div`,{children:[(0,R.jsx)(`div`,{className:`text-[12px] uppercase tracking-wide text-muted font-semibold mb-1.5`,children:e}),t.length===0?(0,R.jsx)(`div`,{className:`text-[13px] text-muted`,children:r(`None`)}):(0,R.jsx)(`div`,{className:`flex flex-wrap gap-1.5`,children:t.map(e=>(0,R.jsxs)(`span`,{className:i(`rounded-full px-2.5 py-1 text-[12.5px] flex items-center gap-1`,n?`bg-surface-2 text-muted`:`bg-accent/12 text-accent`),children:[sp(e,12),` `,e]},e))})]})}function Tm({entry:e}){let t=s(),n=e.decision===`deny`,r=e.ok===!1&&!n;return(0,R.jsxs)(`li`,{className:`flex items-start gap-2.5 rounded-2xl bg-surface-2/60 px-3 py-2`,children:[(0,R.jsx)(`div`,{className:i(`mt-0.5`,n?`text-rose-500`:r?`text-amber-500`:`text-muted`),children:n||r?(0,R.jsx)(Ye,{size:15}):(0,R.jsx)(ke,{size:15})}),(0,R.jsxs)(`div`,{className:`min-w-0 flex-1`,children:[(0,R.jsxs)(`div`,{className:`flex items-center gap-2 text-[13.5px]`,children:[(0,R.jsx)(`span`,{className:`text-muted`,children:sp(e.tool??``,13)}),(0,R.jsx)(`span`,{className:`font-medium truncate`,children:e.summary||e.tool})]}),(0,R.jsxs)(`div`,{className:`mt-0.5 flex flex-wrap items-center gap-x-2 gap-y-0.5 text-[11.5px] text-muted`,children:[(0,R.jsx)(`span`,{children:u(e.ts)}),e.risk&&(0,R.jsx)(up,{risk:e.risk}),e.approved===!0&&(0,R.jsxs)(`span`,{className:`text-emerald-600 dark:text-emerald-300`,children:[t(`approved by you`),e.approval_scope&&e.approval_scope!==`once`?` (${e.approval_scope})`:``]}),e.approved==null&&e.approval_scope&&e.approval_scope!==`once`&&(0,R.jsx)(`span`,{className:`text-emerald-600 dark:text-emerald-300`,children:t(`covered by your {scope} permission`,{scope:e.approval_scope})}),n&&(0,R.jsx)(`span`,{className:`text-rose-500`,children:t(`blocked`)}),r&&(0,R.jsx)(`span`,{className:`text-amber-600`,children:t(`failed`)}),typeof e.duration_ms==`number`&&(0,R.jsxs)(`span`,{children:[(e.duration_ms/1e3).toFixed(1),`s`]})]}),n&&e.reasons&&e.reasons.length>0&&(0,R.jsx)(`div`,{className:`mt-0.5 text-[12px] text-muted`,children:e.reasons.map(v).join(` · `)})]})]})}function Em({title:e,actions:t=[],trailing:n,children:r}){let{state:i,setDrawer:a}=E(),o=s(),[c,l]=(0,L.useState)(!1),u=i.profile?.name||`nanoMuse`,d=i.pendingApprovals.length,f=d>0?d>1?o(`{n} approvals waiting for you`,{n:d}):o(`1 approval waiting for you`):i.status.state===`working`?i.status.detail||o(`On it`):i.status.state===`waiting`?o(`Waiting for you`):null;return(0,R.jsxs)(R.Fragment,{children:[(0,R.jsx)(ne,{profile:i.profile,status:i.status,name:u,statusLine:f,statusTone:f?`accent`:`muted`,spinning:i.status.state===`working`&&d===0,badge:d,onAvatar:()=>l(!0),leading:(0,R.jsx)(te,{onClick:()=>a(!0),label:o(`Chats`),className:`wide:invisible`,children:(0,R.jsx)(Ot,{size:22})}),trailing:n??(0,R.jsx)(Dm,{actions:t})}),(e||r)&&(0,R.jsxs)(`div`,{className:`flex shrink-0 items-center gap-3 pr-5`,children:[(0,R.jsx)(k,{className:`flex-1`,children:e}),r]}),(0,R.jsx)(am,{open:c,onClose:()=>l(!1)})]})}function Dm({actions:e=[]}){let{setTab:t}=E(),n=s(),[r,i]=(0,L.useState)(!1),a=(0,L.useRef)(null);(0,L.useEffect)(()=>{if(!r)return;let e=e=>{a.current?.contains(e.target)||i(!1)},t=e=>{e.key===`Escape`&&i(!1)};return window.addEventListener(`pointerdown`,e),window.addEventListener(`keydown`,t),()=>{window.removeEventListener(`pointerdown`,e),window.removeEventListener(`keydown`,t)}},[r]);let o=e=>{i(!1),t(e)},c=[...e.map(e=>({label:e.label,onClick:()=>{i(!1),e.onClick()}})),{label:n(`Memory`),onClick:()=>o(`memory`)},{label:n(`Settings`),onClick:()=>o(`you`)}];return(0,R.jsxs)(`div`,{ref:a,className:`relative`,children:[(0,R.jsx)(te,{onClick:()=>i(e=>!e),label:n(`More`),expanded:r,children:(0,R.jsx)(pt,{size:22})}),r&&(0,R.jsx)(`ul`,{role:`menu`,className:`absolute right-0 top-12 z-30 min-w-[180px] overflow-hidden rounded-2xl border border-border bg-surface py-1 shadow-xl`,children:c.map(e=>(0,R.jsx)(`li`,{children:(0,R.jsx)(`button`,{type:`button`,role:`menuitem`,onClick:e.onClick,className:`w-full px-4 py-2.5 text-left text-[14.5px] hover:bg-surface-2`,children:e.label})},e.label))})]})}var Om=`nanomuse-naming`;function km(e){return e.replace(/[.*+?^${}()|[\]\\]/g,`\\$&`)}function Am(e,t,n=!1){let r="```"+t,i=e;if(i.includes(r)){let e=RegExp("```"+km(t)+"[ \\t]*\\r?\\n[\\s\\S]*?```",`g`);i=i.replace(e,``);let n=i.lastIndexOf(r);n>=0&&(i=i.slice(0,n))}if(n){let e=i.lastIndexOf("```");e>=0&&r.startsWith(i.slice(e))&&(i=i.slice(0,e))}return i===e?e:i.replace(/\s+$/,``)}function jm(e,t=!1){return Am(e,Om,t)}function Mm(e){return e.filter(e=>!e.this&&e.kind!==`web`&&e.name.trim()!==``)}function Nm(e){let t=/^@([^\s,:;,:;]*)$/.exec(e);return t?t[1]:null}function Pm(e,t,n=6){let r=Nm(e);if(r===null)return[];let i=r.toLowerCase();return Mm(t).filter(e=>e.name.toLowerCase().startsWith(i)).sort((e,t)=>Number(t.online)-Number(e.online)||e.name.localeCompare(t.name)).slice(0,n)}function Fm(e,t){let n=e.trimStart();if(!n.startsWith(`@`))return null;let r=n.slice(1),i=r.toLowerCase(),a=Mm(t),o=a.filter(e=>{let t=e.name.trim().toLowerCase();if(!i.startsWith(t))return!1;let n=r.charAt(t.length);return n===``||/[\s,:;,:;]/.test(n)}).sort((e,t)=>t.name.length-e.name.length);if(o[0])return o[0];let s=/^[^\s,:;,:;]+/.exec(r)?.[0]?.toLowerCase()??``;if(!s)return null;let c=a.filter(e=>e.name.trim().toLowerCase().startsWith(s));if(c.length===1)return c[0];let l=c.filter(e=>e.online);return l.length===1?l[0]:null}var Im=`nm.show_steps`;function Lm(){try{return localStorage.getItem(Im)!==`0`}catch{return!0}}var Rm=Lm(),zm=new Set;function Bm(){return Rm}function Vm(e){Rm=e;try{localStorage.setItem(Im,e?`1`:`0`)}catch{}zm.forEach(e=>e())}function Hm(e){return zm.add(e),()=>zm.delete(e)}function Um(){return(0,L.useSyncExternalStore)(Hm,Bm,Bm)}function Wm(){let{state:e,send:t,sendViaCloud:n,decide:r,loadEvents:i,openFile:a,toast:o,setDrawer:c,setTab:l}=E(),u=s(),{profile:d,status:f,activeThread:p,threads:m}=e,h=e.events[p],g=(0,L.useMemo)(()=>h??[],[h]),_=h!==void 0,v=e.streams[p],b=m.find(e=>e.id===p),[x,S]=(0,L.useState)(!1),[C,w]=(0,L.useState)(null),T=d?.name??`nanoMuse`,D=b?.device?e.hub?.devices.find(e=>e.id===b.device)?.online??null:null,O=nh(e.working[p]),k=(0,L.useRef)(null),ee=(0,L.useRef)(null),A=(0,L.useRef)(!0),[j,re]=(0,L.useState)(!1),N=e.firstrun,P=!!N&&N.phase!==`none`&&N.session_id===p,ie=P&&N.running,ae=y()===`zh-CN`?`zh`:`en`,[oe,se]=(0,L.useState)(null);(0,L.useEffect)(()=>{if(!P||oe?.lang===ae)return;let e=!0;return M.firstrun(ae).then(t=>e&&t.intro&&se({lang:ae,lines:t.intro})).catch(()=>void 0),()=>{e=!1}},[P,ae,oe?.lang]);let ce=e=>{M.firstrunPick(e).then(()=>t(p,e)).catch(e=>o(e.message||u(`Could not send`)))},le=()=>window.dispatchEvent(new Event(`nanomuse:quick-chat`)),[ue,de]=(0,L.useState)(null),fe=e.settings?.onboarded===!0,pe=(0,L.useRef)(!1),me=(0,L.useRef)(!1);(0,L.useEffect)(()=>{if(b?.busy){pe.current||(me.current=ie),pe.current=!0;return}pe.current&&(pe.current=!1,fe&&!me.current&&!ie&&ch(g)&&de(Se()))},[b?.busy,g,fe,ie]);let[he,ge]=(0,L.useState)(null);(0,L.useEffect)(()=>{let{days:e,fresh:t}=ye();t&&ge(e)},[]);let _e=(0,L.useCallback)(()=>{let e=k.current;e&&(e.scrollTop=e.scrollHeight,re(!1))},[]),ve=(0,L.useCallback)(()=>{let e=k.current;if(!e)return;let t=e.scrollHeight-e.scrollTop-e.clientHeight;A.current=t<120,re(t>400)},[]),be=(0,L.useRef)(null);(0,L.useLayoutEffect)(()=>{be.current!==p&&(be.current=p,A.current=!0),A.current&&_e()},[g,v?.text,p,_e]),(0,L.useEffect)(()=>{let e=k.current,t=ee.current;if(!e||!t||typeof ResizeObserver>`u`)return;let n=new ResizeObserver(()=>{A.current?_e():ve()});return n.observe(e),n.observe(t),()=>n.disconnect()},[_e,ve]);let xe=()=>{let e=k.current;e&&e.scrollTo({top:e.scrollHeight,behavior:`smooth`})},Ce=e.pendingApprovals.length,Te=e.pendingApprovals.filter(e=>e.thread===p).length,Ee=(0,L.useMemo)(()=>{let e=!f.thread||f.thread===p;if(Te>0&&!(e&&f.state===`working`))return Te>1?u(`{n} approvals waiting for you`,{n:Te}):u(`1 approval waiting for you`);if(!e)return b?.busy?u(`On it`):void 0;if(f.state===`idle`&&!b?.busy)return;if(f.detail)return f.detail;if(f.state===`waiting`)return u(`Waiting for you`);let t=sh(g);return t?u(`On it: {request}`,{request:t}):u(`On it`)},[f,b,p,Te,g,u]),De=g.filter(e=>e.type===`approval`&&e.status===`pending`).length,Oe=Um(),ke=(0,L.useMemo)(()=>Oe?g:g.filter(e=>e.type!==`tool`),[g,Oe]),Ae={signedIn:!!e.hub?.account.signed_in,chatOnCloud:!!e.settings?.llm.cloud,deviceChat:!!b?.device},je=e=>{let t=ep(ke,e,Ae);return t?()=>n(p,t.text,t.files):void 0},Ne=(0,L.useMemo)(()=>Array.from(new Set(g.flatMap(e=>e.type===`artifact`?[e.path]:[]))),[g]);return(0,R.jsxs)(`div`,{className:`flex h-full flex-col`,children:[(0,R.jsx)(ne,{profile:d,status:f,name:T,statusLine:Ee,statusTone:f.state===`idle`&&!b?.busy?`muted`:`accent`,spinning:(f.state===`working`&&f.thread===p||!!b?.busy)&&Te===0,badge:Ce,onAvatar:()=>S(!0),leading:(0,R.jsx)(te,{onClick:()=>c(!0),label:u(`Chats`),dot:m.length>1&&p!==`main`,className:`wide:invisible`,children:(0,R.jsx)(Ot,{size:22})}),trailing:(0,R.jsx)(Dm,{actions:[{label:u(`Coding agents`),onClick:()=>l(`coding`)}]}),under:b&&b.id!==`main`?b.device?(0,R.jsxs)(`span`,{className:`flex max-w-full items-center gap-1 rounded-full bg-accent/12 px-2.5 py-0.5 text-[11.5px] font-medium text-accent`,children:[D===!1?(0,R.jsx)(`span`,{className:`h-1.5 w-1.5 rounded-full bg-border`}):(0,R.jsx)(`span`,{className:`h-1.5 w-1.5 rounded-full bg-emerald-500`}),(0,R.jsx)(`span`,{className:`truncate`,children:u(`on {device}`,{device:b.device_name||b.device})})]}):b.remote_from?(0,R.jsxs)(`span`,{className:`flex max-w-full items-center gap-1 rounded-full bg-surface-2 px-2.5 py-0.5 text-[11.5px] font-medium text-fg/80`,children:[(0,R.jsx)(It,{size:11}),` `,(0,R.jsx)(`span`,{className:`truncate`,children:u(`from {device}`,{device:b.remote_from.name})})]}):(0,R.jsx)(`span`,{className:`truncate rounded-full bg-surface-2 px-2.5 py-0.5 text-[11.5px] font-medium text-fg/80`,children:b.title}):void 0}),(0,R.jsxs)(`div`,{ref:k,onScroll:ve,className:`relative flex-1 overflow-y-auto px-3 py-3`,children:[(0,R.jsxs)(`div`,{ref:ee,className:`space-y-2.5`,children:[e.hasMore[p]&&g.length>0&&(0,R.jsx)(`div`,{className:`flex justify-center`,children:(0,R.jsx)(`button`,{type:`button`,className:`text-[12.5px] text-accent px-3 py-1 rounded-full bg-surface-2`,onClick:()=>void i(p,g[0]?.id),children:u(`Load earlier messages`)})}),P&&_&&!e.hasMore[p]&&oe&&(0,R.jsx)(Fp,{lines:oe.lines}),_&&g.length===0&&!v&&!P&&(0,R.jsx)(ih,{name:T,device:b?.device?b.device_name||b.device:void 0,onSend:e=>t(p,e).catch(e=>o(e.message||u(`Could not send`)))}),ke.map((e,t)=>(0,R.jsx)(Gm,{event:e,prev:ke[t-1],name:T,onDecide:(t,n)=>r(e.id,t,n).catch(e=>o(e.message||u(`Could not send decision`))),onOpenFile:a,onOpenBrowser:w,files:Ne,onCloudRetry:je(t)},e.id)),v&&v.text&&(0,R.jsx)($m,{text:v.text,streaming:!0,files:Ne,onOpenFile:a}),(b?.busy||f.state!==`idle`)&&!v?.text&&f.state!==`waiting`&&(0,R.jsx)(th,{label:b?.queued?u(`{n} queued`,{n:b.queued}):void 0}),P&&N.phase===`ask_agent_name`&&!b?.busy&&(0,R.jsx)(Ip,{chips:N.chips,chosen:N.chosen,onPick:ce,onElse:le}),O&&!b?.busy&&(0,R.jsx)(rh,{who:O}),!b?.busy&&f.state===`idle`&&ue!==null&&(0,R.jsx)(we,{moment:`tasks`,n:ue,className:`mx-1 my-2`}),!b?.busy&&f.state===`idle`&&he!==null&&(0,R.jsx)(we,{moment:`days_used`,n:he,className:`mx-1 my-2`})]}),j&&(0,R.jsxs)(`button`,{type:`button`,onClick:xe,className:`sticky bottom-2 left-1/2 -translate-x-1/2 rounded-full bg-surface border border-border shadow px-3 py-1.5 text-[12.5px] flex items-center gap-1`,children:[(0,R.jsx)(Me,{size:14}),` `,u(`Latest`),De?` · ${u(`{n} approval`,{n:De})}`:``]})]}),(0,R.jsx)(Rf,{}),(0,R.jsx)(ah,{name:T,busy:!!b?.busy&&De===0,waiting:g.some(e=>e.type===`question`&&e.status===`pending`),onSend:(e,n)=>t(p,e,n).catch(e=>{throw o(e.message||u(`Could not send`)),e})}),(0,R.jsx)(am,{open:x,onClose:()=>S(!1)}),C&&(0,R.jsx)(Ap,{thread:p,eventId:C,onClose:()=>w(null)})]})}function Gm({event:e,prev:t,name:n,onDecide:r,onOpenFile:i,onOpenBrowser:a,files:o,onCloudRetry:s}){let c=qm(t,e)?(0,R.jsx)(Jm,{ts:e.ts}):null,l=(()=>{switch(e.type){case`user`:return(0,R.jsx)(Ym,{event:e,onOpenFile:i});case`assistant`:return e.quiet?(0,R.jsx)(eh,{text:e.text,about:e.about,ts:e.ts}):(0,R.jsx)($m,{text:e.text,reasoning:e.reasoning,continued:t?.type===`assistant`,files:o,onOpenFile:i,spoken:e.via===`call`,modelUsed:e.model_used});case`tool`:return(0,R.jsx)(fp,{event:e});case`approval`:return(0,R.jsx)(hp,{event:e,name:n,onDecide:r});case`question`:return(0,R.jsx)(gp,{event:e,name:n});case`notice`:return(0,R.jsx)(vp,{event:e,onCloudRetry:s});case`artifact`:return(0,R.jsx)(Ep,{event:e,onOpen:i});case`browser`:return(0,R.jsx)(yp,{event:e,onOpen:a});case`hands`:return(0,R.jsx)(bp,{event:e,name:n});case`hold`:return(0,R.jsx)(wp,{event:e,name:n});case`avatar`:return(0,R.jsx)(np,{event:e,name:n});default:return null}})();return l?(0,R.jsxs)(R.Fragment,{children:[c,l]}):null}var Km=6e5;function qm(e,t){return t.ts?!e?.ts||new Date(t.ts).getTime()-new Date(e.ts).getTime()>=Km:!1}function Jm({ts:e}){let t=l(e);return t?(0,R.jsx)(`div`,{className:`pt-2 pb-0.5 text-center text-[11.5px] font-medium text-muted`,children:t}):null}function Ym({event:e,onOpenFile:t}){let n=s(),r=e.files??[],a=r.filter(e=>e.kind===`image`),o=r.filter(e=>e.kind!==`image`);return(0,R.jsxs)(`div`,{className:`rise flex flex-col items-end pl-12`,children:[e.via===`call`?(0,R.jsxs)(`span`,{className:`mb-1 flex items-center gap-1 text-[11.5px] font-medium text-muted`,children:[(0,R.jsx)(Ut,{size:11}),` `,n(`said on a call`)]}):e.via?(0,R.jsx)(`span`,{className:`mb-1 text-[11.5px] font-medium text-muted`,children:n(`asked from {device}`,{device:e.via})}):e.to_device_name||e.to_device?(0,R.jsxs)(`span`,{className:`mb-1 flex items-center gap-1 text-[11.5px] font-medium text-accent`,children:[(0,R.jsx)(It,{size:11}),` `,n(`to {device}`,{device:e.to_device_name||e.to_device||``})]}):(e.via_device_name||e.via_device)&&(0,R.jsx)(`span`,{className:`mb-1 text-[11.5px] font-medium text-muted`,children:n(`From {device}`,{device:e.via_device_name||e.via_device||``})}),a.length>0&&(0,R.jsx)(`div`,{className:`mb-1 flex max-w-full flex-wrap justify-end gap-1.5`,children:a.map(e=>(0,R.jsx)(`button`,{type:`button`,onClick:()=>t(e.path),"aria-label":e.name,className:i(`overflow-hidden rounded-2xl border border-border/60 bg-surface-2 shadow-sm active:scale-[0.98] transition`,a.length===1?`max-h-64 max-w-[240px]`:`h-28 w-28`),children:(0,R.jsx)(`img`,{src:h(e.path),alt:e.name,loading:`lazy`,className:i(`object-cover`,a.length===1?`max-h-64 w-auto max-w-full`:`h-full w-full`)})},e.path))}),o.map(e=>(0,R.jsxs)(`button`,{type:`button`,onClick:()=>t(e.path),className:`mb-1 flex max-w-full items-center gap-2.5 rounded-2xl border border-border bg-surface px-3 py-2 text-left shadow-sm hover:bg-surface-2 active:scale-[0.98] transition`,children:[(0,R.jsx)(`span`,{className:`rounded-xl bg-accent/12 p-2 text-accent`,children:e.kind===`data`?(0,R.jsx)(cn,{size:17}):(0,R.jsx)(mt,{size:17})}),(0,R.jsxs)(`span`,{className:`min-w-0`,children:[(0,R.jsx)(`span`,{className:`block truncate text-[14px] font-medium`,children:e.name}),(0,R.jsx)(`span`,{className:`block text-[11.5px] text-muted`,children:Xm(e.size)})]})]},e.path)),e.text&&(0,R.jsx)(`div`,{className:`bubble-user max-w-full rounded-[20px] bg-bubble-user px-4 py-2.5 text-bubble-user-fg`,children:(0,R.jsx)(`div`,{className:`md text-[15px] leading-[1.45] whitespace-pre-wrap break-words`,children:e.text})})]})}function Xm(e){return e<1024?`${e} B`:e<1048576?`${Math.round(e/1024)} KB`:`${(e/1048576).toFixed(1)} MB`}function Zm(e){let t=e.toLowerCase().split(`.`).pop()??``;return[`csv`,`tsv`,`json`,`xlsx`,`xls`].includes(t)?`data`:`other`}var Qm=`image/*,.pdf,.txt,.md,.csv,.tsv,.json,.log,.html,.xml,.yaml,.yml,.toml,.ics,.vcf,.xlsx,.xls,.docx`;function $m({text:e,reasoning:t,streaming:n,continued:r,files:a,onOpenFile:o,spoken:c,modelUsed:l}){let[u,d]=(0,L.useState)(!1),f=s(),p=(0,L.useMemo)(()=>mf(jm(e,!!n)),[e,n]);return p.length===0&&!n&&!t?null:(0,R.jsx)(`div`,{className:i(`rise flex items-end gap-2 pr-10`,r&&`-mt-1`),children:(0,R.jsxs)(`div`,{className:`min-w-0 max-w-full`,children:[t&&(0,R.jsx)(`button`,{type:`button`,className:`mb-1 ml-1 text-[12px] text-muted`,onClick:()=>d(e=>!e),children:f(u?`Hide thinking`:`Show thinking`)}),t&&u&&(0,R.jsx)(`div`,{className:`mb-1.5 rounded-2xl bg-surface-2/70 px-3 py-2 text-[13px] text-muted whitespace-pre-wrap break-words`,children:t}),p.map((e,t)=>e.bare?(0,R.jsx)(`div`,{className:`my-1 max-w-full`,children:(0,R.jsx)(hf,{text:e.text,files:a,onOpenFile:o})},t):(0,R.jsxs)(`div`,{className:i(`my-1 max-w-[340px] rounded-[20px] bg-surface-2 px-3.5 py-2.5 wide:max-w-[600px]`,c&&`border border-accent/15`),children:[c&&t===0&&(0,R.jsxs)(`div`,{className:`mb-0.5 flex items-center gap-1 text-[11px] font-medium text-accent/80`,children:[(0,R.jsx)(Ut,{size:10}),` `,f(`said on a call`)]}),(0,R.jsx)(hf,{text:e.text,files:a,onOpenFile:o}),n&&t===p.length-1&&(0,R.jsx)(`span`,{className:`inline-block w-1.5 h-4 ml-0.5 align-middle bg-accent/70 animate-pulse rounded-sm`})]},t)),p.length===0&&n&&(0,R.jsx)(`div`,{className:`my-1 rounded-[20px] bg-surface-2 px-3.5 py-2.5`,children:(0,R.jsx)(`span`,{className:`inline-block w-1.5 h-4 align-middle bg-accent/70 animate-pulse rounded-sm`})}),l&&!n&&(0,R.jsx)(`div`,{className:`ml-1 text-[11px] text-muted`,children:f(`Answered by nanoMuse Cloud this time ({model})`,{model:l})})]})})}function eh({text:e,about:n,ts:r}){let[i,a]=(0,L.useState)(!1),o=s(),c=n?t(n.replace(/^Working on your goal: /,``)):o(`background check`);return(0,R.jsx)(`div`,{className:`rise flex justify-center px-6`,children:(0,R.jsxs)(`button`,{type:`button`,onClick:()=>a(e=>!e),className:`max-w-full rounded-2xl px-3 py-1.5 text-[12px] text-muted text-center leading-snug`,children:[(0,R.jsxs)(`span`,{className:`inline-flex items-center gap-1.5`,children:[(0,R.jsx)(Rt,{size:12}),` `,o(`Checked on {label}: nothing new`,{label:c}),r?` · ${u(r)}`:``]}),i&&(0,R.jsx)(`span`,{className:`block mt-1 text-left whitespace-pre-wrap text-[12.5px]`,children:e})]})})}function th({label:e}){return(0,R.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,R.jsxs)(`div`,{className:`rounded-[20px] rounded-bl-md bg-surface-2 px-3.5 py-2.5 flex items-center gap-1`,children:[(0,R.jsx)(`span`,{className:`typing-dot h-2 w-2 rounded-full bg-muted`}),(0,R.jsx)(`span`,{className:`typing-dot h-2 w-2 rounded-full bg-muted`}),(0,R.jsx)(`span`,{className:`typing-dot h-2 w-2 rounded-full bg-muted`})]}),e&&(0,R.jsx)(`span`,{className:`text-[12px] text-muted`,children:e})]})}function nh(e){let t=e?e.at*1e3+N:0,[n,r]=(0,L.useState)(0);return(0,L.useEffect)(()=>{if(!t)return;let e=t-Date.now();if(e<=0){r(t);return}let n=window.setTimeout(()=>r(t),e+50);return()=>window.clearTimeout(n)},[t]),!e||n===t?null:e}function rh({who:e}){let t=s();return(0,R.jsxs)(`div`,{className:`flex items-center gap-1.5 px-1 text-[12px] text-muted`,children:[(0,R.jsx)(A,{size:12,className:`animate-spin`}),(0,R.jsx)(`span`,{children:t(`{device} is working…`,{device:e.device_name||e.device})})]})}function ih({name:e,device:t,onSend:n}){let r=s(),i=t?[r(`What is on your screen right now?`),r(`Which folder are you in, and what is in it?`),r(`Check for updates and tell me what needs a restart`)]:[r(`What can you do for me?`),r(`Plan my week: ask me what's on my plate`),r(`Research and compare two options for me`),r(`Set up a long-term goal and track it`)];return(0,R.jsxs)(`div`,{className:`flex flex-col items-center text-center px-6 pt-10 pb-6 gap-3`,children:[(0,R.jsx)(`div`,{className:`text-[20px] font-semibold`,children:t?r(`This chat goes to {device}.`,{device:t}):r(`Hi, I'm {name}.`,{name:e})}),(0,R.jsx)(`p`,{className:`text-muted text-[14.5px] leading-snug max-w-sm`,children:t?r(`Whatever you ask here, the {name} on {device} does where it is: its shell, its files, its screen. Every step shows up here, and anything that needs an approval asks you here.`,{name:e,device:t}):r(`I don't just answer; I get things done: research, plans, files, code, email, long-running goals. Everything I do shows up here, and anything hard to undo waits for your approval.`)}),(0,R.jsx)(`div`,{className:`mt-2 flex flex-wrap justify-center gap-2`,children:i.map(e=>(0,R.jsx)(`button`,{type:`button`,onClick:()=>n(e),className:`rounded-full bg-surface-2 px-3.5 py-1.5 text-[13.5px] hover:bg-border/60`,children:e},e))})]})}function ah({name:e,busy:t,waiting:n,onSend:r}){let{state:a,draft:o,draftFiles:c,toast:l}=E(),[u,d]=(0,L.useState)(``),[f,p]=(0,L.useState)(!1),m=(0,L.useRef)(``),g=Np((0,L.useCallback)((e,t)=>{let n=m.current,r=n&&!/\s$/.test(n)?` `:``;d(n+r+e+t)},[]),(0,L.useCallback)(e=>l(e),[l])),_=()=>{g.listening||(m.current=u),g.toggle()},[v,y]=(0,L.useState)([]),[b,x]=(0,L.useState)([]);(0,L.useEffect)(()=>{if(!a.draftFiles)return;let e=a.draftFiles.map(e=>({key:`shared-${e.path}`,file:new File([],e.name),preview:e.kind===`image`?h(e.path):null,info:e,error:null}));x(t=>[...t.filter(t=>!e.some(e=>e.key===t.key)),...e].slice(0,10)),c(null)},[a.draftFiles]);let S=(0,L.useRef)(null),C=(0,L.useRef)(null),w=s();(0,L.useEffect)(()=>()=>b.forEach(e=>e.preview?.startsWith(`blob:`)&&URL.revokeObjectURL(e.preview)),[b]),(0,L.useEffect)(()=>{let e=()=>S.current?.focus();return window.addEventListener(`nanomuse:quick-chat`,e),()=>window.removeEventListener(`nanomuse:quick-chat`,e)},[]);let T=e=>{let t=Array.from(e).slice(0,Math.max(0,10-b.length));if(t.length===0)return;let n=t.map(e=>({key:`${e.name}-${e.size}-${e.lastModified}-${Math.random().toString(36).slice(2,7)}`,file:e,preview:e.type.startsWith(`image/`)?URL.createObjectURL(e):null,info:null,error:null}));x(e=>[...e,...n]);for(let e of n)M.upload(e.file).then(t=>x(n=>n.map(n=>n.key===e.key?{...n,info:t}:n))).catch(t=>{let n=t.message?P(t.message):w(`Upload failed`);x(t=>t.map(t=>t.key===e.key?{...t,error:n}:t)),l(n)})},D=e=>x(t=>t.filter(t=>t.key!==e)),O=b.some(e=>!e.info&&!e.error),k=b.flatMap(e=>e.info?[e.info.path]:[]);(0,L.useEffect)(()=>{let e=S.current;e&&(e.style.height=`0px`,e.style.height=`${Math.min(e.scrollHeight,160)}px`)},[u]),(0,L.useEffect)(()=>{if(a.draft===null)return;d(a.draft),o(null);let e=S.current;e&&(e.focus(),e.setSelectionRange(e.value.length,e.value.length))},[a.draft]);let ee=a.settings?.skills?.enabled!==!1;(0,L.useEffect)(()=>{ee&&M.skills().then(e=>y(e.skills.filter(e=>e.enabled))).catch(()=>y([]))},[ee,a.skillsVersion]);let te=/^\/([a-z0-9-]*)$/i.exec(u),j=te?v.filter(e=>e.name.startsWith(te[1].toLowerCase())).slice(0,6):[],ne=e=>{d(`/${e.name} `),S.current?.focus()},re=a.hub?.devices??[],N=Pm(u,re),ie=N.length===0?Fm(u,re):null,ae=e=>{d(`@${e.name} `),S.current?.focus()},oe=e=>{e?.preventDefault();let t=u.trim();if(!t&&k.length===0||O||f)return;g.listening&&g.stop();let n=b;p(!0),d(``),x([]),S.current?.focus(),r(t,k).catch(()=>{d(e=>e||t),x(e=>e.length?e:n)}).finally(()=>p(!1))};return(0,R.jsxs)(`form`,{onSubmit:oe,className:`shrink-0 bg-bg px-3 pt-1.5 pb-1`,children:[t&&!n&&(0,R.jsx)(`div`,{className:`px-2 pb-1 text-[12px] text-muted`,children:w(`{name} is working; anything you send now is picked up right away.`,{name:e})}),j.length>0&&(0,R.jsx)(`ul`,{className:`mb-2 max-h-72 overflow-y-auto rounded-3xl border border-border/70 bg-surface shadow-lg divide-y divide-border/70`,role:`listbox`,"aria-label":w(`Skills`),children:j.map(e=>(0,R.jsx)(`li`,{children:(0,R.jsxs)(`button`,{type:`button`,onClick:()=>ne(e),className:`flex w-full items-center gap-3 px-4 py-2.5 text-left hover:bg-surface-2/70 active:bg-surface-2`,children:[(0,R.jsx)(gn,{size:16,className:`shrink-0 text-accent`}),(0,R.jsxs)(`span`,{className:`min-w-0 flex-1`,children:[(0,R.jsxs)(`span`,{className:`block text-[14px] font-medium`,children:[`/`,e.name]}),(0,R.jsx)(`span`,{className:`block truncate text-[12.5px] text-muted`,children:e.description})]})]})},e.name))}),N.length>0&&(0,R.jsx)(`ul`,{className:`mb-2 max-h-72 overflow-y-auto rounded-3xl border border-border/70 bg-surface shadow-lg divide-y divide-border/70`,role:`listbox`,"aria-label":w(`Devices`),children:N.map(e=>(0,R.jsx)(`li`,{children:(0,R.jsxs)(`button`,{type:`button`,onClick:()=>ae(e),className:`flex w-full items-center gap-3 px-4 py-2.5 text-left hover:bg-surface-2/70 active:bg-surface-2`,children:[(0,R.jsx)(`span`,{className:`shrink-0 text-accent`,children:e.kind===`computer`?(0,R.jsx)(Lt,{size:16}):(0,R.jsx)(tn,{size:16})}),(0,R.jsxs)(`span`,{className:`min-w-0 flex-1`,children:[(0,R.jsxs)(`span`,{className:`block text-[14px] font-medium`,children:[`@`,e.name]}),(0,R.jsx)(`span`,{className:`block truncate text-[12.5px] text-muted`,children:e.online?w(`Runs this there and reports back`):w(`Offline`)})]})]})},e.id))}),ie&&(0,R.jsxs)(`div`,{className:`flex items-center gap-1.5 px-2 pb-1 text-[12px] text-muted`,children:[(0,R.jsx)(It,{size:12}),` `,w(`This goes to {device}.`,{device:ie.name})]}),b.length>0&&(0,R.jsx)(`div`,{className:`mb-1 flex gap-2.5 overflow-x-auto px-1 pt-2.5 pb-1 pr-3`,role:`list`,"aria-label":w(`Attachments`),children:b.map(e=>(0,R.jsxs)(`div`,{role:`listitem`,className:i(`relative shrink-0 rounded-2xl border bg-surface-2`,e.error?`border-danger/60`:`border-border/70`),children:[e.preview?(0,R.jsx)(`img`,{src:e.preview,alt:e.file.name,className:`h-16 w-16 rounded-2xl object-cover`}):(0,R.jsxs)(`div`,{className:`flex h-16 w-40 items-center gap-2 px-2.5`,children:[(0,R.jsx)(`span`,{className:`rounded-xl bg-accent/12 p-1.5 text-accent`,children:Zm(e.file.name)===`data`?(0,R.jsx)(cn,{size:16}):(0,R.jsx)(mt,{size:16})}),(0,R.jsxs)(`span`,{className:`min-w-0`,children:[(0,R.jsx)(`span`,{className:`block truncate text-[12.5px] font-medium`,children:e.file.name}),(0,R.jsx)(`span`,{className:`block text-[11px] text-muted`,children:e.error?w(`Upload failed`):Xm(e.info?.size??e.file.size)})]})]}),!e.info&&!e.error&&(0,R.jsx)(`div`,{className:`absolute inset-0 flex items-center justify-center rounded-2xl bg-bg/50`,children:(0,R.jsx)(A,{size:18,className:`animate-spin text-accent`})}),(0,R.jsx)(`button`,{type:`button`,onClick:()=>D(e.key),"aria-label":w(`Remove`),className:`absolute -right-1.5 -top-1.5 flex h-6 w-6 items-center justify-center rounded-full border border-border bg-surface text-muted shadow-sm`,children:(0,R.jsx)(Fe,{size:13})})]},e.key))}),(0,R.jsxs)(`div`,{className:`flex items-end gap-2 rounded-[26px] border border-border bg-surface px-1.5 py-1.5 shadow-[0_2px_12px_-6px_rgba(0,0,0,0.12)] focus-within:border-fg/20`,children:[(0,R.jsx)(`input`,{ref:C,type:`file`,multiple:!0,accept:Qm,className:`hidden`,onChange:e=>{e.target.files&&T(e.target.files),e.target.value=``}}),(0,R.jsx)(`button`,{type:`button`,onClick:()=>C.current?.click(),"aria-label":w(`Attach a file`),className:`flex h-9 w-9 shrink-0 items-center justify-center rounded-full text-fg/70 transition hover:bg-surface-2 active:scale-95`,children:(0,R.jsx)(I,{size:22})}),(0,R.jsx)(`textarea`,{ref:S,value:u,onChange:e=>d(e.target.value),onPaste:e=>{let t=Array.from(e.clipboardData?.files??[]);t.length>0&&(e.preventDefault(),T(t))},onKeyDown:e=>{if(e.key===`Tab`&&j.length>0&&j[0]){e.preventDefault(),ne(j[0]);return}if(e.key===`Tab`&&N.length>0&&N[0]){e.preventDefault(),ae(N[0]);return}e.key===`Enter`&&!e.shiftKey&&!e.nativeEvent.isComposing&&(e.preventDefault(),oe())},rows:1,placeholder:n?w(`Answer {name}…`,{name:e}):b.length>0?w(`Say what to do with it…`):w(`Message`),className:`flex-1 resize-none bg-transparent px-1 py-2 text-[15px] leading-[1.4] outline-none placeholder:text-muted`}),g.supported&&(0,R.jsx)(Pp,{listening:g.listening,onClick:_}),(0,R.jsx)(`button`,{type:`submit`,disabled:!u.trim()&&k.length===0||O,"aria-label":w(`Send`),className:i(`flex h-9 w-9 shrink-0 items-center justify-center rounded-full transition active:scale-95`,u.trim()||k.length>0?`bg-accent text-accent-fg`:`bg-surface-2 text-muted`,`disabled:opacity-60`),children:(0,R.jsx)(Je,{size:19,strokeWidth:2.5})})]})]})}function oh({threads:e,active:t,onPick:n,onCleared:r,compact:a=!1,grouped:o=!1}){let{state:c,toast:l,dispatch:d}=E(),f=s(),[p,m]=(0,L.useState)(``),[h,g]=(0,L.useState)(!1),_=(0,L.useRef)(null),v=(c.hub?.devices??[]).filter(e=>!e.this&&e.kind!==`web`&&e.online),y=e=>c.hub?.devices.find(t=>t.id===e)?.kind??`phone`,b=async e=>{try{let t=await M.askDevice(e.id);d({type:`ws`,msg:{kind:`thread`,thread:t.thread}}),n(t.thread.id)}catch(e){l(e.message)}},x=async()=>{g(!0);try{let e=await M.createThread(p.trim()||f(`Side chat`));d({type:`ws`,msg:{kind:`thread`,thread:e}}),m(``),n(e.id)}catch(e){l(e.message)}finally{g(!1)}},S=async e=>{if(window.confirm(f(`Delete this side chat and its history?`)))try{await M.deleteThread(e),d({type:`ws`,msg:{kind:`thread_deleted`,thread:e}})}catch(e){l(e.message)}},C=async e=>{if(window.confirm(f(`Clear this conversation? Memory and goals are kept.`)))try{await M.clearThread(e),d({type:`ws`,msg:{kind:`thread_cleared`,thread:e}}),r?.()}catch(e){l(e.message)}},w=e=>(0,R.jsxs)(`li`,{className:i(`group flex items-center gap-2 px-3`,a?`py-2 rounded-xl hover:bg-surface-2/60`:`py-2.5`,e.id===t&&`bg-surface-2/60`),children:[(0,R.jsxs)(`button`,{type:`button`,onClick:()=>n(e.id),className:`flex-1 text-left min-w-0`,children:[(0,R.jsxs)(`div`,{className:i(`font-medium truncate flex items-center gap-2`,a?`text-[13.5px]`:`text-[15px]`),children:[e.device?(0,R.jsx)(`span`,{className:`text-accent`,children:y(e.device)===`computer`?(0,R.jsx)(Lt,{size:14}):(0,R.jsx)(tn,{size:14})}):e.remote_from?(0,R.jsx)(It,{size:14,className:`text-muted`}):null,(0,R.jsx)(`span`,{className:`truncate`,children:e.id===`main`?f(e.title):e.title}),e.busy&&(0,R.jsx)(`span`,{className:`h-1.5 w-1.5 shrink-0 rounded-full bg-amber-400 animate-pulse`})]}),(0,R.jsxs)(`div`,{className:i(`text-muted`,a?`text-[11.5px]`:`text-[12px]`),children:[f(`{n} events`,{n:e.events}),e.queued?` · ${f(`{n} queued`,{n:e.queued})}`:``,` · `,u(e.updated_at)]})]}),(0,R.jsx)(`button`,{type:`button`,"aria-label":f(`Clear`),onClick:()=>void C(e.id),className:i(`p-2 text-muted hover:text-fg`,a&&`opacity-0 group-hover:opacity-100 focus:opacity-100`),children:(0,R.jsx)(Fe,{size:16})}),e.id!==`main`&&(0,R.jsx)(`button`,{type:`button`,"aria-label":f(`Delete`),onClick:()=>void S(e.id),className:i(`p-2 text-muted hover:text-rose-500`,a&&`opacity-0 group-hover:opacity-100 focus:opacity-100`),children:(0,R.jsx)(fn,{size:16})})]},e.id),T=i(`divide-y divide-border overflow-hidden`,a?`rounded-xl`:`rounded-2xl border border-border`),D=`px-3 pb-1 pt-3 text-[11.5px] font-semibold uppercase tracking-wide text-muted`;return(0,R.jsxs)(`div`,{children:[o?(0,R.jsxs)(R.Fragment,{children:[(0,R.jsx)(`div`,{className:D,children:f(`Main chat`)}),(0,R.jsx)(`ul`,{className:T,children:e.filter(e=>e.id===`main`).map(w)}),(0,R.jsxs)(`div`,{className:i(D,`flex items-center justify-between pr-1`),children:[(0,R.jsx)(`span`,{children:f(`Side chats`)}),(0,R.jsx)(`button`,{type:`button`,"aria-label":f(`New side chat`),onClick:()=>_.current?.focus(),className:`flex h-6 w-6 items-center justify-center rounded-full text-muted hover:bg-surface-2 hover:text-fg`,children:(0,R.jsx)(I,{size:15})})]}),(0,R.jsx)(`ul`,{className:T,children:e.filter(e=>e.id!==`main`).map(w)}),e.every(e=>e.id===`main`)&&(0,R.jsx)(`p`,{className:`px-3 py-2 text-[12px] text-muted`,children:f(`A side chat keeps one topic apart from the rest.`)})]}):(0,R.jsx)(`ul`,{className:T,children:e.map(w)}),v.length>0&&(0,R.jsxs)(`div`,{className:`mt-4`,children:[(0,R.jsx)(`div`,{className:`mb-1.5 text-[12px] font-medium text-muted`,children:f(`Ask one of your devices`)}),(0,R.jsx)(`div`,{className:`flex flex-wrap gap-2`,children:v.map(e=>(0,R.jsxs)(`button`,{type:`button`,onClick:()=>void b(e),className:`flex items-center gap-1.5 rounded-full border border-border bg-surface px-3 py-1.5 text-[13px] font-medium hover:bg-surface-2`,children:[e.kind===`phone`?(0,R.jsx)(tn,{size:14,className:`text-accent`}):(0,R.jsx)(Lt,{size:14,className:`text-accent`}),e.name]},e.id))})]}),(0,R.jsxs)(`div`,{className:i(`flex gap-2`,a?`mt-3`:`mt-4`),children:[(0,R.jsx)(`input`,{ref:_,value:p,onChange:e=>m(e.target.value),onKeyDown:e=>{e.key===`Enter`&&!h&&x()},placeholder:f(a?`New side chat`:`New side chat, e.g. “Trip to Kyoto”`),className:i(`min-w-0 flex-1 bg-surface-2 outline-none focus:ring-2 focus:ring-accent/40`,a?`rounded-xl px-3 py-2 text-[13px]`:`rounded-2xl px-3.5 py-2.5 text-[14px]`)}),(0,R.jsxs)(`button`,{type:`button`,disabled:h,onClick:()=>void x(),"aria-label":f(`New`),className:i(`flex items-center gap-1.5 bg-accent text-accent-fg font-medium disabled:opacity-50`,a?`rounded-xl px-2.5`:`rounded-2xl px-3.5 py-2.5`),children:[(0,R.jsx)(jt,{size:18}),` `,!a&&f(`New`)]})]})]})}function sh(e){let t=[...e].reverse().find(e=>e.type===`user`),n=(((t?.type===`user`?t.text:``)||``).split(/\r?\n/).map(e=>e.trim()).find(e=>e.length>0)??``).replace(/\s+/g,` `);if(n.length<=36)return n;let r=n.slice(0,36),i=r.lastIndexOf(` `);return(i>16?r.slice(0,i):r).trimEnd()+`…`}function ch(e){let t=!1;for(let n=e.length-1;n>=0;n--){let r=e[n];if(r.type===`assistant`){if(!r.text||r.quiet)return!1;t=!0;continue}if(r.type===`user`)return t&&!r.via;if(r.type===`notice`)return!1}return!1}function lh(e){let t=Sn(),n=t?`Desktop app (${t.platform}, shell ${t.version})`:`Web app (${navigator.userAgent})`;return`https://github.com/nano-muse/nanoMuse/issues/new?${new URLSearchParams({template:`bug_report.yml`,version:e||``,os:n}).toString()}`}function uh(){let{state:e,setTab:t,openThread:n}=E(),r=s(),[a,o]=(0,L.useState)(!1),[c,l]=(0,L.useState)(!1),[u,d]=(0,L.useState)(``),f=(0,L.useRef)(null),p=$f(),{profile:m,status:h}=e,g=m?.name??`nanoMuse`,_=e.pendingApprovals.length,v=e.goals.filter(e=>e.proposal&&e.status!==`cancelled`).length,y=e.pendingApprovals.filter(t=>t.ts>e.feedSeenAt).length,b=(e.hub?.devices??[]).filter(e=>!e.this&&e.kind!==`web`&&e.online).length,x=_>0?_>1?r(`{n} approvals waiting for you`,{n:_}):r(`1 approval waiting for you`):h.state===`idle`?r(`Idle`):h.detail||(h.state===`waiting`?r(`Waiting for you`):r(`Working…`));(0,L.useEffect)(()=>{if(!c)return;let e=e=>{f.current?.contains(e.target)||l(!1)},t=e=>{e.key===`Escape`&&l(!1)};return document.addEventListener(`mousedown`,e),document.addEventListener(`keydown`,t),()=>{document.removeEventListener(`mousedown`,e),document.removeEventListener(`keydown`,t)}},[c]);let S=[{id:`chat`,label:`Chat`,icon:(0,R.jsx)(At,{size:21}),badge:_},{id:`feed`,label:`Feed`,icon:(0,R.jsx)(Bt,{size:21}),badge:y},{id:`ideas`,label:`Ideas`,icon:(0,R.jsx)(Ct,{size:21})},{id:`goals`,label:`Goals`,icon:(0,R.jsx)(rn,{size:21}),badge:v},{id:`library`,label:`Library`,icon:(0,R.jsx)(St,{size:21})},{id:`devices`,label:`Devices`,icon:(0,R.jsx)(It,{size:21}),dot:b>0},...p?[{id:`coding`,label:`Coding`,icon:(0,R.jsx)(on,{size:21})}]:[]],C=u.trim().toLowerCase(),w=C?e.threads.filter(e=>e.id===`main`||(e.id===`main`?r(e.title):e.title).toLowerCase().includes(C)||(e.device_name??``).toLowerCase().includes(C)):e.threads,T=e=>i(`relative flex w-[60px] flex-col items-center gap-[3px] rounded-xl py-1.5 text-[10.5px] font-medium leading-none transition`,e?`bg-surface-2 text-fg`:`text-fg/65 hover:bg-surface-2/60 hover:text-fg`);return(0,R.jsxs)(`div`,{className:`flex h-full shrink-0`,children:[(0,R.jsxs)(`aside`,{className:`relative flex h-full w-[76px] shrink-0 flex-col items-center border-r border-border bg-surface/70`,children:[(0,R.jsx)(`div`,{className:`titlebar-room`}),(0,R.jsxs)(`button`,{type:`button`,onClick:()=>o(!0),className:`relative mt-3 rounded-full transition hover:scale-[1.04]`,"aria-label":r(`Activity`),title:`${g} · ${x}`,children:[(0,R.jsx)(D,{profile:m,status:h,size:44}),_>0&&(0,R.jsx)(`span`,{className:`pointer-events-none absolute -right-1 -top-1 flex h-[18px] min-w-[18px] items-center justify-center rounded-full border-2 border-surface bg-rose-500 px-1 text-[10.5px] font-bold text-white`,children:_})]}),(0,R.jsx)(`span`,{className:`mt-1.5 max-w-[68px] truncate px-1 text-[11px] font-semibold leading-tight`,children:g}),(0,R.jsx)(`nav`,{className:`mt-3 flex w-full flex-1 flex-col items-center gap-0.5 overflow-y-auto overflow-x-hidden px-2`,children:S.map(n=>{let a=e.tab===n.id;return(0,R.jsxs)(`button`,{type:`button`,onClick:()=>t(n.id),"aria-current":a?`page`:void 0,className:T(a),children:[(0,R.jsx)(`span`,{className:i(a?`text-accent`:`text-fg/60`),children:n.icon}),(0,R.jsx)(`span`,{className:`max-w-full truncate`,children:r(n.label)}),n.badge?(0,R.jsx)(`span`,{className:`absolute right-1.5 top-1 flex h-[17px] min-w-[17px] items-center justify-center rounded-full bg-rose-500 px-1 text-[10px] font-bold text-white`,children:n.badge}):n.dot?(0,R.jsxs)(R.Fragment,{children:[(0,R.jsx)(`span`,{"aria-hidden":`true`,className:`absolute right-3 top-2 h-2 w-2 rounded-full border-2 border-surface bg-emerald-500`}),(0,R.jsx)(`span`,{className:`sr-only`,children:r(`{n} online`,{n:b})})]}):null]},n.id)})}),(0,R.jsxs)(`div`,{className:`flex w-full flex-col items-center gap-0.5 px-2 pb-3 pt-2`,children:[(0,R.jsxs)(`button`,{type:`button`,onClick:()=>t(`account`),"aria-current":e.tab===`account`?`page`:void 0,className:T(e.tab===`account`),title:e.hub?.account.signed_in?e.hub.account.hint:r(`Account`),children:[(0,R.jsx)(mn,{size:21,className:e.tab===`account`?`text-accent`:`text-fg/60`}),(0,R.jsx)(`span`,{className:`max-w-full truncate`,children:r(`Account`)})]}),(0,R.jsxs)(`button`,{type:`button`,onClick:()=>t(`you`),"aria-current":e.tab===`you`?`page`:void 0,className:T(e.tab===`you`),children:[(0,R.jsx)(en,{size:21,className:e.tab===`you`?`text-accent`:`text-fg/60`}),(0,R.jsx)(`span`,{className:`max-w-full truncate`,children:r(`Settings`)})]}),(0,R.jsxs)(`div`,{ref:f,className:`relative w-full`,children:[(0,R.jsxs)(`button`,{type:`button`,onClick:()=>l(e=>!e),"aria-expanded":c,"aria-haspopup":`menu`,className:i(T(c),`mx-auto`),children:[(0,R.jsx)(Ot,{size:21,className:`text-fg/60`}),(0,R.jsx)(`span`,{children:r(`More`)})]}),c&&(0,R.jsxs)(`div`,{role:`menu`,className:`absolute bottom-0 left-[68px] z-30 w-[232px] rounded-2xl border border-border bg-surface p-1.5 shadow-[0_12px_40px_-12px_rgba(0,0,0,0.3)]`,children:[(0,R.jsxs)(`a`,{role:`menuitem`,href:lh(e.version),target:`_blank`,rel:`noreferrer`,onClick:()=>l(!1),className:`flex items-center gap-2.5 rounded-xl px-2.5 py-2 text-[13px] font-medium hover:bg-surface-2`,children:[(0,R.jsx)(ue,{size:16,className:`text-fg/60`}),` `,r(`Report a bug`)]}),(0,R.jsxs)(`button`,{type:`button`,role:`menuitem`,onClick:()=>{l(!1),t(`you`),window.location.hash=`developer`},className:`flex w-full items-center gap-2.5 rounded-xl px-2.5 py-2 text-left text-[13px] font-medium hover:bg-surface-2`,children:[(0,R.jsx)(yn,{size:16,className:`text-fg/60`}),(0,R.jsx)(`span`,{className:`flex-1`,children:r(`Developer tools`)}),(0,R.jsx)(`span`,{className:`text-[11.5px] font-normal text-muted`,children:r(p?`On`:`Off`)})]}),e.version&&(0,R.jsxs)(`div`,{className:`px-2.5 pb-1 pt-1.5 text-[11.5px] text-muted`,children:[`nanoMuse `,e.version]})]})]})]}),(0,R.jsx)(am,{open:a,onClose:()=>o(!1)})]}),e.tab===`chat`&&(0,R.jsxs)(`section`,{className:`flex h-full w-[248px] shrink-0 flex-col border-r border-border bg-surface/40`,"aria-label":r(`Chats`),children:[(0,R.jsx)(`div`,{className:`titlebar-room`}),(0,R.jsxs)(`div`,{className:`px-3 pb-2 pt-4`,children:[(0,R.jsx)(`h2`,{className:`px-1 text-[15px] font-semibold tracking-tight`,children:r(`Chats`)}),(0,R.jsxs)(`label`,{className:`mt-2 flex items-center gap-2 rounded-xl bg-surface-2 px-2.5 py-1.5 text-muted focus-within:ring-2 focus-within:ring-accent/40`,children:[(0,R.jsx)(qt,{size:14,className:`shrink-0`}),(0,R.jsx)(`input`,{value:u,onChange:e=>d(e.target.value),placeholder:r(`Search`),"aria-label":r(`Search chats`),className:`min-w-0 flex-1 bg-transparent text-[13px] text-fg outline-none placeholder:text-muted`}),u&&(0,R.jsx)(`button`,{type:`button`,onClick:()=>d(``),"aria-label":r(`Clear`),className:`shrink-0 hover:text-fg`,children:(0,R.jsx)(Fe,{size:14})})]})]}),(0,R.jsx)(`div`,{className:`min-h-0 flex-1 overflow-y-auto px-2 pb-3`,children:(0,R.jsx)(oh,{threads:w,active:e.activeThread,onPick:e=>n(e),compact:!0,grouped:!0})})]})]})}function dh(){let{state:e,send:t,openThread:n,openFile:r,markFeedSeen:i,setTab:a,toast:o}=E(),[c,l]=(0,L.useState)(null),[u,p]=(0,L.useState)(null),[h,g]=(0,L.useState)(null),[_,v]=(0,L.useState)(null),b=e.profile?.name??`nanoMuse`,x=s(),S=y();(0,L.useEffect)(()=>{let e=!0;return M.feed(80).then(t=>e&&l(t)).catch(e=>o(e.message)),M.upcoming().then(t=>e&&g(t)).catch(()=>void 0),M.feedPosts().then(t=>e&&p(t)).catch(()=>void 0),()=>{e=!1}},[e.feedVersion,e.remindersVersion]),(0,L.useEffect)(()=>{let e=!0;return M.calendar().then(t=>e&&v(t)).catch(()=>void 0),()=>{e=!1}},[e.calendarVersion,e.connectionsVersion]),(0,L.useEffect)(()=>{c&&c.length&&c[0].ts>e.feedSeenAt&&i(c[0].ts)},[c,e.feedSeenAt,i]);let C=(0,L.useMemo)(()=>kh(c??[]),[c,S]),[w,T]=(0,L.useState)(!1),[D,O]=(0,L.useState)(null),[k,ee]=(0,L.useState)(()=>d(fh)===`1`),[j,ne]=(0,L.useState)(!1),re=()=>{f(fh,`1`),ee(!0)},N=async()=>{ne(!0);try{let e=await M.refreshFeedPosts();p(e),e.error&&o(x(`Could not write posts: {error}`,{error:e.error}))}catch(e){o(e.message)}finally{ne(!1)}},P=e=>{t(`main`,e.prompt||`${x(`About this post from my feed:`)}\n\n**${e.title}**\n\n${e.body.slice(0,1200)}`).catch(e=>o(e.message||x(`Could not send`))),n(`main`)},ie=(0,L.useMemo)(()=>mh(u?.posts??[]),[u]),ae=u!==null&&u.posts.length===0;return(0,R.jsxs)(`div`,{className:`flex h-full flex-col`,children:[(0,R.jsx)(Em,{title:``,trailing:(0,R.jsx)(te,{onClick:()=>T(!0),label:x(`Feed settings`),children:(0,R.jsx)(en,{size:22})})}),(0,R.jsxs)(`div`,{className:`flex-1 overflow-y-auto px-3.5 pb-7`,children:[ie.length===0&&(0,R.jsxs)(R.Fragment,{children:[(0,R.jsx)(gh,{text:hh(ph(),new Date)}),!k&&(0,R.jsx)(xh,{instructions:u?.instructions??``,onEdit:()=>T(!0),onAck:re}),ae&&(0,R.jsxs)(R.Fragment,{children:[(0,R.jsx)(Sh,{emoji:`🖼️`,title:x(`Nothing in the feed yet`),body:x(`As we get to know each other, new posts will show up here. Every day at {time} I read what I remember about you (your memory files, the last week of diary, your goals) and write a few short posts.`,{time:u?.time??`08:00`})}),(0,R.jsx)(Sh,{emoji:`📝`,title:x(`Steer it with one sentence`),body:x(`Tap the sliders at the top right to tell me what you want more of, switch the daily routine off, or have me write the first day now.`)}),e.settings&&!e.settings.llm_ready&&(0,R.jsx)(_h,{children:(0,R.jsxs)(`button`,{type:`button`,onClick:()=>a(`you`),className:`flex w-full items-center gap-2 p-4 text-left text-[14px] text-muted`,children:[(0,R.jsx)(F,{size:16,className:`shrink-0 text-accent`}),` `,x(`Add a model first; the feed is written by your agent.`)]})}),(0,R.jsx)(_h,{children:(0,R.jsx)(`div`,{className:`p-4`,children:j?(0,R.jsxs)(`div`,{className:`flex items-center justify-center gap-2.5 text-[15px]`,children:[(0,R.jsx)(A,{size:18,className:`animate-spin text-accent`}),` `,x(`Writing…`)]}):(0,R.jsx)(`button`,{type:`button`,onClick:()=>void N(),className:`h-[46px] w-full rounded-full bg-accent text-[15px] font-semibold text-accent-fg`,children:x(`Write it now`)})})})]})]}),ie.map(([e,t],n)=>(0,R.jsxs)(`section`,{children:[(0,R.jsx)(gh,{text:hh(e,new Date(t[0].ts))}),n===0&&!k&&(0,R.jsx)(xh,{instructions:u?.instructions??``,onEdit:()=>T(!0),onAck:re}),n===0&&j&&(0,R.jsx)(_h,{children:(0,R.jsxs)(`div`,{className:`flex items-center gap-2.5 p-4 text-[15px]`,children:[(0,R.jsx)(A,{size:18,className:`animate-spin text-accent`}),` `,x(`Writing…`)]})}),t.map(e=>(0,R.jsx)(bh,{post:e,onDiscuss:()=>P(e),onInfo:()=>O(e)},e.id))]},e)),(0,R.jsxs)(`div`,{className:`space-y-4 px-0.5 pt-3`,children:[h&&(0,R.jsx)(Th,{data:h,name:b,onSettings:()=>a(`you`),onGoals:()=>a(`goals`)}),_?.configured&&(0,R.jsx)(Eh,{data:_,onAsk:()=>n(`main`)}),c&&c.length===0&&(!u||u.posts.length===0)&&(0,R.jsxs)(`div`,{className:`py-10 text-center text-muted text-[14px] px-6`,children:[(0,R.jsx)(Rt,{size:28,className:`mx-auto mb-2 opacity-60`}),x(`Nothing yet. Once {name} works on a goal in the background or needs your approval, it shows up here.`,{name:b})]}),c&&c.length>0&&(0,R.jsx)(`div`,{className:`px-1 pt-1 text-[12px] font-semibold uppercase tracking-wide text-muted`,children:x(`While you were away`)}),C.map(([t,i])=>(0,R.jsxs)(`section`,{children:[(0,R.jsx)(`div`,{className:`px-1 mb-1.5 text-[12px] uppercase tracking-wide text-muted font-semibold`,children:t}),(0,R.jsx)(`ul`,{className:`space-y-2`,children:i.map(t=>(0,R.jsx)(`li`,{children:(0,R.jsx)(Oh,{item:t,unseen:t.ts>e.feedSeenAt,onOpen:()=>{t.kind===`artifact`&&t.path?r(t.path):n(t.thread)}})},t.id))})]},t))]})]}),(0,R.jsx)(wh,{open:w,onClose:()=>T(!1),data:u,writing:j,onChange:p,onWriteNow:()=>void N()}),(0,R.jsx)(Op,{open:D!==null,onClose:()=>O(null),title:D?.title,children:D&&(0,R.jsxs)(`div`,{className:`space-y-3 px-1 pb-2`,children:[(0,R.jsx)(Ch,{label:x(`Post type`),value:yh(D.area)}),(0,R.jsx)(Ch,{label:x(`Written`),value:new Date(D.ts).toLocaleString(m(),{dateStyle:`medium`,timeStyle:`short`})}),(0,R.jsx)(`button`,{type:`button`,onClick:async()=>{let e=D.id;O(null);try{await M.deleteFeedPost(e),p(t=>t&&{...t,posts:t.posts.filter(t=>t.id!==e)})}catch(e){o(e.message)}},className:`w-full rounded-full bg-surface-2 py-2.5 text-[15px] font-medium text-rose-500`,children:x(`Delete this post`)})]})})]})}var fh=`nanomuse.feed.introAck`;function ph(){let e=new Date;return`${e.getFullYear()}-${String(e.getMonth()+1).padStart(2,`0`)}-${String(e.getDate()).padStart(2,`0`)}`}function mh(e){let t=new Map;for(let n of e){let e=new Date(n.ts),r=`${e.getFullYear()}-${String(e.getMonth()+1).padStart(2,`0`)}-${String(e.getDate()).padStart(2,`0`)}`,i=t.get(r);i?i.push(n):t.set(r,[n])}return[...t.entries()]}function hh(e,t){let n=ph(),r=new Date;r.setDate(r.getDate()-1);let i=`${r.getFullYear()}-${String(r.getMonth()+1).padStart(2,`0`)}-${String(r.getDate()).padStart(2,`0`)}`,a=t.toLocaleDateString(m(),{weekday:`long`});if(e===n){let e=new Date().getHours(),t=_(e<12?`morning`:e<18?`afternoon`:`evening`);return _(`{weekday} {part}`,{weekday:a,part:t})}return e===i?_(`Yesterday`):`${a} · ${t.toLocaleDateString(m(),{month:`short`,day:`numeric`})}`}function gh({text:e}){return(0,R.jsx)(`h2`,{className:`px-1.5 pt-3.5 pb-2 text-[22px] font-bold leading-7`,children:e})}function _h({children:e,className:t}){return(0,R.jsx)(`div`,{className:i(`my-1.5 overflow-hidden rounded-[18px] bg-surface dark:border dark:border-border`,t),children:e})}var vh={planning:`🗓️`,research:`🔍`,goals:`🎯`,money:`💰`,health:`🌿`,home:`🏠`,learning:`📚`,people:`👥`,files:`📄`,fun:`🎈`};function yh(e){switch(e){case`planning`:return _(`Planning`);case`research`:return _(`Research`);case`goals`:return _(`Goals`);case`money`:return _(`Money`);case`health`:return _(`Health`);case`home`:return _(`Home`);case`learning`:return _(`Learning`);case`people`:return _(`People`);case`files`:return _(`Files`);case`fun`:return _(`Fun`);default:return _(`Note`)}}function bh({post:e,onDiscuss:t,onInfo:n}){let r=s();return(0,R.jsx)(_h,{children:(0,R.jsxs)(`article`,{className:`pl-3.5 pr-2.5 pt-3.5 pb-1.5`,children:[(0,R.jsxs)(`div`,{className:`flex items-start gap-3`,children:[(0,R.jsx)(`div`,{className:`flex h-11 w-11 shrink-0 items-center justify-center rounded-xl bg-surface-2 text-[22px] leading-none`,children:vh[e.area]??`📝`}),(0,R.jsxs)(`div`,{className:`min-w-0 flex-1`,children:[(0,R.jsx)(`h3`,{className:`text-[16px] font-semibold leading-[22px]`,children:e.title}),(0,R.jsx)(`div`,{className:`md mt-1 text-[15px] leading-[22px] text-fg/85`,children:(0,R.jsx)(hf,{text:e.body})})]})]}),(0,R.jsxs)(`div`,{className:`mt-1.5 flex items-center`,children:[(0,R.jsxs)(`button`,{type:`button`,onClick:t,className:`flex items-center gap-1.5 rounded-full px-2 py-2 text-[14px] hover:bg-surface-2`,children:[(0,R.jsx)(At,{size:22,strokeWidth:1.8}),` `,r(`Discuss`)]}),(0,R.jsx)(`button`,{type:`button`,onClick:n,"aria-label":r(`About this post`),className:`ml-auto rounded-full p-2 hover:bg-surface-2`,children:(0,R.jsx)(F,{size:22,strokeWidth:1.8})})]})]})})}function xh({instructions:e,onEdit:t,onAck:n}){let r=s();return(0,R.jsxs)(_h,{children:[(0,R.jsxs)(`div`,{className:`px-4 py-3.5`,children:[(0,R.jsx)(`div`,{className:`text-[17px] font-semibold`,children:r(`About the feed`)}),(0,R.jsx)(`p`,{className:`mt-1 text-[13px] leading-[18px] text-muted`,children:r(`Short posts your agent writes for you from what it remembers: your memory files, the last week of diary, your goals. The sentence below steers every post from now on; edit it any time.`)})]}),(0,R.jsxs)(`div`,{className:`border-t border-border/70 px-4 py-3.5`,children:[(0,R.jsx)(`p`,{className:`text-[15px] leading-[22px]`,children:e||r(`Build me a feed about what I care about. Keep it short and direct, easy to skim, no clickbait.`)}),(0,R.jsxs)(`div`,{className:`mt-3.5 flex justify-end gap-2.5`,children:[(0,R.jsx)(`button`,{type:`button`,onClick:t,className:`rounded-full bg-surface-2 px-6 py-2.5 text-[15px] font-medium`,children:r(`Edit`)}),(0,R.jsx)(`button`,{type:`button`,onClick:n,className:`rounded-full bg-accent px-6 py-2.5 text-[15px] font-semibold text-accent-fg`,children:r(`Got it`)})]})]})]})}function Sh({emoji:e,title:t,body:n}){return(0,R.jsx)(_h,{children:(0,R.jsxs)(`div`,{className:`flex items-start gap-3 p-3.5`,children:[(0,R.jsx)(`div`,{className:`flex h-11 w-11 shrink-0 items-center justify-center rounded-xl bg-surface-2 text-[22px] leading-none`,children:e}),(0,R.jsxs)(`div`,{className:`min-w-0 flex-1`,children:[(0,R.jsx)(`div`,{className:`text-[16px] font-semibold leading-[22px]`,children:t}),(0,R.jsx)(`p`,{className:`mt-1 text-[15px] leading-[22px] text-fg/85`,children:n})]})]})})}function Ch({label:e,value:t}){return(0,R.jsxs)(`div`,{className:`flex items-start gap-3 text-[14.5px]`,children:[(0,R.jsx)(`span`,{className:`w-14 shrink-0 text-muted`,children:e}),(0,R.jsx)(`span`,{className:`min-w-0 flex-1 break-words`,children:t})]})}function wh({open:e,onClose:t,data:n,writing:r,onChange:i,onWriteNow:a}){let{toast:o,state:c}=E(),l=s(),[u,d]=(0,L.useState)(``),[f,p]=(0,L.useState)(!1);(0,L.useEffect)(()=>{e&&d(n?.instructions??``)},[e,n]);let m=async()=>{p(!0);try{i(await M.setFeedInstructions({instructions:u})),t()}catch(e){o(e.message)}finally{p(!1)}},h=async e=>{try{i(await M.setFeedInstructions(e))}catch(e){o(e.message)}},g=c.settings?.llm_ready!==!1;return(0,R.jsx)(Op,{open:e,onClose:t,title:l(`Feed`),children:(0,R.jsxs)(`div`,{className:`space-y-3 px-1 pb-2`,children:[(0,R.jsx)(`p`,{className:`text-[13px] leading-[18px] text-muted`,children:l(`Your feed is driven by the instruction below. Any edit you make here applies to every post from now on.`)}),(0,R.jsx)(`textarea`,{value:u,onChange:e=>d(e.target.value),rows:4,maxLength:2e3,placeholder:l(`Build me a feed about what I care about. Keep it short and direct, easy to skim, no clickbait.`),className:`w-full resize-none rounded-2xl bg-surface-2 px-3.5 py-2.5 text-[15px] leading-snug outline-none focus:ring-2 focus:ring-accent/40`}),(0,R.jsxs)(`div`,{className:`space-y-2 rounded-2xl bg-surface-2 px-3.5 py-2.5`,children:[(0,R.jsx)(Pe,{label:l(`Write it every day`),hint:n?.daily===!1?void 0:l(`Daily at {time}`,{time:n?.time??`08:00`}),checked:n?.daily!==!1,onChange:e=>void h({daily:e}),disabled:!n}),n?.daily!==!1&&(0,R.jsxs)(`label`,{className:`flex items-center justify-between gap-3 text-[13px] text-muted`,children:[(0,R.jsx)(`span`,{children:l(`Time of day`)}),(0,R.jsx)(`input`,{type:`time`,value:n?.time??`08:00`,onChange:e=>e.target.value&&void h({time:e.target.value}),className:`rounded-lg bg-surface px-2 py-1 text-[13px] text-fg outline-none focus:ring-2 focus:ring-accent/40`})]}),!g&&(0,R.jsx)(`div`,{className:`text-[12.5px] text-muted`,children:l(`Add a model first; the feed is written by your agent.`)})]}),(0,R.jsxs)(`button`,{type:`button`,onClick:a,disabled:r||!n||!g,className:`flex w-full items-center justify-center gap-2 rounded-full bg-surface-2 py-2.5 text-[15px] font-medium disabled:opacity-60`,children:[r?(0,R.jsx)(A,{size:16,className:`animate-spin`}):(0,R.jsx)(nn,{size:16,className:`text-accent`}),l(r?`Writing…`:`Write it now`)]}),(0,R.jsx)(`button`,{type:`button`,onClick:()=>void m(),disabled:f,className:`h-[46px] w-full rounded-full bg-accent text-[15px] font-semibold text-accent-fg disabled:opacity-60`,children:l(`Save`)})]})})}function Th({data:t,name:n,onSettings:r,onGoals:i}){let a=s(),o=t.queue[0],c=t.reminders.filter(e=>e.status===`active`&&!!e.next_at),l=c[0],d=c.length;return(0,R.jsxs)(`div`,{className:`rounded-3xl border border-border/70 bg-surface shadow-sm px-4 py-3.5`,children:[(0,R.jsxs)(`div`,{className:`flex items-center gap-2 text-[12px] uppercase tracking-wide text-muted font-semibold`,children:[(0,R.jsx)(Xe,{size:13}),` `,a(`Next up`)]}),t.proactive?o?(0,R.jsxs)(`div`,{className:`mt-1.5 text-[14px] leading-snug`,children:[t.busy?a(`Working now`):t.quiet_until?a(`Quiet hours after {time}`,{time:u(t.quiet_until)}):t.next_pass_at?a(`Around {time}`,{time:u(t.next_pass_at)}):a(`Soon`),`: `,(0,R.jsx)(`span`,{className:`font-medium`,children:o.title}),o.next_step&&(0,R.jsxs)(`span`,{className:`text-muted`,children:[` · `,o.next_step]}),o.overdue&&(0,R.jsxs)(`span`,{className:`text-rose-500 font-medium`,children:[` · `,a(`overdue`)]}),t.queue.length>1&&(0,R.jsxs)(`span`,{className:`text-muted`,children:[` · `,a(`{n} more in line`,{n:t.queue.length-1})]})]}):(0,R.jsxs)(`div`,{className:`mt-1.5 text-[14px] leading-snug`,children:[a(`No goal has a next step to work on.`),` `,(0,R.jsx)(`button`,{type:`button`,onClick:i,className:`text-accent font-medium`,children:a(`Add one`)})]}):(0,R.jsxs)(`div`,{className:`mt-1.5 text-[14px] leading-snug`,children:[a(`Background work is off. {name} only acts when you ask.`,{name:n}),` `,(0,R.jsx)(`button`,{type:`button`,onClick:r,className:`text-accent font-medium`,children:a(`Turn it on`)})]}),t.check_ins[0]&&(0,R.jsxs)(`div`,{className:`mt-1.5 text-[12.5px] text-muted`,children:[a(`Check-in on`),` `,(0,R.jsx)(`span`,{className:`font-medium text-fg`,children:t.check_ins[0].title}),` `,e(t.check_ins[0].at),t.check_ins.length>1&&` · ${a(`{n} more`,{n:t.check_ins.length-1})}`]}),l&&(0,R.jsxs)(`div`,{className:`mt-1.5 text-[12.5px] text-muted`,children:[l.kind===`task`?a(`Routine`):a(`Reminder`),` `,(0,R.jsx)(`span`,{className:`font-medium text-fg`,children:l.text}),` `,e(l.next_at),d>1&&` · ${a(`{n} more`,{n:d-1})}`]})]})}function Eh({data:e,onAsk:t}){let n=s(),r=t=>t.start.slice(0,10)<=e.today,a=e.events.filter(r),o=e.events.filter(e=>!r(e)),c=new Date,l=e=>!e.all_day&&new Date(e.end)e.error),d=a.every(l)&&o.length>0,f=d?o:a;return(0,R.jsxs)(`div`,{className:`rounded-3xl border border-border/70 bg-surface shadow-sm px-4 py-3.5`,children:[(0,R.jsxs)(`div`,{className:`flex items-center gap-2 text-[12px] uppercase tracking-wide text-muted font-semibold`,children:[(0,R.jsx)(tt,{size:13}),` `,n(d?`Tomorrow`:`Today`),f.length>0&&(0,R.jsx)(`span`,{className:`ml-auto normal-case tracking-normal font-normal`,children:n(`{n} scheduled`,{n:f.length})})]}),f.length===0?(0,R.jsx)(`div`,{className:`mt-1.5 text-[14px] leading-snug text-muted`,children:n(`Nothing on the calendar today.`)}):(0,R.jsx)(`ul`,{className:`mt-1.5 space-y-1`,children:f.map(e=>(0,R.jsxs)(`li`,{className:i(`flex items-baseline gap-2.5 text-[14px] leading-snug`,!d&&l(e)&&`opacity-50`),children:[(0,R.jsx)(`span`,{className:`w-[86px] shrink-0 tabular-nums text-[12.5px] text-muted`,children:e.all_day?n(`all day`):`${e.start.slice(11,16)}–${e.end.slice(11,16)}`}),(0,R.jsxs)(`span`,{className:`min-w-0 flex-1`,children:[(0,R.jsx)(`span`,{className:`font-medium`,children:e.summary}),e.location&&(0,R.jsxs)(`span`,{className:`text-muted text-[12.5px]`,children:[` `,(0,R.jsx)(Dt,{size:11,className:`inline -mt-0.5`}),` `,e.location]})]})]},`${e.uid}-${e.start}`))}),u.length>0&&(0,R.jsx)(`div`,{className:`mt-1.5 text-[12px] text-rose-500`,children:n(`{name} could not be read`,{name:u.map(e=>e.name).join(`, `)})}),(0,R.jsx)(`button`,{type:`button`,onClick:t,className:`mt-2 text-[12.5px] text-accent font-medium`,children:n(`Ask about your week`)})]})}function Dh(e){return e.replace(/```[\s\S]*?```/g,` `).replace(/^#{1,6}\s+/gm,``).replace(/(\*\*|__|`)/g,``).replace(/^\s*[-*+]\s+/gm,`• `).replace(/\[([^\]]+)\]\([^)]*\)/g,`$1`).trim()}function Oh({item:n,unseen:r,onOpen:a}){let o=s(),c=n.kind===`approval`?(0,R.jsx)(Zt,{size:18}):n.kind===`question`?(0,R.jsx)(kt,{size:18}):n.kind===`artifact`?(0,R.jsx)(mt,{size:18}):n.quiet?(0,R.jsx)(Rt,{size:18}):n.title.startsWith(`New mail: `)?(0,R.jsx)(Et,{size:18}):n.title.startsWith(`Coming up: `)?(0,R.jsx)(et,{size:18}):n.title.startsWith(`Webhook: `)?(0,R.jsx)(_n,{size:18}):(0,R.jsx)(nn,{size:18}),l=n.kind===`approval`?`bg-amber-500/12 text-amber-600 dark:text-amber-300`:n.kind===`question`?`bg-accent/12 text-accent`:`bg-surface-2 text-muted`;return n.quiet?(0,R.jsxs)(`button`,{type:`button`,onClick:a,className:`w-full text-left px-2 py-1.5 flex items-center gap-2 text-[12.5px] text-muted`,children:[(0,R.jsx)(Rt,{size:13,className:`shrink-0`}),(0,R.jsxs)(`span`,{className:`truncate`,children:[o(`{label}: nothing new`,{label:t(n.title.replace(/^Working on your goal: /,``))}),n.text?`: ${n.text}`:``]}),(0,R.jsx)(`span`,{className:`ml-auto shrink-0`,children:e(n.ts)})]}):(0,R.jsx)(`button`,{type:`button`,onClick:a,className:i(`w-full text-left rounded-3xl border bg-surface shadow-sm px-4 py-3 active:scale-[0.99] transition`,r?`border-accent/40`:`border-border/70`),children:(0,R.jsxs)(`div`,{className:`flex items-start gap-3`,children:[(0,R.jsx)(`div`,{className:i(`rounded-2xl p-2 mt-0.5`,l),children:c}),(0,R.jsxs)(`div`,{className:`flex-1 min-w-0`,children:[(0,R.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,R.jsx)(`div`,{className:`font-semibold text-[14.5px] leading-snug truncate`,children:t(n.title)}),r&&(0,R.jsx)(`span`,{className:`h-2 w-2 rounded-full bg-accent shrink-0`})]}),n.text&&(0,R.jsx)(`div`,{className:`mt-0.5 text-[13.5px] text-muted leading-snug line-clamp-3 whitespace-pre-wrap`,children:Dh(n.text)}),(0,R.jsxs)(`div`,{className:`mt-1.5 flex items-center gap-2 text-[12px] text-muted`,children:[(0,R.jsx)(`span`,{children:e(n.ts)}),(0,R.jsx)(`span`,{children:`·`}),(0,R.jsx)(`span`,{className:`truncate`,children:n.thread===`main`?o(n.thread_title):n.thread_title}),(0,R.jsxs)(`span`,{className:`ml-auto flex items-center gap-1 text-accent font-medium`,children:[n.kind===`artifact`?o(`Open`):n.kind===`approval`||n.kind===`question`?o(`Answer`):o(`Open chat`),(0,R.jsx)(qe,{size:13})]})]})]})]})})}function kh(e){let t=new Date,n=new Date(t);n.setDate(t.getDate()-1);let r=e=>{let r=new Date(e);return r.toDateString()===t.toDateString()?_(`Today`):r.toDateString()===n.toDateString()?_(`Yesterday`):r.toLocaleDateString(m(),{weekday:`long`,month:`short`,day:`numeric`})},i=new Map;for(let t of e){let e=r(t.ts);i.set(e,[...i.get(e)??[],t])}return[...i.entries()]}function Ah({children:e,className:t}){return(0,R.jsx)(`div`,{className:i(`mx-4 overflow-hidden rounded-2xl bg-surface dark:border dark:border-border`,t),children:e})}function jh({inset:e=52}){return(0,R.jsx)(`div`,{className:i(`border-t border-border/60`,e===52?`ml-[52px]`:`ml-4`)})}function Mh({icon:e,label:t,value:n,onClick:r,external:a=!1,trailing:o,chevron:s=!0}){let c=(0,R.jsxs)(R.Fragment,{children:[e&&(0,R.jsx)(`span`,{className:`shrink-0 text-fg`,children:e}),(0,R.jsx)(`span`,{className:i(`min-w-0 truncate text-[16px] leading-[21px]`,n?`max-w-[60%] shrink-0`:`flex-1`),children:t}),n&&(0,R.jsx)(`span`,{className:`min-w-0 flex-1 truncate pl-3 text-right text-[14px] leading-[18px] text-muted`,children:n}),o??(s?a?(0,R.jsx)(Ae,{size:16,className:`shrink-0 text-muted/70`}):(0,R.jsx)(rt,{size:18,className:`shrink-0 text-muted/70`}):null)]}),l=`flex min-h-[54px] w-full items-center gap-3.5 px-4 py-2 text-left`;return r?(0,R.jsx)(`button`,{type:`button`,onClick:r,className:i(l,`hover:bg-surface-2/60`),children:c}):(0,R.jsx)(`div`,{className:l,children:c})}function Nh({icon:e,label:t,value:n,checked:r,disabled:a=!1,onChange:o}){return(0,R.jsxs)(`button`,{type:`button`,role:`switch`,"aria-checked":r,disabled:a,onClick:()=>o(!r),className:i(`flex min-h-[54px] w-full items-center gap-3.5 px-4 py-2 text-left`,a?`opacity-60`:`hover:bg-surface-2/60`),children:[e&&(0,R.jsx)(`span`,{className:`shrink-0 text-fg`,children:e}),(0,R.jsx)(`span`,{className:i(`min-w-0 truncate text-[16px] leading-[21px]`,n?`max-w-[60%] shrink-0`:`flex-1`),children:t}),n&&(0,R.jsx)(`span`,{className:`min-w-0 flex-1 truncate pl-3 text-right text-[14px] leading-[18px] text-muted`,children:n}),(0,R.jsx)(Ph,{checked:r})]})}function Ph({checked:e}){return(0,R.jsx)(`span`,{"aria-hidden":!0,className:i(`relative h-7 w-12 shrink-0 rounded-full transition`,e?`bg-accent`:`bg-surface-2 border border-border`),children:(0,R.jsx)(`span`,{className:i(`absolute top-0.5 h-6 w-6 rounded-full bg-white shadow transition`,e?`left-[22px]`:`left-0.5`)})})}function Fh({children:e,className:t}){return(0,R.jsx)(`p`,{className:i(`px-8 py-2 text-[13px] leading-[18px] text-muted`,t),children:e})}function Ih({children:e}){return(0,R.jsx)(`p`,{className:`px-8 pb-2 pt-[18px] text-[13px] leading-[18px] text-muted`,children:e})}var Lh=`https://nanomuse.cn/privacy/`;function Rh({me:e,onChanged:t,flush:n=!1}){let r=s(),{state:a,toast:o}=E(),c=!!a.hub?.account.signed_in,[l,u]=(0,L.useState)(null),[d,f]=(0,L.useState)(!1),p=e??l,m=async()=>{if(c&&!e)try{u(await M.cloudMe())}catch{}};(0,L.useEffect)(()=>{m()},[c,e]);let h=p?.contribute??{on:!1,samples:0},g=h.samples??0,_=h.privacy_url||`https://nanomuse.cn/privacy/`,v=async n=>{f(!0);try{await M.cloudContribute(n),o(r(n?`On. Turn it off here at any time.`:`Off. Nothing more is kept.`)),e?t?.():await m()}catch(e){o(e.message)}finally{f(!1)}},y=async()=>{if(window.confirm(r(`The kept conversations are removed from the server. This cannot be undone.`))){f(!0);try{let n=await M.cloudDeleteSamples();o(r(`{n} turns deleted`,{n:String(n.deleted)})),e?t?.():await m()}catch(e){o(e.message)}finally{f(!1)}}};return(0,R.jsxs)(`div`,{className:i(n&&`-mx-4`),children:[(0,R.jsx)(zh,{signedIn:c}),(0,R.jsx)(Ah,{children:(0,R.jsx)(Nh,{label:r(`Help improve nanoMuse's AI models`),checked:c&&h.on,disabled:d||!c||!p,onChange:e=>void v(e)})}),(0,R.jsxs)(Fh,{children:[r(`While this is on, the text of your chats with the nanoMuse Cloud models (what you wrote, what it answered and the tools it chose to call) is kept on the relay to train the community's own open model. Not your memory or SOUL (the system prompt), not what tools returned, not pictures, and never next to who you are. Your own API key never passes through the relay.`),` `,c?h.default_on!==void 0&&(h.default_on?r(`New accounts start with it on.`):r(`New accounts start with it off.`)):r(`Sign in to nanoMuse Cloud to use it.`),` `,c&&g>0&&r(`{n} turns kept so far.`,{n:String(g)}),` `,(0,R.jsx)(`a`,{href:_,target:`_blank`,rel:`noopener noreferrer`,className:`text-accent underline-offset-2 hover:underline`,children:r(`Privacy policy`)})]}),c&&g>0&&(0,R.jsxs)(Ah,{className:`mt-3`,children:[(0,R.jsx)(Mh,{icon:d?(0,R.jsx)(A,{size:22,className:`animate-spin`}):(0,R.jsx)(fn,{size:22}),label:r(`Delete the kept conversations`),value:r(`{n} turns`,{n:String(g)}),onClick:()=>void y(),chevron:!1}),(0,R.jsx)(jh,{inset:16}),(0,R.jsx)(Fh,{className:`px-4 pb-2.5 pt-2`,children:r(`Removes every turn kept from this account, whether the switch is on or off now. Turning the switch off keeps what was kept until you delete it here.`)})]})]})}function zh({signedIn:e}){let t=s(),{toast:n}=E(),[r,i]=(0,L.useState)(null),[a,o]=(0,L.useState)(!1),c=r?.relay?.counts??{conversations:0,messages:0},l=e&&(c.conversations>0||c.messages>0),u=async()=>{try{i(await M.syncState())}catch{}};(0,L.useEffect)(()=>{u()},[e]);let d=async(e,t)=>{o(!0);try{i(await e()),n(t)}catch(e){n(e.message),await u()}finally{o(!1)}},f=e=>{(e||!l||window.confirm(t(`Off deletes the synced conversations from nanoMuse Cloud. The chats on each device stay.`)))&&d(()=>M.syncSetState(e),t(e?`On. Your devices show the same conversations from now on.`:`Off. Nothing is kept on nanoMuse Cloud any more.`))},p=()=>{window.confirm(t(`The synced conversations are removed from nanoMuse Cloud. The chats on each device stay. This cannot be undone.`))&&d(()=>M.syncDelete(),t(`Synced conversations deleted.`))},m=e=>{d(()=>M.syncSetSideChats(e),t(e?`On. This device's side chats go to the account; the other devices' are on their way.`:`Off. Side chats stay on this device from now on.`))},h=e&&!!r?.enabled;return(0,R.jsxs)(`div`,{className:`mb-6`,children:[(0,R.jsx)(Ah,{children:(0,R.jsx)(Nh,{label:t(`Sync conversations between my devices`),checked:h,disabled:a||!e||!r,onChange:f})}),(0,R.jsxs)(Fh,{children:[t(`The text of your chats is kept on nanoMuse Cloud so every device shows the same conversations. Files and images stay on the device they were made on.`),` `,e?r?.paused?t(`Paused: sign in again to continue.`):l&&t(`{c} chats, {m} messages kept so far.`,{c:String(c.conversations),m:String(c.messages)}):t(`Sign in to nanoMuse Cloud to use it.`)]}),r&&`side_chats`in r&&(0,R.jsxs)(R.Fragment,{children:[(0,R.jsx)(Ah,{className:`mt-3`,children:(0,R.jsx)(Nh,{label:t(`Also sync side chats`),checked:h&&!!r.side_chats,disabled:a||!h,onChange:m})}),(0,R.jsx)(Fh,{children:t(`Off: side chats stay on this device. On: this device's side chats go to the account and the other devices' side chats come here.`)})]}),l&&(0,R.jsxs)(Ah,{className:`mt-3`,children:[(0,R.jsx)(Mh,{icon:a?(0,R.jsx)(A,{size:22,className:`animate-spin`}):(0,R.jsx)(fn,{size:22}),label:t(`Delete synced conversations`),value:t(`{n} chats`,{n:String(c.conversations)}),onClick:p,chevron:!1}),(0,R.jsx)(jh,{inset:16}),(0,R.jsx)(Fh,{className:`px-4 pb-2.5 pt-2`,children:t(`Removes what nanoMuse Cloud stores for this account; the chats on each device stay, and the switch stays on. Deleting a chat on one device deletes it on all of them.`)})]})]})}var Bh=`nm.invite`;function Vh(){try{let e=new URLSearchParams(window.location.search).get(`invite`);if(e){let t=Hh(e);t&&localStorage.setItem(Bh,t)}return localStorage.getItem(Bh)??``}catch{return``}}function Hh(e){return e.toUpperCase().replace(/[^A-Z0-9]/g,``).slice(0,8)}function Uh(e){return/^\s*[+\d]/.test(e)?`tel`:`email`}function Wh({onSignedIn:e,useAsModel:t=!1,cta:n,autoFocus:r=!0}){let a=s(),o=(0,L.useId)(),c=Ce(),[l,u]=(0,L.useState)(`code`),[d,f]=(0,L.useState)(``),[p,m]=(0,L.useState)(``),[h,g]=(0,L.useState)(``),[_,v]=(0,L.useState)(!1),[y,b]=(0,L.useState)(null),[x,S]=(0,L.useState)(null),[C,w]=(0,L.useState)(``),[T,E]=(0,L.useState)(!1);(0,L.useEffect)(()=>{let e=Vh();e&&(w(e),E(!0))},[]);let D=async()=>{if(t){b(`model`);try{await M.cloudUseAsModel()}catch{}}await e()},O=async()=>{let e=d.trim();if(e){b(`code`),S(null);try{await M.cloudCode(e),v(!0)}catch(e){S(a(e.message))}finally{b(null)}}},k=async()=>{let e=d.trim();if(!(!e||p.trim().length<4)){b(`verify`),S(null);try{(await M.cloudVerify(e,p.trim(),C.trim())).created&&Vf(),m(``),v(!1);try{localStorage.removeItem(Bh)}catch{}await D()}catch(e){S(a(e.message))}finally{b(null)}}},ee=async()=>{let e=d.trim();if(e&&h){b(`login`),S(null);try{await M.cloudLogin(e,h),g(``),await D()}catch(e){S(a(e.message))}finally{b(null)}}},te=()=>void(l===`password`?ee():_?k():O()),j=n??a(t?`Sign in and use its model`:`Sign in`);return(0,R.jsxs)(`form`,{className:`space-y-3`,onSubmit:e=>{e.preventDefault(),te()},children:[(0,R.jsxs)(`div`,{className:`grid grid-cols-2 gap-1 rounded-2xl bg-surface-2/70 p-1 text-[13px] font-medium`,children:[(0,R.jsx)(Gh,{active:l===`code`,onClick:()=>u(`code`),icon:(0,R.jsx)(Mt,{size:14}),label:a(`With a code`)}),(0,R.jsx)(Gh,{active:l===`password`,onClick:()=>u(`password`),icon:(0,R.jsx)(xt,{size:14}),label:a(`With a password`)})]}),(0,R.jsxs)(`div`,{children:[(0,R.jsx)(`label`,{htmlFor:`${o}-id`,className:`text-[12px] text-muted`,children:se()?a(`Mainland China phone number or e-mail`):a(`E-mail (or a mainland China phone number)`)}),(0,R.jsx)(`input`,{id:`${o}-id`,value:d,onChange:e=>{f(e.target.value),v(!1)},inputMode:Uh(d),autoComplete:`username`,autoFocus:r,placeholder:a(`138 0000 0000 or you@example.com`),className:i(Ie,`mt-1`)}),l===`code`&&!_&&(!se()||oe(d))&&(0,R.jsx)(`p`,{className:`mt-1.5 text-[12px] text-muted`,children:a(`Text-message codes reach mainland-China numbers only. Use an e-mail address instead.`)})]}),l===`password`?(0,R.jsxs)(`div`,{children:[(0,R.jsx)(`label`,{htmlFor:`${o}-password`,className:`text-[12px] text-muted`,children:a(`Password`)}),(0,R.jsx)(`input`,{id:`${o}-password`,type:`password`,value:h,onChange:e=>g(e.target.value),autoComplete:`current-password`,className:i(Ie,`mt-1`)}),(0,R.jsx)(`p`,{className:`mt-1.5 text-[12px] text-muted`,children:a(`No password yet? Use a code first; set one under Account.`)})]}):(0,R.jsxs)(R.Fragment,{children:[_&&(0,R.jsxs)(`div`,{children:[(0,R.jsx)(`label`,{htmlFor:`${o}-code`,className:`text-[12px] text-muted`,children:a(`The code you received`)}),(0,R.jsx)(`input`,{id:`${o}-code`,value:p,onChange:e=>m(e.target.value.replace(/\D/g,``).slice(0,8)),inputMode:`numeric`,autoComplete:`one-time-code`,placeholder:`123456`,autoFocus:!0,className:i(`w-full rounded-2xl bg-surface-2 px-3.5 py-2.5 text-[14.5px] outline-none focus:ring-2 focus:ring-accent/40`,`mt-1 tracking-[0.3em]`)})]}),T?(0,R.jsxs)(`div`,{children:[(0,R.jsx)(`label`,{htmlFor:`${o}-invite`,className:`text-[12px] text-muted`,children:a(`Invite code (optional)`)}),(0,R.jsx)(`input`,{id:`${o}-invite`,value:C,onChange:e=>w(Hh(e.target.value)),autoComplete:`off`,placeholder:`ABCD2345`,className:i(Ie,`mt-1 tracking-[0.2em] uppercase`)}),(0,R.jsx)(`p`,{className:`mt-1.5 text-[12px] text-muted`,children:a(`A friend's code counts for a new account: you both get ¥{invite} more allowance.`,{invite:(c.invite_bonus_cny??5).toFixed(0)})})]}):(0,R.jsx)(`button`,{type:`button`,onClick:()=>E(!0),className:`text-[12px] text-muted underline-offset-2 hover:underline`,children:a(`Have an invite code?`)})]}),x&&(0,R.jsx)(`div`,{className:`rounded-2xl bg-rose-500/12 px-3 py-2 text-[12.5px] text-rose-700 dark:text-rose-300`,children:x}),(0,R.jsx)(`div`,{className:`flex gap-2`,children:l===`code`&&_?(0,R.jsxs)(R.Fragment,{children:[(0,R.jsx)(`button`,{type:`button`,disabled:y!==null,onClick:()=>void O(),className:je,children:a(`Send again`)}),(0,R.jsxs)(`button`,{type:`submit`,disabled:y!==null||p.trim().length<4,className:i(Ne,`flex-1 py-3`),children:[y?(0,R.jsx)(A,{size:15,className:`animate-spin`}):null,` `,j]})]}):l===`code`?(0,R.jsxs)(`button`,{type:`submit`,disabled:y!==null||!d.trim(),className:i(Ne,`flex-1 py-3`),children:[y===`code`?(0,R.jsx)(A,{size:15,className:`animate-spin`}):null,` `,a(`Send me a code`)]}):(0,R.jsxs)(`button`,{type:`submit`,disabled:y!==null||!d.trim()||!h,className:i(Ne,`flex-1 py-3`),children:[y?(0,R.jsx)(A,{size:15,className:`animate-spin`}):null,` `,j]})})]})}function Gh({active:e,onClick:t,icon:n,label:r}){return(0,R.jsxs)(`button`,{type:`button`,onClick:t,"aria-pressed":e,className:i(`flex items-center justify-center gap-1.5 rounded-xl px-2 py-2 transition`,e?`bg-surface text-fg shadow-sm`:`text-muted hover:text-fg`),children:[n,` `,r]})}function Kh(){let{state:e,refreshSettings:t,refreshHub:n,toast:r,skipSignIn:i}=E(),a=s(),o=e.profile?.name??`nanoMuse`,c=(0,R.jsxs)(`ul`,{className:`grid grid-cols-2 gap-2 text-[12.5px] wide:grid-cols-1 wide:gap-1.5 wide:text-[13.5px]`,children:[(0,R.jsx)(qh,{icon:(0,R.jsx)(It,{size:15}),text:a(`Every device of yours, one nanoMuse`)}),(0,R.jsx)(qh,{icon:(0,R.jsx)(st,{size:15}),text:a(`A model with a free allowance, or your own key`)}),(0,R.jsx)(qh,{icon:(0,R.jsx)(vt,{size:15}),text:a(`It uses your phone and computers for you`)}),(0,R.jsx)(qh,{icon:(0,R.jsx)(Qt,{size:15}),text:a(`Keys in your vault; nothing you say is kept on the relay`)})]});return(0,R.jsxs)(`div`,{className:`relative mx-auto flex h-[100dvh] w-full max-w-[760px] flex-col overflow-hidden bg-bg sm:border-x sm:border-border wide:max-w-none wide:border-0`,children:[(0,R.jsx)(`div`,{className:`pointer-events-none absolute inset-x-0 top-0 h-[46vh] bg-[radial-gradient(ellipse_at_top,rgba(0,100,212,0.14),transparent_65%)] dark:bg-[radial-gradient(ellipse_at_top,rgba(23,147,255,0.2),transparent_65%)] wide:inset-y-0 wide:h-auto wide:bg-[radial-gradient(ellipse_at_left,rgba(0,100,212,0.12),transparent_60%)] wide:dark:bg-[radial-gradient(ellipse_at_left,rgba(23,147,255,0.16),transparent_60%)]`}),(0,R.jsx)(`div`,{className:`titlebar-room relative`}),(0,R.jsx)(`div`,{className:`relative flex-1 overflow-y-auto px-6 pb-8 wide:flex wide:items-center wide:px-12`,children:(0,R.jsxs)(`div`,{className:`mx-auto w-full wide:grid wide:max-w-[980px] wide:grid-cols-[1.1fr_1fr] wide:items-center wide:gap-16`,children:[(0,R.jsxs)(`div`,{className:`safe-top flex flex-col items-center pt-14 text-center wide:items-start wide:pt-0 wide:text-left`,children:[(0,R.jsx)(xn,{size:88,className:`drop-shadow-[0_20px_40px_rgba(0,100,212,0.28)]`}),(0,R.jsx)(`h1`,{className:`mt-6 text-[28px] font-bold tracking-tight wide:text-[34px]`,children:a(`Sign in to {name}`,{name:o})}),(0,R.jsx)(`p`,{className:`mt-2 max-w-sm text-[14.5px] leading-relaxed text-muted wide:max-w-md wide:text-[15.5px]`,children:a(`One free account. It is what lets your phone and computers work as one and brings a model to start with.`)}),(0,R.jsx)(`div`,{className:`mt-7 hidden w-full wide:block`,children:c}),(0,R.jsx)(Te,{compact:!0,className:`mt-6 hidden w-full wide:block`})]}),(0,R.jsxs)(`div`,{children:[(0,R.jsx)(`div`,{className:`mt-8 rounded-[28px] border border-border/70 bg-surface p-5 shadow-sm wide:mt-0 wide:p-7`,children:(0,R.jsx)(Wh,{onSignedIn:async()=>{r(a(`Signed in to nanoMuse Cloud.`)),await Promise.all([t(),n()])}})}),(0,R.jsx)(`button`,{type:`button`,onClick:i,className:`mt-4 w-full rounded-2xl border border-border/70 px-4 py-2.5 text-[13.5px] text-fg/80 hover:bg-surface-2`,"data-testid":`sign-in-skip`,children:a(`Use your own API key instead`)}),(0,R.jsx)(`p`,{className:`mt-2 text-center text-[11.5px] leading-relaxed text-muted`,children:a(`You can sign in later under Connections, for sync and your devices.`)}),(0,R.jsx)(`div`,{className:`mt-6 wide:hidden`,children:c}),(0,R.jsx)(Te,{compact:!0,className:`mt-6 wide:hidden`}),(0,R.jsxs)(`p`,{className:`mt-4 text-center text-[11.5px] leading-relaxed text-muted wide:mt-5`,children:[a(`The relay keeps an account id, a masked identifier, usage counts and your agent's name and look; what else, and what is yours to switch off, is in the`),` `,(0,R.jsx)(`a`,{href:Lh,target:`_blank`,rel:`noopener noreferrer`,className:`underline decoration-dotted underline-offset-2 hover:text-fg`,children:a(`privacy policy`)}),`.`]})]})]})})]})}function qh({icon:e,text:t}){return(0,R.jsxs)(`li`,{className:`flex items-start gap-2 rounded-2xl bg-surface-2/60 px-3 py-2.5 text-fg/80 wide:bg-transparent wide:px-0 wide:py-1`,children:[(0,R.jsx)(`span`,{className:`mt-0.5 text-accent`,children:e}),(0,R.jsx)(`span`,{className:`leading-snug`,children:t})]})}function Jh(e,t,n){return!e||!e.account.required||e.account.signed_in||t?.llm_ready?!1:!n}var Yh=`modulepreload`,Xh=function(e){return`/`+e},Zh={},Qh=function(e){return e.pathname.endsWith(`.css`)},$h=function(e,t,n){let r=Promise.resolve();if(t&&t.length>0){let e,i=document.querySelector(`meta[property=csp-nonce]`),a=i?.nonce||i?.getAttribute(`nonce`);function o(e){return Promise.all(e.map(e=>Promise.resolve(e).then(e=>({status:`fulfilled`,value:e}),e=>({status:`rejected`,reason:e}))))}function s(e){return import.meta.resolve?new URL(import.meta.resolve(e)):new URL(e,import.meta.url)}r=o(t.map(t=>{t=Xh(t,n);let r=s(t);if(r.href in Zh)return;Zh[r.href]=!0;let i=Qh(r);if(e===void 0){e={all:new Set,styles:new Set};let t=document.getElementsByTagName(`link`);for(let n=t.length-1;n>=0;n--){let r=t[n];e.all.add(r.href),r.rel===`stylesheet`&&e.styles.add(r.href)}}if((i?e.styles:e.all).has(r.href))return;let o=document.createElement(`link`);if(o.rel=i?`stylesheet`:Yh,i||(o.as=`script`),o.crossOrigin=``,o.href=r.href,a&&o.setAttribute(`nonce`,a),document.head.appendChild(o),i)return new Promise((e,t)=>{o.addEventListener(`load`,e),o.addEventListener(`error`,()=>t(Error(`Unable to preload CSS for ${r}`)))})}).filter(e=>e!==void 0))}function i(e){let t=new Event(`vite:preloadError`,{cancelable:!0});if(t.payload=e,window.dispatchEvent(t),!t.defaultPrevented)throw e}return r.then(t=>{for(let e of t||[])e.status===`rejected`&&i(e.reason);return e().catch(i)})},eg=(0,L.lazy)(()=>$h(()=>import(`./AccountScreen-bHMDrVr5.js`).then(e=>({default:e.AccountScreen})),__vite__mapDeps([0,1,2,3,4,5,6,7,8]))),tg=(0,L.lazy)(()=>$h(()=>import(`./AvatarStudioScreen-DD2X0R8P.js`).then(e=>({default:e.AvatarStudioScreen})),__vite__mapDeps([9,1,2,3,4,10,8,11]))),ng=(0,L.lazy)(()=>$h(()=>import(`./ChannelsScreen-mBzj7BLf.js`).then(e=>({default:e.ChannelsScreen})),__vite__mapDeps([12,1,3,4,10,8]))),rg=(0,L.lazy)(()=>$h(()=>import(`./CodingScreen-C_tutsx0.js`).then(e=>({default:e.CodingScreen})),__vite__mapDeps([13,1,4,10,8]))),ig=(0,L.lazy)(()=>$h(()=>import(`./ConnectionsScreen-CMt7GOff.js`).then(e=>({default:e.ConnectionsScreen})),__vite__mapDeps([14,1,2,3,4,5,7,15,10,8,16]))),ag=(0,L.lazy)(()=>$h(()=>import(`./DevicesScreen-g6FUY327.js`).then(e=>({default:e.DevicesScreen})),__vite__mapDeps([17,1,3,4,10,8,16]))),og=(0,L.lazy)(()=>$h(()=>import(`./GoalsScreen-Dp2fRaLA.js`).then(e=>({default:e.GoalsScreen})),__vite__mapDeps([18,1,2,3,4]))),sg=(0,L.lazy)(()=>$h(()=>import(`./IdeasScreen-CGfvq5H-.js`).then(e=>({default:e.IdeasScreen})),__vite__mapDeps([19,1,10]))),cg=(0,L.lazy)(()=>$h(()=>import(`./LibraryScreen-B8JlrC_n.js`).then(e=>({default:e.LibraryScreen})),__vite__mapDeps([20,1]))),lg=(0,L.lazy)(()=>$h(()=>import(`./MemoryScreen-M8j03G3u.js`).then(e=>({default:e.MemoryScreen})),__vite__mapDeps([21,1,8]))),ug=(0,L.lazy)(()=>$h(()=>import(`./Onboarding-CtVO6gdK.js`).then(e=>({default:e.Onboarding})),__vite__mapDeps([22,1,2,3,4,23,11,14,5,7,15,10,8,16]))),dg=(0,L.lazy)(()=>$h(()=>import(`./SettingsScreen-CHVg61To.js`).then(e=>({default:e.SettingsScreen})),__vite__mapDeps([24,1,2,3,4,5,6,15,23,11,8]))),fg=(0,L.lazy)(()=>$h(()=>import(`./SkillsScreen-Dr-d7iS7.js`).then(e=>({default:e.SkillsScreen})),__vite__mapDeps([25,1,8])));function pg(){return(0,R.jsx)(`div`,{className:`flex h-full min-h-[40vh] items-center justify-center text-muted`,children:(0,R.jsx)(A,{className:`animate-spin`,size:20})})}var mg=e=>({size:26,strokeWidth:e?2:1.7,fill:e?`currentColor`:`none`,fillOpacity:e?.18:0}),hg=[{id:`chat`,label:`Chat`,icon:e=>(0,R.jsx)(At,{...mg(e)})},{id:`feed`,label:`Feed`,icon:e=>(0,R.jsx)(Bt,{...mg(e)})},{id:`ideas`,label:`Ideas`,icon:e=>(0,R.jsx)(Ct,{...mg(e)})},{id:`goals`,label:`Goals`,icon:e=>(0,R.jsx)(rn,{...mg(e)})},{id:`library`,label:`Library`,icon:e=>(0,R.jsx)(St,{...mg(e)})}];function gg(){let{state:e,setTab:t,openFile:n}=E(),r=Wf(),a=s();(0,L.useEffect)(()=>{let t=e.profile?.name?.trim();document.title=t&&t.toLowerCase()!==`nanomuse`?`${t} · nanoMuse`:`nanoMuse`},[e.profile?.name]),(0,L.useEffect)(()=>{let e=Sn()?.onQuickChat?.(()=>{t(`chat`),requestAnimationFrame(()=>window.dispatchEvent(new Event(`nanomuse:quick-chat`)))});return()=>{typeof e==`function`&&e()}},[t]),(0,L.useEffect)(()=>{let e=()=>{let e=window.location.hash.slice(1);(e&&hg.some(t=>t.id===e)||e===`devices`||e===`you`||e===`memory`||e===`connections`||e===`channels`||e===`skills`||e===`account`||e===`coding`||e===`avatar`)&&t(e)};return e(),window.addEventListener(`hashchange`,e),()=>window.removeEventListener(`hashchange`,e)},[t]);let o=r&&e.hub?.account.signed_in?(0,R.jsx)(Gf,{}):null,c=e.lite&&e.settings!==null&&!e.settings.onboarded;if((0,L.useEffect)(()=>{c&&M.onboarded(!0).catch(()=>void 0)},[c]),e.authError)return(0,R.jsx)(vg,{});if(!e.loaded)return(0,R.jsx)(_g,{error:e.error});if(Jh(e.hub,e.settings,e.signInSkipped))return(0,R.jsx)(Kh,{});if(!e.lite&&e.settings&&!e.settings.onboarded&&!e.onboardingDismissed&&!e.threads.some(e=>e.events>0))return(0,R.jsxs)(L.Suspense,{fallback:(0,R.jsx)(pg,{}),children:[(0,R.jsx)(ug,{}),o]});let l=e.pendingApprovals.length,u=e.goals.filter(e=>e.proposal&&e.status!==`cancelled`).length,d=e.pendingApprovals.filter(t=>t.ts>e.feedSeenAt).length;return(0,R.jsxs)(`div`,{className:i(`mx-auto flex h-[100dvh] max-w-[760px] flex-col bg-bg sm:border-x sm:border-border`,!e.lite&&`wide:max-w-none wide:flex-row wide:border-x-0`),children:[!e.lite&&(0,R.jsx)(`div`,{className:`hidden wide:block wide:h-full`,children:(0,R.jsx)(uh,{})}),(0,R.jsxs)(`div`,{className:`relative flex min-h-0 min-w-0 flex-1 flex-col`,children:[e.gone&&(0,R.jsxs)(`div`,{className:`flex items-center justify-center gap-2 bg-surface-2 text-muted text-[12.5px] py-1`,children:[(0,R.jsx)(vn,{size:14}),` `,a(e.lite?`This demo has ended.`:`This nanoMuse has stopped. Reload the page once it is running again.`)]}),!e.gone&&!e.connected&&e.loaded&&(0,R.jsxs)(`div`,{className:`flex items-center justify-center gap-2 bg-amber-500/15 text-amber-700 dark:text-amber-300 text-[12.5px] py-1`,children:[(0,R.jsx)(vn,{size:14}),` `,a(`Reconnecting to your nanoMuse…`)]}),!e.lite&&(0,R.jsx)(En,{}),(0,R.jsx)(`main`,{className:i(`tabbar-room mx-auto min-h-0 w-full flex-1 wide:max-w-[900px]`,!e.lite&&`wide:pb-0`),children:(0,R.jsxs)(L.Suspense,{fallback:(0,R.jsx)(pg,{}),children:[e.tab===`chat`&&(0,R.jsx)(Wm,{}),e.tab===`feed`&&(0,R.jsx)(dh,{}),e.tab===`ideas`&&(0,R.jsx)(sg,{}),e.tab===`goals`&&(0,R.jsx)(og,{}),e.tab===`library`&&(0,R.jsx)(cg,{}),e.tab===`memory`&&(0,R.jsx)(lg,{}),e.tab===`skills`&&(0,R.jsx)(fg,{}),e.tab===`connections`&&(0,R.jsx)(ig,{}),e.tab===`channels`&&(0,R.jsx)(ng,{}),e.tab===`devices`&&(0,R.jsx)(ag,{}),e.tab===`you`&&(0,R.jsx)(dg,{}),e.tab===`account`&&(0,R.jsx)(eg,{}),e.tab===`coding`&&(0,R.jsx)(rg,{}),e.tab===`avatar`&&(0,R.jsx)(tg,{})]})}),(0,R.jsx)(`nav`,{className:i(`tabbar-float pointer-events-none absolute inset-x-0 z-20 flex justify-center px-4`,!e.lite&&`wide:hidden`),children:(0,R.jsx)(`ul`,{className:`pointer-events-auto flex items-center gap-0.5 rounded-full bg-surface-2/55 px-3.5 py-2 ring-1 ring-border/50 backdrop-blur-2xl`,children:hg.map(n=>{let r=e.tab===n.id,o=n.id===`chat`?l:n.id===`feed`?d:n.id===`goals`?u:0;return(0,R.jsx)(`li`,{children:(0,R.jsxs)(`button`,{type:`button`,onClick:()=>t(n.id),"aria-label":a(n.label),"aria-current":r?`page`:void 0,className:i(`relative flex h-[46px] w-[60px] items-center justify-center rounded-full transition-colors duration-300`,r?`bg-accent-soft text-accent-soft-fg`:`text-muted hover:text-fg`),children:[n.icon(r),o>0&&(0,R.jsx)(`span`,{className:`absolute right-2.5 top-1 flex h-[17px] min-w-[17px] items-center justify-center rounded-full bg-rose-500 px-1 text-[10px] font-bold text-white`,children:o})]})},n.id)})})})]}),(0,R.jsx)(kn,{}),(0,R.jsx)(gf,{path:e.viewer,onClose:()=>n(null)}),o,e.toast&&(0,R.jsx)(`div`,{className:`pointer-events-none fixed inset-x-0 bottom-[calc(6rem+env(safe-area-inset-bottom))] z-[70] flex justify-center px-4`,children:(0,R.jsx)(`div`,{className:`rise rounded-2xl bg-fg text-bg px-4 py-2 text-[13.5px] shadow-lg max-w-sm text-center`,children:e.toast})})]})}function _g({error:e}){let t=s();return(0,R.jsxs)(`div`,{className:`mx-auto flex h-[100dvh] max-w-sm flex-col items-center justify-center px-6 text-center`,children:[(0,R.jsx)(xn,{size:72}),e?(0,R.jsxs)(R.Fragment,{children:[(0,R.jsx)(`p`,{className:`mt-6 text-[15px] font-medium`,children:t(`Could not reach your nanoMuse.`)}),(0,R.jsx)(`p`,{className:`mt-1.5 text-[13px] text-muted`,children:t(e)}),(0,R.jsx)(`button`,{type:`button`,onClick:()=>window.location.reload(),className:`mt-5 rounded-full bg-fg px-5 py-2 text-[14px] font-medium text-bg`,children:t(`Try again`)})]}):(0,R.jsxs)(`p`,{className:`mt-6 flex items-center gap-2 text-[14px] text-muted`,children:[(0,R.jsx)(A,{className:`animate-spin`,size:16}),` `,t(`Connecting to your nanoMuse…`)]})]})}function vg(){let[e,t]=(0,L.useState)(``),n=s();return(0,R.jsxs)(`div`,{className:`mx-auto flex h-[100dvh] max-w-md flex-col items-center justify-center px-6 text-center`,children:[(0,R.jsx)(xn,{size:88}),(0,R.jsx)(`h1`,{className:`mt-4 text-[22px] font-bold`,children:n(`Connect to your nanoMuse`)}),(0,R.jsxs)(`p`,{className:`mt-2 text-[14px] text-muted`,children:[n(`This app talks to the nanoMuse server you run yourself. Scan the QR code printed by`),` `,(0,R.jsx)(`code`,{className:`rounded bg-surface-2 px-1`,children:`nanomuse serve`}),n(`, or paste the access token below.`)]}),(0,R.jsxs)(`form`,{className:`mt-5 w-full flex gap-2`,onSubmit:t=>{t.preventDefault(),e.trim()&&(g(e.trim()),window.location.reload())},children:[(0,R.jsx)(`input`,{value:e,onChange:e=>t(e.target.value),"aria-label":n(`Access token`),placeholder:n(`Access token`),className:`flex-1 rounded-2xl bg-surface-2 px-4 py-2.5 text-[15px] outline-none focus:ring-2 focus:ring-accent/40`}),(0,R.jsx)(`button`,{type:`submit`,className:`rounded-2xl bg-accent text-accent-fg px-4 font-medium`,children:n(`Connect`)})]})]})}a(),ee(),wn(),bn.createRoot(document.getElementById(`root`)).render((0,R.jsx)(L.StrictMode,{children:(0,R.jsx)(T,{children:(0,R.jsx)(gg,{})})}));export{Ut as $,Ff as A,gn as B,Jp as C,Ze as Ct,rp as D,Ke as Dt,ip as E,qe as Et,hf as F,tn as G,sn as H,Mn as I,Xt as J,Qt as K,Sn as L,Nf as M,Pf as N,Zf as O,Af as P,Gt as Q,Cn as R,tm as S,Qe as St,op as T,Je as Tt,on as U,fn as V,nn as W,qt as X,Jt as Y,I as Z,nm as _,ct as _t,Ah as a,Nt as at,rm as b,rt as bt,Ih as c,Tt as ct,Um as d,F as dt,Ht as et,Em as f,vt as ft,Xp as g,ut as gt,Qp as h,pt as ht,Fh as i,It as it,jf as j,$f as k,Nh as l,wt as lt,Yp as m,mt,Rh as n,Rt as nt,jh as o,At as ot,Zp as p,gt as pt,Zt as q,Lh as r,Lt as rt,Mh as s,Et as st,Wh as t,Vt as tt,Vm as u,xt as ut,im as v,st as vt,Op as w,Xe as wt,$p as x,tt as xt,em as y,at as yt,yn as z}; \ No newline at end of file diff --git a/nanomuse/server/static/assets/index-CwUBXfPC.css b/nanomuse/server/static/assets/index-CwUBXfPC.css new file mode 100644 index 000000000..a3236b7a6 --- /dev/null +++ b/nanomuse/server/static/assets/index-CwUBXfPC.css @@ -0,0 +1,2 @@ +/*! tailwindcss v4.3.3 | MIT License | https://tailwindcss.com */ +@layer properties{@supports (((-webkit-hyphens:none)) and (not (margin-trim:inline))) or ((-moz-orient:inline) and (not (color:rgb(from red r g b)))){*,:before,:after,::backdrop{--tw-border-spacing-x:0;--tw-border-spacing-y:0;--tw-translate-x:0;--tw-translate-y:0;--tw-translate-z:0;--tw-space-y-reverse:0;--tw-divide-y-reverse:0;--tw-border-style:solid;--tw-gradient-position:initial;--tw-gradient-from:#0000;--tw-gradient-via:#0000;--tw-gradient-to:#0000;--tw-gradient-stops:initial;--tw-gradient-via-stops:initial;--tw-gradient-from-position:0%;--tw-gradient-via-position:50%;--tw-gradient-to-position:100%;--tw-leading:initial;--tw-font-weight:initial;--tw-tracking:initial;--tw-ordinal:initial;--tw-slashed-zero:initial;--tw-numeric-figure:initial;--tw-numeric-spacing:initial;--tw-numeric-fraction:initial;--tw-shadow:0 0 #0000;--tw-shadow-color:initial;--tw-shadow-alpha:100%;--tw-inset-shadow:0 0 #0000;--tw-inset-shadow-color:initial;--tw-inset-shadow-alpha:100%;--tw-ring-color:initial;--tw-ring-shadow:0 0 #0000;--tw-inset-ring-color:initial;--tw-inset-ring-shadow:0 0 #0000;--tw-ring-inset:initial;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-offset-shadow:0 0 #0000;--tw-blur:initial;--tw-brightness:initial;--tw-contrast:initial;--tw-grayscale:initial;--tw-hue-rotate:initial;--tw-invert:initial;--tw-opacity:initial;--tw-saturate:initial;--tw-sepia:initial;--tw-drop-shadow:initial;--tw-drop-shadow-color:initial;--tw-drop-shadow-alpha:100%;--tw-drop-shadow-size:initial;--tw-backdrop-blur:initial;--tw-backdrop-brightness:initial;--tw-backdrop-contrast:initial;--tw-backdrop-grayscale:initial;--tw-backdrop-hue-rotate:initial;--tw-backdrop-invert:initial;--tw-backdrop-opacity:initial;--tw-backdrop-saturate:initial;--tw-backdrop-sepia:initial;--tw-duration:initial;--tw-scale-x:1;--tw-scale-y:1;--tw-scale-z:1}}}@layer theme{:root,:host{--font-sans:"Figtree", ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", "Noto Sans CJK SC", sans-serif;--font-mono:ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;--color-red-400:oklch(70.4% .191 22.216);--color-red-500:oklch(63.7% .237 25.331);--color-red-600:oklch(57.7% .245 27.325);--color-orange-300:oklch(83.7% .128 66.29);--color-orange-400:oklch(75% .183 55.934);--color-orange-500:oklch(70.5% .213 47.604);--color-orange-600:oklch(64.6% .222 41.116);--color-amber-50:oklch(98.7% .022 95.277);--color-amber-200:oklch(92.4% .12 95.746);--color-amber-300:oklch(87.9% .169 91.605);--color-amber-400:oklch(82.8% .189 84.429);--color-amber-500:oklch(76.9% .188 70.08);--color-amber-600:oklch(66.6% .179 58.318);--color-amber-700:oklch(55.5% .163 48.998);--color-amber-800:oklch(47.3% .137 46.201);--color-emerald-300:oklch(84.5% .143 164.978);--color-emerald-400:oklch(76.5% .177 163.223);--color-emerald-500:oklch(69.6% .17 162.48);--color-emerald-600:oklch(59.6% .145 163.225);--color-emerald-700:oklch(50.8% .118 165.612);--color-teal-700:oklch(51.1% .096 186.391);--color-cyan-300:oklch(86.5% .127 207.078);--color-cyan-500:oklch(71.5% .143 215.221);--color-cyan-600:oklch(60.9% .126 221.723);--color-sky-300:oklch(82.8% .111 230.318);--color-sky-400:oklch(74.6% .16 232.661);--color-sky-500:oklch(68.5% .169 237.323);--color-sky-600:oklch(58.8% .158 241.966);--color-violet-300:oklch(81.1% .111 293.571);--color-violet-500:oklch(60.6% .25 292.717);--color-violet-600:oklch(54.1% .281 293.009);--color-fuchsia-300:oklch(83.3% .145 321.434);--color-fuchsia-500:oklch(66.7% .295 322.15);--color-fuchsia-600:oklch(59.1% .293 322.896);--color-pink-300:oklch(82.3% .12 346.018);--color-pink-500:oklch(65.6% .241 354.308);--color-pink-600:oklch(59.2% .249 .584);--color-rose-300:oklch(81% .117 11.638);--color-rose-400:oklch(71.2% .194 13.428);--color-rose-500:oklch(64.5% .246 16.439);--color-rose-600:oklch(58.6% .253 17.585);--color-rose-700:oklch(51.4% .222 16.935);--color-slate-400:oklch(70.4% .04 256.788);--color-slate-600:oklch(44.6% .043 257.281);--color-slate-700:oklch(37.2% .044 257.287);--color-slate-900:oklch(20.8% .042 265.755);--color-black:#000;--color-white:#fff;--spacing:.25rem;--container-sm:24rem;--container-md:28rem;--container-lg:32rem;--font-weight-normal:400;--font-weight-medium:500;--font-weight-semibold:600;--font-weight-bold:700;--tracking-tight:-.025em;--tracking-normal:0em;--tracking-wide:.025em;--leading-tight:1.25;--leading-snug:1.375;--leading-relaxed:1.625;--radius-sm:.25rem;--radius-md:.375rem;--radius-lg:.5rem;--radius-xl:.75rem;--radius-2xl:1rem;--radius-3xl:1.5rem;--drop-shadow-sm:0 1px 2px #00000026;--animate-spin:spin 1s linear infinite;--animate-pulse:pulse 2s cubic-bezier(.4, 0, .6, 1) infinite;--blur-2xl:40px;--blur-3xl:64px;--default-transition-duration:.15s;--default-transition-timing-function:cubic-bezier(.4, 0, .2, 1);--default-font-family:var(--font-sans);--default-mono-font-family:var(--font-mono);--color-bg:var(--om-bg);--color-surface:var(--om-surface);--color-surface-2:var(--om-surface-2);--color-border:var(--om-border);--color-fg:var(--om-fg);--color-muted:var(--om-muted);--color-accent:var(--om-accent);--color-accent-fg:#fff;--color-accent-soft:var(--om-accent-soft);--color-accent-soft-fg:var(--om-accent-soft-fg);--color-bubble-user:var(--om-bubble-user);--color-bubble-user-fg:var(--om-bubble-user-fg)}}@layer base{*,:after,:before,::backdrop{box-sizing:border-box;border:0 solid;margin:0;padding:0}::file-selector-button{box-sizing:border-box;border:0 solid;margin:0;padding:0}html,:host{-webkit-text-size-adjust:100%;tab-size:4;line-height:1.5;font-family:var(--default-font-family,-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", "Noto Sans", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji");font-feature-settings:var(--default-font-feature-settings,normal);font-variation-settings:var(--default-font-variation-settings,normal);-webkit-tap-highlight-color:transparent}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,samp,pre{font-family:var(--default-mono-font-family,ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace);font-feature-settings:var(--default-mono-font-feature-settings,normal);font-variation-settings:var(--default-mono-font-variation-settings,normal);font-size:1em}small{font-size:80%}sub,sup{vertical-align:baseline;font-size:75%;line-height:0;position:relative}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}:-moz-focusring:where(:not(iframe)){outline:auto}progress{vertical-align:baseline}summary{display:list-item}ol,ul,menu{list-style:none}img,svg,video,canvas,audio,iframe,embed,object{vertical-align:middle;display:block}img,video{max-width:100%;height:auto}button,input,select,optgroup,textarea{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}::file-selector-button{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}:where(select:is([multiple],[size])) optgroup{font-weight:bolder}:where(select:is([multiple],[size])) optgroup option{padding-inline-start:20px}::file-selector-button{margin-inline-end:4px}::placeholder{opacity:1}@supports (not ((-webkit-appearance:-apple-pay-button))) or (contain-intrinsic-size:1px){::placeholder{color:currentColor}@supports (color:color-mix(in lab, red, red)){::placeholder{color:color-mix(in oklab, currentcolor 50%, transparent)}}}textarea{resize:vertical}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-date-and-time-value{min-height:1lh;text-align:inherit}::-webkit-datetime-edit{display:inline-flex}::-webkit-datetime-edit-fields-wrapper{padding:0}::-webkit-datetime-edit{padding-block:0}::-webkit-datetime-edit-year-field{padding-block:0}::-webkit-datetime-edit-month-field{padding-block:0}::-webkit-datetime-edit-day-field{padding-block:0}::-webkit-datetime-edit-hour-field{padding-block:0}::-webkit-datetime-edit-minute-field{padding-block:0}::-webkit-datetime-edit-second-field{padding-block:0}::-webkit-datetime-edit-millisecond-field{padding-block:0}::-webkit-datetime-edit-meridiem-field{padding-block:0}::-webkit-calendar-picker-indicator{line-height:1}:-moz-ui-invalid{box-shadow:none}button,input:where([type=button],[type=reset],[type=submit]){appearance:button}::file-selector-button{appearance:button}::-webkit-inner-spin-button{height:auto}::-webkit-outer-spin-button{height:auto}[hidden]:where(:not([hidden=until-found])){display:none!important}}@layer components;@layer utilities{.\@container{container-type:inline-size}.pointer-events-auto{pointer-events:auto}.pointer-events-none{pointer-events:none}.visible{visibility:visible}.sr-only{clip-path:inset(50%);white-space:nowrap;border-width:0;width:1px;height:1px;margin:-1px;padding:0;position:absolute;overflow:hidden}.absolute{position:absolute}.fixed{position:fixed}.relative{position:relative}.static{position:static}.sticky{position:sticky}.inset-0{inset:0}.inset-x-0{inset-inline:0}.inset-y-0{inset-block:0}.-top-1{top:calc(var(--spacing) * -1)}.-top-1\.5{top:calc(var(--spacing) * -1.5)}.-top-20{top:calc(var(--spacing) * -20)}.top-0{top:0}.top-0\.5{top:calc(var(--spacing) * .5)}.top-1{top:var(--spacing)}.top-1\.5{top:calc(var(--spacing) * 1.5)}.top-1\/2{top:50%}.top-2{top:calc(var(--spacing) * 2)}.top-2\.5{top:calc(var(--spacing) * 2.5)}.top-9{top:calc(var(--spacing) * 9)}.top-12{top:calc(var(--spacing) * 12)}.top-\[3px\]{top:3px}.top-full{top:100%}.-right-0\.5{right:calc(var(--spacing) * -.5)}.-right-1{right:calc(var(--spacing) * -1)}.-right-1\.5{right:calc(var(--spacing) * -1.5)}.-right-16{right:calc(var(--spacing) * -16)}.right-0{right:0}.right-1{right:var(--spacing)}.right-1\.5{right:calc(var(--spacing) * 1.5)}.right-2{right:calc(var(--spacing) * 2)}.right-2\.5{right:calc(var(--spacing) * 2.5)}.right-3{right:calc(var(--spacing) * 3)}.right-4{right:calc(var(--spacing) * 4)}.right-\[3px\]{right:3px}.-bottom-0\.5{bottom:calc(var(--spacing) * -.5)}.bottom-0{bottom:0}.bottom-1{bottom:var(--spacing)}.bottom-2{bottom:calc(var(--spacing) * 2)}.bottom-\[calc\(6rem\+env\(safe-area-inset-bottom\)\)\]{bottom:calc(6rem + env(safe-area-inset-bottom))}.tabbar-float{bottom:calc(12px + env(safe-area-inset-bottom))}.left-0{left:0}.left-0\.5{left:calc(var(--spacing) * .5)}.left-1\.5{left:calc(var(--spacing) * 1.5)}.left-1\/2{left:50%}.left-2\.5{left:calc(var(--spacing) * 2.5)}.left-3{left:calc(var(--spacing) * 3)}.left-4{left:calc(var(--spacing) * 4)}.left-\[18px\]{left:18px}.left-\[22px\]{left:22px}.left-\[26px\]{left:26px}.left-\[68px\]{left:68px}.z-10{z-index:10}.z-20{z-index:20}.z-30{z-index:30}.z-50{z-index:50}.z-\[60\]{z-index:60}.z-\[70\]{z-index:70}.container{width:100%}@media (width>=40rem){.container{max-width:40rem}}@media (width>=48rem){.container{max-width:48rem}}@media (width>=64rem){.container{max-width:64rem}}@media (width>=80rem){.container{max-width:80rem}}@media (width>=96rem){.container{max-width:96rem}}.-mx-4{margin-inline:calc(var(--spacing) * -4)}.mx-1{margin-inline:var(--spacing)}.mx-2{margin-inline:calc(var(--spacing) * 2)}.mx-3{margin-inline:calc(var(--spacing) * 3)}.mx-4{margin-inline:calc(var(--spacing) * 4)}.mx-auto{margin-inline:auto}.my-1{margin-block:var(--spacing)}.my-1\.5{margin-block:calc(var(--spacing) * 1.5)}.my-2{margin-block:calc(var(--spacing) * 2)}.my-8{margin-block:calc(var(--spacing) * 8)}.-mt-0\.5{margin-top:calc(var(--spacing) * -.5)}.-mt-1{margin-top:calc(var(--spacing) * -1)}.-mt-2\.5{margin-top:calc(var(--spacing) * -2.5)}.mt-0\.5{margin-top:calc(var(--spacing) * .5)}.mt-1{margin-top:var(--spacing)}.mt-1\.5{margin-top:calc(var(--spacing) * 1.5)}.mt-2{margin-top:calc(var(--spacing) * 2)}.mt-2\.5{margin-top:calc(var(--spacing) * 2.5)}.mt-3{margin-top:calc(var(--spacing) * 3)}.mt-3\.5{margin-top:calc(var(--spacing) * 3.5)}.mt-4{margin-top:calc(var(--spacing) * 4)}.mt-5{margin-top:calc(var(--spacing) * 5)}.mt-6{margin-top:calc(var(--spacing) * 6)}.mt-7{margin-top:calc(var(--spacing) * 7)}.mt-8{margin-top:calc(var(--spacing) * 8)}.mt-\[2px\]{margin-top:2px}.mt-\[3px\]{margin-top:3px}.mt-\[22px\]{margin-top:22px}.mt-auto{margin-top:auto}.-mr-1\.5{margin-right:calc(var(--spacing) * -1.5)}.-mr-2{margin-right:calc(var(--spacing) * -2)}.mr-2{margin-right:calc(var(--spacing) * 2)}.mr-2\.5{margin-right:calc(var(--spacing) * 2.5)}.mr-3{margin-right:calc(var(--spacing) * 3)}.mr-5{margin-right:calc(var(--spacing) * 5)}.-mb-2{margin-bottom:calc(var(--spacing) * -2)}.mb-0\.5{margin-bottom:calc(var(--spacing) * .5)}.mb-1{margin-bottom:var(--spacing)}.mb-1\.5{margin-bottom:calc(var(--spacing) * 1.5)}.mb-2{margin-bottom:calc(var(--spacing) * 2)}.mb-3{margin-bottom:calc(var(--spacing) * 3)}.mb-4{margin-bottom:calc(var(--spacing) * 4)}.mb-5{margin-bottom:calc(var(--spacing) * 5)}.mb-6{margin-bottom:calc(var(--spacing) * 6)}.-ml-1{margin-left:calc(var(--spacing) * -1)}.ml-0\.5{margin-left:calc(var(--spacing) * .5)}.ml-1{margin-left:var(--spacing)}.ml-1\.5{margin-left:calc(var(--spacing) * 1.5)}.ml-2{margin-left:calc(var(--spacing) * 2)}.ml-2\.5{margin-left:calc(var(--spacing) * 2.5)}.ml-4{margin-left:calc(var(--spacing) * 4)}.ml-\[52px\]{margin-left:52px}.ml-\[76px\]{margin-left:76px}.ml-auto{margin-left:auto}.line-clamp-2{-webkit-line-clamp:2;-webkit-box-orient:vertical;display:-webkit-box;overflow:hidden}.line-clamp-3{-webkit-line-clamp:3;-webkit-box-orient:vertical;display:-webkit-box;overflow:hidden}.line-clamp-4{-webkit-line-clamp:4;-webkit-box-orient:vertical;display:-webkit-box;overflow:hidden}.block{display:block}.contents{display:contents}.flex{display:flex}.grid{display:grid}.hidden{display:none}.inline{display:inline}.inline-block{display:inline-block}.inline-flex{display:inline-flex}.table{display:table}.aspect-\[16\/10\]{aspect-ratio:16/10}.aspect-square{aspect-ratio:1}.h-1{height:var(--spacing)}.h-1\.5{height:calc(var(--spacing) * 1.5)}.h-2{height:calc(var(--spacing) * 2)}.h-2\.5{height:calc(var(--spacing) * 2.5)}.h-3\.5{height:calc(var(--spacing) * 3.5)}.h-4{height:calc(var(--spacing) * 4)}.h-5{height:calc(var(--spacing) * 5)}.h-6{height:calc(var(--spacing) * 6)}.h-7{height:calc(var(--spacing) * 7)}.h-8{height:calc(var(--spacing) * 8)}.h-9{height:calc(var(--spacing) * 9)}.h-10{height:calc(var(--spacing) * 10)}.h-11{height:calc(var(--spacing) * 11)}.h-12{height:calc(var(--spacing) * 12)}.h-14{height:calc(var(--spacing) * 14)}.h-16{height:calc(var(--spacing) * 16)}.h-28{height:calc(var(--spacing) * 28)}.h-40{height:calc(var(--spacing) * 40)}.h-44{height:calc(var(--spacing) * 44)}.h-48{height:calc(var(--spacing) * 48)}.h-\[9px\]{height:9px}.h-\[17px\]{height:17px}.h-\[18px\]{height:18px}.h-\[46px\]{height:46px}.h-\[46vh\]{height:46vh}.h-\[50px\]{height:50px}.h-\[72px\]{height:72px}.h-\[100dvh\]{height:100dvh}.h-\[130px\]{height:130px}.h-\[148px\]{height:148px}.h-\[480px\]{height:480px}.h-full{height:100%}.max-h-28{max-height:calc(var(--spacing) * 28)}.max-h-32{max-height:calc(var(--spacing) * 32)}.max-h-40{max-height:calc(var(--spacing) * 40)}.max-h-52{max-height:calc(var(--spacing) * 52)}.max-h-64{max-height:calc(var(--spacing) * 64)}.max-h-72{max-height:calc(var(--spacing) * 72)}.max-h-\[60vh\]{max-height:60vh}.max-h-\[92dvh\]{max-height:92dvh}.max-h-full{max-height:100%}.min-h-0{min-height:0}.min-h-\[40vh\]{min-height:40vh}.min-h-\[44px\]{min-height:44px}.min-h-\[54px\]{min-height:54px}.min-h-\[56px\]{min-height:56px}.\!w-auto{width:auto!important}.w-1{width:var(--spacing)}.w-1\.5{width:calc(var(--spacing) * 1.5)}.w-2{width:calc(var(--spacing) * 2)}.w-2\.5{width:calc(var(--spacing) * 2.5)}.w-5{width:calc(var(--spacing) * 5)}.w-6{width:calc(var(--spacing) * 6)}.w-7{width:calc(var(--spacing) * 7)}.w-8{width:calc(var(--spacing) * 8)}.w-9{width:calc(var(--spacing) * 9)}.w-10{width:calc(var(--spacing) * 10)}.w-11{width:calc(var(--spacing) * 11)}.w-12{width:calc(var(--spacing) * 12)}.w-14{width:calc(var(--spacing) * 14)}.w-16{width:calc(var(--spacing) * 16)}.w-28{width:calc(var(--spacing) * 28)}.w-40{width:calc(var(--spacing) * 40)}.w-44{width:calc(var(--spacing) * 44)}.w-48{width:calc(var(--spacing) * 48)}.w-56{width:calc(var(--spacing) * 56)}.w-\[9px\]{width:9px}.w-\[46px\]{width:46px}.w-\[60px\]{width:60px}.w-\[64px\]{width:64px}.w-\[72px\]{width:72px}.w-\[74px\]{width:74px}.w-\[76px\]{width:76px}.w-\[82vw\]{width:82vw}.w-\[86px\]{width:86px}.w-\[148px\]{width:148px}.w-\[188px\]{width:188px}.w-\[232px\]{width:232px}.w-\[248px\]{width:248px}.w-\[260px\]{width:260px}.w-\[300px\]{width:300px}.w-\[900px\]{width:900px}.w-auto{width:auto}.w-fit{width:fit-content}.w-full{width:100%}.max-w-\[60\%\]{max-width:60%}.max-w-\[68px\]{max-width:68px}.max-w-\[86\%\]{max-width:86%}.max-w-\[240px\]{max-width:240px}.max-w-\[320px\]{max-width:320px}.max-w-\[340px\]{max-width:340px}.max-w-\[360px\]{max-width:360px}.max-w-\[520px\]{max-width:520px}.max-w-\[560px\]{max-width:560px}.max-w-\[600px\]{max-width:600px}.max-w-\[720px\]{max-width:720px}.max-w-\[760px\]{max-width:760px}.max-w-\[calc\(100\%-128px\)\]{max-width:calc(100% - 128px)}.max-w-full{max-width:100%}.max-w-md{max-width:var(--container-md)}.max-w-sm{max-width:var(--container-sm)}.min-w-0{min-width:0}.min-w-\[17px\]{min-width:17px}.min-w-\[18px\]{min-width:18px}.min-w-\[180px\]{min-width:180px}.min-w-full{min-width:100%}.flex-1{flex:1}.shrink-0{flex-shrink:0}.border-separate{border-collapse:separate}.border-spacing-0{--tw-border-spacing-x:0px;--tw-border-spacing-y:0px;border-spacing:var(--tw-border-spacing-x) var(--tw-border-spacing-y)}.origin-top-left{transform-origin:0 0}.-translate-x-1\/2{--tw-translate-x:calc(calc(1 / 2 * 100%) * -1);translate:var(--tw-translate-x) var(--tw-translate-y)}.-translate-y-1\/2{--tw-translate-y:calc(calc(1 / 2 * 100%) * -1);translate:var(--tw-translate-x) var(--tw-translate-y)}.scale-\[0\.3333\]{scale:.3333}.animate-pulse{animation:var(--animate-pulse)}.animate-spin{animation:var(--animate-spin)}.cursor-crosshair{cursor:crosshair}.cursor-pointer{cursor:pointer}.resize-none{resize:none}.resize-y{resize:vertical}.scroll-mt-4{scroll-margin-top:calc(var(--spacing) * 4)}.list-decimal{list-style-type:decimal}.grid-cols-1{grid-template-columns:repeat(1,minmax(0,1fr))}.grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}.grid-cols-4{grid-template-columns:repeat(4,minmax(0,1fr))}.grid-cols-8{grid-template-columns:repeat(8,minmax(0,1fr))}.grid-cols-\[1fr_1fr_auto\]{grid-template-columns:1fr 1fr auto}.grid-cols-\[1fr_84px\]{grid-template-columns:1fr 84px}.grid-cols-\[auto_1fr\]{grid-template-columns:auto 1fr}.flex-col{flex-direction:column}.flex-wrap{flex-wrap:wrap}.items-baseline{align-items:baseline}.items-center{align-items:center}.items-end{align-items:flex-end}.items-start{align-items:flex-start}.justify-between{justify-content:space-between}.justify-center{justify-content:center}.justify-end{justify-content:flex-end}.justify-start{justify-content:flex-start}.gap-0\.5{gap:calc(var(--spacing) * .5)}.gap-1{gap:var(--spacing)}.gap-1\.5{gap:calc(var(--spacing) * 1.5)}.gap-2{gap:calc(var(--spacing) * 2)}.gap-2\.5{gap:calc(var(--spacing) * 2.5)}.gap-3{gap:calc(var(--spacing) * 3)}.gap-3\.5{gap:calc(var(--spacing) * 3.5)}.gap-4{gap:calc(var(--spacing) * 4)}.gap-\[3px\]{gap:3px}:where(.space-y-0\.5>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * .5) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * .5) * calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-1>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(var(--spacing) * var(--tw-space-y-reverse));margin-block-end:calc(var(--spacing) * calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-1\.5>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * 1.5) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * 1.5) * calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-2>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * 2) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * 2) * calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-2\.5>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * 2.5) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * 2.5) * calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-3>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * 3) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * 3) * calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-3\.5>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * 3.5) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * 3.5) * calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-4>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * 4) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * 4) * calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-5>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * 5) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * 5) * calc(1 - var(--tw-space-y-reverse)))}.gap-x-1\.5{column-gap:calc(var(--spacing) * 1.5)}.gap-x-2{column-gap:calc(var(--spacing) * 2)}.gap-x-3{column-gap:calc(var(--spacing) * 3)}.gap-x-4{column-gap:calc(var(--spacing) * 4)}.gap-y-0\.5{row-gap:calc(var(--spacing) * .5)}.gap-y-1{row-gap:var(--spacing)}.gap-y-1\.5{row-gap:calc(var(--spacing) * 1.5)}:where(.divide-y>:not(:last-child)){--tw-divide-y-reverse:0;border-bottom-style:var(--tw-border-style);border-top-style:var(--tw-border-style);border-top-width:calc(1px * var(--tw-divide-y-reverse));border-bottom-width:calc(1px * calc(1 - var(--tw-divide-y-reverse)))}:where(.divide-border>:not(:last-child)),:where(.divide-border\/60>:not(:last-child)){border-color:var(--color-border)}@supports (color:color-mix(in lab, red, red)){:where(.divide-border\/60>:not(:last-child)){border-color:color-mix(in oklab, var(--color-border) 60%, transparent)}}:where(.divide-border\/70>:not(:last-child)){border-color:var(--color-border)}@supports (color:color-mix(in lab, red, red)){:where(.divide-border\/70>:not(:last-child)){border-color:color-mix(in oklab, var(--color-border) 70%, transparent)}}.self-center{align-self:center}.self-start{align-self:flex-start}.truncate{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.overflow-auto{overflow:auto}.overflow-hidden{overflow:hidden}.overflow-x-auto{overflow-x:auto}.overflow-x-hidden{overflow-x:hidden}.overflow-y-auto{overflow-y:auto}.rounded{border-radius:.25rem}.rounded-2xl{border-radius:var(--radius-2xl)}.rounded-3xl{border-radius:var(--radius-3xl)}.rounded-\[10px\]{border-radius:10px}.rounded-\[13px\]{border-radius:13px}.rounded-\[14px\]{border-radius:14px}.rounded-\[18px\]{border-radius:18px}.rounded-\[20px\]{border-radius:20px}.rounded-\[22px\]{border-radius:22px}.rounded-\[26px\]{border-radius:26px}.rounded-\[28px\]{border-radius:28px}.rounded-full{border-radius:2147483647px}.rounded-lg{border-radius:var(--radius-lg)}.rounded-md{border-radius:var(--radius-md)}.rounded-sm{border-radius:var(--radius-sm)}.rounded-xl{border-radius:var(--radius-xl)}.rounded-t-3xl{border-top-left-radius:var(--radius-3xl);border-top-right-radius:var(--radius-3xl)}.rounded-t-\[28px\]{border-top-left-radius:28px;border-top-right-radius:28px}.rounded-tl-lg{border-top-left-radius:var(--radius-lg)}.rounded-br-lg{border-bottom-right-radius:var(--radius-lg)}.rounded-bl-lg{border-bottom-left-radius:var(--radius-lg)}.rounded-bl-md{border-bottom-left-radius:var(--radius-md)}.border{border-style:var(--tw-border-style);border-width:1px}.border-0{border-style:var(--tw-border-style);border-width:0}.border-2{border-style:var(--tw-border-style);border-width:2px}.border-\[1\.5px\]{border-style:var(--tw-border-style);border-width:1.5px}.border-y{border-block-style:var(--tw-border-style);border-block-width:1px}.border-t{border-top-style:var(--tw-border-style);border-top-width:1px}.border-r{border-right-style:var(--tw-border-style);border-right-width:1px}.border-b{border-bottom-style:var(--tw-border-style);border-bottom-width:1px}.border-dashed{--tw-border-style:dashed;border-style:dashed}.border-accent,.border-accent\/15{border-color:var(--color-accent)}@supports (color:color-mix(in lab, red, red)){.border-accent\/15{border-color:color-mix(in oklab, var(--color-accent) 15%, transparent)}}.border-accent\/25{border-color:var(--color-accent)}@supports (color:color-mix(in lab, red, red)){.border-accent\/25{border-color:color-mix(in oklab, var(--color-accent) 25%, transparent)}}.border-accent\/30{border-color:var(--color-accent)}@supports (color:color-mix(in lab, red, red)){.border-accent\/30{border-color:color-mix(in oklab, var(--color-accent) 30%, transparent)}}.border-accent\/40{border-color:var(--color-accent)}@supports (color:color-mix(in lab, red, red)){.border-accent\/40{border-color:color-mix(in oklab, var(--color-accent) 40%, transparent)}}.border-accent\/50{border-color:var(--color-accent)}@supports (color:color-mix(in lab, red, red)){.border-accent\/50{border-color:color-mix(in oklab, var(--color-accent) 50%, transparent)}}.border-amber-400\/40{border-color:#fcbb0066}@supports (color:color-mix(in lab, red, red)){.border-amber-400\/40{border-color:color-mix(in oklab, var(--color-amber-400) 40%, transparent)}}.border-amber-500\/50{border-color:#f99c0080}@supports (color:color-mix(in lab, red, red)){.border-amber-500\/50{border-color:color-mix(in oklab, var(--color-amber-500) 50%, transparent)}}.border-bg{border-color:var(--color-bg)}.border-border,.border-border\/60{border-color:var(--color-border)}@supports (color:color-mix(in lab, red, red)){.border-border\/60{border-color:color-mix(in oklab, var(--color-border) 60%, transparent)}}.border-border\/70{border-color:var(--color-border)}@supports (color:color-mix(in lab, red, red)){.border-border\/70{border-color:color-mix(in oklab, var(--color-border) 70%, transparent)}}.border-border\/80{border-color:var(--color-border)}@supports (color:color-mix(in lab, red, red)){.border-border\/80{border-color:color-mix(in oklab, var(--color-border) 80%, transparent)}}.border-current{border-color:currentColor}.border-fg{border-color:var(--color-fg)}.border-rose-400{border-color:var(--color-rose-400)}.border-rose-400\/60{border-color:#ff667f99}@supports (color:color-mix(in lab, red, red)){.border-rose-400\/60{border-color:color-mix(in oklab, var(--color-rose-400) 60%, transparent)}}.border-rose-500\/25{border-color:#ff235740}@supports (color:color-mix(in lab, red, red)){.border-rose-500\/25{border-color:color-mix(in oklab, var(--color-rose-500) 25%, transparent)}}.border-surface{border-color:var(--color-surface)}.border-transparent{border-color:#0000}.border-t-transparent{border-top-color:#0000}.bg-\[\#2fb344\]{background-color:#2fb344}.bg-\[\#f1efeb\]{background-color:#f1efeb}.bg-accent{background-color:var(--color-accent)}.bg-accent-soft{background-color:var(--color-accent-soft)}.bg-accent\/5{background-color:var(--color-accent)}@supports (color:color-mix(in lab, red, red)){.bg-accent\/5{background-color:color-mix(in oklab, var(--color-accent) 5%, transparent)}}.bg-accent\/8{background-color:var(--color-accent)}@supports (color:color-mix(in lab, red, red)){.bg-accent\/8{background-color:color-mix(in oklab, var(--color-accent) 8%, transparent)}}.bg-accent\/10{background-color:var(--color-accent)}@supports (color:color-mix(in lab, red, red)){.bg-accent\/10{background-color:color-mix(in oklab, var(--color-accent) 10%, transparent)}}.bg-accent\/12{background-color:var(--color-accent)}@supports (color:color-mix(in lab, red, red)){.bg-accent\/12{background-color:color-mix(in oklab, var(--color-accent) 12%, transparent)}}.bg-accent\/15{background-color:var(--color-accent)}@supports (color:color-mix(in lab, red, red)){.bg-accent\/15{background-color:color-mix(in oklab, var(--color-accent) 15%, transparent)}}.bg-accent\/70{background-color:var(--color-accent)}@supports (color:color-mix(in lab, red, red)){.bg-accent\/70{background-color:color-mix(in oklab, var(--color-accent) 70%, transparent)}}.bg-accent\/\[0\.06\]{background-color:var(--color-accent)}@supports (color:color-mix(in lab, red, red)){.bg-accent\/\[0\.06\]{background-color:color-mix(in oklab, var(--color-accent) 6%, transparent)}}.bg-amber-50\/70{background-color:#fffbebb3}@supports (color:color-mix(in lab, red, red)){.bg-amber-50\/70{background-color:color-mix(in oklab, var(--color-amber-50) 70%, transparent)}}.bg-amber-400{background-color:var(--color-amber-400)}.bg-amber-400\/15{background-color:#fcbb0026}@supports (color:color-mix(in lab, red, red)){.bg-amber-400\/15{background-color:color-mix(in oklab, var(--color-amber-400) 15%, transparent)}}.bg-amber-500{background-color:var(--color-amber-500)}.bg-amber-500\/10{background-color:#f99c001a}@supports (color:color-mix(in lab, red, red)){.bg-amber-500\/10{background-color:color-mix(in oklab, var(--color-amber-500) 10%, transparent)}}.bg-amber-500\/12{background-color:#f99c001f}@supports (color:color-mix(in lab, red, red)){.bg-amber-500\/12{background-color:color-mix(in oklab, var(--color-amber-500) 12%, transparent)}}.bg-amber-500\/15{background-color:#f99c0026}@supports (color:color-mix(in lab, red, red)){.bg-amber-500\/15{background-color:color-mix(in oklab, var(--color-amber-500) 15%, transparent)}}.bg-bg,.bg-bg\/50{background-color:var(--color-bg)}@supports (color:color-mix(in lab, red, red)){.bg-bg\/50{background-color:color-mix(in oklab, var(--color-bg) 50%, transparent)}}.bg-bg\/60{background-color:var(--color-bg)}@supports (color:color-mix(in lab, red, red)){.bg-bg\/60{background-color:color-mix(in oklab, var(--color-bg) 60%, transparent)}}.bg-bg\/80{background-color:var(--color-bg)}@supports (color:color-mix(in lab, red, red)){.bg-bg\/80{background-color:color-mix(in oklab, var(--color-bg) 80%, transparent)}}.bg-black\/20{background-color:#0003}@supports (color:color-mix(in lab, red, red)){.bg-black\/20{background-color:color-mix(in oklab, var(--color-black) 20%, transparent)}}.bg-black\/40{background-color:#0006}@supports (color:color-mix(in lab, red, red)){.bg-black\/40{background-color:color-mix(in oklab, var(--color-black) 40%, transparent)}}.bg-black\/45{background-color:#00000073}@supports (color:color-mix(in lab, red, red)){.bg-black\/45{background-color:color-mix(in oklab, var(--color-black) 45%, transparent)}}.bg-black\/60{background-color:#0009}@supports (color:color-mix(in lab, red, red)){.bg-black\/60{background-color:color-mix(in oklab, var(--color-black) 60%, transparent)}}.bg-border{background-color:var(--color-border)}.bg-bubble-user{background-color:var(--color-bubble-user)}.bg-cyan-500\/12{background-color:#00b7d71f}@supports (color:color-mix(in lab, red, red)){.bg-cyan-500\/12{background-color:color-mix(in oklab, var(--color-cyan-500) 12%, transparent)}}.bg-emerald-500{background-color:var(--color-emerald-500)}.bg-emerald-500\/12{background-color:#00bb7f1f}@supports (color:color-mix(in lab, red, red)){.bg-emerald-500\/12{background-color:color-mix(in oklab, var(--color-emerald-500) 12%, transparent)}}.bg-emerald-500\/15{background-color:#00bb7f26}@supports (color:color-mix(in lab, red, red)){.bg-emerald-500\/15{background-color:color-mix(in oklab, var(--color-emerald-500) 15%, transparent)}}.bg-fg,.bg-fg\/40{background-color:var(--color-fg)}@supports (color:color-mix(in lab, red, red)){.bg-fg\/40{background-color:color-mix(in oklab, var(--color-fg) 40%, transparent)}}.bg-fuchsia-500\/12{background-color:#e12afb1f}@supports (color:color-mix(in lab, red, red)){.bg-fuchsia-500\/12{background-color:color-mix(in oklab, var(--color-fuchsia-500) 12%, transparent)}}.bg-muted,.bg-muted\/35{background-color:var(--color-muted)}@supports (color:color-mix(in lab, red, red)){.bg-muted\/35{background-color:color-mix(in oklab, var(--color-muted) 35%, transparent)}}.bg-orange-500\/12{background-color:#fe6e001f}@supports (color:color-mix(in lab, red, red)){.bg-orange-500\/12{background-color:color-mix(in oklab, var(--color-orange-500) 12%, transparent)}}.bg-pink-500{background-color:var(--color-pink-500)}.bg-pink-500\/12{background-color:#f6339a1f}@supports (color:color-mix(in lab, red, red)){.bg-pink-500\/12{background-color:color-mix(in oklab, var(--color-pink-500) 12%, transparent)}}.bg-red-500{background-color:var(--color-red-500)}.bg-rose-400{background-color:var(--color-rose-400)}.bg-rose-500{background-color:var(--color-rose-500)}.bg-rose-500\/12{background-color:#ff23571f}@supports (color:color-mix(in lab, red, red)){.bg-rose-500\/12{background-color:color-mix(in oklab, var(--color-rose-500) 12%, transparent)}}.bg-rose-500\/15{background-color:#ff235726}@supports (color:color-mix(in lab, red, red)){.bg-rose-500\/15{background-color:color-mix(in oklab, var(--color-rose-500) 15%, transparent)}}.bg-rose-500\/\[0\.04\]{background-color:#ff23570a}@supports (color:color-mix(in lab, red, red)){.bg-rose-500\/\[0\.04\]{background-color:color-mix(in oklab, var(--color-rose-500) 4%, transparent)}}.bg-sky-500\/12{background-color:#00a5ef1f}@supports (color:color-mix(in lab, red, red)){.bg-sky-500\/12{background-color:color-mix(in oklab, var(--color-sky-500) 12%, transparent)}}.bg-surface{background-color:var(--color-surface)}.bg-surface-2,.bg-surface-2\/40{background-color:var(--color-surface-2)}@supports (color:color-mix(in lab, red, red)){.bg-surface-2\/40{background-color:color-mix(in oklab, var(--color-surface-2) 40%, transparent)}}.bg-surface-2\/55{background-color:var(--color-surface-2)}@supports (color:color-mix(in lab, red, red)){.bg-surface-2\/55{background-color:color-mix(in oklab, var(--color-surface-2) 55%, transparent)}}.bg-surface-2\/60{background-color:var(--color-surface-2)}@supports (color:color-mix(in lab, red, red)){.bg-surface-2\/60{background-color:color-mix(in oklab, var(--color-surface-2) 60%, transparent)}}.bg-surface-2\/70{background-color:var(--color-surface-2)}@supports (color:color-mix(in lab, red, red)){.bg-surface-2\/70{background-color:color-mix(in oklab, var(--color-surface-2) 70%, transparent)}}.bg-surface-2\/80{background-color:var(--color-surface-2)}@supports (color:color-mix(in lab, red, red)){.bg-surface-2\/80{background-color:color-mix(in oklab, var(--color-surface-2) 80%, transparent)}}.bg-surface\/40{background-color:var(--color-surface)}@supports (color:color-mix(in lab, red, red)){.bg-surface\/40{background-color:color-mix(in oklab, var(--color-surface) 40%, transparent)}}.bg-surface\/70{background-color:var(--color-surface)}@supports (color:color-mix(in lab, red, red)){.bg-surface\/70{background-color:color-mix(in oklab, var(--color-surface) 70%, transparent)}}.bg-surface\/90{background-color:var(--color-surface)}@supports (color:color-mix(in lab, red, red)){.bg-surface\/90{background-color:color-mix(in oklab, var(--color-surface) 90%, transparent)}}.bg-transparent{background-color:#0000}.bg-violet-500{background-color:var(--color-violet-500)}.bg-violet-500\/12{background-color:#8d54ff1f}@supports (color:color-mix(in lab, red, red)){.bg-violet-500\/12{background-color:color-mix(in oklab, var(--color-violet-500) 12%, transparent)}}.bg-white{background-color:var(--color-white)}.bg-white\/80{background-color:#fffc}@supports (color:color-mix(in lab, red, red)){.bg-white\/80{background-color:color-mix(in oklab, var(--color-white) 80%, transparent)}}.bg-gradient-to-b{--tw-gradient-position:to bottom in oklab;background-image:linear-gradient(var(--tw-gradient-stops))}.bg-gradient-to-br{--tw-gradient-position:to bottom right in oklab;background-image:linear-gradient(var(--tw-gradient-stops))}.bg-\[radial-gradient\(ellipse_at_top\,rgba\(0\,100\,212\,0\.14\)\,transparent_65\%\)\]{background-image:radial-gradient(at top,#0064d424,#0000 65%)}.from-\[\#7d6bc7\]{--tw-gradient-from:#7d6bc7;--tw-gradient-stops:var(--tw-gradient-via-stops,var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position))}.from-\[\#b0413e\]{--tw-gradient-from:#b0413e;--tw-gradient-stops:var(--tw-gradient-via-stops,var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position))}.from-accent{--tw-gradient-from:var(--color-accent);--tw-gradient-stops:var(--tw-gradient-via-stops,var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position))}.from-emerald-500{--tw-gradient-from:var(--color-emerald-500);--tw-gradient-stops:var(--tw-gradient-via-stops,var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position))}.from-orange-400{--tw-gradient-from:var(--color-orange-400);--tw-gradient-stops:var(--tw-gradient-via-stops,var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position))}.from-slate-400{--tw-gradient-from:var(--color-slate-400);--tw-gradient-stops:var(--tw-gradient-via-stops,var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position))}.from-slate-700{--tw-gradient-from:var(--color-slate-700);--tw-gradient-stops:var(--tw-gradient-via-stops,var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position))}.to-\[\#7a1f1f\]{--tw-gradient-to:#7a1f1f;--tw-gradient-stops:var(--tw-gradient-via-stops,var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position))}.to-\[\#574494\]{--tw-gradient-to:#574494;--tw-gradient-stops:var(--tw-gradient-via-stops,var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position))}.to-amber-600{--tw-gradient-to:var(--color-amber-600);--tw-gradient-stops:var(--tw-gradient-via-stops,var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position))}.to-sky-400{--tw-gradient-to:var(--color-sky-400);--tw-gradient-stops:var(--tw-gradient-via-stops,var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position))}.to-slate-600{--tw-gradient-to:var(--color-slate-600);--tw-gradient-stops:var(--tw-gradient-via-stops,var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position))}.to-slate-900{--tw-gradient-to:var(--color-slate-900);--tw-gradient-stops:var(--tw-gradient-via-stops,var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position))}.to-teal-700{--tw-gradient-to:var(--color-teal-700);--tw-gradient-stops:var(--tw-gradient-via-stops,var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position))}.object-contain{object-fit:contain}.object-cover{object-fit:cover}.object-top{object-position:top}.p-0\.5{padding:calc(var(--spacing) * .5)}.p-1{padding:var(--spacing)}.p-1\.5{padding:calc(var(--spacing) * 1.5)}.p-2{padding:calc(var(--spacing) * 2)}.p-2\.5{padding:calc(var(--spacing) * 2.5)}.p-3{padding:calc(var(--spacing) * 3)}.p-3\.5{padding:calc(var(--spacing) * 3.5)}.p-4{padding:calc(var(--spacing) * 4)}.p-5{padding:calc(var(--spacing) * 5)}.p-6{padding:calc(var(--spacing) * 6)}.p-8{padding:calc(var(--spacing) * 8)}.\!px-3\.5{padding-inline:calc(var(--spacing) * 3.5)!important}.px-0\.5{padding-inline:calc(var(--spacing) * .5)}.px-1{padding-inline:var(--spacing)}.px-1\.5{padding-inline:calc(var(--spacing) * 1.5)}.px-2{padding-inline:calc(var(--spacing) * 2)}.px-2\.5{padding-inline:calc(var(--spacing) * 2.5)}.px-3{padding-inline:calc(var(--spacing) * 3)}.px-3\.5{padding-inline:calc(var(--spacing) * 3.5)}.px-4{padding-inline:calc(var(--spacing) * 4)}.px-5{padding-inline:calc(var(--spacing) * 5)}.px-6{padding-inline:calc(var(--spacing) * 6)}.px-8{padding-inline:calc(var(--spacing) * 8)}.px-16{padding-inline:calc(var(--spacing) * 16)}.\!py-1\.5{padding-block:calc(var(--spacing) * 1.5)!important}.py-0\.5{padding-block:calc(var(--spacing) * .5)}.py-1{padding-block:var(--spacing)}.py-1\.5{padding-block:calc(var(--spacing) * 1.5)}.py-2{padding-block:calc(var(--spacing) * 2)}.py-2\.5{padding-block:calc(var(--spacing) * 2.5)}.py-3{padding-block:calc(var(--spacing) * 3)}.py-3\.5{padding-block:calc(var(--spacing) * 3.5)}.py-4{padding-block:calc(var(--spacing) * 4)}.py-6{padding-block:calc(var(--spacing) * 6)}.py-8{padding-block:calc(var(--spacing) * 8)}.py-10{padding-block:calc(var(--spacing) * 10)}.pt-0{padding-top:0}.pt-0\.5{padding-top:calc(var(--spacing) * .5)}.pt-1{padding-top:var(--spacing)}.pt-1\.5{padding-top:calc(var(--spacing) * 1.5)}.pt-2{padding-top:calc(var(--spacing) * 2)}.pt-2\.5{padding-top:calc(var(--spacing) * 2.5)}.pt-3{padding-top:calc(var(--spacing) * 3)}.pt-3\.5{padding-top:calc(var(--spacing) * 3.5)}.pt-4{padding-top:calc(var(--spacing) * 4)}.pt-5{padding-top:calc(var(--spacing) * 5)}.pt-6{padding-top:calc(var(--spacing) * 6)}.pt-9{padding-top:calc(var(--spacing) * 9)}.pt-10{padding-top:calc(var(--spacing) * 10)}.pt-14{padding-top:calc(var(--spacing) * 14)}.pt-\[3px\]{padding-top:3px}.pt-\[18px\]{padding-top:18px}.pt-\[22px\]{padding-top:22px}.pr-1{padding-right:var(--spacing)}.pr-2{padding-right:calc(var(--spacing) * 2)}.pr-2\.5{padding-right:calc(var(--spacing) * 2.5)}.pr-3{padding-right:calc(var(--spacing) * 3)}.pr-5{padding-right:calc(var(--spacing) * 5)}.pr-8{padding-right:calc(var(--spacing) * 8)}.pr-10{padding-right:calc(var(--spacing) * 10)}.pb-0\.5{padding-bottom:calc(var(--spacing) * .5)}.pb-1{padding-bottom:var(--spacing)}.pb-1\.5{padding-bottom:calc(var(--spacing) * 1.5)}.pb-2{padding-bottom:calc(var(--spacing) * 2)}.pb-2\.5{padding-bottom:calc(var(--spacing) * 2.5)}.pb-3{padding-bottom:calc(var(--spacing) * 3)}.pb-3\.5{padding-bottom:calc(var(--spacing) * 3.5)}.pb-4{padding-bottom:calc(var(--spacing) * 4)}.pb-5{padding-bottom:calc(var(--spacing) * 5)}.pb-6{padding-bottom:calc(var(--spacing) * 6)}.pb-7{padding-bottom:calc(var(--spacing) * 7)}.pb-8{padding-bottom:calc(var(--spacing) * 8)}.tabbar-room{padding-bottom:calc(74px + env(safe-area-inset-bottom))}.pl-3{padding-left:calc(var(--spacing) * 3)}.pl-3\.5{padding-left:calc(var(--spacing) * 3.5)}.pl-4{padding-left:calc(var(--spacing) * 4)}.pl-5{padding-left:calc(var(--spacing) * 5)}.pl-7{padding-left:calc(var(--spacing) * 7)}.pl-9{padding-left:calc(var(--spacing) * 9)}.pl-12{padding-left:calc(var(--spacing) * 12)}.pl-\[18px\]{padding-left:18px}.text-center{text-align:center}.text-left{text-align:left}.text-right{text-align:right}.align-middle{vertical-align:middle}.font-mono{font-family:var(--font-mono)}.font-sans{font-family:var(--font-sans)}.text-\[10\.5px\]{font-size:10.5px}.text-\[10px\]{font-size:10px}.text-\[11\.5px\]{font-size:11.5px}.text-\[11px\]{font-size:11px}.text-\[12\.5px\]{font-size:12.5px}.text-\[12px\]{font-size:12px}.text-\[13\.5px\]{font-size:13.5px}.text-\[13px\]{font-size:13px}.text-\[14\.5px\]{font-size:14.5px}.text-\[14px\]{font-size:14px}.text-\[15px\]{font-size:15px}.text-\[16px\]{font-size:16px}.text-\[17px\]{font-size:17px}.text-\[18px\]{font-size:18px}.text-\[20px\]{font-size:20px}.text-\[21px\]{font-size:21px}.text-\[22px\]{font-size:22px}.text-\[24px\]{font-size:24px}.text-\[26px\]{font-size:26px}.text-\[28px\]{font-size:28px}.text-\[30px\]{font-size:30px}.text-\[64px\]{font-size:64px}.leading-4{--tw-leading:calc(var(--spacing) * 4);line-height:calc(var(--spacing) * 4)}.leading-6{--tw-leading:calc(var(--spacing) * 6);line-height:calc(var(--spacing) * 6)}.leading-7{--tw-leading:calc(var(--spacing) * 7);line-height:calc(var(--spacing) * 7)}.leading-8{--tw-leading:calc(var(--spacing) * 8);line-height:calc(var(--spacing) * 8)}.leading-\[1\.4\]{--tw-leading:1.4;line-height:1.4}.leading-\[1\.5\]{--tw-leading:1.5;line-height:1.5}.leading-\[1\.45\]{--tw-leading:1.45;line-height:1.45}.leading-\[14px\]{--tw-leading:14px;line-height:14px}.leading-\[17px\]{--tw-leading:17px;line-height:17px}.leading-\[18px\]{--tw-leading:18px;line-height:18px}.leading-\[19px\]{--tw-leading:19px;line-height:19px}.leading-\[20px\]{--tw-leading:20px;line-height:20px}.leading-\[21px\]{--tw-leading:21px;line-height:21px}.leading-\[22px\]{--tw-leading:22px;line-height:22px}.leading-\[26px\]{--tw-leading:26px;line-height:26px}.leading-\[34px\]{--tw-leading:34px;line-height:34px}.leading-none{--tw-leading:1;line-height:1}.leading-relaxed{--tw-leading:var(--leading-relaxed);line-height:var(--leading-relaxed)}.leading-snug{--tw-leading:var(--leading-snug);line-height:var(--leading-snug)}.leading-tight{--tw-leading:var(--leading-tight);line-height:var(--leading-tight)}.font-bold{--tw-font-weight:var(--font-weight-bold);font-weight:var(--font-weight-bold)}.font-medium{--tw-font-weight:var(--font-weight-medium);font-weight:var(--font-weight-medium)}.font-normal{--tw-font-weight:var(--font-weight-normal);font-weight:var(--font-weight-normal)}.font-semibold{--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold)}.tracking-\[0\.2em\]{--tw-tracking:.2em;letter-spacing:.2em}.tracking-\[0\.3em\]{--tw-tracking:.3em;letter-spacing:.3em}.tracking-normal{--tw-tracking:var(--tracking-normal);letter-spacing:var(--tracking-normal)}.tracking-tight{--tw-tracking:var(--tracking-tight);letter-spacing:var(--tracking-tight)}.tracking-wide{--tw-tracking:var(--tracking-wide);letter-spacing:var(--tracking-wide)}.break-words{overflow-wrap:break-word}.break-all{word-break:break-all}.whitespace-nowrap{white-space:nowrap}.whitespace-pre-wrap{white-space:pre-wrap}.text-accent{color:var(--color-accent)}.text-accent-fg{color:var(--color-accent-fg)}.text-accent-soft-fg{color:var(--color-accent-soft-fg)}.text-accent\/80{color:var(--color-accent)}@supports (color:color-mix(in lab, red, red)){.text-accent\/80{color:color-mix(in oklab, var(--color-accent) 80%, transparent)}}.text-amber-500{color:var(--color-amber-500)}.text-amber-600{color:var(--color-amber-600)}.text-amber-700{color:var(--color-amber-700)}.text-amber-800{color:var(--color-amber-800)}.text-bg{color:var(--color-bg)}.text-bubble-user-fg{color:var(--color-bubble-user-fg)}.text-cyan-600{color:var(--color-cyan-600)}.text-emerald-500{color:var(--color-emerald-500)}.text-emerald-600{color:var(--color-emerald-600)}.text-emerald-700{color:var(--color-emerald-700)}.text-fg,.text-fg\/45{color:var(--color-fg)}@supports (color:color-mix(in lab, red, red)){.text-fg\/45{color:color-mix(in oklab, var(--color-fg) 45%, transparent)}}.text-fg\/60{color:var(--color-fg)}@supports (color:color-mix(in lab, red, red)){.text-fg\/60{color:color-mix(in oklab, var(--color-fg) 60%, transparent)}}.text-fg\/65{color:var(--color-fg)}@supports (color:color-mix(in lab, red, red)){.text-fg\/65{color:color-mix(in oklab, var(--color-fg) 65%, transparent)}}.text-fg\/70{color:var(--color-fg)}@supports (color:color-mix(in lab, red, red)){.text-fg\/70{color:color-mix(in oklab, var(--color-fg) 70%, transparent)}}.text-fg\/75{color:var(--color-fg)}@supports (color:color-mix(in lab, red, red)){.text-fg\/75{color:color-mix(in oklab, var(--color-fg) 75%, transparent)}}.text-fg\/80{color:var(--color-fg)}@supports (color:color-mix(in lab, red, red)){.text-fg\/80{color:color-mix(in oklab, var(--color-fg) 80%, transparent)}}.text-fg\/85{color:var(--color-fg)}@supports (color:color-mix(in lab, red, red)){.text-fg\/85{color:color-mix(in oklab, var(--color-fg) 85%, transparent)}}.text-fg\/90{color:var(--color-fg)}@supports (color:color-mix(in lab, red, red)){.text-fg\/90{color:color-mix(in oklab, var(--color-fg) 90%, transparent)}}.text-fuchsia-600{color:var(--color-fuchsia-600)}.text-muted,.text-muted\/70{color:var(--color-muted)}@supports (color:color-mix(in lab, red, red)){.text-muted\/70{color:color-mix(in oklab, var(--color-muted) 70%, transparent)}}.text-muted\/80{color:var(--color-muted)}@supports (color:color-mix(in lab, red, red)){.text-muted\/80{color:color-mix(in oklab, var(--color-muted) 80%, transparent)}}.text-orange-600{color:var(--color-orange-600)}.text-pink-600{color:var(--color-pink-600)}.text-red-600{color:var(--color-red-600)}.text-rose-500{color:var(--color-rose-500)}.text-rose-600{color:var(--color-rose-600)}.text-rose-700{color:var(--color-rose-700)}.text-sky-600{color:var(--color-sky-600)}.text-violet-600{color:var(--color-violet-600)}.text-white{color:var(--color-white)}.text-white\/85{color:#ffffffd9}@supports (color:color-mix(in lab, red, red)){.text-white\/85{color:color-mix(in oklab, var(--color-white) 85%, transparent)}}.text-white\/90{color:#ffffffe6}@supports (color:color-mix(in lab, red, red)){.text-white\/90{color:color-mix(in oklab, var(--color-white) 90%, transparent)}}.capitalize{text-transform:capitalize}.normal-case{text-transform:none}.uppercase{text-transform:uppercase}.ordinal{--tw-ordinal:ordinal;font-variant-numeric:var(--tw-ordinal,) var(--tw-slashed-zero,) var(--tw-numeric-figure,) var(--tw-numeric-spacing,) var(--tw-numeric-fraction,)}.tabular-nums{--tw-numeric-spacing:tabular-nums;font-variant-numeric:var(--tw-ordinal,) var(--tw-slashed-zero,) var(--tw-numeric-figure,) var(--tw-numeric-spacing,) var(--tw-numeric-fraction,)}.line-through{text-decoration-line:line-through}.underline{text-decoration-line:underline}.decoration-border{-webkit-text-decoration-color:var(--color-border);-webkit-text-decoration-color:var(--color-border);-webkit-text-decoration-color:var(--color-border);text-decoration-color:var(--color-border)}.decoration-dotted{text-decoration-style:dotted}.underline-offset-2{text-underline-offset:2px}.accent-\[var\(--om-accent\)\]{accent-color:var(--om-accent)}.accent-accent{accent-color:var(--color-accent)}.opacity-0{opacity:0}.opacity-45{opacity:.45}.opacity-50{opacity:.5}.opacity-60{opacity:.6}.opacity-70{opacity:.7}.opacity-80{opacity:.8}.opacity-90{opacity:.9}.shadow{--tw-shadow:0 1px 3px 0 var(--tw-shadow-color,#0000001a), 0 1px 2px -1px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.shadow-2xl{--tw-shadow:0 25px 50px -12px var(--tw-shadow-color,#00000040);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.shadow-\[0_1px_4px_rgba\(0\,0\,0\,0\.14\)\]{--tw-shadow:0 1px 4px var(--tw-shadow-color,#00000024);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.shadow-\[0_1px_4px_rgba\(0\,0\,0\,0\.16\)\]{--tw-shadow:0 1px 4px var(--tw-shadow-color,#00000029);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.shadow-\[0_1px_4px_rgba\(0\,0\,0\,0\.18\)\]{--tw-shadow:0 1px 4px var(--tw-shadow-color,#0000002e);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.shadow-\[0_2px_12px_-6px_rgba\(0\,0\,0\,0\.12\)\]{--tw-shadow:0 2px 12px -6px var(--tw-shadow-color,#0000001f);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.shadow-\[0_2px_12px_rgba\(0\,0\,0\,0\.12\)\]{--tw-shadow:0 2px 12px var(--tw-shadow-color,#0000001f);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.shadow-\[0_4px_20px_-12px_rgba\(0\,0\,0\,0\.2\)\]{--tw-shadow:0 4px 20px -12px var(--tw-shadow-color,#0003);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.shadow-\[0_12px_40px_-12px_rgba\(0\,0\,0\,0\.3\)\]{--tw-shadow:0 12px 40px -12px var(--tw-shadow-color,#0000004d);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.shadow-lg{--tw-shadow:0 10px 15px -3px var(--tw-shadow-color,#0000001a), 0 4px 6px -4px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.shadow-md{--tw-shadow:0 4px 6px -1px var(--tw-shadow-color,#0000001a), 0 2px 4px -2px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.shadow-sm{--tw-shadow:0 1px 3px 0 var(--tw-shadow-color,#0000001a), 0 1px 2px -1px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.shadow-xl{--tw-shadow:0 20px 25px -5px var(--tw-shadow-color,#0000001a), 0 8px 10px -6px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.ring,.ring-1{--tw-ring-shadow:var(--tw-ring-inset,) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.ring-2{--tw-ring-shadow:var(--tw-ring-inset,) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.ring-\[2\.5px\]{--tw-ring-shadow:var(--tw-ring-inset,) 0 0 0 calc(2.5px + var(--tw-ring-offset-width)) var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.ring-\[3px\]{--tw-ring-shadow:var(--tw-ring-inset,) 0 0 0 calc(3px + var(--tw-ring-offset-width)) var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.ring-accent,.ring-accent\/40{--tw-ring-color:var(--color-accent)}@supports (color:color-mix(in lab, red, red)){.ring-accent\/40{--tw-ring-color:color-mix(in oklab, var(--color-accent) 40%, transparent)}}.ring-border\/50{--tw-ring-color:var(--color-border)}@supports (color:color-mix(in lab, red, red)){.ring-border\/50{--tw-ring-color:color-mix(in oklab, var(--color-border) 50%, transparent)}}.ring-offset-2{--tw-ring-offset-width:2px;--tw-ring-offset-shadow:var(--tw-ring-inset,) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color)}.ring-offset-bg{--tw-ring-offset-color:var(--color-bg)}.blur-3xl{--tw-blur:blur(var(--blur-3xl));filter:var(--tw-blur,) var(--tw-brightness,) var(--tw-contrast,) var(--tw-grayscale,) var(--tw-hue-rotate,) var(--tw-invert,) var(--tw-saturate,) var(--tw-sepia,) var(--tw-drop-shadow,)}.drop-shadow-\[0_20px_40px_rgba\(0\,100\,212\,0\.28\)\]{--tw-drop-shadow-size:drop-shadow(0 20px 40px var(--tw-drop-shadow-color,#0064d447));--tw-drop-shadow:var(--tw-drop-shadow-size);filter:var(--tw-blur,) var(--tw-brightness,) var(--tw-contrast,) var(--tw-grayscale,) var(--tw-hue-rotate,) var(--tw-invert,) var(--tw-saturate,) var(--tw-sepia,) var(--tw-drop-shadow,)}.drop-shadow-sm{--tw-drop-shadow-size:drop-shadow(0 1px 2px var(--tw-drop-shadow-color,#00000026));--tw-drop-shadow:drop-shadow(var(--drop-shadow-sm));filter:var(--tw-blur,) var(--tw-brightness,) var(--tw-contrast,) var(--tw-grayscale,) var(--tw-hue-rotate,) var(--tw-invert,) var(--tw-saturate,) var(--tw-sepia,) var(--tw-drop-shadow,)}.filter{filter:var(--tw-blur,) var(--tw-brightness,) var(--tw-contrast,) var(--tw-grayscale,) var(--tw-hue-rotate,) var(--tw-invert,) var(--tw-saturate,) var(--tw-sepia,) var(--tw-drop-shadow,)}.backdrop-blur{--tw-backdrop-blur:blur(8px);-webkit-backdrop-filter:var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,);backdrop-filter:var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,)}.backdrop-blur-2xl{--tw-backdrop-blur:blur(var(--blur-2xl));-webkit-backdrop-filter:var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,);backdrop-filter:var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,)}.backdrop-blur-\[2px\]{--tw-backdrop-blur:blur(2px);-webkit-backdrop-filter:var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,);backdrop-filter:var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,)}.transition{transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to,opacity,box-shadow,transform,translate,scale,rotate,filter,-webkit-backdrop-filter,backdrop-filter,display,content-visibility,overlay,pointer-events;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-all{transition-property:all;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-colors{transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.duration-300{--tw-duration:.3s;transition-duration:.3s}.will-change-transform{will-change:transform}.outline-none{--tw-outline-style:none;outline-style:none}.select-all{-webkit-user-select:all;user-select:all}.select-none{-webkit-user-select:none;user-select:none}@media (hover:hover){.group-hover\:opacity-100:is(:where(.group):hover *){opacity:1}}.placeholder\:text-muted::placeholder{color:var(--color-muted)}.odd\:bg-surface:nth-child(odd){background-color:var(--color-surface)}.focus-within\:border-fg\/20:focus-within{border-color:var(--color-fg)}@supports (color:color-mix(in lab, red, red)){.focus-within\:border-fg\/20:focus-within{border-color:color-mix(in oklab, var(--color-fg) 20%, transparent)}}.focus-within\:ring-2:focus-within{--tw-ring-shadow:var(--tw-ring-inset,) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.focus-within\:ring-accent\/40:focus-within{--tw-ring-color:var(--color-accent)}@supports (color:color-mix(in lab, red, red)){.focus-within\:ring-accent\/40:focus-within{--tw-ring-color:color-mix(in oklab, var(--color-accent) 40%, transparent)}}@media (hover:hover){.hover\:scale-\[1\.04\]:hover{scale:1.04}.hover\:bg-accent\/15:hover{background-color:var(--color-accent)}@supports (color:color-mix(in lab, red, red)){.hover\:bg-accent\/15:hover{background-color:color-mix(in oklab, var(--color-accent) 15%, transparent)}}.hover\:bg-border\/60:hover{background-color:var(--color-border)}@supports (color:color-mix(in lab, red, red)){.hover\:bg-border\/60:hover{background-color:color-mix(in oklab, var(--color-border) 60%, transparent)}}.hover\:bg-rose-500\/10:hover{background-color:#ff23571a}@supports (color:color-mix(in lab, red, red)){.hover\:bg-rose-500\/10:hover{background-color:color-mix(in oklab, var(--color-rose-500) 10%, transparent)}}.hover\:bg-surface:hover{background-color:var(--color-surface)}.hover\:bg-surface-2:hover,.hover\:bg-surface-2\/60:hover{background-color:var(--color-surface-2)}@supports (color:color-mix(in lab, red, red)){.hover\:bg-surface-2\/60:hover{background-color:color-mix(in oklab, var(--color-surface-2) 60%, transparent)}}.hover\:bg-surface-2\/70:hover{background-color:var(--color-surface-2)}@supports (color:color-mix(in lab, red, red)){.hover\:bg-surface-2\/70:hover{background-color:color-mix(in oklab, var(--color-surface-2) 70%, transparent)}}.hover\:text-accent:hover{color:var(--color-accent)}.hover\:text-fg:hover{color:var(--color-fg)}.hover\:text-rose-500:hover{color:var(--color-rose-500)}.hover\:underline:hover{text-decoration-line:underline}.hover\:opacity-90:hover{opacity:.9}.hover\:opacity-100:hover{opacity:1}.hover\:ring-2:hover{--tw-ring-shadow:var(--tw-ring-inset,) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.hover\:ring-accent:hover,.hover\:ring-accent\/60:hover{--tw-ring-color:var(--color-accent)}@supports (color:color-mix(in lab, red, red)){.hover\:ring-accent\/60:hover{--tw-ring-color:color-mix(in oklab, var(--color-accent) 60%, transparent)}}}.focus\:border-accent:focus{border-color:var(--color-accent)}.focus\:bg-surface-2:focus{background-color:var(--color-surface-2)}.focus\:opacity-100:focus{opacity:1}.focus\:ring-2:focus{--tw-ring-shadow:var(--tw-ring-inset,) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.focus\:ring-accent\/40:focus{--tw-ring-color:var(--color-accent)}@supports (color:color-mix(in lab, red, red)){.focus\:ring-accent\/40:focus{--tw-ring-color:color-mix(in oklab, var(--color-accent) 40%, transparent)}}.focus\:outline-none:focus{--tw-outline-style:none;outline-style:none}.active\:scale-95:active{--tw-scale-x:95%;--tw-scale-y:95%;--tw-scale-z:95%;scale:var(--tw-scale-x) var(--tw-scale-y)}.active\:scale-\[0\.98\]:active{scale:.98}.active\:scale-\[0\.99\]:active{scale:.99}.active\:bg-surface-2:active,.active\:bg-surface-2\/70:active{background-color:var(--color-surface-2)}@supports (color:color-mix(in lab, red, red)){.active\:bg-surface-2\/70:active{background-color:color-mix(in oklab, var(--color-surface-2) 70%, transparent)}}.disabled\:opacity-40:disabled{opacity:.4}.disabled\:opacity-50:disabled{opacity:.5}.disabled\:opacity-60:disabled{opacity:.6}.disabled\:opacity-70:disabled{opacity:.7}@media (width>=40rem){.sm\:hidden{display:none}.sm\:max-w-lg{max-width:var(--container-lg)}.sm\:grid-cols-5{grid-template-columns:repeat(5,minmax(0,1fr))}.sm\:items-center{align-items:center}.sm\:justify-center{justify-content:center}.sm\:rounded-3xl{border-radius:var(--radius-3xl)}.sm\:rounded-\[28px\]{border-radius:28px}.sm\:border-x{border-inline-style:var(--tw-border-style);border-inline-width:1px}.sm\:border-border{border-color:var(--color-border)}}@container (width>=42rem){.\@2xl\:grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}}.dark\:border:where([data-theme=dark],[data-theme=dark] *){border-style:var(--tw-border-style);border-width:1px}.dark\:border-border:where([data-theme=dark],[data-theme=dark] *){border-color:var(--color-border)}.dark\:bg-accent\/\[0\.10\]:where([data-theme=dark],[data-theme=dark] *){background-color:var(--color-accent)}@supports (color:color-mix(in lab, red, red)){.dark\:bg-accent\/\[0\.10\]:where([data-theme=dark],[data-theme=dark] *){background-color:color-mix(in oklab, var(--color-accent) 10%, transparent)}}.dark\:bg-amber-400\/\[0\.08\]:where([data-theme=dark],[data-theme=dark] *){background-color:#fcbb0014}@supports (color:color-mix(in lab, red, red)){.dark\:bg-amber-400\/\[0\.08\]:where([data-theme=dark],[data-theme=dark] *){background-color:color-mix(in oklab, var(--color-amber-400) 8%, transparent)}}.dark\:bg-\[radial-gradient\(ellipse_at_top\,rgba\(23\,147\,255\,0\.2\)\,transparent_65\%\)\]:where([data-theme=dark],[data-theme=dark] *){background-image:radial-gradient(at top,#1793ff33,#0000 65%)}.dark\:text-amber-200:where([data-theme=dark],[data-theme=dark] *){color:var(--color-amber-200)}.dark\:text-amber-300:where([data-theme=dark],[data-theme=dark] *){color:var(--color-amber-300)}.dark\:text-cyan-300:where([data-theme=dark],[data-theme=dark] *){color:var(--color-cyan-300)}.dark\:text-emerald-300:where([data-theme=dark],[data-theme=dark] *){color:var(--color-emerald-300)}.dark\:text-emerald-400:where([data-theme=dark],[data-theme=dark] *){color:var(--color-emerald-400)}.dark\:text-fuchsia-300:where([data-theme=dark],[data-theme=dark] *){color:var(--color-fuchsia-300)}.dark\:text-orange-300:where([data-theme=dark],[data-theme=dark] *){color:var(--color-orange-300)}.dark\:text-pink-300:where([data-theme=dark],[data-theme=dark] *){color:var(--color-pink-300)}.dark\:text-red-400:where([data-theme=dark],[data-theme=dark] *){color:var(--color-red-400)}.dark\:text-rose-300:where([data-theme=dark],[data-theme=dark] *){color:var(--color-rose-300)}.dark\:text-rose-400:where([data-theme=dark],[data-theme=dark] *){color:var(--color-rose-400)}.dark\:text-sky-300:where([data-theme=dark],[data-theme=dark] *){color:var(--color-sky-300)}.dark\:text-violet-300:where([data-theme=dark],[data-theme=dark] *){color:var(--color-violet-300)}.dark\:shadow-none:where([data-theme=dark],[data-theme=dark] *){--tw-shadow:0 0 #0000;box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}@media (width>=64rem){.wide\:invisible{visibility:hidden}}:where(html.desktop) .wide\:invisible{visibility:hidden}@media (width>=64rem){.wide\:inset-y-0{inset-block:0}}:where(html.desktop) .wide\:inset-y-0{inset-block:0}@media (width>=64rem){.wide\:mt-0{margin-top:0}}:where(html.desktop) .wide\:mt-0{margin-top:0}@media (width>=64rem){.wide\:mt-5{margin-top:calc(var(--spacing) * 5)}}:where(html.desktop) .wide\:mt-5{margin-top:calc(var(--spacing) * 5)}@media (width>=64rem){.wide\:block{display:block}}:where(html.desktop) .wide\:block{display:block}@media (width>=64rem){.wide\:flex{display:flex}}:where(html.desktop) .wide\:flex{display:flex}@media (width>=64rem){.wide\:grid{display:grid}}:where(html.desktop) .wide\:grid{display:grid}@media (width>=64rem){.wide\:hidden{display:none}}:where(html.desktop) .wide\:hidden{display:none}@media (width>=64rem){.wide\:h-auto{height:auto}}:where(html.desktop) .wide\:h-auto{height:auto}@media (width>=64rem){.wide\:h-full{height:100%}}:where(html.desktop) .wide\:h-full{height:100%}@media (width>=64rem){.wide\:max-w-\[600px\]{max-width:600px}}:where(html.desktop) .wide\:max-w-\[600px\]{max-width:600px}@media (width>=64rem){.wide\:max-w-\[900px\]{max-width:900px}}:where(html.desktop) .wide\:max-w-\[900px\]{max-width:900px}@media (width>=64rem){.wide\:max-w-\[980px\]{max-width:980px}}:where(html.desktop) .wide\:max-w-\[980px\]{max-width:980px}@media (width>=64rem){.wide\:max-w-md{max-width:var(--container-md)}}:where(html.desktop) .wide\:max-w-md{max-width:var(--container-md)}@media (width>=64rem){.wide\:max-w-none{max-width:none}}:where(html.desktop) .wide\:max-w-none{max-width:none}@media (width>=64rem){.wide\:grid-cols-1{grid-template-columns:repeat(1,minmax(0,1fr))}}:where(html.desktop) .wide\:grid-cols-1{grid-template-columns:repeat(1,minmax(0,1fr))}@media (width>=64rem){.wide\:grid-cols-4{grid-template-columns:repeat(4,minmax(0,1fr))}}:where(html.desktop) .wide\:grid-cols-4{grid-template-columns:repeat(4,minmax(0,1fr))}@media (width>=64rem){.wide\:grid-cols-\[1\.1fr_1fr\]{grid-template-columns:1.1fr 1fr}}:where(html.desktop) .wide\:grid-cols-\[1\.1fr_1fr\]{grid-template-columns:1.1fr 1fr}@media (width>=64rem){.wide\:flex-row{flex-direction:row}}:where(html.desktop) .wide\:flex-row{flex-direction:row}@media (width>=64rem){.wide\:items-center{align-items:center}}:where(html.desktop) .wide\:items-center{align-items:center}@media (width>=64rem){.wide\:items-start{align-items:flex-start}}:where(html.desktop) .wide\:items-start{align-items:flex-start}@media (width>=64rem){.wide\:gap-1\.5{gap:calc(var(--spacing) * 1.5)}}:where(html.desktop) .wide\:gap-1\.5{gap:calc(var(--spacing) * 1.5)}@media (width>=64rem){.wide\:gap-16{gap:calc(var(--spacing) * 16)}}:where(html.desktop) .wide\:gap-16{gap:calc(var(--spacing) * 16)}@media (width>=64rem){.wide\:border-0{border-style:var(--tw-border-style);border-width:0}}:where(html.desktop) .wide\:border-0{border-style:var(--tw-border-style);border-width:0}@media (width>=64rem){.wide\:border-x-0{border-inline-style:var(--tw-border-style);border-inline-width:0}}:where(html.desktop) .wide\:border-x-0{border-inline-style:var(--tw-border-style);border-inline-width:0}@media (width>=64rem){.wide\:bg-transparent{background-color:#0000}}:where(html.desktop) .wide\:bg-transparent{background-color:#0000}@media (width>=64rem){.wide\:bg-\[radial-gradient\(ellipse_at_left\,rgba\(0\,100\,212\,0\.12\)\,transparent_60\%\)\]{background-image:radial-gradient(at 0,#0064d41f,#0000 60%)}}:where(html.desktop) .wide\:bg-\[radial-gradient\(ellipse_at_left\,rgba\(0\,100\,212\,0\.12\)\,transparent_60\%\)\]{background-image:radial-gradient(at 0,#0064d41f,#0000 60%)}@media (width>=64rem){.wide\:p-7{padding:calc(var(--spacing) * 7)}}:where(html.desktop) .wide\:p-7{padding:calc(var(--spacing) * 7)}@media (width>=64rem){.wide\:px-0{padding-inline:0}}:where(html.desktop) .wide\:px-0{padding-inline:0}@media (width>=64rem){.wide\:px-12{padding-inline:calc(var(--spacing) * 12)}}:where(html.desktop) .wide\:px-12{padding-inline:calc(var(--spacing) * 12)}@media (width>=64rem){.wide\:py-1{padding-block:var(--spacing)}}:where(html.desktop) .wide\:py-1{padding-block:var(--spacing)}@media (width>=64rem){.wide\:pt-0{padding-top:0}}:where(html.desktop) .wide\:pt-0{padding-top:0}@media (width>=64rem){.wide\:pb-0{padding-bottom:0}}:where(html.desktop) .wide\:pb-0{padding-bottom:0}@media (width>=64rem){.wide\:text-left{text-align:left}}:where(html.desktop) .wide\:text-left{text-align:left}@media (width>=64rem){.wide\:text-\[13\.5px\]{font-size:13.5px}}:where(html.desktop) .wide\:text-\[13\.5px\]{font-size:13.5px}@media (width>=64rem){.wide\:text-\[15\.5px\]{font-size:15.5px}}:where(html.desktop) .wide\:text-\[15\.5px\]{font-size:15.5px}@media (width>=64rem){.wide\:text-\[34px\]{font-size:34px}}:where(html.desktop) .wide\:text-\[34px\]{font-size:34px}@media (width>=64rem){.wide\:dark\:bg-\[radial-gradient\(ellipse_at_left\,rgba\(23\,147\,255\,0\.16\)\,transparent_60\%\)\]:where([data-theme=dark],[data-theme=dark] *){background-image:radial-gradient(at 0,#1793ff29,#0000 60%)}}:where(html.desktop) .wide\:dark\:bg-\[radial-gradient\(ellipse_at_left\,rgba\(23\,147\,255\,0\.16\)\,transparent_60\%\)\]:where([data-theme=dark],[data-theme=dark] *){background-image:radial-gradient(at 0,#1793ff29,#0000 60%)}.\[\&\+\&\]\:mt-1\.5+.\[\&\+\&\]\:mt-1\.5{margin-top:calc(var(--spacing) * 1.5)}}@font-face{font-family:Figtree;font-style:normal;font-weight:300 900;font-display:swap;src:url(/fonts/figtree-latin.woff2)format("woff2");unicode-range:U+??,U+131,U+152-153,U+2BB-2BC,U+2C6,U+2DA,U+2DC,U+304,U+308,U+329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}@font-face{font-family:Figtree;font-style:normal;font-weight:300 900;font-display:swap;src:url(/fonts/figtree-latin-ext.woff2)format("woff2");unicode-range:U+100-2BA,U+2BD-2C5,U+2C7-2CC,U+2CE-2D7,U+2DD-2FF,U+304,U+308,U+329,U+1D00-1DBF,U+1E00-1E9F,U+1EF2-1EFF,U+2020,U+20A0-20AB,U+20AD-20C0,U+2113,U+2C60-2C7F,U+A720-A7FF}:root{--om-bg:#fcfcfc;--om-surface:#fff;--om-surface-2:#f2f2f4;--om-border:#e7e7ea;--om-fg:#111112;--om-muted:#6b6b71;--om-accent:#0064d4;--om-accent-soft:#e5f0ff;--om-accent-soft-fg:#012f80;--om-bubble-user:#d8e9ff;--om-bubble-user-fg:#111112;--lightningcss-light:initial;--lightningcss-dark: ;color-scheme:light}html[data-theme=dark]{--om-bg:#181819;--om-surface:#202022;--om-surface-2:#2a2a2d;--om-border:#333337;--om-fg:#fff;--om-muted:#9d9da4;--om-accent:#1793ff;--om-accent-soft:#1a2b4a;--om-accent-soft-fg:#e5f0ff;--om-bubble-user:#1c3d66;--om-bubble-user-fg:#fff;--lightningcss-light: ;--lightningcss-dark:initial;color-scheme:dark}html,body,#root{height:100%}body{background:var(--om-bg);color:var(--om-fg);font-family:var(--font-sans);-webkit-font-smoothing:antialiased;-webkit-tap-highlight-color:transparent;overscroll-behavior-y:none;margin:0}.safe-top{padding-top:env(safe-area-inset-top)}.titlebar-room{display:none}html.desktop[data-platform=darwin] .titlebar-room{-webkit-app-region:drag;flex-shrink:0;height:28px;display:block}.safe-bottom{padding-bottom:env(safe-area-inset-bottom)}*{scrollbar-width:thin;scrollbar-color:var(--om-border) transparent}::-webkit-scrollbar{width:6px;height:6px}::-webkit-scrollbar-thumb{background:var(--om-border);border-radius:999px}::-webkit-scrollbar-track{background:0 0}@media (pointer:coarse),(width<=480px){*{scrollbar-width:none}::-webkit-scrollbar{display:none}}.no-scrollbar::-webkit-scrollbar{display:none}.no-scrollbar{scrollbar-width:none}.md>:first-child{margin-top:0}.md>:last-child{margin-bottom:0}.md p{margin:.35em 0}.md ul,.md ol{margin:.35em 0;padding-left:1.3em}.md ul{list-style:outside}.md ol{list-style:decimal}.md li{margin:.15em 0}.md h1,.md h2,.md h3,.md h4{margin:.7em 0 .3em;font-weight:650;line-height:1.3}.md h1{font-size:1.15em}.md h2{font-size:1.08em}.md h3,.md h4{font-size:1em}.md a{color:var(--om-accent);text-underline-offset:2px;word-break:break-all;text-decoration:underline}.bubble-user .md a{color:var(--om-accent)}.md code{background:#7f7fa029;border-radius:6px;padding:.1em .35em;font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;font-size:.86em}.md pre{color:#eaeaf5;background:#0f0f19e6;border-radius:12px;margin:.5em 0;padding:.7em .85em;font-size:.82em;line-height:1.45;overflow-x:auto}.md pre code{font-size:inherit;background:0 0;padding:0}.md .md-file{color:var(--om-accent);background:var(--om-accent);font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;font-size:.86em}@supports (color:color-mix(in lab, red, red)){.md .md-file{background:color-mix(in srgb, var(--om-accent) 12%, transparent)}}.md .md-file{text-underline-offset:2px;word-break:break-all;border-radius:6px;padding:.1em .4em;-webkit-text-decoration:underline dotted;text-decoration:underline dotted}.md blockquote{border-left:3px solid var(--om-border);color:var(--om-muted);margin:.5em 0;padding-left:.8em}.md table{border-collapse:collapse;max-width:100%;margin:.5em 0;font-size:.9em;display:block;overflow-x:auto}.md th,.md td{border:1px solid var(--om-border);text-align:left;padding:.3em .55em}.md hr{border:0;border-top:1px solid var(--om-border);margin:.7em 0}.md img{border-radius:10px;max-width:100%}@keyframes om-breathe{0%,to{transform:translateY(0)scale(1)}50%{transform:translateY(-1.5%)scale(1.025)}}@keyframes om-sway{0%,to{transform:rotate(-4deg)translateY(0)}25%{transform:rotate(0)translateY(-2%)}50%{transform:rotate(4deg)translateY(0)}75%{transform:rotate(0)translateY(-2%)}}@keyframes om-hop{0%,70%,to{transform:translateY(0)scale(1)}78%{transform:translateY(-9%)scale(1.04,.97)}86%{transform:translateY(0)scale(.98,1.03)}92%{transform:translateY(-3%)scale(1)}}@keyframes om-wiggle{0%,to{transform:rotate(0)}20%{transform:rotate(-10deg)scale(1.06)}45%{transform:rotate(9deg)scale(1.06)}70%{transform:rotate(-5deg)}}.avatar-idle{animation:4.5s ease-in-out infinite om-breathe}.avatar-working{animation:2.6s ease-in-out infinite om-sway}.avatar-waiting{animation:3.2s ease-in-out infinite om-hop}.avatar-wiggle{animation:.6s ease-in-out om-wiggle}@keyframes om-pop{0%{transform:scale(.6)}70%{transform:scale(1.06)}to{transform:scale(1)}}.avatar-pop{animation:.55s cubic-bezier(.34,1.56,.64,1) om-pop}@media (prefers-reduced-motion:reduce){.avatar-idle,.avatar-working,.avatar-waiting,.avatar-wiggle,.avatar-pop{animation:none}}@keyframes om-blink{50%{opacity:.25}}.typing-dot{animation:1.1s infinite om-blink}.typing-dot:nth-child(2){animation-delay:.18s}.typing-dot:nth-child(3){animation-delay:.36s}@keyframes om-rise{0%{opacity:0;transform:translateY(6px)}to{opacity:1;transform:none}}.rise{animation:.18s ease-out om-rise}@keyframes om-sheet{0%{transform:translateY(100%)}to{transform:none}}.sheet-in{animation:.22s cubic-bezier(.2,.8,.2,1) om-sheet}@keyframes om-drawer-in{0%{transform:translate(-100%)}to{transform:none}}.drawer-in{animation:.2s ease-out om-drawer-in}@property --tw-border-spacing-x{syntax:"";inherits:false;initial-value:0}@property --tw-border-spacing-y{syntax:"";inherits:false;initial-value:0}@property --tw-translate-x{syntax:"*";inherits:false;initial-value:0}@property --tw-translate-y{syntax:"*";inherits:false;initial-value:0}@property --tw-translate-z{syntax:"*";inherits:false;initial-value:0}@property --tw-space-y-reverse{syntax:"*";inherits:false;initial-value:0}@property --tw-divide-y-reverse{syntax:"*";inherits:false;initial-value:0}@property --tw-border-style{syntax:"*";inherits:false;initial-value:solid}@property --tw-gradient-position{syntax:"*";inherits:false}@property --tw-gradient-from{syntax:"";inherits:false;initial-value:#0000}@property --tw-gradient-via{syntax:"";inherits:false;initial-value:#0000}@property --tw-gradient-to{syntax:"";inherits:false;initial-value:#0000}@property --tw-gradient-stops{syntax:"*";inherits:false}@property --tw-gradient-via-stops{syntax:"*";inherits:false}@property --tw-gradient-from-position{syntax:"";inherits:false;initial-value:0%}@property --tw-gradient-via-position{syntax:"";inherits:false;initial-value:50%}@property --tw-gradient-to-position{syntax:"";inherits:false;initial-value:100%}@property --tw-leading{syntax:"*";inherits:false}@property --tw-font-weight{syntax:"*";inherits:false}@property --tw-tracking{syntax:"*";inherits:false}@property --tw-ordinal{syntax:"*";inherits:false}@property --tw-slashed-zero{syntax:"*";inherits:false}@property --tw-numeric-figure{syntax:"*";inherits:false}@property --tw-numeric-spacing{syntax:"*";inherits:false}@property --tw-numeric-fraction{syntax:"*";inherits:false}@property --tw-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-shadow-color{syntax:"*";inherits:false}@property --tw-shadow-alpha{syntax:"";inherits:false;initial-value:100%}@property --tw-inset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-shadow-color{syntax:"*";inherits:false}@property --tw-inset-shadow-alpha{syntax:"";inherits:false;initial-value:100%}@property --tw-ring-color{syntax:"*";inherits:false}@property --tw-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-ring-color{syntax:"*";inherits:false}@property --tw-inset-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-ring-inset{syntax:"*";inherits:false}@property --tw-ring-offset-width{syntax:"";inherits:false;initial-value:0}@property --tw-ring-offset-color{syntax:"*";inherits:false;initial-value:#fff}@property --tw-ring-offset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-blur{syntax:"*";inherits:false}@property --tw-brightness{syntax:"*";inherits:false}@property --tw-contrast{syntax:"*";inherits:false}@property --tw-grayscale{syntax:"*";inherits:false}@property --tw-hue-rotate{syntax:"*";inherits:false}@property --tw-invert{syntax:"*";inherits:false}@property --tw-opacity{syntax:"*";inherits:false}@property --tw-saturate{syntax:"*";inherits:false}@property --tw-sepia{syntax:"*";inherits:false}@property --tw-drop-shadow{syntax:"*";inherits:false}@property --tw-drop-shadow-color{syntax:"*";inherits:false}@property --tw-drop-shadow-alpha{syntax:"";inherits:false;initial-value:100%}@property --tw-drop-shadow-size{syntax:"*";inherits:false}@property --tw-backdrop-blur{syntax:"*";inherits:false}@property --tw-backdrop-brightness{syntax:"*";inherits:false}@property --tw-backdrop-contrast{syntax:"*";inherits:false}@property --tw-backdrop-grayscale{syntax:"*";inherits:false}@property --tw-backdrop-hue-rotate{syntax:"*";inherits:false}@property --tw-backdrop-invert{syntax:"*";inherits:false}@property --tw-backdrop-opacity{syntax:"*";inherits:false}@property --tw-backdrop-saturate{syntax:"*";inherits:false}@property --tw-backdrop-sepia{syntax:"*";inherits:false}@property --tw-duration{syntax:"*";inherits:false}@property --tw-scale-x{syntax:"*";inherits:false;initial-value:1}@property --tw-scale-y{syntax:"*";inherits:false;initial-value:1}@property --tw-scale-z{syntax:"*";inherits:false;initial-value:1}@keyframes spin{to{transform:rotate(360deg)}}@keyframes pulse{50%{opacity:.5}} diff --git a/nanomuse/server/static/assets/index-D-ZnIXbP.css b/nanomuse/server/static/assets/index-D-ZnIXbP.css deleted file mode 100644 index 12015268c..000000000 --- a/nanomuse/server/static/assets/index-D-ZnIXbP.css +++ /dev/null @@ -1,2 +0,0 @@ -/*! tailwindcss v4.3.3 | MIT License | https://tailwindcss.com */ -@layer properties{@supports (((-webkit-hyphens:none)) and (not (margin-trim:inline))) or ((-moz-orient:inline) and (not (color:rgb(from red r g b)))){*,:before,:after,::backdrop{--tw-border-spacing-x:0;--tw-border-spacing-y:0;--tw-translate-x:0;--tw-translate-y:0;--tw-translate-z:0;--tw-space-y-reverse:0;--tw-divide-y-reverse:0;--tw-border-style:solid;--tw-gradient-position:initial;--tw-gradient-from:#0000;--tw-gradient-via:#0000;--tw-gradient-to:#0000;--tw-gradient-stops:initial;--tw-gradient-via-stops:initial;--tw-gradient-from-position:0%;--tw-gradient-via-position:50%;--tw-gradient-to-position:100%;--tw-leading:initial;--tw-font-weight:initial;--tw-tracking:initial;--tw-ordinal:initial;--tw-slashed-zero:initial;--tw-numeric-figure:initial;--tw-numeric-spacing:initial;--tw-numeric-fraction:initial;--tw-shadow:0 0 #0000;--tw-shadow-color:initial;--tw-shadow-alpha:100%;--tw-inset-shadow:0 0 #0000;--tw-inset-shadow-color:initial;--tw-inset-shadow-alpha:100%;--tw-ring-color:initial;--tw-ring-shadow:0 0 #0000;--tw-inset-ring-color:initial;--tw-inset-ring-shadow:0 0 #0000;--tw-ring-inset:initial;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-offset-shadow:0 0 #0000;--tw-blur:initial;--tw-brightness:initial;--tw-contrast:initial;--tw-grayscale:initial;--tw-hue-rotate:initial;--tw-invert:initial;--tw-opacity:initial;--tw-saturate:initial;--tw-sepia:initial;--tw-drop-shadow:initial;--tw-drop-shadow-color:initial;--tw-drop-shadow-alpha:100%;--tw-drop-shadow-size:initial;--tw-backdrop-blur:initial;--tw-backdrop-brightness:initial;--tw-backdrop-contrast:initial;--tw-backdrop-grayscale:initial;--tw-backdrop-hue-rotate:initial;--tw-backdrop-invert:initial;--tw-backdrop-opacity:initial;--tw-backdrop-saturate:initial;--tw-backdrop-sepia:initial;--tw-scale-x:1;--tw-scale-y:1;--tw-scale-z:1}}}@layer theme{:root,:host{--font-sans:"Figtree", ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", "Noto Sans CJK SC", sans-serif;--font-mono:ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;--color-red-400:oklch(70.4% .191 22.216);--color-red-500:oklch(63.7% .237 25.331);--color-red-600:oklch(57.7% .245 27.325);--color-orange-300:oklch(83.7% .128 66.29);--color-orange-400:oklch(75% .183 55.934);--color-orange-500:oklch(70.5% .213 47.604);--color-orange-600:oklch(64.6% .222 41.116);--color-amber-50:oklch(98.7% .022 95.277);--color-amber-200:oklch(92.4% .12 95.746);--color-amber-300:oklch(87.9% .169 91.605);--color-amber-400:oklch(82.8% .189 84.429);--color-amber-500:oklch(76.9% .188 70.08);--color-amber-600:oklch(66.6% .179 58.318);--color-amber-700:oklch(55.5% .163 48.998);--color-amber-800:oklch(47.3% .137 46.201);--color-emerald-300:oklch(84.5% .143 164.978);--color-emerald-400:oklch(76.5% .177 163.223);--color-emerald-500:oklch(69.6% .17 162.48);--color-emerald-600:oklch(59.6% .145 163.225);--color-emerald-700:oklch(50.8% .118 165.612);--color-teal-700:oklch(51.1% .096 186.391);--color-cyan-300:oklch(86.5% .127 207.078);--color-cyan-500:oklch(71.5% .143 215.221);--color-cyan-600:oklch(60.9% .126 221.723);--color-sky-300:oklch(82.8% .111 230.318);--color-sky-400:oklch(74.6% .16 232.661);--color-sky-500:oklch(68.5% .169 237.323);--color-sky-600:oklch(58.8% .158 241.966);--color-violet-300:oklch(81.1% .111 293.571);--color-violet-500:oklch(60.6% .25 292.717);--color-violet-600:oklch(54.1% .281 293.009);--color-fuchsia-300:oklch(83.3% .145 321.434);--color-fuchsia-500:oklch(66.7% .295 322.15);--color-fuchsia-600:oklch(59.1% .293 322.896);--color-pink-300:oklch(82.3% .12 346.018);--color-pink-500:oklch(65.6% .241 354.308);--color-pink-600:oklch(59.2% .249 .584);--color-rose-300:oklch(81% .117 11.638);--color-rose-400:oklch(71.2% .194 13.428);--color-rose-500:oklch(64.5% .246 16.439);--color-rose-600:oklch(58.6% .253 17.585);--color-rose-700:oklch(51.4% .222 16.935);--color-slate-400:oklch(70.4% .04 256.788);--color-slate-600:oklch(44.6% .043 257.281);--color-slate-700:oklch(37.2% .044 257.287);--color-slate-900:oklch(20.8% .042 265.755);--color-black:#000;--color-white:#fff;--spacing:.25rem;--container-sm:24rem;--container-md:28rem;--container-lg:32rem;--font-weight-normal:400;--font-weight-medium:500;--font-weight-semibold:600;--font-weight-bold:700;--tracking-tight:-.025em;--tracking-normal:0em;--tracking-wide:.025em;--leading-tight:1.25;--leading-snug:1.375;--leading-relaxed:1.625;--radius-sm:.25rem;--radius-md:.375rem;--radius-lg:.5rem;--radius-xl:.75rem;--radius-2xl:1rem;--radius-3xl:1.5rem;--drop-shadow-sm:0 1px 2px #00000026;--animate-spin:spin 1s linear infinite;--animate-pulse:pulse 2s cubic-bezier(.4, 0, .6, 1) infinite;--blur-3xl:64px;--default-transition-duration:.15s;--default-transition-timing-function:cubic-bezier(.4, 0, .2, 1);--default-font-family:var(--font-sans);--default-mono-font-family:var(--font-mono);--color-bg:var(--om-bg);--color-surface:var(--om-surface);--color-surface-2:var(--om-surface-2);--color-border:var(--om-border);--color-fg:var(--om-fg);--color-muted:var(--om-muted);--color-accent:var(--om-accent);--color-accent-fg:#fff;--color-bubble-user:var(--om-bubble-user);--color-bubble-user-fg:var(--om-bubble-user-fg)}}@layer base{*,:after,:before,::backdrop{box-sizing:border-box;border:0 solid;margin:0;padding:0}::file-selector-button{box-sizing:border-box;border:0 solid;margin:0;padding:0}html,:host{-webkit-text-size-adjust:100%;tab-size:4;line-height:1.5;font-family:var(--default-font-family,-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", "Noto Sans", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji");font-feature-settings:var(--default-font-feature-settings,normal);font-variation-settings:var(--default-font-variation-settings,normal);-webkit-tap-highlight-color:transparent}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,samp,pre{font-family:var(--default-mono-font-family,ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace);font-feature-settings:var(--default-mono-font-feature-settings,normal);font-variation-settings:var(--default-mono-font-variation-settings,normal);font-size:1em}small{font-size:80%}sub,sup{vertical-align:baseline;font-size:75%;line-height:0;position:relative}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}:-moz-focusring:where(:not(iframe)){outline:auto}progress{vertical-align:baseline}summary{display:list-item}ol,ul,menu{list-style:none}img,svg,video,canvas,audio,iframe,embed,object{vertical-align:middle;display:block}img,video{max-width:100%;height:auto}button,input,select,optgroup,textarea{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}::file-selector-button{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}:where(select:is([multiple],[size])) optgroup{font-weight:bolder}:where(select:is([multiple],[size])) optgroup option{padding-inline-start:20px}::file-selector-button{margin-inline-end:4px}::placeholder{opacity:1}@supports (not ((-webkit-appearance:-apple-pay-button))) or (contain-intrinsic-size:1px){::placeholder{color:currentColor}@supports (color:color-mix(in lab, red, red)){::placeholder{color:color-mix(in oklab, currentcolor 50%, transparent)}}}textarea{resize:vertical}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-date-and-time-value{min-height:1lh;text-align:inherit}::-webkit-datetime-edit{display:inline-flex}::-webkit-datetime-edit-fields-wrapper{padding:0}::-webkit-datetime-edit{padding-block:0}::-webkit-datetime-edit-year-field{padding-block:0}::-webkit-datetime-edit-month-field{padding-block:0}::-webkit-datetime-edit-day-field{padding-block:0}::-webkit-datetime-edit-hour-field{padding-block:0}::-webkit-datetime-edit-minute-field{padding-block:0}::-webkit-datetime-edit-second-field{padding-block:0}::-webkit-datetime-edit-millisecond-field{padding-block:0}::-webkit-datetime-edit-meridiem-field{padding-block:0}::-webkit-calendar-picker-indicator{line-height:1}:-moz-ui-invalid{box-shadow:none}button,input:where([type=button],[type=reset],[type=submit]){appearance:button}::file-selector-button{appearance:button}::-webkit-inner-spin-button{height:auto}::-webkit-outer-spin-button{height:auto}[hidden]:where(:not([hidden=until-found])){display:none!important}}@layer components;@layer utilities{.\@container{container-type:inline-size}.pointer-events-none{pointer-events:none}.visible{visibility:visible}.sr-only{clip-path:inset(50%);white-space:nowrap;border-width:0;width:1px;height:1px;margin:-1px;padding:0;position:absolute;overflow:hidden}.absolute{position:absolute}.fixed{position:fixed}.relative{position:relative}.static{position:static}.sticky{position:sticky}.inset-0{inset:0}.inset-x-0{inset-inline:0}.inset-y-0{inset-block:0}.-top-1{top:calc(var(--spacing) * -1)}.-top-1\.5{top:calc(var(--spacing) * -1.5)}.-top-20{top:calc(var(--spacing) * -20)}.top-0{top:0}.top-0\.5{top:calc(var(--spacing) * .5)}.top-1{top:var(--spacing)}.top-1\.5{top:calc(var(--spacing) * 1.5)}.top-1\/2{top:50%}.top-2{top:calc(var(--spacing) * 2)}.top-2\.5{top:calc(var(--spacing) * 2.5)}.top-9{top:calc(var(--spacing) * 9)}.top-12{top:calc(var(--spacing) * 12)}.top-\[3px\]{top:3px}.top-full{top:100%}.-right-0\.5{right:calc(var(--spacing) * -.5)}.-right-1{right:calc(var(--spacing) * -1)}.-right-1\.5{right:calc(var(--spacing) * -1.5)}.-right-16{right:calc(var(--spacing) * -16)}.right-0{right:0}.right-1{right:var(--spacing)}.right-1\.5{right:calc(var(--spacing) * 1.5)}.right-2{right:calc(var(--spacing) * 2)}.right-3{right:calc(var(--spacing) * 3)}.right-4{right:calc(var(--spacing) * 4)}.right-\[3px\]{right:3px}.-bottom-0\.5{bottom:calc(var(--spacing) * -.5)}.bottom-0{bottom:0}.bottom-1{bottom:var(--spacing)}.bottom-2{bottom:calc(var(--spacing) * 2)}.bottom-24{bottom:calc(var(--spacing) * 24)}.left-0{left:0}.left-0\.5{left:calc(var(--spacing) * .5)}.left-1\.5{left:calc(var(--spacing) * 1.5)}.left-1\/2{left:50%}.left-2\.5{left:calc(var(--spacing) * 2.5)}.left-3{left:calc(var(--spacing) * 3)}.left-4{left:calc(var(--spacing) * 4)}.left-\[18px\]{left:18px}.left-\[22px\]{left:22px}.left-\[26px\]{left:26px}.left-\[68px\]{left:68px}.z-10{z-index:10}.z-20{z-index:20}.z-30{z-index:30}.z-50{z-index:50}.z-\[60\]{z-index:60}.z-\[70\]{z-index:70}.container{width:100%}@media (width>=40rem){.container{max-width:40rem}}@media (width>=48rem){.container{max-width:48rem}}@media (width>=64rem){.container{max-width:64rem}}@media (width>=80rem){.container{max-width:80rem}}@media (width>=96rem){.container{max-width:96rem}}.-mx-4{margin-inline:calc(var(--spacing) * -4)}.mx-1{margin-inline:var(--spacing)}.mx-2{margin-inline:calc(var(--spacing) * 2)}.mx-3{margin-inline:calc(var(--spacing) * 3)}.mx-4{margin-inline:calc(var(--spacing) * 4)}.mx-auto{margin-inline:auto}.my-1{margin-block:var(--spacing)}.my-1\.5{margin-block:calc(var(--spacing) * 1.5)}.my-2{margin-block:calc(var(--spacing) * 2)}.my-8{margin-block:calc(var(--spacing) * 8)}.-mt-0\.5{margin-top:calc(var(--spacing) * -.5)}.-mt-1{margin-top:calc(var(--spacing) * -1)}.-mt-2\.5{margin-top:calc(var(--spacing) * -2.5)}.mt-0\.5{margin-top:calc(var(--spacing) * .5)}.mt-1{margin-top:var(--spacing)}.mt-1\.5{margin-top:calc(var(--spacing) * 1.5)}.mt-2{margin-top:calc(var(--spacing) * 2)}.mt-2\.5{margin-top:calc(var(--spacing) * 2.5)}.mt-3{margin-top:calc(var(--spacing) * 3)}.mt-3\.5{margin-top:calc(var(--spacing) * 3.5)}.mt-4{margin-top:calc(var(--spacing) * 4)}.mt-5{margin-top:calc(var(--spacing) * 5)}.mt-6{margin-top:calc(var(--spacing) * 6)}.mt-7{margin-top:calc(var(--spacing) * 7)}.mt-8{margin-top:calc(var(--spacing) * 8)}.mt-\[2px\]{margin-top:2px}.mt-\[3px\]{margin-top:3px}.mt-\[22px\]{margin-top:22px}.mt-auto{margin-top:auto}.-mr-1\.5{margin-right:calc(var(--spacing) * -1.5)}.-mr-2{margin-right:calc(var(--spacing) * -2)}.mr-2{margin-right:calc(var(--spacing) * 2)}.mr-2\.5{margin-right:calc(var(--spacing) * 2.5)}.mr-3{margin-right:calc(var(--spacing) * 3)}.mr-5{margin-right:calc(var(--spacing) * 5)}.-mb-2{margin-bottom:calc(var(--spacing) * -2)}.mb-0\.5{margin-bottom:calc(var(--spacing) * .5)}.mb-1{margin-bottom:var(--spacing)}.mb-1\.5{margin-bottom:calc(var(--spacing) * 1.5)}.mb-2{margin-bottom:calc(var(--spacing) * 2)}.mb-3{margin-bottom:calc(var(--spacing) * 3)}.mb-4{margin-bottom:calc(var(--spacing) * 4)}.mb-5{margin-bottom:calc(var(--spacing) * 5)}.mb-6{margin-bottom:calc(var(--spacing) * 6)}.-ml-1{margin-left:calc(var(--spacing) * -1)}.ml-0\.5{margin-left:calc(var(--spacing) * .5)}.ml-1{margin-left:var(--spacing)}.ml-1\.5{margin-left:calc(var(--spacing) * 1.5)}.ml-2{margin-left:calc(var(--spacing) * 2)}.ml-2\.5{margin-left:calc(var(--spacing) * 2.5)}.ml-4{margin-left:calc(var(--spacing) * 4)}.ml-\[52px\]{margin-left:52px}.ml-\[76px\]{margin-left:76px}.ml-auto{margin-left:auto}.line-clamp-2{-webkit-line-clamp:2;-webkit-box-orient:vertical;display:-webkit-box;overflow:hidden}.line-clamp-3{-webkit-line-clamp:3;-webkit-box-orient:vertical;display:-webkit-box;overflow:hidden}.line-clamp-4{-webkit-line-clamp:4;-webkit-box-orient:vertical;display:-webkit-box;overflow:hidden}.block{display:block}.contents{display:contents}.flex{display:flex}.grid{display:grid}.hidden{display:none}.inline{display:inline}.inline-block{display:inline-block}.inline-flex{display:inline-flex}.table{display:table}.aspect-\[16\/10\]{aspect-ratio:16/10}.aspect-square{aspect-ratio:1}.h-1{height:var(--spacing)}.h-1\.5{height:calc(var(--spacing) * 1.5)}.h-2{height:calc(var(--spacing) * 2)}.h-2\.5{height:calc(var(--spacing) * 2.5)}.h-3\.5{height:calc(var(--spacing) * 3.5)}.h-4{height:calc(var(--spacing) * 4)}.h-5{height:calc(var(--spacing) * 5)}.h-6{height:calc(var(--spacing) * 6)}.h-7{height:calc(var(--spacing) * 7)}.h-8{height:calc(var(--spacing) * 8)}.h-9{height:calc(var(--spacing) * 9)}.h-10{height:calc(var(--spacing) * 10)}.h-11{height:calc(var(--spacing) * 11)}.h-12{height:calc(var(--spacing) * 12)}.h-14{height:calc(var(--spacing) * 14)}.h-16{height:calc(var(--spacing) * 16)}.h-28{height:calc(var(--spacing) * 28)}.h-40{height:calc(var(--spacing) * 40)}.h-44{height:calc(var(--spacing) * 44)}.h-48{height:calc(var(--spacing) * 48)}.h-\[9px\]{height:9px}.h-\[17px\]{height:17px}.h-\[18px\]{height:18px}.h-\[46px\]{height:46px}.h-\[46vh\]{height:46vh}.h-\[50px\]{height:50px}.h-\[72px\]{height:72px}.h-\[100dvh\]{height:100dvh}.h-\[130px\]{height:130px}.h-\[148px\]{height:148px}.h-\[480px\]{height:480px}.h-full{height:100%}.max-h-28{max-height:calc(var(--spacing) * 28)}.max-h-32{max-height:calc(var(--spacing) * 32)}.max-h-40{max-height:calc(var(--spacing) * 40)}.max-h-52{max-height:calc(var(--spacing) * 52)}.max-h-64{max-height:calc(var(--spacing) * 64)}.max-h-72{max-height:calc(var(--spacing) * 72)}.max-h-\[60vh\]{max-height:60vh}.max-h-\[92dvh\]{max-height:92dvh}.max-h-full{max-height:100%}.min-h-0{min-height:0}.min-h-\[40vh\]{min-height:40vh}.min-h-\[44px\]{min-height:44px}.min-h-\[54px\]{min-height:54px}.min-h-\[56px\]{min-height:56px}.\!w-auto{width:auto!important}.w-1{width:var(--spacing)}.w-1\.5{width:calc(var(--spacing) * 1.5)}.w-2{width:calc(var(--spacing) * 2)}.w-2\.5{width:calc(var(--spacing) * 2.5)}.w-5{width:calc(var(--spacing) * 5)}.w-6{width:calc(var(--spacing) * 6)}.w-7{width:calc(var(--spacing) * 7)}.w-8{width:calc(var(--spacing) * 8)}.w-9{width:calc(var(--spacing) * 9)}.w-10{width:calc(var(--spacing) * 10)}.w-11{width:calc(var(--spacing) * 11)}.w-12{width:calc(var(--spacing) * 12)}.w-14{width:calc(var(--spacing) * 14)}.w-16{width:calc(var(--spacing) * 16)}.w-28{width:calc(var(--spacing) * 28)}.w-40{width:calc(var(--spacing) * 40)}.w-44{width:calc(var(--spacing) * 44)}.w-48{width:calc(var(--spacing) * 48)}.w-56{width:calc(var(--spacing) * 56)}.w-\[9px\]{width:9px}.w-\[46px\]{width:46px}.w-\[60px\]{width:60px}.w-\[64px\]{width:64px}.w-\[72px\]{width:72px}.w-\[74px\]{width:74px}.w-\[76px\]{width:76px}.w-\[82vw\]{width:82vw}.w-\[86px\]{width:86px}.w-\[148px\]{width:148px}.w-\[188px\]{width:188px}.w-\[232px\]{width:232px}.w-\[248px\]{width:248px}.w-\[260px\]{width:260px}.w-\[300px\]{width:300px}.w-\[900px\]{width:900px}.w-auto{width:auto}.w-fit{width:fit-content}.w-full{width:100%}.max-w-\[60\%\]{max-width:60%}.max-w-\[68px\]{max-width:68px}.max-w-\[86\%\]{max-width:86%}.max-w-\[240px\]{max-width:240px}.max-w-\[320px\]{max-width:320px}.max-w-\[340px\]{max-width:340px}.max-w-\[360px\]{max-width:360px}.max-w-\[520px\]{max-width:520px}.max-w-\[560px\]{max-width:560px}.max-w-\[600px\]{max-width:600px}.max-w-\[720px\]{max-width:720px}.max-w-\[760px\]{max-width:760px}.max-w-\[calc\(100\%-128px\)\]{max-width:calc(100% - 128px)}.max-w-full{max-width:100%}.max-w-md{max-width:var(--container-md)}.max-w-sm{max-width:var(--container-sm)}.min-w-0{min-width:0}.min-w-\[17px\]{min-width:17px}.min-w-\[18px\]{min-width:18px}.min-w-\[180px\]{min-width:180px}.min-w-full{min-width:100%}.flex-1{flex:1}.shrink-0{flex-shrink:0}.border-separate{border-collapse:separate}.border-spacing-0{--tw-border-spacing-x:0px;--tw-border-spacing-y:0px;border-spacing:var(--tw-border-spacing-x) var(--tw-border-spacing-y)}.origin-top-left{transform-origin:0 0}.-translate-x-1\/2{--tw-translate-x:calc(calc(1 / 2 * 100%) * -1);translate:var(--tw-translate-x) var(--tw-translate-y)}.-translate-y-1\/2{--tw-translate-y:calc(calc(1 / 2 * 100%) * -1);translate:var(--tw-translate-x) var(--tw-translate-y)}.scale-\[0\.3333\]{scale:.3333}.animate-pulse{animation:var(--animate-pulse)}.animate-spin{animation:var(--animate-spin)}.cursor-crosshair{cursor:crosshair}.cursor-pointer{cursor:pointer}.resize-none{resize:none}.resize-y{resize:vertical}.scroll-mt-4{scroll-margin-top:calc(var(--spacing) * 4)}.list-decimal{list-style-type:decimal}.grid-cols-1{grid-template-columns:repeat(1,minmax(0,1fr))}.grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}.grid-cols-4{grid-template-columns:repeat(4,minmax(0,1fr))}.grid-cols-8{grid-template-columns:repeat(8,minmax(0,1fr))}.grid-cols-\[1fr_1fr_auto\]{grid-template-columns:1fr 1fr auto}.grid-cols-\[1fr_84px\]{grid-template-columns:1fr 84px}.grid-cols-\[auto_1fr\]{grid-template-columns:auto 1fr}.flex-col{flex-direction:column}.flex-wrap{flex-wrap:wrap}.items-baseline{align-items:baseline}.items-center{align-items:center}.items-end{align-items:flex-end}.items-start{align-items:flex-start}.justify-between{justify-content:space-between}.justify-center{justify-content:center}.justify-end{justify-content:flex-end}.justify-evenly{justify-content:space-evenly}.justify-start{justify-content:flex-start}.gap-0\.5{gap:calc(var(--spacing) * .5)}.gap-1{gap:var(--spacing)}.gap-1\.5{gap:calc(var(--spacing) * 1.5)}.gap-2{gap:calc(var(--spacing) * 2)}.gap-2\.5{gap:calc(var(--spacing) * 2.5)}.gap-3{gap:calc(var(--spacing) * 3)}.gap-3\.5{gap:calc(var(--spacing) * 3.5)}.gap-4{gap:calc(var(--spacing) * 4)}.gap-\[3px\]{gap:3px}:where(.space-y-0\.5>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * .5) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * .5) * calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-1>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(var(--spacing) * var(--tw-space-y-reverse));margin-block-end:calc(var(--spacing) * calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-1\.5>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * 1.5) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * 1.5) * calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-2>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * 2) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * 2) * calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-2\.5>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * 2.5) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * 2.5) * calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-3>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * 3) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * 3) * calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-3\.5>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * 3.5) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * 3.5) * calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-4>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * 4) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * 4) * calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-5>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * 5) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * 5) * calc(1 - var(--tw-space-y-reverse)))}.gap-x-1\.5{column-gap:calc(var(--spacing) * 1.5)}.gap-x-2{column-gap:calc(var(--spacing) * 2)}.gap-x-3{column-gap:calc(var(--spacing) * 3)}.gap-x-4{column-gap:calc(var(--spacing) * 4)}.gap-y-0\.5{row-gap:calc(var(--spacing) * .5)}.gap-y-1{row-gap:var(--spacing)}.gap-y-1\.5{row-gap:calc(var(--spacing) * 1.5)}:where(.divide-y>:not(:last-child)){--tw-divide-y-reverse:0;border-bottom-style:var(--tw-border-style);border-top-style:var(--tw-border-style);border-top-width:calc(1px * var(--tw-divide-y-reverse));border-bottom-width:calc(1px * calc(1 - var(--tw-divide-y-reverse)))}:where(.divide-border>:not(:last-child)),:where(.divide-border\/60>:not(:last-child)){border-color:var(--color-border)}@supports (color:color-mix(in lab, red, red)){:where(.divide-border\/60>:not(:last-child)){border-color:color-mix(in oklab, var(--color-border) 60%, transparent)}}:where(.divide-border\/70>:not(:last-child)){border-color:var(--color-border)}@supports (color:color-mix(in lab, red, red)){:where(.divide-border\/70>:not(:last-child)){border-color:color-mix(in oklab, var(--color-border) 70%, transparent)}}.self-center{align-self:center}.self-start{align-self:flex-start}.truncate{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.overflow-auto{overflow:auto}.overflow-hidden{overflow:hidden}.overflow-x-auto{overflow-x:auto}.overflow-x-hidden{overflow-x:hidden}.overflow-y-auto{overflow-y:auto}.rounded{border-radius:.25rem}.rounded-2xl{border-radius:var(--radius-2xl)}.rounded-3xl{border-radius:var(--radius-3xl)}.rounded-\[10px\]{border-radius:10px}.rounded-\[13px\]{border-radius:13px}.rounded-\[14px\]{border-radius:14px}.rounded-\[18px\]{border-radius:18px}.rounded-\[20px\]{border-radius:20px}.rounded-\[22px\]{border-radius:22px}.rounded-\[26px\]{border-radius:26px}.rounded-\[28px\]{border-radius:28px}.rounded-full{border-radius:2147483647px}.rounded-lg{border-radius:var(--radius-lg)}.rounded-md{border-radius:var(--radius-md)}.rounded-sm{border-radius:var(--radius-sm)}.rounded-xl{border-radius:var(--radius-xl)}.rounded-t-3xl{border-top-left-radius:var(--radius-3xl);border-top-right-radius:var(--radius-3xl)}.rounded-t-\[28px\]{border-top-left-radius:28px;border-top-right-radius:28px}.rounded-tl-lg{border-top-left-radius:var(--radius-lg)}.rounded-br-lg{border-bottom-right-radius:var(--radius-lg)}.rounded-bl-lg{border-bottom-left-radius:var(--radius-lg)}.rounded-bl-md{border-bottom-left-radius:var(--radius-md)}.border{border-style:var(--tw-border-style);border-width:1px}.border-0{border-style:var(--tw-border-style);border-width:0}.border-2{border-style:var(--tw-border-style);border-width:2px}.border-\[1\.5px\]{border-style:var(--tw-border-style);border-width:1.5px}.border-y{border-block-style:var(--tw-border-style);border-block-width:1px}.border-t{border-top-style:var(--tw-border-style);border-top-width:1px}.border-r{border-right-style:var(--tw-border-style);border-right-width:1px}.border-b{border-bottom-style:var(--tw-border-style);border-bottom-width:1px}.border-dashed{--tw-border-style:dashed;border-style:dashed}.border-accent,.border-accent\/15{border-color:var(--color-accent)}@supports (color:color-mix(in lab, red, red)){.border-accent\/15{border-color:color-mix(in oklab, var(--color-accent) 15%, transparent)}}.border-accent\/25{border-color:var(--color-accent)}@supports (color:color-mix(in lab, red, red)){.border-accent\/25{border-color:color-mix(in oklab, var(--color-accent) 25%, transparent)}}.border-accent\/30{border-color:var(--color-accent)}@supports (color:color-mix(in lab, red, red)){.border-accent\/30{border-color:color-mix(in oklab, var(--color-accent) 30%, transparent)}}.border-accent\/40{border-color:var(--color-accent)}@supports (color:color-mix(in lab, red, red)){.border-accent\/40{border-color:color-mix(in oklab, var(--color-accent) 40%, transparent)}}.border-accent\/50{border-color:var(--color-accent)}@supports (color:color-mix(in lab, red, red)){.border-accent\/50{border-color:color-mix(in oklab, var(--color-accent) 50%, transparent)}}.border-amber-400\/40{border-color:#fcbb0066}@supports (color:color-mix(in lab, red, red)){.border-amber-400\/40{border-color:color-mix(in oklab, var(--color-amber-400) 40%, transparent)}}.border-amber-500\/50{border-color:#f99c0080}@supports (color:color-mix(in lab, red, red)){.border-amber-500\/50{border-color:color-mix(in oklab, var(--color-amber-500) 50%, transparent)}}.border-bg{border-color:var(--color-bg)}.border-border,.border-border\/60{border-color:var(--color-border)}@supports (color:color-mix(in lab, red, red)){.border-border\/60{border-color:color-mix(in oklab, var(--color-border) 60%, transparent)}}.border-border\/70{border-color:var(--color-border)}@supports (color:color-mix(in lab, red, red)){.border-border\/70{border-color:color-mix(in oklab, var(--color-border) 70%, transparent)}}.border-border\/80{border-color:var(--color-border)}@supports (color:color-mix(in lab, red, red)){.border-border\/80{border-color:color-mix(in oklab, var(--color-border) 80%, transparent)}}.border-current{border-color:currentColor}.border-fg{border-color:var(--color-fg)}.border-rose-400{border-color:var(--color-rose-400)}.border-rose-400\/60{border-color:#ff667f99}@supports (color:color-mix(in lab, red, red)){.border-rose-400\/60{border-color:color-mix(in oklab, var(--color-rose-400) 60%, transparent)}}.border-rose-500\/25{border-color:#ff235740}@supports (color:color-mix(in lab, red, red)){.border-rose-500\/25{border-color:color-mix(in oklab, var(--color-rose-500) 25%, transparent)}}.border-surface{border-color:var(--color-surface)}.border-transparent{border-color:#0000}.border-t-transparent{border-top-color:#0000}.bg-\[\#2fb344\]{background-color:#2fb344}.bg-\[\#f1efeb\]{background-color:#f1efeb}.bg-accent,.bg-accent\/5{background-color:var(--color-accent)}@supports (color:color-mix(in lab, red, red)){.bg-accent\/5{background-color:color-mix(in oklab, var(--color-accent) 5%, transparent)}}.bg-accent\/8{background-color:var(--color-accent)}@supports (color:color-mix(in lab, red, red)){.bg-accent\/8{background-color:color-mix(in oklab, var(--color-accent) 8%, transparent)}}.bg-accent\/10{background-color:var(--color-accent)}@supports (color:color-mix(in lab, red, red)){.bg-accent\/10{background-color:color-mix(in oklab, var(--color-accent) 10%, transparent)}}.bg-accent\/12{background-color:var(--color-accent)}@supports (color:color-mix(in lab, red, red)){.bg-accent\/12{background-color:color-mix(in oklab, var(--color-accent) 12%, transparent)}}.bg-accent\/15{background-color:var(--color-accent)}@supports (color:color-mix(in lab, red, red)){.bg-accent\/15{background-color:color-mix(in oklab, var(--color-accent) 15%, transparent)}}.bg-accent\/70{background-color:var(--color-accent)}@supports (color:color-mix(in lab, red, red)){.bg-accent\/70{background-color:color-mix(in oklab, var(--color-accent) 70%, transparent)}}.bg-accent\/\[0\.06\]{background-color:var(--color-accent)}@supports (color:color-mix(in lab, red, red)){.bg-accent\/\[0\.06\]{background-color:color-mix(in oklab, var(--color-accent) 6%, transparent)}}.bg-amber-50\/70{background-color:#fffbebb3}@supports (color:color-mix(in lab, red, red)){.bg-amber-50\/70{background-color:color-mix(in oklab, var(--color-amber-50) 70%, transparent)}}.bg-amber-400{background-color:var(--color-amber-400)}.bg-amber-400\/15{background-color:#fcbb0026}@supports (color:color-mix(in lab, red, red)){.bg-amber-400\/15{background-color:color-mix(in oklab, var(--color-amber-400) 15%, transparent)}}.bg-amber-500{background-color:var(--color-amber-500)}.bg-amber-500\/10{background-color:#f99c001a}@supports (color:color-mix(in lab, red, red)){.bg-amber-500\/10{background-color:color-mix(in oklab, var(--color-amber-500) 10%, transparent)}}.bg-amber-500\/12{background-color:#f99c001f}@supports (color:color-mix(in lab, red, red)){.bg-amber-500\/12{background-color:color-mix(in oklab, var(--color-amber-500) 12%, transparent)}}.bg-amber-500\/15{background-color:#f99c0026}@supports (color:color-mix(in lab, red, red)){.bg-amber-500\/15{background-color:color-mix(in oklab, var(--color-amber-500) 15%, transparent)}}.bg-bg,.bg-bg\/50{background-color:var(--color-bg)}@supports (color:color-mix(in lab, red, red)){.bg-bg\/50{background-color:color-mix(in oklab, var(--color-bg) 50%, transparent)}}.bg-bg\/60{background-color:var(--color-bg)}@supports (color:color-mix(in lab, red, red)){.bg-bg\/60{background-color:color-mix(in oklab, var(--color-bg) 60%, transparent)}}.bg-bg\/80{background-color:var(--color-bg)}@supports (color:color-mix(in lab, red, red)){.bg-bg\/80{background-color:color-mix(in oklab, var(--color-bg) 80%, transparent)}}.bg-black\/20{background-color:#0003}@supports (color:color-mix(in lab, red, red)){.bg-black\/20{background-color:color-mix(in oklab, var(--color-black) 20%, transparent)}}.bg-black\/40{background-color:#0006}@supports (color:color-mix(in lab, red, red)){.bg-black\/40{background-color:color-mix(in oklab, var(--color-black) 40%, transparent)}}.bg-black\/45{background-color:#00000073}@supports (color:color-mix(in lab, red, red)){.bg-black\/45{background-color:color-mix(in oklab, var(--color-black) 45%, transparent)}}.bg-black\/60{background-color:#0009}@supports (color:color-mix(in lab, red, red)){.bg-black\/60{background-color:color-mix(in oklab, var(--color-black) 60%, transparent)}}.bg-border{background-color:var(--color-border)}.bg-bubble-user{background-color:var(--color-bubble-user)}.bg-cyan-500\/12{background-color:#00b7d71f}@supports (color:color-mix(in lab, red, red)){.bg-cyan-500\/12{background-color:color-mix(in oklab, var(--color-cyan-500) 12%, transparent)}}.bg-emerald-500{background-color:var(--color-emerald-500)}.bg-emerald-500\/12{background-color:#00bb7f1f}@supports (color:color-mix(in lab, red, red)){.bg-emerald-500\/12{background-color:color-mix(in oklab, var(--color-emerald-500) 12%, transparent)}}.bg-emerald-500\/15{background-color:#00bb7f26}@supports (color:color-mix(in lab, red, red)){.bg-emerald-500\/15{background-color:color-mix(in oklab, var(--color-emerald-500) 15%, transparent)}}.bg-fg,.bg-fg\/40{background-color:var(--color-fg)}@supports (color:color-mix(in lab, red, red)){.bg-fg\/40{background-color:color-mix(in oklab, var(--color-fg) 40%, transparent)}}.bg-fuchsia-500\/12{background-color:#e12afb1f}@supports (color:color-mix(in lab, red, red)){.bg-fuchsia-500\/12{background-color:color-mix(in oklab, var(--color-fuchsia-500) 12%, transparent)}}.bg-muted,.bg-muted\/35{background-color:var(--color-muted)}@supports (color:color-mix(in lab, red, red)){.bg-muted\/35{background-color:color-mix(in oklab, var(--color-muted) 35%, transparent)}}.bg-orange-500\/12{background-color:#fe6e001f}@supports (color:color-mix(in lab, red, red)){.bg-orange-500\/12{background-color:color-mix(in oklab, var(--color-orange-500) 12%, transparent)}}.bg-pink-500{background-color:var(--color-pink-500)}.bg-pink-500\/12{background-color:#f6339a1f}@supports (color:color-mix(in lab, red, red)){.bg-pink-500\/12{background-color:color-mix(in oklab, var(--color-pink-500) 12%, transparent)}}.bg-red-500{background-color:var(--color-red-500)}.bg-rose-400{background-color:var(--color-rose-400)}.bg-rose-500{background-color:var(--color-rose-500)}.bg-rose-500\/12{background-color:#ff23571f}@supports (color:color-mix(in lab, red, red)){.bg-rose-500\/12{background-color:color-mix(in oklab, var(--color-rose-500) 12%, transparent)}}.bg-rose-500\/15{background-color:#ff235726}@supports (color:color-mix(in lab, red, red)){.bg-rose-500\/15{background-color:color-mix(in oklab, var(--color-rose-500) 15%, transparent)}}.bg-rose-500\/\[0\.04\]{background-color:#ff23570a}@supports (color:color-mix(in lab, red, red)){.bg-rose-500\/\[0\.04\]{background-color:color-mix(in oklab, var(--color-rose-500) 4%, transparent)}}.bg-sky-500\/12{background-color:#00a5ef1f}@supports (color:color-mix(in lab, red, red)){.bg-sky-500\/12{background-color:color-mix(in oklab, var(--color-sky-500) 12%, transparent)}}.bg-surface{background-color:var(--color-surface)}.bg-surface-2,.bg-surface-2\/40{background-color:var(--color-surface-2)}@supports (color:color-mix(in lab, red, red)){.bg-surface-2\/40{background-color:color-mix(in oklab, var(--color-surface-2) 40%, transparent)}}.bg-surface-2\/60{background-color:var(--color-surface-2)}@supports (color:color-mix(in lab, red, red)){.bg-surface-2\/60{background-color:color-mix(in oklab, var(--color-surface-2) 60%, transparent)}}.bg-surface-2\/70{background-color:var(--color-surface-2)}@supports (color:color-mix(in lab, red, red)){.bg-surface-2\/70{background-color:color-mix(in oklab, var(--color-surface-2) 70%, transparent)}}.bg-surface-2\/80{background-color:var(--color-surface-2)}@supports (color:color-mix(in lab, red, red)){.bg-surface-2\/80{background-color:color-mix(in oklab, var(--color-surface-2) 80%, transparent)}}.bg-surface\/40{background-color:var(--color-surface)}@supports (color:color-mix(in lab, red, red)){.bg-surface\/40{background-color:color-mix(in oklab, var(--color-surface) 40%, transparent)}}.bg-surface\/70{background-color:var(--color-surface)}@supports (color:color-mix(in lab, red, red)){.bg-surface\/70{background-color:color-mix(in oklab, var(--color-surface) 70%, transparent)}}.bg-surface\/90{background-color:var(--color-surface)}@supports (color:color-mix(in lab, red, red)){.bg-surface\/90{background-color:color-mix(in oklab, var(--color-surface) 90%, transparent)}}.bg-transparent{background-color:#0000}.bg-violet-500{background-color:var(--color-violet-500)}.bg-violet-500\/12{background-color:#8d54ff1f}@supports (color:color-mix(in lab, red, red)){.bg-violet-500\/12{background-color:color-mix(in oklab, var(--color-violet-500) 12%, transparent)}}.bg-white{background-color:var(--color-white)}.bg-white\/80{background-color:#fffc}@supports (color:color-mix(in lab, red, red)){.bg-white\/80{background-color:color-mix(in oklab, var(--color-white) 80%, transparent)}}.bg-gradient-to-b{--tw-gradient-position:to bottom in oklab;background-image:linear-gradient(var(--tw-gradient-stops))}.bg-gradient-to-br{--tw-gradient-position:to bottom right in oklab;background-image:linear-gradient(var(--tw-gradient-stops))}.bg-\[radial-gradient\(ellipse_at_top\,rgba\(0\,100\,212\,0\.14\)\,transparent_65\%\)\]{background-image:radial-gradient(at top,#0064d424,#0000 65%)}.from-\[\#7d6bc7\]{--tw-gradient-from:#7d6bc7;--tw-gradient-stops:var(--tw-gradient-via-stops,var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position))}.from-\[\#b0413e\]{--tw-gradient-from:#b0413e;--tw-gradient-stops:var(--tw-gradient-via-stops,var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position))}.from-accent{--tw-gradient-from:var(--color-accent);--tw-gradient-stops:var(--tw-gradient-via-stops,var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position))}.from-emerald-500{--tw-gradient-from:var(--color-emerald-500);--tw-gradient-stops:var(--tw-gradient-via-stops,var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position))}.from-orange-400{--tw-gradient-from:var(--color-orange-400);--tw-gradient-stops:var(--tw-gradient-via-stops,var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position))}.from-slate-400{--tw-gradient-from:var(--color-slate-400);--tw-gradient-stops:var(--tw-gradient-via-stops,var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position))}.from-slate-700{--tw-gradient-from:var(--color-slate-700);--tw-gradient-stops:var(--tw-gradient-via-stops,var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position))}.to-\[\#7a1f1f\]{--tw-gradient-to:#7a1f1f;--tw-gradient-stops:var(--tw-gradient-via-stops,var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position))}.to-\[\#574494\]{--tw-gradient-to:#574494;--tw-gradient-stops:var(--tw-gradient-via-stops,var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position))}.to-amber-600{--tw-gradient-to:var(--color-amber-600);--tw-gradient-stops:var(--tw-gradient-via-stops,var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position))}.to-sky-400{--tw-gradient-to:var(--color-sky-400);--tw-gradient-stops:var(--tw-gradient-via-stops,var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position))}.to-slate-600{--tw-gradient-to:var(--color-slate-600);--tw-gradient-stops:var(--tw-gradient-via-stops,var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position))}.to-slate-900{--tw-gradient-to:var(--color-slate-900);--tw-gradient-stops:var(--tw-gradient-via-stops,var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position))}.to-teal-700{--tw-gradient-to:var(--color-teal-700);--tw-gradient-stops:var(--tw-gradient-via-stops,var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position))}.object-contain{object-fit:contain}.object-cover{object-fit:cover}.object-top{object-position:top}.p-0\.5{padding:calc(var(--spacing) * .5)}.p-1{padding:var(--spacing)}.p-1\.5{padding:calc(var(--spacing) * 1.5)}.p-2{padding:calc(var(--spacing) * 2)}.p-2\.5{padding:calc(var(--spacing) * 2.5)}.p-3{padding:calc(var(--spacing) * 3)}.p-3\.5{padding:calc(var(--spacing) * 3.5)}.p-4{padding:calc(var(--spacing) * 4)}.p-5{padding:calc(var(--spacing) * 5)}.p-6{padding:calc(var(--spacing) * 6)}.p-8{padding:calc(var(--spacing) * 8)}.\!px-3\.5{padding-inline:calc(var(--spacing) * 3.5)!important}.px-0\.5{padding-inline:calc(var(--spacing) * .5)}.px-1{padding-inline:var(--spacing)}.px-1\.5{padding-inline:calc(var(--spacing) * 1.5)}.px-2{padding-inline:calc(var(--spacing) * 2)}.px-2\.5{padding-inline:calc(var(--spacing) * 2.5)}.px-3{padding-inline:calc(var(--spacing) * 3)}.px-3\.5{padding-inline:calc(var(--spacing) * 3.5)}.px-4{padding-inline:calc(var(--spacing) * 4)}.px-5{padding-inline:calc(var(--spacing) * 5)}.px-6{padding-inline:calc(var(--spacing) * 6)}.px-8{padding-inline:calc(var(--spacing) * 8)}.px-16{padding-inline:calc(var(--spacing) * 16)}.\!py-1\.5{padding-block:calc(var(--spacing) * 1.5)!important}.py-0\.5{padding-block:calc(var(--spacing) * .5)}.py-1{padding-block:var(--spacing)}.py-1\.5{padding-block:calc(var(--spacing) * 1.5)}.py-2{padding-block:calc(var(--spacing) * 2)}.py-2\.5{padding-block:calc(var(--spacing) * 2.5)}.py-3{padding-block:calc(var(--spacing) * 3)}.py-3\.5{padding-block:calc(var(--spacing) * 3.5)}.py-4{padding-block:calc(var(--spacing) * 4)}.py-6{padding-block:calc(var(--spacing) * 6)}.py-8{padding-block:calc(var(--spacing) * 8)}.py-10{padding-block:calc(var(--spacing) * 10)}.pt-0{padding-top:0}.pt-0\.5{padding-top:calc(var(--spacing) * .5)}.pt-1{padding-top:var(--spacing)}.pt-1\.5{padding-top:calc(var(--spacing) * 1.5)}.pt-2{padding-top:calc(var(--spacing) * 2)}.pt-2\.5{padding-top:calc(var(--spacing) * 2.5)}.pt-3{padding-top:calc(var(--spacing) * 3)}.pt-3\.5{padding-top:calc(var(--spacing) * 3.5)}.pt-4{padding-top:calc(var(--spacing) * 4)}.pt-5{padding-top:calc(var(--spacing) * 5)}.pt-6{padding-top:calc(var(--spacing) * 6)}.pt-9{padding-top:calc(var(--spacing) * 9)}.pt-10{padding-top:calc(var(--spacing) * 10)}.pt-14{padding-top:calc(var(--spacing) * 14)}.pt-\[3px\]{padding-top:3px}.pt-\[18px\]{padding-top:18px}.pt-\[22px\]{padding-top:22px}.pr-1{padding-right:var(--spacing)}.pr-2{padding-right:calc(var(--spacing) * 2)}.pr-2\.5{padding-right:calc(var(--spacing) * 2.5)}.pr-3{padding-right:calc(var(--spacing) * 3)}.pr-5{padding-right:calc(var(--spacing) * 5)}.pr-8{padding-right:calc(var(--spacing) * 8)}.pr-10{padding-right:calc(var(--spacing) * 10)}.pb-0\.5{padding-bottom:calc(var(--spacing) * .5)}.pb-1{padding-bottom:var(--spacing)}.pb-1\.5{padding-bottom:calc(var(--spacing) * 1.5)}.pb-2{padding-bottom:calc(var(--spacing) * 2)}.pb-2\.5{padding-bottom:calc(var(--spacing) * 2.5)}.pb-3{padding-bottom:calc(var(--spacing) * 3)}.pb-3\.5{padding-bottom:calc(var(--spacing) * 3.5)}.pb-4{padding-bottom:calc(var(--spacing) * 4)}.pb-5{padding-bottom:calc(var(--spacing) * 5)}.pb-6{padding-bottom:calc(var(--spacing) * 6)}.pb-7{padding-bottom:calc(var(--spacing) * 7)}.pb-8{padding-bottom:calc(var(--spacing) * 8)}.pl-3{padding-left:calc(var(--spacing) * 3)}.pl-3\.5{padding-left:calc(var(--spacing) * 3.5)}.pl-4{padding-left:calc(var(--spacing) * 4)}.pl-5{padding-left:calc(var(--spacing) * 5)}.pl-7{padding-left:calc(var(--spacing) * 7)}.pl-9{padding-left:calc(var(--spacing) * 9)}.pl-12{padding-left:calc(var(--spacing) * 12)}.pl-\[18px\]{padding-left:18px}.text-center{text-align:center}.text-left{text-align:left}.text-right{text-align:right}.align-middle{vertical-align:middle}.font-mono{font-family:var(--font-mono)}.font-sans{font-family:var(--font-sans)}.text-\[10\.5px\]{font-size:10.5px}.text-\[10px\]{font-size:10px}.text-\[11\.5px\]{font-size:11.5px}.text-\[11px\]{font-size:11px}.text-\[12\.5px\]{font-size:12.5px}.text-\[12px\]{font-size:12px}.text-\[13\.5px\]{font-size:13.5px}.text-\[13px\]{font-size:13px}.text-\[14\.5px\]{font-size:14.5px}.text-\[14px\]{font-size:14px}.text-\[15px\]{font-size:15px}.text-\[16px\]{font-size:16px}.text-\[17px\]{font-size:17px}.text-\[18px\]{font-size:18px}.text-\[20px\]{font-size:20px}.text-\[21px\]{font-size:21px}.text-\[22px\]{font-size:22px}.text-\[24px\]{font-size:24px}.text-\[26px\]{font-size:26px}.text-\[28px\]{font-size:28px}.text-\[30px\]{font-size:30px}.text-\[64px\]{font-size:64px}.leading-4{--tw-leading:calc(var(--spacing) * 4);line-height:calc(var(--spacing) * 4)}.leading-6{--tw-leading:calc(var(--spacing) * 6);line-height:calc(var(--spacing) * 6)}.leading-7{--tw-leading:calc(var(--spacing) * 7);line-height:calc(var(--spacing) * 7)}.leading-8{--tw-leading:calc(var(--spacing) * 8);line-height:calc(var(--spacing) * 8)}.leading-\[1\.4\]{--tw-leading:1.4;line-height:1.4}.leading-\[1\.5\]{--tw-leading:1.5;line-height:1.5}.leading-\[1\.45\]{--tw-leading:1.45;line-height:1.45}.leading-\[14px\]{--tw-leading:14px;line-height:14px}.leading-\[17px\]{--tw-leading:17px;line-height:17px}.leading-\[18px\]{--tw-leading:18px;line-height:18px}.leading-\[19px\]{--tw-leading:19px;line-height:19px}.leading-\[20px\]{--tw-leading:20px;line-height:20px}.leading-\[21px\]{--tw-leading:21px;line-height:21px}.leading-\[22px\]{--tw-leading:22px;line-height:22px}.leading-\[26px\]{--tw-leading:26px;line-height:26px}.leading-\[34px\]{--tw-leading:34px;line-height:34px}.leading-none{--tw-leading:1;line-height:1}.leading-relaxed{--tw-leading:var(--leading-relaxed);line-height:var(--leading-relaxed)}.leading-snug{--tw-leading:var(--leading-snug);line-height:var(--leading-snug)}.leading-tight{--tw-leading:var(--leading-tight);line-height:var(--leading-tight)}.font-bold{--tw-font-weight:var(--font-weight-bold);font-weight:var(--font-weight-bold)}.font-medium{--tw-font-weight:var(--font-weight-medium);font-weight:var(--font-weight-medium)}.font-normal{--tw-font-weight:var(--font-weight-normal);font-weight:var(--font-weight-normal)}.font-semibold{--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold)}.tracking-\[0\.2em\]{--tw-tracking:.2em;letter-spacing:.2em}.tracking-\[0\.3em\]{--tw-tracking:.3em;letter-spacing:.3em}.tracking-normal{--tw-tracking:var(--tracking-normal);letter-spacing:var(--tracking-normal)}.tracking-tight{--tw-tracking:var(--tracking-tight);letter-spacing:var(--tracking-tight)}.tracking-wide{--tw-tracking:var(--tracking-wide);letter-spacing:var(--tracking-wide)}.break-words{overflow-wrap:break-word}.break-all{word-break:break-all}.whitespace-nowrap{white-space:nowrap}.whitespace-pre-wrap{white-space:pre-wrap}.text-accent{color:var(--color-accent)}.text-accent-fg{color:var(--color-accent-fg)}.text-accent\/80{color:var(--color-accent)}@supports (color:color-mix(in lab, red, red)){.text-accent\/80{color:color-mix(in oklab, var(--color-accent) 80%, transparent)}}.text-amber-500{color:var(--color-amber-500)}.text-amber-600{color:var(--color-amber-600)}.text-amber-700{color:var(--color-amber-700)}.text-amber-800{color:var(--color-amber-800)}.text-bg{color:var(--color-bg)}.text-bubble-user-fg{color:var(--color-bubble-user-fg)}.text-cyan-600{color:var(--color-cyan-600)}.text-emerald-500{color:var(--color-emerald-500)}.text-emerald-600{color:var(--color-emerald-600)}.text-emerald-700{color:var(--color-emerald-700)}.text-fg,.text-fg\/45{color:var(--color-fg)}@supports (color:color-mix(in lab, red, red)){.text-fg\/45{color:color-mix(in oklab, var(--color-fg) 45%, transparent)}}.text-fg\/60{color:var(--color-fg)}@supports (color:color-mix(in lab, red, red)){.text-fg\/60{color:color-mix(in oklab, var(--color-fg) 60%, transparent)}}.text-fg\/65{color:var(--color-fg)}@supports (color:color-mix(in lab, red, red)){.text-fg\/65{color:color-mix(in oklab, var(--color-fg) 65%, transparent)}}.text-fg\/70{color:var(--color-fg)}@supports (color:color-mix(in lab, red, red)){.text-fg\/70{color:color-mix(in oklab, var(--color-fg) 70%, transparent)}}.text-fg\/75{color:var(--color-fg)}@supports (color:color-mix(in lab, red, red)){.text-fg\/75{color:color-mix(in oklab, var(--color-fg) 75%, transparent)}}.text-fg\/80{color:var(--color-fg)}@supports (color:color-mix(in lab, red, red)){.text-fg\/80{color:color-mix(in oklab, var(--color-fg) 80%, transparent)}}.text-fg\/85{color:var(--color-fg)}@supports (color:color-mix(in lab, red, red)){.text-fg\/85{color:color-mix(in oklab, var(--color-fg) 85%, transparent)}}.text-fg\/90{color:var(--color-fg)}@supports (color:color-mix(in lab, red, red)){.text-fg\/90{color:color-mix(in oklab, var(--color-fg) 90%, transparent)}}.text-fuchsia-600{color:var(--color-fuchsia-600)}.text-muted,.text-muted\/70{color:var(--color-muted)}@supports (color:color-mix(in lab, red, red)){.text-muted\/70{color:color-mix(in oklab, var(--color-muted) 70%, transparent)}}.text-muted\/80{color:var(--color-muted)}@supports (color:color-mix(in lab, red, red)){.text-muted\/80{color:color-mix(in oklab, var(--color-muted) 80%, transparent)}}.text-orange-600{color:var(--color-orange-600)}.text-pink-600{color:var(--color-pink-600)}.text-red-600{color:var(--color-red-600)}.text-rose-500{color:var(--color-rose-500)}.text-rose-600{color:var(--color-rose-600)}.text-rose-700{color:var(--color-rose-700)}.text-sky-600{color:var(--color-sky-600)}.text-violet-600{color:var(--color-violet-600)}.text-white{color:var(--color-white)}.text-white\/85{color:#ffffffd9}@supports (color:color-mix(in lab, red, red)){.text-white\/85{color:color-mix(in oklab, var(--color-white) 85%, transparent)}}.text-white\/90{color:#ffffffe6}@supports (color:color-mix(in lab, red, red)){.text-white\/90{color:color-mix(in oklab, var(--color-white) 90%, transparent)}}.capitalize{text-transform:capitalize}.normal-case{text-transform:none}.uppercase{text-transform:uppercase}.ordinal{--tw-ordinal:ordinal;font-variant-numeric:var(--tw-ordinal,) var(--tw-slashed-zero,) var(--tw-numeric-figure,) var(--tw-numeric-spacing,) var(--tw-numeric-fraction,)}.tabular-nums{--tw-numeric-spacing:tabular-nums;font-variant-numeric:var(--tw-ordinal,) var(--tw-slashed-zero,) var(--tw-numeric-figure,) var(--tw-numeric-spacing,) var(--tw-numeric-fraction,)}.line-through{text-decoration-line:line-through}.underline{text-decoration-line:underline}.decoration-border{-webkit-text-decoration-color:var(--color-border);-webkit-text-decoration-color:var(--color-border);-webkit-text-decoration-color:var(--color-border);text-decoration-color:var(--color-border)}.decoration-dotted{text-decoration-style:dotted}.underline-offset-2{text-underline-offset:2px}.accent-\[var\(--om-accent\)\]{accent-color:var(--om-accent)}.accent-accent{accent-color:var(--color-accent)}.opacity-0{opacity:0}.opacity-45{opacity:.45}.opacity-50{opacity:.5}.opacity-60{opacity:.6}.opacity-70{opacity:.7}.opacity-80{opacity:.8}.opacity-90{opacity:.9}.shadow{--tw-shadow:0 1px 3px 0 var(--tw-shadow-color,#0000001a), 0 1px 2px -1px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.shadow-2xl{--tw-shadow:0 25px 50px -12px var(--tw-shadow-color,#00000040);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.shadow-\[0_1px_4px_rgba\(0\,0\,0\,0\.14\)\]{--tw-shadow:0 1px 4px var(--tw-shadow-color,#00000024);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.shadow-\[0_1px_4px_rgba\(0\,0\,0\,0\.16\)\]{--tw-shadow:0 1px 4px var(--tw-shadow-color,#00000029);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.shadow-\[0_1px_4px_rgba\(0\,0\,0\,0\.18\)\]{--tw-shadow:0 1px 4px var(--tw-shadow-color,#0000002e);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.shadow-\[0_2px_12px_-6px_rgba\(0\,0\,0\,0\.12\)\]{--tw-shadow:0 2px 12px -6px var(--tw-shadow-color,#0000001f);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.shadow-\[0_2px_12px_rgba\(0\,0\,0\,0\.12\)\]{--tw-shadow:0 2px 12px var(--tw-shadow-color,#0000001f);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.shadow-\[0_4px_20px_-12px_rgba\(0\,0\,0\,0\.2\)\]{--tw-shadow:0 4px 20px -12px var(--tw-shadow-color,#0003);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.shadow-\[0_12px_40px_-12px_rgba\(0\,0\,0\,0\.3\)\]{--tw-shadow:0 12px 40px -12px var(--tw-shadow-color,#0000004d);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.shadow-lg{--tw-shadow:0 10px 15px -3px var(--tw-shadow-color,#0000001a), 0 4px 6px -4px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.shadow-md{--tw-shadow:0 4px 6px -1px var(--tw-shadow-color,#0000001a), 0 2px 4px -2px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.shadow-sm{--tw-shadow:0 1px 3px 0 var(--tw-shadow-color,#0000001a), 0 1px 2px -1px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.shadow-xl{--tw-shadow:0 20px 25px -5px var(--tw-shadow-color,#0000001a), 0 8px 10px -6px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.ring{--tw-ring-shadow:var(--tw-ring-inset,) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.ring-2{--tw-ring-shadow:var(--tw-ring-inset,) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.ring-\[2\.5px\]{--tw-ring-shadow:var(--tw-ring-inset,) 0 0 0 calc(2.5px + var(--tw-ring-offset-width)) var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.ring-\[3px\]{--tw-ring-shadow:var(--tw-ring-inset,) 0 0 0 calc(3px + var(--tw-ring-offset-width)) var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.ring-accent,.ring-accent\/40{--tw-ring-color:var(--color-accent)}@supports (color:color-mix(in lab, red, red)){.ring-accent\/40{--tw-ring-color:color-mix(in oklab, var(--color-accent) 40%, transparent)}}.ring-offset-2{--tw-ring-offset-width:2px;--tw-ring-offset-shadow:var(--tw-ring-inset,) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color)}.ring-offset-bg{--tw-ring-offset-color:var(--color-bg)}.blur-3xl{--tw-blur:blur(var(--blur-3xl));filter:var(--tw-blur,) var(--tw-brightness,) var(--tw-contrast,) var(--tw-grayscale,) var(--tw-hue-rotate,) var(--tw-invert,) var(--tw-saturate,) var(--tw-sepia,) var(--tw-drop-shadow,)}.drop-shadow-\[0_20px_40px_rgba\(0\,100\,212\,0\.28\)\]{--tw-drop-shadow-size:drop-shadow(0 20px 40px var(--tw-drop-shadow-color,#0064d447));--tw-drop-shadow:var(--tw-drop-shadow-size);filter:var(--tw-blur,) var(--tw-brightness,) var(--tw-contrast,) var(--tw-grayscale,) var(--tw-hue-rotate,) var(--tw-invert,) var(--tw-saturate,) var(--tw-sepia,) var(--tw-drop-shadow,)}.drop-shadow-sm{--tw-drop-shadow-size:drop-shadow(0 1px 2px var(--tw-drop-shadow-color,#00000026));--tw-drop-shadow:drop-shadow(var(--drop-shadow-sm));filter:var(--tw-blur,) var(--tw-brightness,) var(--tw-contrast,) var(--tw-grayscale,) var(--tw-hue-rotate,) var(--tw-invert,) var(--tw-saturate,) var(--tw-sepia,) var(--tw-drop-shadow,)}.filter{filter:var(--tw-blur,) var(--tw-brightness,) var(--tw-contrast,) var(--tw-grayscale,) var(--tw-hue-rotate,) var(--tw-invert,) var(--tw-saturate,) var(--tw-sepia,) var(--tw-drop-shadow,)}.backdrop-blur{--tw-backdrop-blur:blur(8px);-webkit-backdrop-filter:var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,);backdrop-filter:var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,)}.backdrop-blur-\[2px\]{--tw-backdrop-blur:blur(2px);-webkit-backdrop-filter:var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,);backdrop-filter:var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,)}.transition{transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to,opacity,box-shadow,transform,translate,scale,rotate,filter,-webkit-backdrop-filter,backdrop-filter,display,content-visibility,overlay,pointer-events;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-all{transition-property:all;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-colors{transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.will-change-transform{will-change:transform}.outline-none{--tw-outline-style:none;outline-style:none}.select-all{-webkit-user-select:all;user-select:all}.select-none{-webkit-user-select:none;user-select:none}@media (hover:hover){.group-hover\:opacity-100:is(:where(.group):hover *){opacity:1}}.placeholder\:text-muted::placeholder{color:var(--color-muted)}.odd\:bg-surface:nth-child(odd){background-color:var(--color-surface)}.focus-within\:border-fg\/20:focus-within{border-color:var(--color-fg)}@supports (color:color-mix(in lab, red, red)){.focus-within\:border-fg\/20:focus-within{border-color:color-mix(in oklab, var(--color-fg) 20%, transparent)}}.focus-within\:ring-2:focus-within{--tw-ring-shadow:var(--tw-ring-inset,) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.focus-within\:ring-accent\/40:focus-within{--tw-ring-color:var(--color-accent)}@supports (color:color-mix(in lab, red, red)){.focus-within\:ring-accent\/40:focus-within{--tw-ring-color:color-mix(in oklab, var(--color-accent) 40%, transparent)}}@media (hover:hover){.hover\:scale-\[1\.04\]:hover{scale:1.04}.hover\:bg-accent\/15:hover{background-color:var(--color-accent)}@supports (color:color-mix(in lab, red, red)){.hover\:bg-accent\/15:hover{background-color:color-mix(in oklab, var(--color-accent) 15%, transparent)}}.hover\:bg-border\/60:hover{background-color:var(--color-border)}@supports (color:color-mix(in lab, red, red)){.hover\:bg-border\/60:hover{background-color:color-mix(in oklab, var(--color-border) 60%, transparent)}}.hover\:bg-rose-500\/10:hover{background-color:#ff23571a}@supports (color:color-mix(in lab, red, red)){.hover\:bg-rose-500\/10:hover{background-color:color-mix(in oklab, var(--color-rose-500) 10%, transparent)}}.hover\:bg-surface:hover{background-color:var(--color-surface)}.hover\:bg-surface-2:hover,.hover\:bg-surface-2\/60:hover{background-color:var(--color-surface-2)}@supports (color:color-mix(in lab, red, red)){.hover\:bg-surface-2\/60:hover{background-color:color-mix(in oklab, var(--color-surface-2) 60%, transparent)}}.hover\:bg-surface-2\/70:hover{background-color:var(--color-surface-2)}@supports (color:color-mix(in lab, red, red)){.hover\:bg-surface-2\/70:hover{background-color:color-mix(in oklab, var(--color-surface-2) 70%, transparent)}}.hover\:text-accent:hover{color:var(--color-accent)}.hover\:text-fg:hover{color:var(--color-fg)}.hover\:text-rose-500:hover{color:var(--color-rose-500)}.hover\:underline:hover{text-decoration-line:underline}.hover\:opacity-90:hover{opacity:.9}.hover\:opacity-100:hover{opacity:1}.hover\:ring-2:hover{--tw-ring-shadow:var(--tw-ring-inset,) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.hover\:ring-accent:hover,.hover\:ring-accent\/60:hover{--tw-ring-color:var(--color-accent)}@supports (color:color-mix(in lab, red, red)){.hover\:ring-accent\/60:hover{--tw-ring-color:color-mix(in oklab, var(--color-accent) 60%, transparent)}}}.focus\:border-accent:focus{border-color:var(--color-accent)}.focus\:bg-surface-2:focus{background-color:var(--color-surface-2)}.focus\:opacity-100:focus{opacity:1}.focus\:ring-2:focus{--tw-ring-shadow:var(--tw-ring-inset,) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.focus\:ring-accent\/40:focus{--tw-ring-color:var(--color-accent)}@supports (color:color-mix(in lab, red, red)){.focus\:ring-accent\/40:focus{--tw-ring-color:color-mix(in oklab, var(--color-accent) 40%, transparent)}}.focus\:outline-none:focus{--tw-outline-style:none;outline-style:none}.active\:scale-95:active{--tw-scale-x:95%;--tw-scale-y:95%;--tw-scale-z:95%;scale:var(--tw-scale-x) var(--tw-scale-y)}.active\:scale-\[0\.98\]:active{scale:.98}.active\:scale-\[0\.99\]:active{scale:.99}.active\:bg-surface-2:active,.active\:bg-surface-2\/70:active{background-color:var(--color-surface-2)}@supports (color:color-mix(in lab, red, red)){.active\:bg-surface-2\/70:active{background-color:color-mix(in oklab, var(--color-surface-2) 70%, transparent)}}.disabled\:opacity-40:disabled{opacity:.4}.disabled\:opacity-50:disabled{opacity:.5}.disabled\:opacity-60:disabled{opacity:.6}.disabled\:opacity-70:disabled{opacity:.7}@media (width>=40rem){.sm\:hidden{display:none}.sm\:max-w-lg{max-width:var(--container-lg)}.sm\:grid-cols-5{grid-template-columns:repeat(5,minmax(0,1fr))}.sm\:items-center{align-items:center}.sm\:justify-center{justify-content:center}.sm\:rounded-3xl{border-radius:var(--radius-3xl)}.sm\:rounded-\[28px\]{border-radius:28px}.sm\:border-x{border-inline-style:var(--tw-border-style);border-inline-width:1px}.sm\:border-border{border-color:var(--color-border)}}@container (width>=42rem){.\@2xl\:grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}}.dark\:border:where([data-theme=dark],[data-theme=dark] *){border-style:var(--tw-border-style);border-width:1px}.dark\:border-border:where([data-theme=dark],[data-theme=dark] *){border-color:var(--color-border)}.dark\:bg-accent\/\[0\.10\]:where([data-theme=dark],[data-theme=dark] *){background-color:var(--color-accent)}@supports (color:color-mix(in lab, red, red)){.dark\:bg-accent\/\[0\.10\]:where([data-theme=dark],[data-theme=dark] *){background-color:color-mix(in oklab, var(--color-accent) 10%, transparent)}}.dark\:bg-amber-400\/\[0\.08\]:where([data-theme=dark],[data-theme=dark] *){background-color:#fcbb0014}@supports (color:color-mix(in lab, red, red)){.dark\:bg-amber-400\/\[0\.08\]:where([data-theme=dark],[data-theme=dark] *){background-color:color-mix(in oklab, var(--color-amber-400) 8%, transparent)}}.dark\:bg-\[radial-gradient\(ellipse_at_top\,rgba\(23\,147\,255\,0\.2\)\,transparent_65\%\)\]:where([data-theme=dark],[data-theme=dark] *){background-image:radial-gradient(at top,#1793ff33,#0000 65%)}.dark\:text-amber-200:where([data-theme=dark],[data-theme=dark] *){color:var(--color-amber-200)}.dark\:text-amber-300:where([data-theme=dark],[data-theme=dark] *){color:var(--color-amber-300)}.dark\:text-cyan-300:where([data-theme=dark],[data-theme=dark] *){color:var(--color-cyan-300)}.dark\:text-emerald-300:where([data-theme=dark],[data-theme=dark] *){color:var(--color-emerald-300)}.dark\:text-emerald-400:where([data-theme=dark],[data-theme=dark] *){color:var(--color-emerald-400)}.dark\:text-fuchsia-300:where([data-theme=dark],[data-theme=dark] *){color:var(--color-fuchsia-300)}.dark\:text-orange-300:where([data-theme=dark],[data-theme=dark] *){color:var(--color-orange-300)}.dark\:text-pink-300:where([data-theme=dark],[data-theme=dark] *){color:var(--color-pink-300)}.dark\:text-red-400:where([data-theme=dark],[data-theme=dark] *){color:var(--color-red-400)}.dark\:text-rose-300:where([data-theme=dark],[data-theme=dark] *){color:var(--color-rose-300)}.dark\:text-rose-400:where([data-theme=dark],[data-theme=dark] *){color:var(--color-rose-400)}.dark\:text-sky-300:where([data-theme=dark],[data-theme=dark] *){color:var(--color-sky-300)}.dark\:text-violet-300:where([data-theme=dark],[data-theme=dark] *){color:var(--color-violet-300)}.dark\:shadow-none:where([data-theme=dark],[data-theme=dark] *){--tw-shadow:0 0 #0000;box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}@media (width>=64rem){.wide\:invisible{visibility:hidden}}:where(html.desktop) .wide\:invisible{visibility:hidden}@media (width>=64rem){.wide\:inset-y-0{inset-block:0}}:where(html.desktop) .wide\:inset-y-0{inset-block:0}@media (width>=64rem){.wide\:mt-0{margin-top:0}}:where(html.desktop) .wide\:mt-0{margin-top:0}@media (width>=64rem){.wide\:mt-5{margin-top:calc(var(--spacing) * 5)}}:where(html.desktop) .wide\:mt-5{margin-top:calc(var(--spacing) * 5)}@media (width>=64rem){.wide\:block{display:block}}:where(html.desktop) .wide\:block{display:block}@media (width>=64rem){.wide\:flex{display:flex}}:where(html.desktop) .wide\:flex{display:flex}@media (width>=64rem){.wide\:grid{display:grid}}:where(html.desktop) .wide\:grid{display:grid}@media (width>=64rem){.wide\:hidden{display:none}}:where(html.desktop) .wide\:hidden{display:none}@media (width>=64rem){.wide\:h-auto{height:auto}}:where(html.desktop) .wide\:h-auto{height:auto}@media (width>=64rem){.wide\:h-full{height:100%}}:where(html.desktop) .wide\:h-full{height:100%}@media (width>=64rem){.wide\:max-w-\[600px\]{max-width:600px}}:where(html.desktop) .wide\:max-w-\[600px\]{max-width:600px}@media (width>=64rem){.wide\:max-w-\[900px\]{max-width:900px}}:where(html.desktop) .wide\:max-w-\[900px\]{max-width:900px}@media (width>=64rem){.wide\:max-w-\[980px\]{max-width:980px}}:where(html.desktop) .wide\:max-w-\[980px\]{max-width:980px}@media (width>=64rem){.wide\:max-w-md{max-width:var(--container-md)}}:where(html.desktop) .wide\:max-w-md{max-width:var(--container-md)}@media (width>=64rem){.wide\:max-w-none{max-width:none}}:where(html.desktop) .wide\:max-w-none{max-width:none}@media (width>=64rem){.wide\:grid-cols-1{grid-template-columns:repeat(1,minmax(0,1fr))}}:where(html.desktop) .wide\:grid-cols-1{grid-template-columns:repeat(1,minmax(0,1fr))}@media (width>=64rem){.wide\:grid-cols-4{grid-template-columns:repeat(4,minmax(0,1fr))}}:where(html.desktop) .wide\:grid-cols-4{grid-template-columns:repeat(4,minmax(0,1fr))}@media (width>=64rem){.wide\:grid-cols-\[1\.1fr_1fr\]{grid-template-columns:1.1fr 1fr}}:where(html.desktop) .wide\:grid-cols-\[1\.1fr_1fr\]{grid-template-columns:1.1fr 1fr}@media (width>=64rem){.wide\:flex-row{flex-direction:row}}:where(html.desktop) .wide\:flex-row{flex-direction:row}@media (width>=64rem){.wide\:items-center{align-items:center}}:where(html.desktop) .wide\:items-center{align-items:center}@media (width>=64rem){.wide\:items-start{align-items:flex-start}}:where(html.desktop) .wide\:items-start{align-items:flex-start}@media (width>=64rem){.wide\:gap-1\.5{gap:calc(var(--spacing) * 1.5)}}:where(html.desktop) .wide\:gap-1\.5{gap:calc(var(--spacing) * 1.5)}@media (width>=64rem){.wide\:gap-16{gap:calc(var(--spacing) * 16)}}:where(html.desktop) .wide\:gap-16{gap:calc(var(--spacing) * 16)}@media (width>=64rem){.wide\:border-0{border-style:var(--tw-border-style);border-width:0}}:where(html.desktop) .wide\:border-0{border-style:var(--tw-border-style);border-width:0}@media (width>=64rem){.wide\:border-x-0{border-inline-style:var(--tw-border-style);border-inline-width:0}}:where(html.desktop) .wide\:border-x-0{border-inline-style:var(--tw-border-style);border-inline-width:0}@media (width>=64rem){.wide\:bg-transparent{background-color:#0000}}:where(html.desktop) .wide\:bg-transparent{background-color:#0000}@media (width>=64rem){.wide\:bg-\[radial-gradient\(ellipse_at_left\,rgba\(0\,100\,212\,0\.12\)\,transparent_60\%\)\]{background-image:radial-gradient(at 0,#0064d41f,#0000 60%)}}:where(html.desktop) .wide\:bg-\[radial-gradient\(ellipse_at_left\,rgba\(0\,100\,212\,0\.12\)\,transparent_60\%\)\]{background-image:radial-gradient(at 0,#0064d41f,#0000 60%)}@media (width>=64rem){.wide\:p-7{padding:calc(var(--spacing) * 7)}}:where(html.desktop) .wide\:p-7{padding:calc(var(--spacing) * 7)}@media (width>=64rem){.wide\:px-0{padding-inline:0}}:where(html.desktop) .wide\:px-0{padding-inline:0}@media (width>=64rem){.wide\:px-12{padding-inline:calc(var(--spacing) * 12)}}:where(html.desktop) .wide\:px-12{padding-inline:calc(var(--spacing) * 12)}@media (width>=64rem){.wide\:py-1{padding-block:var(--spacing)}}:where(html.desktop) .wide\:py-1{padding-block:var(--spacing)}@media (width>=64rem){.wide\:pt-0{padding-top:0}}:where(html.desktop) .wide\:pt-0{padding-top:0}@media (width>=64rem){.wide\:text-left{text-align:left}}:where(html.desktop) .wide\:text-left{text-align:left}@media (width>=64rem){.wide\:text-\[13\.5px\]{font-size:13.5px}}:where(html.desktop) .wide\:text-\[13\.5px\]{font-size:13.5px}@media (width>=64rem){.wide\:text-\[15\.5px\]{font-size:15.5px}}:where(html.desktop) .wide\:text-\[15\.5px\]{font-size:15.5px}@media (width>=64rem){.wide\:text-\[34px\]{font-size:34px}}:where(html.desktop) .wide\:text-\[34px\]{font-size:34px}@media (width>=64rem){.wide\:dark\:bg-\[radial-gradient\(ellipse_at_left\,rgba\(23\,147\,255\,0\.16\)\,transparent_60\%\)\]:where([data-theme=dark],[data-theme=dark] *){background-image:radial-gradient(at 0,#1793ff29,#0000 60%)}}:where(html.desktop) .wide\:dark\:bg-\[radial-gradient\(ellipse_at_left\,rgba\(23\,147\,255\,0\.16\)\,transparent_60\%\)\]:where([data-theme=dark],[data-theme=dark] *){background-image:radial-gradient(at 0,#1793ff29,#0000 60%)}.\[\&\+\&\]\:mt-1\.5+.\[\&\+\&\]\:mt-1\.5{margin-top:calc(var(--spacing) * 1.5)}}@font-face{font-family:Figtree;font-style:normal;font-weight:300 900;font-display:swap;src:url(/fonts/figtree-latin.woff2)format("woff2");unicode-range:U+??,U+131,U+152-153,U+2BB-2BC,U+2C6,U+2DA,U+2DC,U+304,U+308,U+329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}@font-face{font-family:Figtree;font-style:normal;font-weight:300 900;font-display:swap;src:url(/fonts/figtree-latin-ext.woff2)format("woff2");unicode-range:U+100-2BA,U+2BD-2C5,U+2C7-2CC,U+2CE-2D7,U+2DD-2FF,U+304,U+308,U+329,U+1D00-1DBF,U+1E00-1E9F,U+1EF2-1EFF,U+2020,U+20A0-20AB,U+20AD-20C0,U+2113,U+2C60-2C7F,U+A720-A7FF}:root{--om-bg:#fcfcfc;--om-surface:#fff;--om-surface-2:#f2f2f4;--om-border:#e7e7ea;--om-fg:#111112;--om-muted:#6b6b71;--om-accent:#0064d4;--om-bubble-user:#d8e9ff;--om-bubble-user-fg:#111112;--lightningcss-light:initial;--lightningcss-dark: ;color-scheme:light}html[data-theme=dark]{--om-bg:#181819;--om-surface:#202022;--om-surface-2:#2a2a2d;--om-border:#333337;--om-fg:#fff;--om-muted:#9d9da4;--om-accent:#1793ff;--om-bubble-user:#1c3d66;--om-bubble-user-fg:#fff;--lightningcss-light: ;--lightningcss-dark:initial;color-scheme:dark}html,body,#root{height:100%}body{background:var(--om-bg);color:var(--om-fg);font-family:var(--font-sans);-webkit-font-smoothing:antialiased;-webkit-tap-highlight-color:transparent;overscroll-behavior-y:none;margin:0}.safe-top{padding-top:env(safe-area-inset-top)}.titlebar-room{display:none}html.desktop[data-platform=darwin] .titlebar-room{-webkit-app-region:drag;flex-shrink:0;height:28px;display:block}.safe-bottom{padding-bottom:env(safe-area-inset-bottom)}*{scrollbar-width:thin;scrollbar-color:var(--om-border) transparent}::-webkit-scrollbar{width:6px;height:6px}::-webkit-scrollbar-thumb{background:var(--om-border);border-radius:999px}::-webkit-scrollbar-track{background:0 0}@media (pointer:coarse),(width<=480px){*{scrollbar-width:none}::-webkit-scrollbar{display:none}}.no-scrollbar::-webkit-scrollbar{display:none}.no-scrollbar{scrollbar-width:none}.md>:first-child{margin-top:0}.md>:last-child{margin-bottom:0}.md p{margin:.35em 0}.md ul,.md ol{margin:.35em 0;padding-left:1.3em}.md ul{list-style:outside}.md ol{list-style:decimal}.md li{margin:.15em 0}.md h1,.md h2,.md h3,.md h4{margin:.7em 0 .3em;font-weight:650;line-height:1.3}.md h1{font-size:1.15em}.md h2{font-size:1.08em}.md h3,.md h4{font-size:1em}.md a{color:var(--om-accent);text-underline-offset:2px;word-break:break-all;text-decoration:underline}.bubble-user .md a{color:var(--om-accent)}.md code{background:#7f7fa029;border-radius:6px;padding:.1em .35em;font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;font-size:.86em}.md pre{color:#eaeaf5;background:#0f0f19e6;border-radius:12px;margin:.5em 0;padding:.7em .85em;font-size:.82em;line-height:1.45;overflow-x:auto}.md pre code{font-size:inherit;background:0 0;padding:0}.md .md-file{color:var(--om-accent);background:var(--om-accent);font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;font-size:.86em}@supports (color:color-mix(in lab, red, red)){.md .md-file{background:color-mix(in srgb, var(--om-accent) 12%, transparent)}}.md .md-file{text-underline-offset:2px;word-break:break-all;border-radius:6px;padding:.1em .4em;-webkit-text-decoration:underline dotted;text-decoration:underline dotted}.md blockquote{border-left:3px solid var(--om-border);color:var(--om-muted);margin:.5em 0;padding-left:.8em}.md table{border-collapse:collapse;max-width:100%;margin:.5em 0;font-size:.9em;display:block;overflow-x:auto}.md th,.md td{border:1px solid var(--om-border);text-align:left;padding:.3em .55em}.md hr{border:0;border-top:1px solid var(--om-border);margin:.7em 0}.md img{border-radius:10px;max-width:100%}@keyframes om-breathe{0%,to{transform:translateY(0)scale(1)}50%{transform:translateY(-1.5%)scale(1.025)}}@keyframes om-sway{0%,to{transform:rotate(-4deg)translateY(0)}25%{transform:rotate(0)translateY(-2%)}50%{transform:rotate(4deg)translateY(0)}75%{transform:rotate(0)translateY(-2%)}}@keyframes om-hop{0%,70%,to{transform:translateY(0)scale(1)}78%{transform:translateY(-9%)scale(1.04,.97)}86%{transform:translateY(0)scale(.98,1.03)}92%{transform:translateY(-3%)scale(1)}}@keyframes om-wiggle{0%,to{transform:rotate(0)}20%{transform:rotate(-10deg)scale(1.06)}45%{transform:rotate(9deg)scale(1.06)}70%{transform:rotate(-5deg)}}.avatar-idle{animation:4.5s ease-in-out infinite om-breathe}.avatar-working{animation:2.6s ease-in-out infinite om-sway}.avatar-waiting{animation:3.2s ease-in-out infinite om-hop}.avatar-wiggle{animation:.6s ease-in-out om-wiggle}@keyframes om-pop{0%{transform:scale(.6)}70%{transform:scale(1.06)}to{transform:scale(1)}}.avatar-pop{animation:.55s cubic-bezier(.34,1.56,.64,1) om-pop}@media (prefers-reduced-motion:reduce){.avatar-idle,.avatar-working,.avatar-waiting,.avatar-wiggle,.avatar-pop{animation:none}}@keyframes om-blink{50%{opacity:.25}}.typing-dot{animation:1.1s infinite om-blink}.typing-dot:nth-child(2){animation-delay:.18s}.typing-dot:nth-child(3){animation-delay:.36s}@keyframes om-rise{0%{opacity:0;transform:translateY(6px)}to{opacity:1;transform:none}}.rise{animation:.18s ease-out om-rise}@keyframes om-sheet{0%{transform:translateY(100%)}to{transform:none}}.sheet-in{animation:.22s cubic-bezier(.2,.8,.2,1) om-sheet}@keyframes om-drawer-in{0%{transform:translate(-100%)}to{transform:none}}.drawer-in{animation:.2s ease-out om-drawer-in}@property --tw-border-spacing-x{syntax:"";inherits:false;initial-value:0}@property --tw-border-spacing-y{syntax:"";inherits:false;initial-value:0}@property --tw-translate-x{syntax:"*";inherits:false;initial-value:0}@property --tw-translate-y{syntax:"*";inherits:false;initial-value:0}@property --tw-translate-z{syntax:"*";inherits:false;initial-value:0}@property --tw-space-y-reverse{syntax:"*";inherits:false;initial-value:0}@property --tw-divide-y-reverse{syntax:"*";inherits:false;initial-value:0}@property --tw-border-style{syntax:"*";inherits:false;initial-value:solid}@property --tw-gradient-position{syntax:"*";inherits:false}@property --tw-gradient-from{syntax:"";inherits:false;initial-value:#0000}@property --tw-gradient-via{syntax:"";inherits:false;initial-value:#0000}@property --tw-gradient-to{syntax:"";inherits:false;initial-value:#0000}@property --tw-gradient-stops{syntax:"*";inherits:false}@property --tw-gradient-via-stops{syntax:"*";inherits:false}@property --tw-gradient-from-position{syntax:"";inherits:false;initial-value:0%}@property --tw-gradient-via-position{syntax:"";inherits:false;initial-value:50%}@property --tw-gradient-to-position{syntax:"";inherits:false;initial-value:100%}@property --tw-leading{syntax:"*";inherits:false}@property --tw-font-weight{syntax:"*";inherits:false}@property --tw-tracking{syntax:"*";inherits:false}@property --tw-ordinal{syntax:"*";inherits:false}@property --tw-slashed-zero{syntax:"*";inherits:false}@property --tw-numeric-figure{syntax:"*";inherits:false}@property --tw-numeric-spacing{syntax:"*";inherits:false}@property --tw-numeric-fraction{syntax:"*";inherits:false}@property --tw-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-shadow-color{syntax:"*";inherits:false}@property --tw-shadow-alpha{syntax:"";inherits:false;initial-value:100%}@property --tw-inset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-shadow-color{syntax:"*";inherits:false}@property --tw-inset-shadow-alpha{syntax:"";inherits:false;initial-value:100%}@property --tw-ring-color{syntax:"*";inherits:false}@property --tw-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-ring-color{syntax:"*";inherits:false}@property --tw-inset-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-ring-inset{syntax:"*";inherits:false}@property --tw-ring-offset-width{syntax:"";inherits:false;initial-value:0}@property --tw-ring-offset-color{syntax:"*";inherits:false;initial-value:#fff}@property --tw-ring-offset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-blur{syntax:"*";inherits:false}@property --tw-brightness{syntax:"*";inherits:false}@property --tw-contrast{syntax:"*";inherits:false}@property --tw-grayscale{syntax:"*";inherits:false}@property --tw-hue-rotate{syntax:"*";inherits:false}@property --tw-invert{syntax:"*";inherits:false}@property --tw-opacity{syntax:"*";inherits:false}@property --tw-saturate{syntax:"*";inherits:false}@property --tw-sepia{syntax:"*";inherits:false}@property --tw-drop-shadow{syntax:"*";inherits:false}@property --tw-drop-shadow-color{syntax:"*";inherits:false}@property --tw-drop-shadow-alpha{syntax:"";inherits:false;initial-value:100%}@property --tw-drop-shadow-size{syntax:"*";inherits:false}@property --tw-backdrop-blur{syntax:"*";inherits:false}@property --tw-backdrop-brightness{syntax:"*";inherits:false}@property --tw-backdrop-contrast{syntax:"*";inherits:false}@property --tw-backdrop-grayscale{syntax:"*";inherits:false}@property --tw-backdrop-hue-rotate{syntax:"*";inherits:false}@property --tw-backdrop-invert{syntax:"*";inherits:false}@property --tw-backdrop-opacity{syntax:"*";inherits:false}@property --tw-backdrop-saturate{syntax:"*";inherits:false}@property --tw-backdrop-sepia{syntax:"*";inherits:false}@property --tw-scale-x{syntax:"*";inherits:false;initial-value:1}@property --tw-scale-y{syntax:"*";inherits:false;initial-value:1}@property --tw-scale-z{syntax:"*";inherits:false;initial-value:1}@keyframes spin{to{transform:rotate(360deg)}}@keyframes pulse{50%{opacity:.5}} diff --git a/nanomuse/server/static/index.html b/nanomuse/server/static/index.html index 794872b3d..b5389e5ca 100644 --- a/nanomuse/server/static/index.html +++ b/nanomuse/server/static/index.html @@ -25,13 +25,13 @@ nanoMuse - + - +
diff --git a/web/src/App.tsx b/web/src/App.tsx index 55a4efd13..00528a0ae 100644 --- a/web/src/App.tsx +++ b/web/src/App.tsx @@ -41,7 +41,7 @@ function Loading() { ); } -/** The five glyphs: outlined at rest, filled with the page's ink when selected — the fill is the state. */ +/** The five glyphs: outlined at rest, filled with the button's own ink when selected. The fill is the state. */ const glyph = (active: boolean) => ({ size: 26, strokeWidth: active ? 2 : 1.7, fill: active ? "currentColor" : "none", fillOpacity: active ? 0.18 : 0 }); const TABS: Array<{ id: Tab; label: string; icon: (active: boolean) => ReactNode }> = [ { id: "chat", label: "Chat", icon: (a) => }, @@ -129,7 +129,7 @@ export default function App() { )} -
+
{state.gone && (
{t(state.lite ? "This demo has ended." : "This nanoMuse has stopped. Reload the page once it is running again.")} @@ -141,7 +141,9 @@ export default function App() {
)} {!state.lite && } -
+ {/* `tabbar-room` keeps the screens, the chat's composer included, above the floating bar; + a wide window has the sidebar instead and gives the room back. */} +
}> {state.tab === "chat" && } {state.tab === "feed" && } @@ -159,11 +161,15 @@ export default function App() { {state.tab === "avatar" && }
- {/* Muse's bottom bar, as the Android app draws it: a plain strip, five glyphs, the current one - filled and dark, the others outlined and softer — no labels, no pill. In lite (the phone in - the showcase) it shows whatever the width; otherwise a wide window has the sidebar instead. */} -
{/* Muse's bottom bar, as the Android app draws it: a floating frosted-glass pill, five glyphs, icons only. The pill sits 12px above the bottom edge, blurs what is behind it and carries - a hairline edge; the current tab shows its filled glyph on a soft blue indicator, the - others stay outlined in the muted grey. No labels: the fill and the indicator are the + a hairline edge; the current tab shows its filled glyph on an ink indicator (black in the + light theme, white in the dark one, the glyph in the opposite colour), the others stay + outlined in the muted grey. No labels: the fill and the indicator are the state. The pill is as wide as the chat's composer above it (the same 12px from the sides, `px-3` on the Composer's form), 420px at most and centred on a wider screen; the five slots share it equally and the indicator disc keeps its 60 by 46 inside the slot. In lite @@ -182,9 +183,9 @@ export default function App() { onClick={() => setTab(tab.id)} aria-label={t(tab.label)} aria-current={active ? "page" : undefined} - className={cx("flex h-[46px] w-full items-center justify-center", active ? "text-accent-soft-fg" : "text-muted hover:text-fg")} + className={cx("flex h-[46px] w-full items-center justify-center", active ? "text-ink-fg" : "text-muted hover:text-fg")} > - + {tab.icon(active)} {badge > 0 && ( From 9612d2ca0444b26ff8b226b21135834f96a5eaca Mon Sep 17 00:00:00 2001 From: lgy0404 <2528379691@qq.com> Date: Sun, 11 Oct 2026 23:47:51 +0800 Subject: [PATCH 52/98] feat(runtime): a list of custom OpenAI-compatible endpoints behind the model slots The single "Other OpenAI-compatible endpoint" slot the web console wrote meant a second gateway replaced the first and its key. The runtime now keeps a list of custom endpoints in app-settings.json ("endpoints": id, label, base URL, the models it serves, and the key as a vault reference of its own, ENDPOINT__API_KEY), served and changed through POST / PUT / DELETE /api/connections/endpoints and POST /api/connections/endpoints/{id}/models. The chat, hands, picture and clip setters take "endpoint" in place of an address and a key, so the console never handles vault names; a rename, a new key or a new address reaches every slot that uses the endpoint, and removing one is refused while the chat model answers through it. A chat model set from the app on a host the catalogue does not list is moved into the list once, on the next start: the same address as endpoint number one, its key copied to the endpoint's own vault entry and the slot pointed at that entry, nothing asked. A slot from config.toml or on a catalogue host is left alone. Tests cover the helpers, add / set / rename / rekey / move / remove, the saved-list fallback of /api/llm/models, and the one-time migration, with the model listing faked and no network. Docs: the API table and the configuration page, in English and Chinese. For #294 Signed-off-by: lgy0404 <2528379691@qq.com> --- CHANGELOG.md | 1 + docs/app.md | 12 +- docs/configuration.md | 2 +- docs/zh/app.md | 12 +- docs/zh/configuration.md | 2 +- nanomuse/server/api.py | 62 +++++- nanomuse/server/connections.py | 154 ++++++++++---- nanomuse/server/endpoints.py | 370 +++++++++++++++++++++++++++++++++ tests/test_endpoints_api.py | 317 ++++++++++++++++++++++++++++ 9 files changed, 879 insertions(+), 53 deletions(-) create mode 100644 nanomuse/server/endpoints.py create mode 100644 tests/test_endpoints_api.py diff --git a/CHANGELOG.md b/CHANGELOG.md index f36ab756d..11f6d6c26 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,7 @@ All notable changes to nanoMuse. The format follows [Keep a Changelog](https://k ### Runtime - **OpenCode Go is in the own-key catalogue, and the runtime tells it which conversation a call belongs to.** Go ($10 a month, Go Plus $40) is the subscription beside Zen on `https://opencode.ai/zen/go/v1`, a key from [opencode.ai/auth](https://opencode.ai/auth). OpenCode asks a client to name itself and to send one stable id per conversation in `x-opencode-session`. A catalogue entry can now name such a header (`session_header`); for one that does, the chat clients send `nanoMuse/` as the user agent (unless `extra_headers` sets one) and the header on every request, with the conversation's id while the agent loop works on a turn (the hands' model included) and an id of the client's own for a call outside a conversation. A slot that points an OpenAI-shaped provider at Go's address gets the same. Chat only, on the OpenAI shape, as with Zen (thanks @PovedaAqui). +- **Several custom OpenAI-compatible endpoints at once.** The runtime keeps a list of them in `app-settings.json` (`endpoints`: id, name, address, the models it serves, and its key in the vault as `ENDPOINT__API_KEY`) in place of the single *Other OpenAI-compatible endpoint* slot, so adding a gateway no longer replaces the one before. `POST`, `PUT` and `DELETE /api/connections/endpoints` add, change and remove an entry, `POST /api/connections/endpoints/{id}/models` asks it for its models again, and `PUT /api/connections/llm`, `/gui`, `/image` and `/video` take `endpoint` instead of an address and a key; a rename, a new key or a new address reaches every slot that uses the endpoint, and removing one is refused while the chat model answers through it. A chat model set from the app on an unlisted host becomes endpoint number one on the next start, its key copied to the endpoint's own vault entry, nothing asked (reported by @Alasco123, #294). - **The web tools' tests no longer depend on the machine's resolver.** The fetch tests use hosts under the reserved `.example` domain, and the SSRF guard asks DNS about a host before the mocked transport sees the request; on a resolver that answers unknown names with `127.0.0.1` or `0.0.0.0` instead of "no such name", the guard refused `shop.example` and three tests failed. The test suite now answers every `.example` host itself with a fixed public address, and a new test checks that `localhost` and `.internal` names are still refused without asking DNS at all. The guard in the runtime is unchanged (reported by @Mola-maker, #339). ### Web diff --git a/docs/app.md b/docs/app.md index 180026187..b642d264a 100644 --- a/docs/app.md +++ b/docs/app.md @@ -167,10 +167,14 @@ Everything the app does goes through this API, so another front-end (a Telegram | POST | `/api/hooks/{id}?key=` | a trigger's webhook: no app token, the key is the credential (also accepted as `X-Hook-Key`); the body (≤ 64 KB, JSON pretty-printed) is the context. 404 for a wrong id or key, 409 once cancelled, 429 when deliveries come too close | | GET | `/api/files` · `/api/files/{path}?download=1` | list / read workspace files (HTML and SVG are served with `Content-Security-Policy: sandbox`) | | GET / PUT | `/api/settings` | view / change `{profile{name (≤ 20), avatar, emoji, color, tagline (≤ 60), tone, communication, style, user_name, proactive, goal_interval_minutes}, sentinel_mode, show_thinking, language}`; the view includes `onboarded` and `llm_ready` | -| GET | `/api/connections` | model (`key_source`: vault · config · missing · none), provider presets, email, browser, MCP servers (`connected`, `tools`, `from_app`), vault names, `onboarded` | -| PUT | `/api/connections/llm` `{provider, model, base_url, tool_mode, api_key}` | change the model; `api_key` set → stored in the vault, `""` → no key, omitted → unchanged. Takes effect immediately in every thread | +| GET | `/api/connections` | model (`key_source`: vault · config · missing · none; `endpoint` when it is one of the list), provider presets, `endpoints` (the custom OpenAI-compatible endpoints of the list, each `{id, label, base_url, key_source, models, slots}`, never a key), email, browser, MCP servers (`connected`, `tools`, `from_app`), vault names, `onboarded` | +| PUT | `/api/connections/llm` `{provider, model, base_url, tool_mode, api_key}` or `{endpoint, model, tool_mode}` | change the model; `api_key` set → stored in the vault, `""` → no key, omitted → unchanged. `endpoint` names one of the list, which lends the slot its address and its own key by reference. Takes effect immediately in every thread | | POST | `/api/connections/llm/test` | one short round trip to the model: `{ok, reply, ms}` or `{ok: false, error}` | -| POST | `/api/llm/models` `{preset, base_url, api_key}` | the models an endpoint offers: its `/models` (then `/v1/models`) with the given key (or, without one, the key in the vault), returning `{models, source: "live"}`; when it cannot be reached, the preset's catalogue with `source: "catalogue"` and `error`. Saves nothing | +| POST | `/api/llm/models` `{preset, base_url, api_key}` or `{endpoint}` | the models an endpoint offers: its `/models` (then `/v1/models`) with the given key (or, without one, the key in the vault), returning `{models, source: "live"}`; when it cannot be reached, the preset's catalogue with `source: "catalogue"` and `error`, or, for an `endpoint` of the list, the models saved with it. Saves nothing | +| POST | `/api/connections/endpoints` `{label, base_url, api_key, models}` | add a custom OpenAI-compatible endpoint to the list (#294): `label` optional (the host otherwise), `api_key` optional (vault: `ENDPOINT__API_KEY`), `models` the ids it serves, comma-separated, when it does not list them (400 with a sentence when neither is there). Answers the entry; the address of nanoMuse Cloud or of a catalogue preset is refused | +| PUT | `/api/connections/endpoints/{id}` `{label, base_url, api_key, models}` | change an endpoint: a new name, address, key (`""` removes it) or typed models; omitted fields stay. Every slot that uses the endpoint follows. 404 for an unknown id | +| DELETE | `/api/connections/endpoints/{id}` | remove an endpoint and its vault key; hands, pictures or clips set on it go back to automatic. 409 while the chat model answers through it | +| POST | `/api/connections/endpoints/{id}/models` | ask the endpoint for its models again and save them: the entry plus `source: "live"`, or `"kept"` with `error` when it did not answer and the saved list stands | | PUT | `/api/connections/embeddings` `{mode, model, base_url, api_key}` | recall by meaning: `mode` auto/on/off; `base_url` `""` → the model's endpoint; `model` `""` → the endpoint's default; `api_key` set → vault (`EMBEDDINGS_API_KEY`), `""` → the model's key, omitted → unchanged. Rebuilds the embedder on the spot | | POST | `/api/connections/embeddings/test` | one embeddings call, then every memory indexed: `{ok, model, dims, indexed, ms}` or `{ok: false, error}` | | PUT | `/api/connections/search` `{provider, api_key, base_url}` | web search: `provider` duckduckgo/brave/tavily/searxng; `api_key` set → vault (`SEARCH_API_KEY`), `""` removes it, omitted → unchanged; `base_url` the SearXNG instance. Applies to the next search | @@ -187,7 +191,7 @@ Everything the app does goes through this API, so another front-end (a Telegram | POST | `/api/connections/contacts/test` | re-read every book: `{ok, contacts, sources}` or `{ok: false, error}` | | GET | `/api/contacts?q=&limit=` | look people up as the agent does: `[{id, name, emails[], phones[], org, …}]` | | PUT | `/api/connections/browser` `{enabled}` | turn the browser tool on or off | -| PUT | `/api/connections/gui` `{enabled, provider, model, base_url, api_key}` | operating the phone ([gui.md](gui.md)): the switch adds or removes the phone tools at once; the model fields are the operator's own model (`""` → the main model's); `api_key` set → vault (`GUI_API_KEY`), `""` → the main key, omitted → unchanged | +| PUT | `/api/connections/gui` `{enabled, provider, model, base_url, api_key}` | operating the phone ([gui.md](gui.md)): the switch adds or removes the phone tools at once; the model fields are the operator's own model (`""` → the main model's); `api_key` set → vault (`GUI_API_KEY`), `""` → the main key, omitted → unchanged. `endpoint` instead of `provider` / `base_url` / `api_key` names an endpoint of the list, as for the chat model; so do `PUT /api/connections/image` and `/video` | | POST | `/api/connections/gui/test` | one short round trip to the operator's model: `{ok, reply, ms}` or `{ok: false, error}` | | GET | `/api/phone` | `{connected, device{id, name, platform, gui, apps, width, height}, gui_enabled, last_screen, screen}`: which phone is connected and the last screen it sent | | POST · DELETE | `/api/connections/mcp` `{name, command, args[], env{}, url, risk}` · `/api/connections/mcp/{name}` | connect a server now (502 if it does not come up) / disconnect and remove one added from the app | diff --git a/docs/configuration.md b/docs/configuration.md index 6b816e6dc..1a08b2f1b 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -82,7 +82,7 @@ Provider recipes: | vLLM / LM Studio | your served name | `http://localhost:8000/v1` | set `tool_mode = "prompt"` if the server ignores `tools` | | Company gateway | as required | as required | use `extra_headers` / `extra_body`; pick the provider by the API shape the gateway speaks | -The same presets are offered in the web console (*Connections → Chat model*, and on first run), each with a link to where its key comes from; the exact hostnames live in `PROVIDERS` in `nanomuse/server/connections.py`. A `base_url` saved from the app that has no path gains `/v1` (`http://host:8000` → `http://host:8000/v1`); the presets' own hosts are kept as they are. Ollama and custom endpoints may have no key. +The same presets are offered in the web console (*Connections → Chat model*, and on first run), each with a link to where its key comes from; the exact hostnames live in `PROVIDERS` in `nanomuse/server/connections.py`. A `base_url` saved from the app that has no path gains `/v1` (`http://host:8000` → `http://host:8000/v1`); the presets' own hosts are kept as they are. Ollama and custom endpoints may have no key. Custom endpoints added from the web console are a list (`endpoints` in `app-settings.json`, each `{id, label, base_url, api_key, models}` with the key in the vault as `ENDPOINT__API_KEY`); a slot set on one of them carries its address and that vault reference, so this file never needs to know about the list ([web.md](web.md#where-it-shows)). A `[llm]` chat model set here on an unlisted host stays as it is; only one set from the app is moved into the list. `provider` may also be an id from the provider catalogue, [`nanomuse/llm/providers.json`](../nanomuse/llm/providers.json) (`bailian`, `deepseek`, `moonshot`, `zhipu`, `openrouter`, `openai`, `gemini`, …), in which case `base_url` and, when empty, `model` fill in from the catalogue and only `api_key` is yours. The catalogue also says what each provider's key covers (chat, the hands, pictures, clips); `GET /api/providers` on the server reports which slots use which provider and what that leaves uncovered, and the app shows one sentence for a feature nothing covers ([own-key.md](own-key.md)). diff --git a/docs/zh/app.md b/docs/zh/app.md index cc0fdf180..a3c9d6619 100644 --- a/docs/zh/app.md +++ b/docs/zh/app.md @@ -165,10 +165,14 @@ Meta 的 Muse「自己会做事,但不会做太多」。「设置」里的*主 | POST | `/api/hooks/{id}?key=` | 触发器的 webhook:不要应用令牌,key 就是凭据(也接受 `X-Hook-Key` 头);请求体(≤ 64 KB,JSON 会格式化)就是上下文。id 或 key 错了返回 404,已取消返回 409,投递太密返回 429 | | GET | `/api/files` · `/api/files/{path}?download=1` | 列出 / 读取工作区文件(HTML 和 SVG 带着 `Content-Security-Policy: sandbox` 返回) | | GET / PUT | `/api/settings` | 查看 / 修改 `{profile{name (≤ 20), avatar, emoji, color, tagline (≤ 60), tone, communication, style, user_name, proactive, goal_interval_minutes}, sentinel_mode, show_thinking, language}`;查看时还包含 `onboarded` 和 `llm_ready` | -| GET | `/api/connections` | 模型(`key_source`:vault · config · missing · none)、服务商预设、邮件、浏览器、MCP 服务器(`connected`、`tools`、`from_app`)、保险库里的名字、`onboarded` | -| PUT | `/api/connections/llm` `{provider, model, base_url, tool_mode, api_key}` | 换模型;`api_key` 给了 → 存进保险库,`""` → 不用 key,没给 → 不变。在每个会话里立即生效 | +| GET | `/api/connections` | 模型(`key_source`:vault · config · missing · none;是列表里的接口时带 `endpoint`)、服务商预设、`endpoints`(列表里的自定义 OpenAI 兼容接口,每个是 `{id, label, base_url, key_source, models, slots}`,从不带 key)、邮件、浏览器、MCP 服务器(`connected`、`tools`、`from_app`)、保险库里的名字、`onboarded` | +| PUT | `/api/connections/llm` `{provider, model, base_url, tool_mode, api_key}` 或 `{endpoint, model, tool_mode}` | 换模型;`api_key` 给了 → 存进保险库,`""` → 不用 key,没给 → 不变。`endpoint` 指向列表里的一个接口,槽位借用它的地址和它自己的 key(按引用)。在每个会话里立即生效 | | POST | `/api/connections/llm/test` | 和模型来一次简短往返:`{ok, reply, ms}` 或 `{ok: false, error}` | -| POST | `/api/llm/models` `{preset, base_url, api_key}` | 一个端点提供的模型:查它的 `/models`(然后 `/v1/models`),用给定的 key,没给就用保险库里的,返回 `{models, source: "live"}`;连不上时返回预设的内置目录,带 `source: "catalogue"` 和 `error`。什么都不保存 | +| POST | `/api/llm/models` `{preset, base_url, api_key}` 或 `{endpoint}` | 一个端点提供的模型:查它的 `/models`(然后 `/v1/models`),用给定的 key,没给就用保险库里的,返回 `{models, source: "live"}`;连不上时返回预设的内置目录,带 `source: "catalogue"` 和 `error`;对列表里的 `endpoint` 则返回随它保存的模型。什么都不保存 | +| POST | `/api/connections/endpoints` `{label, base_url, api_key, models}` | 往列表里添加一个自定义 OpenAI 兼容接口(#294):`label` 可选(不填就用主机名),`api_key` 可选(保险库:`ENDPOINT__API_KEY`),`models` 是它提供的模型 id,逗号分隔,在它列不出模型时填(两者都没有时回 400 和一句话)。返回这个条目;nanoMuse Cloud 或目录预设的地址会被拒绝 | +| PUT | `/api/connections/endpoints/{id}` `{label, base_url, api_key, models}` | 修改一个接口:新名字、新地址、新 key(`""` 删掉)或手填的模型;没给的字段不变。用到这个接口的每个槽位一起跟着变。id 不存在回 404 | +| DELETE | `/api/connections/endpoints/{id}` | 移除一个接口和它在保险库里的 key;设在它上面的双手、图片或短片回到自动。对话模型正通过它回答时回 409 | +| POST | `/api/connections/endpoints/{id}/models` | 重新向接口要一遍模型并保存:返回条目加 `source: "live"`,它没回答时是 `"kept"` 和 `error`,沿用已保存的列表 | | PUT | `/api/connections/embeddings` `{mode, model, base_url, api_key}` | 按含义召回:`mode` 为 auto/on/off;`base_url` 为 `""` → 用模型的端点;`model` 为 `""` → 用端点的默认值;`api_key` 给了 → 保险库(`EMBEDDINGS_API_KEY`),`""` → 用模型的 key,没给 → 不变。当场重建向量模型 | | POST | `/api/connections/embeddings/test` | 调一次向量接口,然后给每条记忆建索引:`{ok, model, dims, indexed, ms}` 或 `{ok: false, error}` | | PUT | `/api/connections/search` `{provider, api_key, base_url}` | 网页搜索:`provider` 为 duckduckgo/brave/tavily/searxng;`api_key` 给了 → 保险库(`SEARCH_API_KEY`),`""` 删掉它,没给 → 不变;`base_url` 是 SearXNG 实例。从下一次搜索起生效 | @@ -185,7 +189,7 @@ Meta 的 Muse「自己会做事,但不会做太多」。「设置」里的*主 | POST | `/api/connections/contacts/test` | 把每本通讯录重读一遍:`{ok, contacts, sources}` 或 `{ok: false, error}` | | GET | `/api/contacts?q=&limit=` | 按智能体的方式查人:`[{id, name, emails[], phones[], org, …}]` | | PUT | `/api/connections/browser` `{enabled}` | 打开或关闭浏览器工具 | -| PUT | `/api/connections/gui` `{enabled, provider, model, base_url, api_key}` | 操作手机([gui.md](gui.md)):这个开关立刻添加或移除手机工具;模型字段是操作器自己的模型(`""` → 用主模型的);`api_key` 给了 → 保险库(`GUI_API_KEY`),`""` → 用主 key,没给 → 不变 | +| PUT | `/api/connections/gui` `{enabled, provider, model, base_url, api_key}` | 操作手机([gui.md](gui.md)):这个开关立刻添加或移除手机工具;模型字段是操作器自己的模型(`""` → 用主模型的);`api_key` 给了 → 保险库(`GUI_API_KEY`),`""` → 用主 key,没给 → 不变。用 `endpoint` 代替 `provider` / `base_url` / `api_key` 时指向列表里的一个接口,和对话模型一样;`PUT /api/connections/image` 和 `/video` 也是 | | POST | `/api/connections/gui/test` | 和操作器的模型来一次简短往返:`{ok, reply, ms}` 或 `{ok: false, error}` | | GET | `/api/phone` | `{connected, device{id, name, platform, gui, apps, width, height}, gui_enabled, last_screen, screen}`:哪台手机连着,以及它最后发来的屏幕 | | POST · DELETE | `/api/connections/mcp` `{name, command, args[], env{}, url, risk}` · `/api/connections/mcp/{name}` | 现在就连接一个服务器(起不来返回 502)/ 断开并移除一个从应用里添加的 | diff --git a/docs/zh/configuration.md b/docs/zh/configuration.md index 7041da828..633c9403a 100644 --- a/docs/zh/configuration.md +++ b/docs/zh/configuration.md @@ -82,7 +82,7 @@ video_base_url = "" # the asynchronous video API when it is not o | vLLM / LM Studio | 你起的服务名 | `http://localhost:8000/v1` | 服务器不理会 `tools` 的话,设 `tool_mode = "prompt"` | | 公司网关 | 按要求 | 按要求 | 用 `extra_headers` / `extra_body`;按网关说的 API 形状来选 provider | -网页控制台提供同一组预设(「连接 → 对话模型」,以及第一次打开时),每个都带一个链接,指向它的 key 从哪里领;确切的主机名在 `nanomuse/server/connections.py` 的 `PROVIDERS` 里。从 App 保存的 `base_url` 如果没有路径,会补上 `/v1`(`http://host:8000` → `http://host:8000/v1`);预设自带的主机原样保留。Ollama 和自定义端点可以没有 key。 +网页控制台提供同一组预设(「连接 → 对话模型」,以及第一次打开时),每个都带一个链接,指向它的 key 从哪里领;确切的主机名在 `nanomuse/server/connections.py` 的 `PROVIDERS` 里。从 App 保存的 `base_url` 如果没有路径,会补上 `/v1`(`http://host:8000` → `http://host:8000/v1`);预设自带的主机原样保留。Ollama 和自定义端点可以没有 key。从网页控制台添加的自定义接口是一个列表(`app-settings.json` 里的 `endpoints`,每项是 `{id, label, base_url, api_key, models}`,key 以 `ENDPOINT__API_KEY` 存在保险库里);设在其中一个接口上的槽位带着它的地址和那个保险库引用,所以这个文件不需要知道列表的存在([web.md](web.md#where-it-shows))。在这里设在目录外主机上的 `[llm]` 对话模型保持原样;只有从 App 里设的那个会搬进列表。 `provider` 也可以是服务商目录 [`nanomuse/llm/providers.json`](../../nanomuse/llm/providers.json) 里的一个 id(`bailian`、`deepseek`、`moonshot`、`zhipu`、`openrouter`、`openai`、`gemini`……),这时 `base_url` 以及(为空时的)`model` 从目录里填上,只有 `api_key` 是你自己的。目录还写明每家服务商的 key 覆盖什么(聊天、手、图片、短视频);服务器上的 `GET /api/providers` 报告每个槽位用的是哪家服务商、还剩哪些没被覆盖,App 对一项没人覆盖的功能只显示一句话([own-key.md](own-key.md))。 diff --git a/nanomuse/server/api.py b/nanomuse/server/api.py index 38a184822..b6a5b4adc 100644 --- a/nanomuse/server/api.py +++ b/nanomuse/server/api.py @@ -27,6 +27,8 @@ PUT /api/connections/gui the hands' model (a protocol or a catalogue id, as for llm) POST /api/connections/gui/test GET|PUT /api/connections/image|video where pictures and clips come from: provider (a catalogue id), model, base_url, api_key POST /api/llm/models the models an endpoint offers (live /models, else the catalogue) + POST /api/connections/endpoints {label,base_url,api_key,models} PUT|DELETE /api/connections/endpoints/{id} + POST /api/connections/endpoints/{id}/models custom OpenAI-compatible endpoints, several at once (#294) GET /api/providers (?lang=en|zh®ion=cn|global) the provider catalogue, which slots use which, what that covers POST /api/chatgpt/login GET /api/chatgpt/status GET /api/chatgpt/usage POST /api/chatgpt/callback {url} POST /api/chatgpt/logout @@ -195,24 +197,43 @@ class LLMBody(BaseModel): api_key: str | None = None # `[llm] proxy`: http(s):// or socks5(h):// for this slot's requests only; "" clears it proxy: str | None = None + # one of the endpoint list (#294): the slot takes its address and its key; provider, + # base_url and api_key in the body are then ignored + endpoint: str | None = None class MediaBody(BaseModel): """One of the ``image`` / ``video`` slots. ``provider`` is a catalogue id, or ``openai`` / ``openai_responses`` with a ``base_url``; ``model`` empty means the catalogue's default; ``api_key`` goes into the vault, "" removes it, None keeps it. All four "" clears the - slot: pictures (clips) come from the chat provider again, or the account.""" + slot: pictures (clips) come from the chat provider again, or the account. ``endpoint`` + names one of the endpoint list instead of a provider (#294).""" provider: str | None = None model: str | None = None base_url: str | None = None api_key: str | None = None + endpoint: str | None = None class LLMModelsBody(BaseModel): preset: str = "" base_url: str = "" api_key: str = "" + # one of the endpoint list (#294): its address and its own key + endpoint: str = "" + + +class EndpointBody(BaseModel): + """A custom OpenAI-compatible endpoint of the list (#294). ``base_url`` is required to + add one; ``label`` empty means the host name; ``api_key`` goes into the vault, "" means + no key (a local server), None keeps it; ``models`` are the ids the person typed, for an + endpoint that does not list its own (a string with commas, or a list).""" + + label: str | None = Field(default=None, max_length=200) + base_url: str | None = Field(default=None, max_length=2000) + api_key: str | None = Field(default=None, max_length=4000) + models: str | list[str] | None = None class ChatGptCallbackBody(BaseModel): @@ -928,6 +949,45 @@ async def llm_models(body: LLMModelsBody) -> dict[str, Any]: """The models an endpoint offers (its /models, else the preset's catalogue); saves nothing.""" return await conn.llm_models(body.model_dump()) + # ------------------------------------------------------------------ endpoints (#294) + @app.post("/api/connections/endpoints", dependencies=dep) + async def add_endpoint(body: EndpointBody) -> dict[str, Any]: + """A custom OpenAI-compatible endpoint added to the list: its models are asked for + (``GET /models``) unless typed; 400 when there is neither.""" + try: + return await conn.endpoints.add(body.model_dump(exclude_none=True)) + except ValueError as exc: + raise HTTPException(400, str(exc)) from exc + + @app.put("/api/connections/endpoints/{endpoint_id}", dependencies=dep) + async def update_endpoint(endpoint_id: str, body: EndpointBody) -> dict[str, Any]: + """Rename, change the key or the address, retype the models; the slots that use the + endpoint follow a new address or key.""" + try: + return await conn.endpoints.update(endpoint_id, body.model_dump(exclude_none=True)) + except ValueError as exc: + status = 404 if str(exc).startswith("no endpoint") else 400 + raise HTTPException(status, str(exc)) from exc + + @app.delete("/api/connections/endpoints/{endpoint_id}", dependencies=dep) + async def remove_endpoint(endpoint_id: str) -> dict[str, Any]: + """The endpoint, its key and the hands, picture and clip slots that used it (back to + automatic); 409 while the chat model answers through it.""" + try: + if not conn.endpoints.remove(endpoint_id): + raise HTTPException(404, "no such endpoint") + except ValueError as exc: + raise HTTPException(409, str(exc)) from exc + return {"ok": True} + + @app.post("/api/connections/endpoints/{endpoint_id}/models", dependencies=dep) + async def refresh_endpoint_models(endpoint_id: str) -> dict[str, Any]: + """Ask the endpoint for its models again; the saved list stays when it does not answer.""" + try: + return await conn.endpoints.refresh_models(endpoint_id) + except ValueError as exc: + raise HTTPException(404, str(exc)) from exc + # ------------------------------------------------------------------ providers (contract C11) @app.get("/api/providers", dependencies=dep) async def providers( diff --git a/nanomuse/server/connections.py b/nanomuse/server/connections.py index d8713aef6..463a2bec2 100644 --- a/nanomuse/server/connections.py +++ b/nanomuse/server/connections.py @@ -37,6 +37,7 @@ from nanomuse.logger import logger from nanomuse.schema import Message from nanomuse.search import WebSearchProvider +from nanomuse.server.endpoints import Endpoints from nanomuse.server.failures import describe_failure from nanomuse.tools import ( Calendar, @@ -261,6 +262,49 @@ def normalize_base_url(url: str) -> str: return url +async def fetch_models(base_url: str, key: str = "") -> tuple[list[str], str]: + """The model ids an OpenAI-compatible endpoint lists (``GET /models``, then ``/v1/models`` + when the address names no version), sorted; with an empty list, one word on why + (``404``, ``HTTP 401``, ``ConnectError``, ``empty list``). Never raises.""" + headers = {"Authorization": f"Bearer {key}"} if key else {} + candidates = [f"{base_url}/models"] + if not re.search(r"/v\d+$", base_url): + candidates.append(f"{base_url}/v1/models") + error = "" + try: + import httpx + + async with httpx.AsyncClient(timeout=8.0, follow_redirects=True) as client: + for url in candidates: + try: + r = await client.get(url, headers=headers) + except httpx.HTTPError as exc: + error = f"{type(exc).__name__}" + continue + if r.status_code == 404: + error = "404" + continue + if r.status_code >= 400: + error = f"HTTP {r.status_code}" + break + data = r.json() + rows = data.get("data") if isinstance(data, dict) else data + ids = sorted( + { + str(row.get("id") if isinstance(row, dict) else row) + for row in (rows or []) + if (row.get("id") if isinstance(row, dict) else row) + } + ) + if ids: + return ids, "" + error = "empty list" + break + except Exception as exc: # noqa: BLE001 + error = f"{type(exc).__name__}" + return [], error + + PROXY_SCHEMES = ("http", "https", "socks5", "socks5h") @@ -344,6 +388,13 @@ def __init__(self, svc: MuseService): self._toml_sources = [ c for c in svc.settings.connectors.contacts.sources if c.name not in app_sources ] + # custom OpenAI-compatible endpoints, several at once (#294); the chat slot of before + # on an unlisted host becomes endpoint number one on the first start with the list + self.endpoints = Endpoints(self) + try: + self.endpoints.migrate() + except (OSError, ValueError, VaultError) as exc: + logger.warning("the endpoint list could not be set up: {}", exc) # ------------------------------------------------------------------ helpers @property @@ -433,8 +484,12 @@ def view(self) -> dict[str, Any]: and getattr(self.svc, "hub", None) is not None and s.llm.base_url.rstrip("/") == model_url(self.svc.hub.cloud.base_url) ), + # the endpoint of the list the slot points at (#294); "" for any other host + "endpoint": self.endpoints.id_for(s.llm.endpoint), }, "providers": self._providers(), + # the custom OpenAI-compatible endpoints, several at once (#294): never a key + "endpoints": self.endpoints.view(), "embeddings": self._embeddings_view(), "search": self._search_view(), "email": { @@ -548,7 +603,16 @@ def _contacts_view(self) -> dict[str, Any]: # ------------------------------------------------------------------ model def set_llm(self, body: dict[str, Any]) -> dict[str, Any]: + """The chat model. ``endpoint`` names one of the list (#294): the slot takes its + address and its key by reference, and ``provider``, ``base_url`` and ``api_key`` in + the body are ignored; the other fields apply as always.""" llm = dict(self.data.get("llm") or {}) + body = dict(body) + if body.get("endpoint"): + fields = self.endpoints.slot_fields(str(body["endpoint"])) + body.update({"provider": fields["provider"], "base_url": fields["base_url"]}) + body["api_key"] = None + llm["api_key"] = fields["api_key"] for key in ("provider", "model", "base_url", "tool_mode", "image_model", "video_model"): if body.get(key) is not None: llm[key] = str(body[key]).strip() @@ -830,52 +894,38 @@ async def llm_models(self, body: dict[str, Any]) -> dict[str, Any]: preset = PROVIDERS.get(preset_id) or {} base_url = normalize_base_url(str(body.get("base_url") or preset.get("base_url") or "")) catalogue: list[str] = list(preset.get("models") or []) + key = str(body.get("api_key") or "").strip() + endpoint = self.endpoints.get(str(body.get("endpoint") or "")) + if endpoint is not None: + # one of the endpoint list (#294): its address and its own key, and the models it + # was saved with when it does not answer now + base_url = str(endpoint["base_url"]) + catalogue = [str(m) for m in endpoint.get("models") or []] + if not key: + key = self.vault.resolve(str(endpoint.get("api_key") or ""), strict=False) if not base_url: return {"models": catalogue, "source": "catalogue"} - key = str(body.get("api_key") or "").strip() if not key and normalize_base_url(self.settings.llm.base_url or "") == base_url: key = self.vault.resolve(self.settings.llm.api_key or "", strict=False) - headers = {"Authorization": f"Bearer {key}"} if key else {} - candidates = [f"{base_url}/models"] - if not re.search(r"/v\d+$", base_url): - candidates.append(f"{base_url}/v1/models") - error = "" - try: - import httpx - - async with httpx.AsyncClient(timeout=8.0, follow_redirects=True) as client: - for url in candidates: - try: - r = await client.get(url, headers=headers) - except httpx.HTTPError as exc: - error = f"{type(exc).__name__}" - continue - if r.status_code == 404: - error = "404" - continue - if r.status_code >= 400: - error = f"HTTP {r.status_code}" - break - data = r.json() - rows = data.get("data") if isinstance(data, dict) else data - ids = sorted( - { - str(row.get("id") if isinstance(row, dict) else row) - for row in (rows or []) - if (row.get("id") if isinstance(row, dict) else row) - } - ) - if ids: - return { - "models": ids, - "image_models": [i for i in ids if looks_like_image_model(i)], - "video_models": [i for i in ids if looks_like_video_model(i)], - "source": "live", - } - error = "empty list" - break - except Exception as exc: # noqa: BLE001 - error = f"{type(exc).__name__}" + if self.vault.has_placeholders(key): + key = "" + ids, error = await fetch_models(base_url, key) + if ids: + return { + "models": ids, + "image_models": [i for i in ids if looks_like_image_model(i)], + "video_models": [i for i in ids if looks_like_video_model(i)], + "source": "live", + } + if endpoint is not None: + # the saved list serves the picture and clip pickers too + return { + "models": catalogue, + "image_models": [i for i in catalogue if looks_like_image_model(i)], + "video_models": [i for i in catalogue if looks_like_video_model(i)], + "source": "catalogue", + "error": error, + } return {"models": catalogue, "source": "catalogue", "error": error} async def test_llm(self) -> dict[str, Any]: @@ -1260,6 +1310,8 @@ def _gui_view(self) -> dict[str, Any]: "cloud": self.svc.app.llm_is_cloud(), "base_url": gui.base_url or "", "key_source": self._key_source(gui.api_key), + # the endpoint of the list the slot points at (#294); "" for any other host + "endpoint": self.endpoints.id_for(gui.endpoint) if gui.model else "", "max_steps": gui.max_steps, "phone": self.svc.phone.status(), } @@ -1273,6 +1325,13 @@ def set_gui(self, body: dict[str, Any]) -> dict[str, Any]: model; a catalogue id brings its endpoint along and must have models that see. """ gui = dict(self.data.get("gui") or {}) + body = dict(body) + if body.get("endpoint"): + # one of the endpoint list (#294): its address, its key by reference + fields = self.endpoints.slot_fields(str(body["endpoint"])) + body.update({"provider": fields["provider"], "base_url": fields["base_url"]}) + body["api_key"] = None + gui["api_key"] = fields["api_key"] if body.get("enabled") is not None: gui["enabled"] = bool(body["enabled"]) for key in ("provider", "model", "base_url"): @@ -1351,6 +1410,8 @@ def media_view(self, slot: str) -> dict[str, Any]: "model": media.model, "base_url": media.base_url or "", "key_source": self._key_source(media.api_key), + # the endpoint of the list the slot points at (#294); "" for any other host + "endpoint": self.endpoints.id_for(media.endpoint) if media.configured else "", "configured": media.configured, "from_app": bool(self.data.get(slot)), "effective_provider": resolved["provider"] if resolved else "", @@ -1368,6 +1429,14 @@ def set_media(self, slot: str, body: dict[str, Any]) -> dict[str, Any]: if slot not in _MEDIA_KEYS: raise ValueError("slot must be 'image' or 'video'") media = dict(self.data.get(slot) or {}) + body = dict(body) + if body.get("endpoint"): + # one of the endpoint list (#294): its address, its key by reference + fields = self.endpoints.slot_fields(str(body["endpoint"])) + body.update({"provider": fields["provider"], "base_url": fields["base_url"]}) + body["api_key"] = fields["api_key"] or None + if not fields["api_key"]: + media["api_key"] = "" for key in ("provider", "model", "base_url"): if body.get(key) is not None: media[key] = str(body[key]).strip() @@ -1560,4 +1629,5 @@ def set_onboarded(self, done: bool = True) -> None: "PROVIDERS", "VIDEO_KEY", "Connections", + "fetch_models", ] diff --git a/nanomuse/server/endpoints.py b/nanomuse/server/endpoints.py new file mode 100644 index 000000000..e5b6ba9fc --- /dev/null +++ b/nanomuse/server/endpoints.py @@ -0,0 +1,370 @@ +"""Custom OpenAI-compatible endpoints, several at once (#294). + +The four model slots (``[llm]``, ``[gui]``, ``[image]``, ``[video]``) each hold one provider, +one address and one key. Before this module the web console offered a single *Other +OpenAI-compatible endpoint* row, so a second gateway could only replace the first. Now the +app keeps a list of endpoints in ``/app-settings.json`` under ``endpoints``: each +one has a stable id, a name the person typed (the host name by default), its base URL, its +key as a vault reference, and the models it serves (the endpoint's own ``/models`` when it +answers, else the ids the person typed). A slot that should use one is set from it +(``PUT /api/connections/llm {"endpoint": id, "model": ...}`` and the same for ``gui``, +``image`` and ``video``), so the console never handles a vault name. + +On the first start with this module the chat slot is migrated: when it points at a host the +catalogue does not list, that host becomes endpoint number one, its key copied to the +endpoint's own vault entry, and the slot keeps working as it did, without a question asked. + +Nothing here is shown to the model, and no key ever leaves the vault: the list carries +``{{vault:ENDPOINT__API_KEY}}`` references and the view says only where a key is. +""" + +from __future__ import annotations + +import re +import secrets +import time +from typing import TYPE_CHECKING, Any +from urllib.parse import urlsplit + +from nanomuse.cloud import model_url +from nanomuse.logger import logger + +if TYPE_CHECKING: + from nanomuse.server.connections import Connections + +#: the slots an endpoint can serve, in the order of the Models contract +SLOTS: tuple[str, ...] = ("chat", "hands", "image", "video") +#: how many model ids a person may type for one endpoint, and how long each may be +MAX_TYPED_MODELS = 40 +MAX_MODEL_ID = 120 +#: the app settings key the list lives under +DATA_KEY = "endpoints" + + +def key_name(endpoint_id: str) -> str: + """The vault entry an endpoint's key is kept under: ``ENDPOINT__API_KEY``.""" + stem = re.sub(r"[^A-Z0-9]+", "_", endpoint_id.upper()).strip("_") or "ENDPOINT" + return f"ENDPOINT_{stem}_API_KEY" + + +def typed_model_ids(value: Any) -> list[str]: + """The model ids a person typed (a comma- or newline-separated field, or a list): + trimmed, without duplicates, at most 40 of up to 120 characters each.""" + if isinstance(value, list): + raw = [str(v) for v in value] + elif isinstance(value, str): + raw = re.split(r"[,\n]", value) + else: + raw = [] + out: list[str] = [] + for piece in raw: + model_id = piece.strip() + if not model_id or len(model_id) > MAX_MODEL_ID or model_id in out: + continue + out.append(model_id) + if len(out) == MAX_TYPED_MODELS: + break + return out + + +def host_label(base_url: str) -> str: + """The name an endpoint gets when the person types none: its host, with the port when + the address names one (two local servers are then told apart).""" + parts = urlsplit(base_url) + host = parts.hostname or base_url + return f"{host}:{parts.port}" if parts.port else host + + +class Endpoints: + """The list behind *Add endpoint*: owned by :class:`Connections`, which holds the + settings file, the vault and the slot setters.""" + + def __init__(self, conn: Connections): + self.conn = conn + + # ------------------------------------------------------------------ the list + def rows(self) -> list[dict[str, Any]]: + rows = self.conn.data.get(DATA_KEY) + return ( + [r for r in rows if isinstance(r, dict) and r.get("id")] + if isinstance(rows, list) + else [] + ) + + def get(self, endpoint_id: str) -> dict[str, Any] | None: + for row in self.rows(): + if row.get("id") == endpoint_id: + return row + return None + + def _write(self, rows: list[dict[str, Any]]) -> None: + self.conn.data[DATA_KEY] = rows + self.conn._save() + + def _new_id(self) -> str: + taken = {r["id"] for r in self.rows()} + while True: + candidate = "ep-" + secrets.token_hex(4) + if candidate not in taken: + return candidate + + @staticmethod + def _same(a: str | None, b: str | None) -> bool: + return bool(a) and bool(b) and str(a).rstrip("/") == str(b).rstrip("/") + + def id_for(self, base_url: str | None) -> str: + """The endpoint whose address a slot points at; "" for any other host.""" + for row in self.rows(): + if self._same(row.get("base_url"), base_url): + return str(row["id"]) + return "" + + def slots_of(self, endpoint_id: str) -> list[str]: + """The slots that use the endpoint today, by address.""" + row = self.get(endpoint_id) + if row is None: + return [] + s = self.conn.settings + used: list[str] = [] + if self._same(s.llm.endpoint, row["base_url"]): + used.append("chat") + if s.gui.model and self._same(s.gui.endpoint, row["base_url"]): + used.append("hands") + for slot in ("image", "video"): + media = getattr(s, slot) + if media.configured and self._same(media.endpoint, row["base_url"]): + used.append(slot) + return used + + def view(self) -> list[dict[str, Any]]: + """What the app shows: never a key, only where it is.""" + return [ + { + "id": row["id"], + "label": row.get("label") or host_label(str(row.get("base_url") or "")), + "base_url": row.get("base_url") or "", + "key_source": self.conn._key_source(str(row.get("api_key") or "")), + "models": [str(m) for m in row.get("models") or []], + "slots": self.slots_of(str(row["id"])), + } + for row in self.rows() + ] + + def slot_fields(self, endpoint_id: str) -> dict[str, str]: + """What a slot takes from an endpoint: the plain OpenAI protocol, its address, its + key by reference (or no key).""" + row = self.get(endpoint_id) + if row is None: + raise ValueError(f"no endpoint {endpoint_id!r}; add it first") + return { + "provider": "openai", + "base_url": str(row.get("base_url") or ""), + "api_key": str(row.get("api_key") or ""), + } + + # ------------------------------------------------------------------ migration + def migrate(self) -> None: + """Once, on the first start with the list: the chat slot set from the app on a host + the catalogue does not list becomes endpoint number one. Its key is copied into the + endpoint's own vault entry and the slot is pointed at that entry, so changing the + key on the endpoint later changes it for the slot too. Nothing is asked.""" + if DATA_KEY in self.conn.data: + return + rows: list[dict[str, Any]] = [] + llm = dict(self.conn.data.get("llm") or {}) + base_url = str(llm.get("base_url") or "").rstrip("/") + if base_url and self._unlisted(base_url) and (llm.get("provider") or "openai") == "openai": + endpoint_id = self._new_id() + row: dict[str, Any] = { + "id": endpoint_id, + "label": host_label(base_url), + "base_url": base_url, + "api_key": "", + "models": [str(llm["model"])] if llm.get("model") else [], + "at": int(time.time()), + } + ref = str(llm.get("api_key") or "") + if ref: + value = self.conn.vault.resolve(ref, strict=False) + if value and not self.conn.vault.has_placeholders(value): + name = key_name(endpoint_id) + self.conn.vault.set(name, str(value)) + row["api_key"] = "{{vault:" + name + "}}" + llm["api_key"] = row["api_key"] + self.conn.data["llm"] = llm + self.conn.settings.llm.api_key = row["api_key"] + rows.append(row) + logger.info("the chat model's endpoint {} is now endpoint number one", base_url) + self._write(rows) + + def _unlisted(self, base_url: str) -> bool: + """A host that is neither a catalogue vendor, nor a preset of the app, nor the + account's relay: the kind the custom row used to hold.""" + from nanomuse.llm import catalogue + from nanomuse.server.connections import PROVIDERS + + if self._same(base_url, model_url(self.conn.settings.cloud.base_url)): + return False + if any(self._same(base_url, str(p.get("base_url") or "")) for p in PROVIDERS.values()): + return False + return catalogue.load().by_base_url(base_url) is None + + # ------------------------------------------------------------------ add / change / remove + def _check_url(self, base_url: str) -> str: + from nanomuse.server.connections import normalize_base_url + + url = normalize_base_url(base_url) + if not re.match(r"^https?://[^/\s]+", url): + raise ValueError("the address must start with http:// or https://") + if self._same(url, model_url(self.conn.settings.cloud.base_url)): + raise ValueError("that is nanoMuse Cloud; it is the account, not an endpoint") + return url + + async def _models_for(self, base_url: str, key: str, typed: list[str]) -> list[str]: + """The ids the person typed first, then what the endpoint lists; a ValueError when + there is neither (a slot cannot pick from an empty list).""" + from nanomuse.server.connections import fetch_models + + listed, _error = await fetch_models(base_url, key) + models = typed + [m for m in listed if m not in typed] + if not models: + raise ValueError( + "the endpoint did not list its models (GET /models); type the ids of the " + "models it serves, separated by commas" + ) + return models + + async def add(self, body: dict[str, Any]) -> dict[str, Any]: + """A new endpoint: ``base_url`` (required), ``label`` (the host when empty), + ``api_key`` (into the vault; empty for a server that wants none), ``models`` (typed + ids; the endpoint's own list is added after them).""" + base_url = self._check_url(str(body.get("base_url") or "")) + key = str(body.get("api_key") or "").strip() + if key and re.search(r"\s", key): + raise ValueError("a key has no spaces in it") + typed = typed_model_ids(body.get("models")) + models = await self._models_for(base_url, key, typed) + endpoint_id = self._new_id() + row: dict[str, Any] = { + "id": endpoint_id, + "label": str(body.get("label") or "").strip()[:80] or host_label(base_url), + "base_url": base_url, + "api_key": "", + "models": models, + "at": int(time.time()), + } + if key: + name = key_name(endpoint_id) + self.conn.vault.set(name, key) + row["api_key"] = "{{vault:" + name + "}}" + self._write([*self.rows(), row]) + self.conn._publish() + return self._one(endpoint_id) + + async def update(self, endpoint_id: str, body: dict[str, Any]) -> dict[str, Any]: + """Rename, change the key or the address, or retype the models. A key or address + that changed asks the endpoint for its models again (typed ids stay first); the + slots that use the endpoint follow it.""" + row = self.get(endpoint_id) + if row is None: + raise ValueError(f"no endpoint {endpoint_id!r}") + changed = dict(row) + if body.get("label") is not None: + changed["label"] = str(body["label"]).strip()[:80] or host_label(changed["base_url"]) + moved = False + if body.get("base_url") is not None: + url = self._check_url(str(body["base_url"])) + moved = not self._same(url, changed["base_url"]) + changed["base_url"] = url + api_key = body.get("api_key") + rekeyed = False + if api_key: + key = str(api_key).strip() + if re.search(r"\s", key): + raise ValueError("a key has no spaces in it") + name = key_name(endpoint_id) + self.conn.vault.set(name, key) + changed["api_key"] = "{{vault:" + name + "}}" + rekeyed = True + elif api_key == "": + self.conn.vault.delete(key_name(endpoint_id)) + changed["api_key"] = "" + rekeyed = True + typed = typed_model_ids(body.get("models")) if body.get("models") is not None else [] + if typed or moved or rekeyed: + key = self.conn.vault.resolve(changed["api_key"] or "", strict=False) + if self.conn.vault.has_placeholders(key): + key = "" + kept = typed or [str(m) for m in changed.get("models") or []] + try: + changed["models"] = await self._models_for(changed["base_url"], key, kept) + except ValueError: + if not kept: + raise + changed["models"] = kept + used = self.slots_of(endpoint_id) + self._write([changed if r.get("id") == endpoint_id else r for r in self.rows()]) + if moved or rekeyed: + for slot in used: + self._follow(slot, endpoint_id) + self.conn._publish() + return self._one(endpoint_id) + + def _follow(self, slot: str, endpoint_id: str) -> None: + """A slot that used the endpoint takes its new address or key.""" + if slot == "chat": + self.conn.set_llm({"endpoint": endpoint_id}) + elif slot == "hands": + self.conn.set_gui({"endpoint": endpoint_id}) + else: + self.conn.set_media(slot, {"endpoint": endpoint_id}) + + def remove(self, endpoint_id: str) -> bool: + """The endpoint, its key and the slots that pointed at it (back to automatic). The + chat slot cannot be left empty, so an endpoint it uses is refused until another + chat model is chosen.""" + row = self.get(endpoint_id) + if row is None: + return False + used = self.slots_of(endpoint_id) + if "chat" in used: + raise ValueError( + "the chat model answers through this endpoint; pick another chat model first" + ) + for slot in used: + if slot == "hands": + self.conn.set_gui({"provider": "", "model": "", "base_url": "", "api_key": ""}) + else: + self.conn.set_media( + slot, {"provider": "", "model": "", "base_url": "", "api_key": ""} + ) + self.conn.vault.delete(key_name(endpoint_id)) + self._write([r for r in self.rows() if r.get("id") != endpoint_id]) + self.conn._publish() + return True + + async def refresh_models(self, endpoint_id: str) -> dict[str, Any]: + """Ask the endpoint for its models again; the list stays when it does not answer.""" + row = self.get(endpoint_id) + if row is None: + raise ValueError(f"no endpoint {endpoint_id!r}") + from nanomuse.server.connections import fetch_models + + key = self.conn.vault.resolve(str(row.get("api_key") or ""), strict=False) + if self.conn.vault.has_placeholders(key): + key = "" + listed, error = await fetch_models(str(row["base_url"]), key) + if listed: + changed = {**row, "models": listed} + self._write([changed if r.get("id") == endpoint_id else r for r in self.rows()]) + self.conn._publish() + return {**self._one(endpoint_id), "source": "live" if listed else "kept", "error": error} + + def _one(self, endpoint_id: str) -> dict[str, Any]: + for entry in self.view(): + if entry["id"] == endpoint_id: + return entry + raise ValueError(f"no endpoint {endpoint_id!r}") + + +__all__ = ["DATA_KEY", "SLOTS", "Endpoints", "host_label", "key_name", "typed_model_ids"] diff --git a/tests/test_endpoints_api.py b/tests/test_endpoints_api.py new file mode 100644 index 000000000..4a1637486 --- /dev/null +++ b/tests/test_endpoints_api.py @@ -0,0 +1,317 @@ +"""Custom OpenAI-compatible endpoints, several at once (#294): ``/api/connections/endpoints``. + +The list behind the web console's *Add endpoint*: each entry has a stable id, a name, an +address, a key in the vault and a model list; a slot is set from one by id. The endpoint's +``/models`` is a stub on ``fetch_models``; nothing reaches the network. +""" + +from __future__ import annotations + +import json +from collections.abc import Iterator +from pathlib import Path + +import pytest +from fastapi.testclient import TestClient + +from nanomuse.config import Settings, apply_app_settings, load_app_settings +from nanomuse.llm import MockLLM +from nanomuse.server import connections as conn_module +from nanomuse.server import create_app +from nanomuse.server.endpoints import host_label, key_name, typed_model_ids +from nanomuse.server.service import MuseService +from nanomuse.vault.vault import CredentialVault + +GATEWAY = "https://gateway.example/v1" +SECOND = "https://second.example/v1" + + +def _make(settings: Settings) -> tuple[TestClient, MuseService]: + settings.server.token = "secret-token" + service = MuseService(settings, llm=MockLLM([])) + app = create_app(settings, service) + client = TestClient(app) + client.headers["Authorization"] = "Bearer secret-token" + return client, service + + +@pytest.fixture() +def server(settings: Settings) -> Iterator[tuple[TestClient, MuseService]]: + client, service = _make(settings) + with client: + yield client, service + + +@pytest.fixture() +def listed(monkeypatch: pytest.MonkeyPatch) -> dict[str, list[str]]: + """What each address lists on ``GET /models``, and the key each call carried.""" + answers: dict[str, list[str]] = {GATEWAY: ["b-model", "a-model", "qwen-image-3.0"]} + keys: list[str] = [] + + async def fake(base_url: str, key: str = "") -> tuple[list[str], str]: + keys.append(key) + ids = answers.get(base_url, []) + return (sorted(ids), "") if ids else ([], "404") + + monkeypatch.setattr(conn_module, "fetch_models", fake) + answers["__keys__"] = keys + return answers + + +def _endpoints(client: TestClient) -> list[dict]: + return client.get("/api/connections").json()["endpoints"] + + +def test_helpers(): + assert key_name("ep-7f3a9c21") == "ENDPOINT_EP_7F3A9C21_API_KEY" + assert host_label("https://gateway.example/v1") == "gateway.example" + assert host_label("http://127.0.0.1:8000/v1") == "127.0.0.1:8000" + assert typed_model_ids("glm-4.7, glm-4.7, , kimi-k2.5\n") == ["glm-4.7", "kimi-k2.5"] + assert typed_model_ids(["a", "b", "a"]) == ["a", "b"] + assert typed_model_ids(None) == [] + assert len(typed_model_ids(",".join(f"m{i}" for i in range(60)))) == 40 + + +def test_add_lists_the_models_and_keeps_the_key_in_the_vault(server, listed, settings): + client, service = server + assert _endpoints(client) == [] + assert client.get("/api/connections").json()["llm"]["endpoint"] == "" + # the key is refused with a space; the relay is the account, not an endpoint; no scheme is added + assert ( + client.post( + "/api/connections/endpoints", json={"base_url": GATEWAY, "api_key": "sk x"} + ).status_code + == 400 + ) + relay = client.post( + "/api/connections/endpoints", json={"base_url": settings.cloud.base_url + "/v1"} + ) + assert relay.status_code == 400 and "nanoMuse Cloud" in relay.json()["detail"] + added = client.post( + "/api/connections/endpoints", + json={"base_url": "gateway.example/v1", "api_key": "sk-gateway-1", "models": "my-typed"}, + ) + assert added.status_code == 200, added.text + entry = added.json() + assert entry["id"].startswith("ep-") and entry["label"] == "gateway.example" + assert entry["base_url"] == GATEWAY and entry["key_source"] == "vault" + # typed ids first, the endpoint's own after them; nothing uses it yet + assert entry["models"] == ["my-typed", "a-model", "b-model", "qwen-image-3.0"] + assert entry["slots"] == [] + assert listed["__keys__"][-1] == "sk-gateway-1" + # the key is in the vault under the endpoint's own name and nowhere else + name = key_name(entry["id"]) + assert service.app.vault.get(name) == "sk-gateway-1" + assert "sk-gateway" not in json.dumps(entry) + saved = load_app_settings(settings.data_dir) + assert "sk-gateway" not in json.dumps(saved) + assert saved["endpoints"][0]["api_key"] == "{{vault:" + name + "}}" + # an endpoint that lists nothing and had nothing typed is refused before anything is written + silent = client.post("/api/connections/endpoints", json={"base_url": SECOND, "api_key": "sk-2"}) + assert silent.status_code == 400 and "type the ids" in silent.json()["detail"] + assert len(_endpoints(client)) == 1 + assert [n for n in service.app.vault.names() if n.startswith("ENDPOINT_")] == [name] + # typed ids make it; a server without a key is allowed + second = client.post( + "/api/connections/endpoints", + json={"base_url": SECOND, "label": "Second", "models": ["s-1"]}, + ) + assert second.status_code == 200 + assert second.json()["key_source"] == "none" and second.json()["models"] == ["s-1"] + + +def test_slots_are_set_from_an_endpoint_by_id(server, listed, settings): + client, service = server + first = client.post( + "/api/connections/endpoints", json={"base_url": GATEWAY, "api_key": "sk-1"} + ).json() + second = client.post( + "/api/connections/endpoints", json={"base_url": SECOND, "models": "s-1, s-vl"} + ).json() + # the chat model: the slot takes the address and the key by reference, never the key itself + r = client.put("/api/connections/llm", json={"endpoint": first["id"], "model": "a-model"}) + assert r.status_code == 200, r.text + assert r.json()["endpoint"] == first["id"] and r.json()["key_source"] == "vault" + assert settings.llm.base_url == GATEWAY and settings.llm.model == "a-model" + assert settings.llm.api_key == "{{vault:" + key_name(first["id"]) + "}}" + assert "sk-1" not in json.dumps(load_app_settings(settings.data_dir)) + # the hands and the pictures from the other endpoint, which has no key + hands = client.put("/api/connections/gui", json={"endpoint": second["id"], "model": "s-vl"}) + assert hands.status_code == 200, hands.text + assert hands.json()["endpoint"] == second["id"] and settings.gui.base_url == SECOND + assert settings.gui.model == "s-vl" and settings.gui.api_key == "" + image = client.put("/api/connections/image", json={"endpoint": second["id"], "model": "s-1"}) + assert image.status_code == 200, image.text + assert image.json()["endpoint"] == second["id"] and settings.image.base_url == SECOND + view = {e["id"]: e for e in _endpoints(client)} + assert view[first["id"]]["slots"] == ["chat"] + assert view[second["id"]]["slots"] == ["hands", "image"] + # an id nobody has is a plain 400 + assert ( + client.put("/api/connections/llm", json={"endpoint": "ep-nobody", "model": "x"}).status_code + == 400 + ) + # the model list for a slot's picker: the endpoint's own key is used, the saved list stands in + models = client.post("/api/llm/models", json={"endpoint": first["id"]}).json() + assert models["source"] == "live" and listed["__keys__"][-1] == "sk-1" + kept = client.post("/api/llm/models", json={"endpoint": second["id"]}).json() + assert kept == { + "models": ["s-1", "s-vl"], + "image_models": [], + "video_models": [], + "source": "catalogue", + "error": "404", + } + assert service.app.vault.get(key_name(second["id"])) is None + + +def test_rename_rekey_and_move_follow_through_to_the_slots(server, listed, settings): + client, service = server + first = client.post( + "/api/connections/endpoints", json={"base_url": GATEWAY, "api_key": "sk-1"} + ).json() + client.put("/api/connections/llm", json={"endpoint": first["id"], "model": "a-model"}) + client.put("/api/connections/gui", json={"endpoint": first["id"], "model": "b-model"}) + path = f"/api/connections/endpoints/{first['id']}" + # rename: the label only + renamed = client.put(path, json={"label": " Work gateway "}).json() + assert renamed["label"] == "Work gateway" and renamed["slots"] == ["chat", "hands"] + # a new key: the vault entry changes under the same name, so the slots need no change + rekeyed = client.put(path, json={"api_key": "sk-1-new"}) + assert rekeyed.status_code == 200 + assert service.app.vault.get(key_name(first["id"])) == "sk-1-new" + assert settings.llm.api_key == "{{vault:" + key_name(first["id"]) + "}}" + assert listed["__keys__"][-1] == "sk-1-new", ( + "the model list is asked for again with the new key" + ) + # a new address: the slots that used the endpoint move with it; the models stay when it lists none + listed[SECOND] = [] + moved = client.put(path, json={"base_url": SECOND}).json() + assert moved["base_url"] == SECOND + assert moved["models"] == ["a-model", "b-model", "qwen-image-3.0"] + assert settings.llm.base_url == SECOND and settings.gui.base_url == SECOND + assert settings.llm.model == "a-model" and settings.gui.model == "b-model" + assert client.get("/api/connections").json()["llm"]["endpoint"] == first["id"] + # typed models replace the list, the endpoint's own after them + listed[SECOND] = ["listed-z"] + retyped = client.put(path, json={"models": "typed-one"}).json() + assert retyped["models"] == ["typed-one", "listed-z"] + # asking again keeps typed ids out: the live list is the truth + again = client.post(path + "/models").json() + assert again["source"] == "live" and again["models"] == ["listed-z"] + # an unknown id is 404 for both + assert ( + client.put("/api/connections/endpoints/ep-nobody", json={"label": "x"}).status_code == 404 + ) + assert client.post("/api/connections/endpoints/ep-nobody/models").status_code == 404 + + +def test_remove_refuses_the_chat_endpoint_and_clears_the_dependent_slots(server, listed, settings): + client, service = server + first = client.post( + "/api/connections/endpoints", json={"base_url": GATEWAY, "api_key": "sk-1"} + ).json() + second = client.post( + "/api/connections/endpoints", json={"base_url": SECOND, "api_key": "sk-2", "models": "s-1"} + ).json() + client.put("/api/connections/llm", json={"endpoint": first["id"], "model": "a-model"}) + client.put("/api/connections/gui", json={"endpoint": first["id"], "model": "b-model"}) + client.put("/api/connections/video", json={"endpoint": first["id"], "model": "wan-x"}) + # the chat model answers through it: refused with a sentence, nothing changes + refused = client.delete(f"/api/connections/endpoints/{first['id']}") + assert refused.status_code == 409 and "chat model" in refused.json()["detail"] + assert len(_endpoints(client)) == 2 and service.app.vault.get(key_name(first["id"])) == "sk-1" + # the chat moves to the other endpoint; now the first can go, and the hands and clips go back to automatic + client.put("/api/connections/llm", json={"endpoint": second["id"], "model": "s-1"}) + assert settings.llm.api_key == "{{vault:" + key_name(second["id"]) + "}}" + gone = client.delete(f"/api/connections/endpoints/{first['id']}") + assert gone.status_code == 200 and gone.json() == {"ok": True} + assert [e["id"] for e in _endpoints(client)] == [second["id"]] + assert service.app.vault.get(key_name(first["id"])) is None + assert settings.gui.model == "" and settings.gui.base_url is None + assert settings.video.configured is False + data = client.get("/api/connections").json() + assert data["gui"]["endpoint"] == "" and data["video"]["endpoint"] == "" + assert data["llm"]["endpoint"] == second["id"] + assert client.delete(f"/api/connections/endpoints/{first['id']}").status_code == 404 + + +def _app_settings(settings: Settings, llm: dict) -> None: + """A chat slot set from the app on an earlier run, layered as ``load_settings`` does.""" + settings.data_dir.mkdir(parents=True, exist_ok=True) + (settings.data_dir / "app-settings.json").write_text( + json.dumps({"version": 1, "llm": llm}), "utf-8" + ) + apply_app_settings(settings, load_app_settings(settings.data_dir)) + + +def test_the_single_custom_slot_is_migrated_once(settings: Settings, listed): + """An existing user with *Other OpenAI-compatible endpoint* set from the app finds it as + endpoint number one: same address, the key copied to the endpoint's own vault entry, + the chat slot pointed at that entry, nothing asked.""" + vault = CredentialVault(settings.vault_file, settings.vault_key_file) + vault.set("LLM_API_KEY", "sk-old-gateway") + _app_settings( + settings, + { + "provider": "openai", + "model": "my-model", + "base_url": GATEWAY, + "api_key": "{{vault:LLM_API_KEY}}", + }, + ) + client, service = _make(settings) + with client: + rows = _endpoints(client) + assert len(rows) == 1 + one = rows[0] + assert one["label"] == "gateway.example" and one["base_url"] == GATEWAY + assert one["models"] == ["my-model"] and one["key_source"] == "vault" + assert one["slots"] == ["chat"] + name = key_name(one["id"]) + assert service.app.vault.get(name) == "sk-old-gateway" + assert service.app.vault.get("LLM_API_KEY") == "sk-old-gateway", ( + "the old entry is left alone" + ) + # the chat slot works as before, through the endpoint's own entry now + llm = client.get("/api/connections").json()["llm"] + assert ( + llm["endpoint"] == one["id"] + and llm["key_source"] == "vault" + and llm["model"] == "my-model" + ) + assert settings.llm.api_key == "{{vault:" + name + "}}" and settings.llm.base_url == GATEWAY + saved = load_app_settings(settings.data_dir) + assert saved["llm"]["api_key"] == "{{vault:" + name + "}}" + assert "sk-old" not in json.dumps(saved) + # a second start finds the list and adds nothing + client2, _ = _make(settings) + with client2: + assert [e["id"] for e in _endpoints(client2)] == [one["id"]] + + +def test_a_catalogue_slot_or_a_config_slot_is_not_migrated(settings: Settings, tmp_path: Path): + _app_settings( + settings, + { + "provider": "openai", + "model": "deepseek-chat", + "base_url": "https://api.deepseek.com", + "api_key": "{{vault:LLM_API_KEY}}", + }, + ) + client, _ = _make(settings) + with client: + assert _endpoints(client) == [] + assert load_app_settings(settings.data_dir)["endpoints"] == [] + # a slot from config.toml alone (nothing set from the app) stays the file's business + other = Settings() + other.data_dir = tmp_path / "other" + other.agent.workspace = tmp_path / "other-ws" + other.llm.base_url = GATEWAY + other.llm.api_key = "plain" + other.llm.stream = False + other.ensure_dirs() + client2, _ = _make(other) + with client2: + assert _endpoints(client2) == [] From 7e8d2d2e86186965616a28a0e76ca35d914719dd Mon Sep 17 00:00:00 2001 From: lgy0404 <2528379691@qq.com> Date: Sun, 11 Oct 2026 23:48:09 +0800 Subject: [PATCH 53/98] feat(web): several custom endpoints on the Connections screen The chat model card shows the runtime's endpoint list under "Local or your own endpoint": one tile per endpoint, reading its name over its host, and "Add an endpoint" as the last tile with a form for a name, the address, a key (or none) and the model ids when the endpoint does not list them. A chosen endpoint shows a card with where its key is, how many models it serves and which slots use it, and the ways to change it: rename, change key, edit models, ask for its models again, remove (with the runtime's refusal while the chat answers through it). Saving the chat model names the endpoint by id; the address and the key are never retyped. The hands picker gains one group per other endpoint and the pictures and clips selects list them under "Your endpoints", each saved by id as well. The summary, the "Currently" lines and the media rows read the endpoint's name. A runtime without the list shows the single "Other OpenAI-compatible endpoint" tile as before, and a chat model set on an unlisted host outside the list keeps that tile too. models.ts carries the pure parts (the picker values, the labels, the hands groups, the row values with endpoints) and models.test.ts checks them; the zh-CN dictionary has every new sentence. The built console is rebuilt. Docs: web.md in English and Chinese. For #294 Signed-off-by: lgy0404 <2528379691@qq.com> --- CHANGELOG.md | 1 + docs/web.md | 32 ++ docs/zh/web.md | 2 + ...-bHMDrVr5.js => AccountScreen-BltVqMHJ.js} | 2 +- ...r-gR2knlot.js => AvatarPicker-CwYa9V6R.js} | 2 +- ...0R8P.js => AvatarStudioScreen-BFsBKlhk.js} | 2 +- ...ackBar-Dl56jHZM.js => BackBar-DqcCClHf.js} | 2 +- ...mBzj7BLf.js => ChannelsScreen-Cil6hJ5n.js} | 2 +- ...Card-CtVHK0qc.js => CloudCard-B2Mi7bjZ.js} | 2 +- ...n-C_tutsx0.js => CodingScreen-BulrK8KC.js} | 2 +- .../assets/ConnectionsScreen-CMt7GOff.js | 1 - .../assets/ConnectionsScreen-DzFdAyKl.js | 1 + ...-g6FUY327.js => DevicesScreen-Cox4s7Rb.js} | 2 +- .../{Form-DwKuBk1V.js => Form-B3Ejw5aI.js} | 2 +- ...en-Dp2fRaLA.js => GoalsScreen-ChIUN2rA.js} | 2 +- ...en-CGfvq5H-.js => IdeasScreen-DKf-8dhs.js} | 2 +- ...m-BTGczGT_.js => IdentityForm-BweNfU4E.js} | 2 +- ...-B8JlrC_n.js => LibraryScreen-CLqu6Lu-.js} | 2 +- ...n-M8j03G3u.js => MemoryScreen-B7ALbqAO.js} | 2 +- ...der-Pw-NI98v.js => MuseHeader-BDWXHKHT.js} | 2 +- .../static/assets/Onboarding-CtVO6gdK.js | 1 - .../static/assets/Onboarding-D3RCeowq.js | 1 + ...CHVg61To.js => SettingsScreen-xI3hlacs.js} | 2 +- ...n-Dr-d7iS7.js => SkillsScreen-qZE6bdL9.js} | 2 +- ...udge-DjXecvWj.js => StarNudge-B8P2bPEz.js} | 2 +- ...d-BokpXv9J.js => clapperboard-C1_tjTS2.js} | 2 +- ...p-CzaFBl6C.js => database-zap-6Cufqig1.js} | 2 +- ...-Xj5fjR8v.js => external-link-CZH-rQLq.js} | 2 +- .../{image-crWy0a06.js => image-kcW5PNCE.js} | 2 +- .../server/static/assets/index-CwUBXfPC.css | 2 - .../{index-CIdGZ5PB.js => index-DKrXW2Qj.js} | 6 +- .../server/static/assets/index-e3JVbMkJ.css | 2 + .../{plug-Bj_5EEV3.js => plug-Cn-mgW7a.js} | 2 +- ...-cw-BKgIzslL.js => refresh-cw-qw351CFk.js} | 2 +- nanomuse/server/static/index.html | 14 +- web/src/api.ts | 21 +- web/src/i18n/zh-CN.ts | 45 ++ web/src/models.test.ts | 66 ++- web/src/models.ts | 90 ++- web/src/screens/ConnectionsScreen.tsx | 527 ++++++++++++++++-- web/src/screens/Onboarding.tsx | 8 +- web/src/types.ts | 22 + 42 files changed, 796 insertions(+), 94 deletions(-) rename nanomuse/server/static/assets/{AccountScreen-bHMDrVr5.js => AccountScreen-BltVqMHJ.js} (97%) rename nanomuse/server/static/assets/{AvatarPicker-gR2knlot.js => AvatarPicker-CwYa9V6R.js} (95%) rename nanomuse/server/static/assets/{AvatarStudioScreen-DD2X0R8P.js => AvatarStudioScreen-BFsBKlhk.js} (97%) rename nanomuse/server/static/assets/{BackBar-Dl56jHZM.js => BackBar-DqcCClHf.js} (85%) rename nanomuse/server/static/assets/{ChannelsScreen-mBzj7BLf.js => ChannelsScreen-Cil6hJ5n.js} (97%) rename nanomuse/server/static/assets/{CloudCard-CtVHK0qc.js => CloudCard-B2Mi7bjZ.js} (95%) rename nanomuse/server/static/assets/{CodingScreen-C_tutsx0.js => CodingScreen-BulrK8KC.js} (98%) delete mode 100644 nanomuse/server/static/assets/ConnectionsScreen-CMt7GOff.js create mode 100644 nanomuse/server/static/assets/ConnectionsScreen-DzFdAyKl.js rename nanomuse/server/static/assets/{DevicesScreen-g6FUY327.js => DevicesScreen-Cox4s7Rb.js} (97%) rename nanomuse/server/static/assets/{Form-DwKuBk1V.js => Form-B3Ejw5aI.js} (97%) rename nanomuse/server/static/assets/{GoalsScreen-Dp2fRaLA.js => GoalsScreen-ChIUN2rA.js} (99%) rename nanomuse/server/static/assets/{IdeasScreen-CGfvq5H-.js => IdeasScreen-DKf-8dhs.js} (99%) rename nanomuse/server/static/assets/{IdentityForm-BTGczGT_.js => IdentityForm-BweNfU4E.js} (97%) rename nanomuse/server/static/assets/{LibraryScreen-B8JlrC_n.js => LibraryScreen-CLqu6Lu-.js} (97%) rename nanomuse/server/static/assets/{MemoryScreen-M8j03G3u.js => MemoryScreen-B7ALbqAO.js} (97%) rename nanomuse/server/static/assets/{MuseHeader-Pw-NI98v.js => MuseHeader-BDWXHKHT.js} (76%) delete mode 100644 nanomuse/server/static/assets/Onboarding-CtVO6gdK.js create mode 100644 nanomuse/server/static/assets/Onboarding-D3RCeowq.js rename nanomuse/server/static/assets/{SettingsScreen-CHVg61To.js => SettingsScreen-xI3hlacs.js} (98%) rename nanomuse/server/static/assets/{SkillsScreen-Dr-d7iS7.js => SkillsScreen-qZE6bdL9.js} (98%) rename nanomuse/server/static/assets/{StarNudge-DjXecvWj.js => StarNudge-B8P2bPEz.js} (99%) rename nanomuse/server/static/assets/{clapperboard-BokpXv9J.js => clapperboard-C1_tjTS2.js} (81%) rename nanomuse/server/static/assets/{database-zap-CzaFBl6C.js => database-zap-6Cufqig1.js} (80%) rename nanomuse/server/static/assets/{external-link-Xj5fjR8v.js => external-link-CZH-rQLq.js} (79%) rename nanomuse/server/static/assets/{image-crWy0a06.js => image-kcW5PNCE.js} (75%) delete mode 100644 nanomuse/server/static/assets/index-CwUBXfPC.css rename nanomuse/server/static/assets/{index-CIdGZ5PB.js => index-DKrXW2Qj.js} (99%) create mode 100644 nanomuse/server/static/assets/index-e3JVbMkJ.css rename nanomuse/server/static/assets/{plug-Bj_5EEV3.js => plug-Cn-mgW7a.js} (77%) rename nanomuse/server/static/assets/{refresh-cw-BKgIzslL.js => refresh-cw-qw351CFk.js} (79%) diff --git a/CHANGELOG.md b/CHANGELOG.md index 11f6d6c26..28babf92c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,6 +17,7 @@ All notable changes to nanoMuse. The format follows [Keep a Changelog](https://k ### Web - **The phone layout's tab bar is a floating frosted-glass pill.** The five tabs sit in a rounded pill 12 px above the bottom edge, icons only and no labels; the pill is translucent over a blur of what is behind it and has a hairline edge. The current tab shows its filled glyph on a soft blue indicator, the others stay outlined in grey. The screens and the chat's composer keep clear of the pill, and the toast rises above it; a wide window and the desktop app keep the sidebar (follows #329 by @Ichiro786). +- **Several custom OpenAI-compatible endpoints on the Connections screen.** Under *Local or your own endpoint* each endpoint of the runtime's list is a tile reading its name over its host, and *Add an endpoint* is the last tile: a name, the address, a key or *No key*, and the model ids when the endpoint does not list them. A chosen endpoint shows a card with where its key is, how many models it serves and which slots use it, with *Rename*, *Change key*, *Edit models*, *Ask for its models* and *Remove*; saving the chat model names the endpoint by id, never its key. The *Hands model* picker gains one group per other endpoint, and the *Making pictures* and *Making clips* selects list them under *Your endpoints*, so a second gateway can serve the hands while the first answers the chat. The *Chat model* summary and the *Currently* lines read the endpoint's name (reported by @Alasco123, #294). ### Desktop diff --git a/docs/web.md b/docs/web.md index 7cf218515..f07177907 100644 --- a/docs/web.md +++ b/docs/web.md @@ -36,6 +36,38 @@ requests only (`[llm] proxy`; nanoMuse Cloud never goes through it, a SOCKS address needs `httpx[socks]` on the runtime); a saved password comes back as dots, and an emptied field clears it. +**Connections → Chat model → Your own endpoints.** A server that speaks the +OpenAI API but is not in the catalogue (a gateway, a relay, vLLM or LM Studio +on another machine) is an *endpoint* of the runtime's list, and the list holds +as many as you use (#294). Under *Local or your own endpoint* each saved +endpoint is a tile, reading its name over its host, and the last tile is *Add +an endpoint*: a name (optional; the host otherwise), the base URL, the API key +(or *No key*), and the ids of its models when it does not list them at +`/models` (the form says so when it does not). The key goes into the vault +under the endpoint's own name (`ENDPOINT__API_KEY`); adding a second +endpoint never touches the first's. With an endpoint's tile chosen, a card +under the tiles says where its key is, how many models it serves and which +slots answer through it, with *Rename*, *Change key*, *Edit models*, *Ask for +its models* and *Remove*; the chat model picker lists the endpoint's models, +and *Save* sets the chat slot by the endpoint's id (`PUT /api/connections/llm +{"endpoint": "", "model": ...}`), never by retyping its address or key. +Renaming, rekeying or moving an endpoint reaches every slot that uses it. The +*Hands model* picker gains one group per other endpoint of the list; a model +picked there sends the hands' screenshots through that endpoint with its key +(`PUT /api/connections/gui {"endpoint": "", "model": ...}`), and the +*Making pictures* and *Making clips* selects list the endpoints under *Your +endpoints* the same way (`PUT /api/connections/image` / `/video` with +`endpoint` and `model`). Removing an endpoint is refused while the chat model +answers through it (pick another chat model first); hands, pictures or clips +set on it go back to *Automatic*, and its key leaves the vault. A chat model +set on *Other OpenAI-compatible endpoint* before the list existed becomes +endpoint number one on the runtime's next start, its key copied to the +endpoint's own vault entry; nothing is asked. The list is `GET +/api/connections` → `endpoints`, each `{id, label, base_url, key_source, +models, slots}`, never a key; the routes are in [app.md](app.md#api). A +runtime without the list offers the single *Other OpenAI-compatible endpoint* +tile as before. + **Connections → Making pictures, Making clips.** The two media rows of the Models contract (0.1.41), one card each under the chat model. The value is `provider · model` as the runtime resolves it (`GET /api/connections` → diff --git a/docs/zh/web.md b/docs/zh/web.md index e660abb4c..d171a053f 100644 --- a/docs/zh/web.md +++ b/docs/zh/web.md @@ -10,6 +10,8 @@ **连接 → 对话模型。** 服务商卡片是运行时的预设,所在地区的首选排第一(中国大陆是阿里云百炼,其他地方是 OpenRouter;[region.ts](../../web/src/region.ts))。卡片下面是所选服务商在目录里的那一行:它的 key 覆盖什么,以及需要知道的事(Kimi 的几个版本、OpenRouter 的 Image API、ChatGPT 的注意事项)。「动手模型」选择器列出能看图的模型;它的默认值是目录里这个服务商自己的动手模型(`defaults.hands`),服务商没有能看图的模型而你登录了账号时,则是账号的动手模型;既没有 `vision` 也没有账号的服务商得到的是那一句话,而不是一个看不见的动手模型。下面的「代理(可选)」接受 `http://host:port`、`https://` 或 `socks5://` 地址,只用于这个服务商的请求(`[llm] proxy`;nanoMuse Cloud 的请求从不经过它,SOCKS 地址需要运行时装了 `httpx[socks]`);存过的密码回显为圆点,清空字段就清掉它。 +**连接 → 对话模型 → 你自己的接口。** 说 OpenAI API 但不在目录里的服务(网关、中转、另一台机器上的 vLLM 或 LM Studio)是运行时「接口列表」里的一个接口,列表里放几个都行(#294)。「本地或你自己的端点」下面,每个已保存的接口是一块卡片,显示名字和主机名;最后一块是「添加接口」:名字(可选,不填就用主机名)、Base URL、API key(或「无需密钥」),以及它在 `/models` 列不出模型时手填的模型 id(列不出时表单会这么说)。key 以接口自己的名字进保险库(`ENDPOINT__API_KEY`);再添加一个接口,绝不会碰到前一个的 key。选中一个接口的卡片后,卡片下面有一张小卡说明它的 key 在哪、提供几个模型、哪些槽位正通过它回答,带「改名」「换密钥」「编辑模型」「重新获取模型」和「移除」;对话模型选择器列出这个接口的模型,「保存」按接口的 id 设置对话槽位(`PUT /api/connections/llm {"endpoint": "", "model": ...}`),不用再填地址或 key。给接口改名、换 key 或换地址,用到它的每个槽位一起变。「动手模型」选择器为列表里的其他每个接口多出一组;在那里选的模型让双手的截图走那个接口、用它的 key(`PUT /api/connections/gui {"endpoint": "", "model": ...}`),「生成图片」和「生成视频」的下拉框在「你的接口」下同样列出这些接口(`PUT /api/connections/image` / `/video` 带 `endpoint` 和 `model`)。对话模型正通过某个接口回答时不能移除它(先换一个对话模型);设在它上面的双手、图片或短片回到「自动」,它的 key 从保险库里删掉。在列表出现之前设在「其他 OpenAI 兼容接口」上的对话模型,运行时下次启动时会成为一号接口,key 复制到接口自己的保险库条目里,不问任何问题。列表是 `GET /api/connections` → `endpoints`,每个是 `{id, label, base_url, key_source, models, slots}`,从不带 key;路由在 [app.md](app.md#api)。没有列表的运行时还是像以前那样只有一块「其他 OpenAI 兼容接口」。 + **连接 → 生成图片、生成视频。** 模型约定(0.1.41)的两行媒体槽位,各一张卡片,放在对话模型下面。值是运行时解析出的「服务商 · 模型」(`GET /api/connections` → `image` / `video`:槽位的设置和它的 `effective_*`):明确的选择优先,否则是对话服务商自己的图片模型(它有的话),否则登录时是账号的,再否则是那一句话和一个「添加服务商」按钮。选择器第一项是「自动」,然后是登录时的「nanoMuse Cloud」一组、有这项能力时的「对话模型的服务商」(用它的 key,不用再粘贴),以及「添加服务商」下面所在地区每一家有这项能力的目录服务商,加上一个带 Base URL 的「其他 OpenAI 兼容接口」;没有这项能力的服务商不会出现。模型可以从接口列出的里面选(nanoMuse Cloud 上是中继的菜单和账号可用的其他模型),也可以留给目录的默认值。「保存」调用 `PUT /api/connections/image` 或 `/video`,带 `provider`(目录 id,或 `openai` 加 `base_url`)、`model`、`base_url`、`api_key`(进保险库,名为 `IMAGE_API_KEY` / `VIDEO_API_KEY`;中继那一行写的是账号的 key,对话服务商那一行留给对话的 key);「自动」把四项都发空,也就是清掉这个槽位。三个依赖槽位的样子一致:「自动」是「动手模型」选择器和两行媒体槽位的服务商下拉框的第一项,保存它就让槽位回到解析顺序(动手是 `PUT /api/connections/gui {"model": ""}`),控件下面一行「当前为 服务商 · 模型」说明今天解析成什么,来自运行时的 `effective_*` 字段。没有这些路由的运行时不显示这两行。模块是 `web/src/models.ts`(行的值、选择器的选项);`web/src/models.test.ts` 检查它。 「动手模型」「图片模型」「短片模型」三个控件是同一个选择器(`web/src/components/ModelPicker.tsx`):一个写着「服务商 · 模型」的按钮,点开是一个面板,「自动」排第一。列表很长的服务商(OpenRouter、硅基流动)起初只显示八个模型,目录里这个槽位的默认模型和你当前选的排在最前,组尾是「还有 {n} 个」;所有行加起来超过八个时,「搜索模型」输入框边打字边按模型 id 或名称过滤每一组(都不匹配时显示「没有匹配的模型」)。按 Esc 或点面板外面关闭。折叠和搜索的逻辑在 `web/src/model-list.ts`,由 `web/src/model-list.test.ts` 检查。 diff --git a/nanomuse/server/static/assets/AccountScreen-bHMDrVr5.js b/nanomuse/server/static/assets/AccountScreen-BltVqMHJ.js similarity index 97% rename from nanomuse/server/static/assets/AccountScreen-bHMDrVr5.js rename to nanomuse/server/static/assets/AccountScreen-BltVqMHJ.js index 18b7955ab..d3ff78bf0 100644 --- a/nanomuse/server/static/assets/AccountScreen-bHMDrVr5.js +++ b/nanomuse/server/static/assets/AccountScreen-BltVqMHJ.js @@ -1 +1 @@ -import{E as e,J as t,K as n,Q as r,R as i,Y as a,b as o,f as s,k as c,q as l,x as u}from"./MuseHeader-Pw-NI98v.js";import{A as d,s as f,t as p}from"./StarNudge-DjXecvWj.js";import{n as m}from"./external-link-Xj5fjR8v.js";import{a as h,i as g}from"./Form-DwKuBk1V.js";import{t as _}from"./clapperboard-BokpXv9J.js";import{t as v}from"./database-zap-CzaFBl6C.js";import{t as y}from"./image-crWy0a06.js";import{$ as b,A as x,G as S,J as C,K as w,V as T,ct as E,gt as D,ot as O,t as k,ut as A}from"./index-CIdGZ5PB.js";import{t as j}from"./BackBar-Dl56jHZM.js";var M=t(`gift`,[[`path`,{d:`M12 7v14`,key:`1akyts`}],[`path`,{d:`M20 11v8a2 2 0 0 1-2 2H6a2 2 0 0 1-2-2v-8`,key:`1sqzm4`}],[`path`,{d:`M7.5 7a1 1 0 0 1 0-5A4.8 8 0 0 1 12 7a4.8 8 0 0 1 4.5-5 1 1 0 0 1 0 5`,key:`kc0143`}],[`rect`,{x:`3`,y:`7`,width:`18`,height:`4`,rx:`1`,key:`1hberx`}]]),N=r(a(),1),P=o();function F(){let{state:e,toast:t,setTab:r}=s(),i=n(),a=e.hub?.account??null,[o,c]=(0,N.useState)(null),[l,d]=(0,N.useState)(null),[m,h]=(0,N.useState)(null),[g,_]=(0,N.useState)(!1),v=!!a?.signed_in,y=f(),b=async()=>{if(v){_(!0);try{let[e,t,n]=await Promise.all([u.cloudMe(),u.cloudSessions(),u.cloudEvents(40)]);c(e),d(t.sessions),h(n.events)}catch(e){t(e.message)}finally{_(!1)}}};return(0,N.useEffect)(()=>{b()},[v,a?.has_password]),(0,P.jsxs)(`div`,{className:`flex h-full flex-col`,children:[(0,P.jsx)(j,{title:i(`Account`),description:i(v?`nanoMuse Cloud · one account for all your devices`:`Sign in to nanoMuse Cloud`)}),(0,P.jsx)(`div`,{className:`flex-1 overflow-y-auto px-4 pb-8 space-y-4`,children:v?(0,P.jsxs)(P.Fragment,{children:[(0,P.jsx)(L,{account:a,me:o}),o&&(0,P.jsx)(p,{moment:`signed_in`}),o&&(0,P.jsx)(R,{me:o,onChanged:()=>void b()}),o?.invite?.code&&(0,P.jsx)(B,{invite:o.invite}),o&&(0,P.jsx)(H,{me:o}),o&&(0,P.jsx)(z,{me:o}),(0,P.jsx)(W,{account:a,onChanged:()=>void b()}),(0,P.jsx)(G,{sessions:l,loading:g,onChanged:()=>void b()}),m&&m.length>0&&(0,P.jsx)(q,{events:m}),(0,P.jsx)(J,{account:a,onDone:()=>r(`chat`)})]}):(0,P.jsxs)(I,{children:[(0,P.jsx)(`p`,{className:`text-[13.5px] text-muted leading-relaxed`,children:i(`Free. One account for all your devices, with a model and ¥{allowance} of use to start; a code the first time, a password afterwards if you like.`,{allowance:(y.allowance_cny??10).toFixed(0)})}),(0,P.jsx)(k,{onSignedIn:()=>t(i(`Signed in to nanoMuse Cloud.`))})]})})]})}function I({title:t,children:n,tone:r}){return(0,P.jsxs)(`section`,{className:e(`rounded-3xl border p-4 space-y-3 shadow-sm`,r===`danger`?`border-rose-500/25 bg-rose-500/[0.04]`:`border-border/70 bg-surface`),children:[t&&(0,P.jsx)(`h2`,{className:`text-[12px] font-semibold uppercase tracking-wide text-muted`,children:t}),n]})}function L({account:e,me:t}){let r=n(),a=e?.hint??``,o=t?.account.created_at?new Date(t.account.created_at*1e3):null;return(0,P.jsxs)(`section`,{className:`relative overflow-hidden rounded-3xl border border-border/70 bg-surface p-5 shadow-sm`,children:[(0,P.jsx)(`div`,{className:`pointer-events-none absolute -right-16 -top-20 h-48 w-48 rounded-full bg-accent/15 blur-3xl`}),(0,P.jsxs)(`div`,{className:`flex items-center gap-4`,children:[(0,P.jsx)(`div`,{className:`flex h-14 w-14 shrink-0 items-center justify-center rounded-2xl bg-gradient-to-br from-accent to-sky-400 text-[22px] font-bold text-white shadow-md`,children:(a.replace(/[^a-z0-9]/gi,``).slice(0,1)||`n`).toUpperCase()}),(0,P.jsxs)(`div`,{className:`min-w-0 flex-1`,children:[(0,P.jsx)(`div`,{className:`truncate text-[18px] font-semibold tracking-tight`,children:a}),(0,P.jsxs)(`div`,{className:`mt-0.5 flex flex-wrap items-center gap-x-2 gap-y-0.5 text-[12.5px] text-muted`,children:[(0,P.jsx)(`span`,{children:e?.channel===`phone`||e?.channel===`sms`?r(`Mobile number`):r(`E-mail`)}),o&&(0,P.jsxs)(`span`,{children:[`· `,r(`since {date}`,{date:o.toLocaleDateString(i())})]}),t?.account.member&&(0,P.jsxs)(`span`,{className:`inline-flex items-center gap-1 rounded-full bg-emerald-500/12 px-2 py-0.5 text-[11px] font-medium text-emerald-700 dark:text-emerald-300`,children:[(0,P.jsx)(w,{size:11}),` `,r(`Unlimited`)]})]})]})]}),e?.account_id&&(0,P.jsxs)(`div`,{className:`mt-4 flex items-center justify-between gap-3 rounded-2xl bg-surface-2/70 px-3 py-2 text-[12px]`,children:[(0,P.jsx)(`span`,{className:`text-muted`,children:r(`Account id`)}),(0,P.jsx)(`code`,{className:`truncate font-mono text-[11.5px] text-fg/80`,children:e.account_id})]})]})}function R({me:t,onChanged:r}){let i=n(),a=t.spend,o=a.grant??a.daily_cap??0,s=a.grant===void 0?a.today:a.total,c=a.left??(a.unlimited?null:Math.max(0,o-s)),l=!a.unlimited&&o>0,u=l?Math.min(100,Math.round(s/o*100)):0,f=a.usd_cny??0,p=e=>f>0?` ≈ $${(e/f).toFixed(2)}`:``,m=l&&(c??0)<=0,h=l&&!m&&(a.warn??u>=80),g={left:c,grant:o,invite_url:t.invite?.url,invite_bonus_cny:a.invite_bonus_cny??t.invite?.bonus_cny,invitee_bonus_cny:a.invitee_bonus_cny??t.invite?.invitee_bonus_cny,own_key_docs:a.own_key_docs,guidance:a.guidance};return(0,P.jsxs)(I,{title:i(`Free allowance`),children:[(0,P.jsxs)(`div`,{className:`flex items-end justify-between gap-3`,children:[(0,P.jsxs)(`div`,{children:[(0,P.jsx)(`div`,{className:`text-[28px] font-bold tracking-tight leading-none`,children:l?(0,P.jsxs)(P.Fragment,{children:[`¥`,(c??0).toFixed(2),(0,P.jsxs)(`span`,{className:`text-[14px] font-medium text-muted`,children:[` `,i(`left of ¥{grant}`,{grant:o.toFixed(0)})]})]}):(0,P.jsxs)(P.Fragment,{children:[`¥`,s.toFixed(2)]})}),(0,P.jsx)(`div`,{className:`mt-1 text-[12.5px] text-muted`,children:l?i(`¥{spent} used{usd}; the allowance does not reset.`,{spent:s.toFixed(2),usd:p(s)}):i(`No limit on this account.`)})]}),(0,P.jsxs)(`div`,{className:`text-right text-[12.5px] text-muted`,children:[(0,P.jsx)(`div`,{children:i(`All time`)}),(0,P.jsxs)(`div`,{className:`text-[15px] font-semibold text-fg`,children:[`¥`,a.total.toFixed(2)]}),f>0&&(0,P.jsxs)(`div`,{className:`text-[11.5px]`,children:[`≈ $`,(a.total/f).toFixed(2)]})]})]}),l&&(0,P.jsx)(`div`,{className:`h-2 overflow-hidden rounded-full bg-surface-2`,children:(0,P.jsx)(`div`,{className:e(`h-full rounded-full transition-all`,u>=100?`bg-rose-500`:u>=80?`bg-amber-500`:`bg-accent`),style:{width:`${u}%`}})}),l&&(0,P.jsxs)(`p`,{className:`text-[12.5px] text-muted`,children:[i(`¥{allowance} to start, +¥{invite} for each friend you invite, and +¥{invite} for them; after that, your own key keeps the model going.`,{allowance:(a.allowance_cny??10).toFixed(0),invite:(g.invite_bonus_cny??5).toFixed(0)}),` `,!m&&!h&&d(i,{signed_in:!0,channel:t.account.channel,region:t.account.region})]}),(m||h)&&(0,P.jsx)(x,{info:g,exhausted:m,onChanged:r})]})}function z({me:e}){let t=n(),{setTab:r}=s(),i=e.contribute??{on:!1,samples:0};return(0,P.jsx)(I,{title:t(`Data controls`),children:(0,P.jsxs)(`button`,{type:`button`,onClick:()=>{window.location.hash=`data`,r(`you`)},className:`flex w-full items-center gap-3 text-left`,children:[(0,P.jsx)(`span`,{className:`flex h-9 w-9 shrink-0 items-center justify-center rounded-xl bg-surface-2 text-fg`,children:(0,P.jsx)(v,{size:18})}),(0,P.jsxs)(`span`,{className:`min-w-0 flex-1`,children:[(0,P.jsx)(`span`,{className:`block text-[14px] font-medium`,children:t(`Help improve nanoMuse's AI models`)}),(0,P.jsxs)(`span`,{className:`block text-[12.5px] text-muted`,children:[i.on?t(`On`):t(`Off`),i.samples>0&&` · ${t(`{n} turns kept so far`,{n:String(i.samples)})}`]})]}),(0,P.jsx)(`span`,{className:`text-[13px] font-medium text-accent`,children:t(`Open`)})]})})}function B({invite:t}){let r=n(),{toast:i}=s(),a=t.url||`https://nanomuse.cn/web/?invite=${t.code}`,o=t.earned_cny??t.invites*t.bonus_cny,c=async e=>{try{await navigator.clipboard.writeText(e),i(r(`Copied`))}catch{i(e)}},l=async()=>{let e=r(`Try nanoMuse with me, a fully open-source personal agent, free to use. Sign up with my code {code}: {link}`,{code:t.code,link:a}),n=navigator;if(n.share)try{await n.share({text:e});return}catch{}await c(e)};return(0,P.jsxs)(I,{title:r(`Invite a friend`),children:[(0,P.jsx)(`p`,{className:`text-[12.5px] text-muted`,children:r(`Each new person who signs up with your code adds ¥{bonus} to your allowance, and ¥{bonus} to theirs. It never expires.`,{bonus:t.bonus_cny.toFixed(0)})}),(0,P.jsxs)(`div`,{className:`flex items-center justify-between gap-3 rounded-2xl bg-surface-2/70 px-3 py-2`,children:[(0,P.jsxs)(`div`,{children:[(0,P.jsx)(`div`,{className:`text-[11px] text-muted`,children:r(`Your code`)}),(0,P.jsx)(`code`,{className:`font-mono text-[18px] font-semibold tracking-[0.2em]`,children:t.code})]}),(0,P.jsxs)(`button`,{type:`button`,onClick:()=>void c(t.code),className:e(h,`inline-flex items-center gap-1.5`),children:[(0,P.jsx)(D,{size:14}),` `,r(`Copy`)]})]}),(0,P.jsxs)(`div`,{className:`flex gap-2`,children:[(0,P.jsxs)(`button`,{type:`button`,onClick:()=>void l(),className:e(g,`inline-flex flex-1 items-center justify-center gap-1.5 py-2.5`),children:[(0,P.jsx)(C,{size:14}),` `,r(`Share the link`)]}),(0,P.jsxs)(`button`,{type:`button`,onClick:()=>void c(a),className:e(h,`inline-flex items-center gap-1.5`),children:[(0,P.jsx)(M,{size:14}),` `,r(`Copy the link`)]})]}),(0,P.jsxs)(`p`,{className:`text-[12.5px] text-muted`,children:[r(`{n} friends joined`,{n:String(t.invites)}),o>0&&(0,P.jsxs)(P.Fragment,{children:[` · `,r(`¥{amount} added by invitations`,{amount:o.toFixed(0)})]})]})]})}var V={chat:{label:`Chat`,icon:(0,P.jsx)(O,{size:15}),tone:`bg-accent`},image:{label:`Pictures`,icon:(0,P.jsx)(y,{size:15}),tone:`bg-violet-500`},video:{label:`Clips`,icon:(0,P.jsx)(_,{size:15}),tone:`bg-pink-500`},realtime:{label:`Calls`,icon:(0,P.jsx)(b,{size:15}),tone:`bg-emerald-500`}};function H({me:t}){let r=n(),[i,a]=(0,N.useState)(`today`),o=i===`today`?t.usage.today.by_kind:t.usage.total.by_kind,s=t.usage.kinds.length?t.usage.kinds:[`chat`,`image`,`video`,`realtime`],c=new Map(o.map(e=>[e.kind,e])),l=o.reduce((e,t)=>e+t.cost_cny,0),u=t.usage.total.by_model.slice(0,8);return(0,P.jsxs)(I,{title:r(`Usage`),children:[(0,P.jsxs)(`div`,{className:`flex items-center justify-between`,children:[(0,P.jsx)(`p`,{className:`text-[12.5px] text-muted`,children:r(`Every kind of use is counted, not just the chat model.`)}),(0,P.jsx)(`div`,{className:`flex rounded-full bg-surface-2/80 p-0.5 text-[12px] font-medium`,children:[`today`,`total`].map(t=>(0,P.jsx)(`button`,{type:`button`,onClick:()=>a(t),className:e(`rounded-full px-2.5 py-1 transition`,i===t?`bg-surface shadow-sm`:`text-muted`),children:r(t===`today`?`Today`:`All time`)},t))})]}),l>0&&(0,P.jsx)(`div`,{className:`flex h-2.5 overflow-hidden rounded-full bg-surface-2`,children:s.map(t=>{let n=c.get(t);return!n||n.cost_cny<=0?null:(0,P.jsx)(`div`,{className:e(`h-full`,V[t]?.tone??`bg-fg/40`),style:{width:`${n.cost_cny/l*100}%`},title:r(V[t]?.label??t)},t)})}),(0,P.jsx)(`ul`,{className:`grid grid-cols-2 gap-2`,children:s.map(t=>{let n=c.get(t),i=V[t];return(0,P.jsxs)(`li`,{className:`rounded-2xl bg-surface-2/60 p-3`,children:[(0,P.jsxs)(`div`,{className:`flex items-center gap-1.5 text-[12.5px] text-muted`,children:[(0,P.jsx)(`span`,{className:e(`flex h-5 w-5 items-center justify-center rounded-md text-white`,i?.tone??`bg-fg/40`),children:i?.icon}),r(i?.label??t)]}),(0,P.jsxs)(`div`,{className:`mt-1.5 text-[17px] font-semibold tracking-tight`,children:[`¥`,(n?.cost_cny??0).toFixed(2)]}),(0,P.jsx)(`div`,{className:`text-[11.5px] text-muted`,children:n?t===`realtime`?r(`{n} answers · {tokens} tokens`,{n:n.requests,tokens:U(n.prompt_tokens+n.completion_tokens)}):t===`chat`?r(`{n} requests · {tokens} tokens`,{n:n.requests,tokens:U(n.prompt_tokens+n.completion_tokens)}):r(`{n} requests`,{n:n.requests}):r(`Nothing yet`)})]},t)})}),u.length>0&&(0,P.jsxs)(`div`,{children:[(0,P.jsx)(`div`,{className:`mb-1.5 text-[12px] font-medium text-muted`,children:r(`By model, all time`)}),(0,P.jsx)(`ul`,{className:`divide-y divide-border/60 rounded-2xl border border-border/60`,children:u.map(t=>(0,P.jsxs)(`li`,{className:`flex items-center gap-2 px-3 py-2 text-[12.5px]`,children:[(0,P.jsx)(`span`,{className:e(`h-2 w-2 shrink-0 rounded-full`,V[t.kind]?.tone??`bg-fg/40`)}),(0,P.jsx)(`span`,{className:`min-w-0 flex-1 truncate font-mono text-[12px]`,children:t.model}),(0,P.jsx)(`span`,{className:`text-muted`,children:U(t.prompt_tokens+t.completion_tokens)}),(0,P.jsxs)(`span`,{className:`w-16 text-right font-medium`,children:[`¥`,t.cost_cny.toFixed(2)]})]},`${t.model}-${t.kind}`))})]})]})}function U(e){return e>=1e6?`${(e/1e6).toFixed(1)}M`:e>=1e3?`${(e/1e3).toFixed(e>=1e5?0:1)}k`:String(e)}function W({account:t,onChanged:r}){let i=n(),{toast:a}=s(),o=!!t?.has_password,[c,d]=(0,N.useState)(!1),[f,p]=(0,N.useState)(``),[h,g]=(0,N.useState)(``),[_,v]=(0,N.useState)(``),[y,b]=(0,N.useState)(!1),[x,S]=(0,N.useState)(null),C=async(e=!1)=>{if(!(!e&&(h.length<8||h!==_))){b(!0),S(null);try{await u.cloudPassword(e?``:h,o?f:void 0),a(i(e?`Password removed.`:o?`Password changed.`:`Password set.`)),d(!1),p(``),g(``),v(``),r()}catch(e){S(i(e.message))}finally{b(!1)}}};return(0,P.jsxs)(I,{title:i(`Password`),children:[(0,P.jsxs)(`div`,{className:`flex items-center gap-3`,children:[(0,P.jsx)(`span`,{className:e(`flex h-9 w-9 items-center justify-center rounded-xl`,o?`bg-emerald-500/12 text-emerald-600 dark:text-emerald-300`:`bg-surface-2 text-muted`),children:(0,P.jsx)(A,{size:17})}),(0,P.jsxs)(`div`,{className:`min-w-0 flex-1 text-[13.5px]`,children:[(0,P.jsx)(`div`,{className:`font-medium`,children:i(o?`A password is set`:`No password yet`)}),(0,P.jsx)(`div`,{className:`text-[12.5px] text-muted`,children:i(o?`Sign in with it on a new device, or with a code as before.`:`Optional. With one, a new device can sign in without waiting for a code.`)})]}),!c&&(0,P.jsx)(`button`,{type:`button`,onClick:()=>d(!0),className:e(`flex items-center justify-center gap-1.5 rounded-2xl border border-border px-4 py-2.5 text-[14px] font-medium text-muted disabled:opacity-40`,`shrink-0 px-3 py-2 text-[13px]`),children:i(o?`Change`:`Set`)})]}),c&&(0,P.jsxs)(`form`,{className:`space-y-2.5`,onSubmit:e=>{e.preventDefault(),C()},children:[o&&(0,P.jsx)(`input`,{type:`password`,value:f,onChange:e=>p(e.target.value),placeholder:i(`Current password`),autoComplete:`current-password`,className:`w-full rounded-2xl bg-surface-2 px-3.5 py-2.5 text-[14.5px] outline-none focus:ring-2 focus:ring-accent/40`}),(0,P.jsx)(`input`,{type:`password`,value:h,onChange:e=>g(e.target.value),placeholder:i(`New password (8 characters or more)`),autoComplete:`new-password`,autoFocus:!0,className:`w-full rounded-2xl bg-surface-2 px-3.5 py-2.5 text-[14.5px] outline-none focus:ring-2 focus:ring-accent/40`}),(0,P.jsx)(`input`,{type:`password`,value:_,onChange:e=>v(e.target.value),placeholder:i(`Once more`),autoComplete:`new-password`,className:`w-full rounded-2xl bg-surface-2 px-3.5 py-2.5 text-[14.5px] outline-none focus:ring-2 focus:ring-accent/40`}),_&&h!==_&&(0,P.jsx)(`p`,{className:`text-[12px] text-rose-600 dark:text-rose-300`,children:i(`The two do not match.`)}),x&&(0,P.jsx)(`p`,{className:`rounded-2xl bg-rose-500/12 px-3 py-2 text-[12.5px] text-rose-700 dark:text-rose-300`,children:x}),(0,P.jsxs)(`div`,{className:`flex flex-wrap gap-2`,children:[(0,P.jsxs)(`button`,{type:`submit`,disabled:y||h.length<8||h!==_||o&&!f,className:e(`flex items-center justify-center gap-1.5 rounded-2xl bg-accent text-accent-fg px-4 py-2.5 text-[14px] font-medium disabled:opacity-40`,`flex-1`),children:[y?(0,P.jsx)(l,{size:15,className:`animate-spin`}):(0,P.jsx)(m,{size:15}),` `,i(o?`Change password`:`Set password`)]}),o&&(0,P.jsx)(`button`,{type:`button`,disabled:y||!f,onClick:()=>void C(!0),className:`flex items-center justify-center gap-1.5 rounded-2xl border border-border px-4 py-2.5 text-[14px] font-medium text-muted disabled:opacity-40`,children:i(`Remove`)}),(0,P.jsx)(`button`,{type:`button`,onClick:()=>d(!1),className:`flex items-center justify-center gap-1.5 rounded-2xl border border-border px-4 py-2.5 text-[14px] font-medium text-muted disabled:opacity-40`,children:i(`Cancel`)})]})]})]})}function G({sessions:e,loading:t,onChanged:r}){let a=n(),{toast:o}=s(),[d,f]=(0,N.useState)(null),p=async e=>{if(window.confirm(a(`Sign out {device}? It will need to sign in again.`,{device:e.device||e.prefix}))){f(e.prefix);try{await u.cloudRevokeSession(e.prefix),r()}catch(e){o(e.message)}finally{f(null)}}};return(0,P.jsx)(I,{title:a(`Signed in on`),children:e?(0,P.jsx)(`ul`,{className:`divide-y divide-border/60`,children:e.map(e=>(0,P.jsxs)(`li`,{className:`flex items-center gap-3 py-2.5`,children:[(0,P.jsx)(`span`,{className:`flex h-9 w-9 shrink-0 items-center justify-center rounded-xl bg-surface-2 text-fg/70`,children:(0,P.jsx)(S,{size:17})}),(0,P.jsxs)(`div`,{className:`min-w-0 flex-1`,children:[(0,P.jsxs)(`div`,{className:`flex items-center gap-2 text-[13.5px] font-medium`,children:[(0,P.jsx)(`span`,{className:`truncate`,children:e.device||a(`Unnamed device`)}),e.current&&(0,P.jsx)(`span`,{className:`rounded-full bg-accent/12 px-2 py-0.5 text-[10.5px] font-semibold text-accent`,children:a(`This one`)})]}),(0,P.jsxs)(`div`,{className:`truncate text-[12px] text-muted`,children:[e.via===`password`?a(`password`):a(`code`),` · `,a(`since {date}`,{date:new Date(e.created_at*1e3).toLocaleDateString(i())}),e.last_used_at?` · ${a(`used {when}`,{when:c(e.last_used_at)})}`:``]})]}),!e.current&&(0,P.jsx)(`button`,{type:`button`,disabled:d!==null,onClick:()=>void p(e),className:`rounded-full px-3 py-1.5 text-[12.5px] font-medium text-rose-600 hover:bg-rose-500/10 dark:text-rose-300`,children:d===e.prefix?(0,P.jsx)(l,{size:14,className:`animate-spin`}):a(`Sign out`)})]},e.prefix))}):(0,P.jsx)(`div`,{className:`flex justify-center py-3 text-muted`,children:t?(0,P.jsx)(l,{size:18,className:`animate-spin`}):null})})}var K={"account.created":`Account created`,"sign_in.code":`Signed in with a code`,"sign_in.password":`Signed in with the password`,"sign_in.failed":`A sign-in attempt failed`,sign_out:`Signed out`,"sign_out.all":`Signed out everywhere`,"password.set":`Password set`,"password.changed":`Password changed`,"password.cleared":`Password removed`,"budget.refused":`A request was refused: the allowance is used up`,"call.ended":`Call ended`,"upstream.error":`The model provider returned an error`,"credit.granted":`Allowance added`,"pool.set":`Allowance adjusted`,"invite.accepted":`Signed up with a friend's code`,"invite.used":`A friend signed up with your code`,"invite.unknown":`An invite code was not recognised`,"contribute.default":`Data controls: on for new accounts`,"contribute.on":`Data controls: help improve turned on`,"contribute.off":`Data controls: help improve turned off`,"contribute.deleted":`Data controls: kept conversations deleted`,"profile.put":`Agent's name and look saved`,"profile.clear":`Agent's name and look cleared`};function q({events:e}){let t=n(),[r,i]=(0,N.useState)(!1),a=r?e:e.slice(0,6);return(0,P.jsxs)(I,{title:t(`Recent activity`),children:[(0,P.jsx)(`ul`,{className:`space-y-2`,children:a.map((e,n)=>(0,P.jsxs)(`li`,{className:`flex gap-3 text-[12.5px]`,children:[(0,P.jsx)(`span`,{className:`w-[74px] shrink-0 text-muted`,children:c(e.ts)}),(0,P.jsxs)(`span`,{className:`min-w-0 flex-1`,children:[(0,P.jsx)(`span`,{className:`font-medium`,children:t(K[e.kind]??e.kind)}),e.detail&&(0,P.jsx)(`span`,{className:`ml-1.5 break-all text-muted`,children:e.detail})]})]},`${e.ts}-${n}`))}),e.length>6&&(0,P.jsx)(`button`,{type:`button`,onClick:()=>i(e=>!e),className:`text-[12.5px] font-medium text-accent`,children:r?t(`Show less`):t(`Show all {n}`,{n:e.length})})]})}function J({account:t,onDone:r}){let i=n(),{toast:a}=s(),[o,c]=(0,N.useState)(null),d=async e=>{let t=i(e===`here`?`Sign out of nanoMuse Cloud on this device? The hub and the Cloud model stop working here until you sign in again.`:e===`all`?`Sign out on every device, including this one?`:`Delete the account? The relay forgets your identifier, your devices and your usage. This cannot be undone.`);if(window.confirm(t)&&(e!==`delete`||window.confirm(i(`Really delete it?`)))){c(e);try{e===`here`?await u.cloudSignOut():e===`all`?await u.cloudSignOutAll(!0):await u.cloudDelete(),a(i(e===`delete`?`Account deleted.`:`Signed out.`)),r()}catch(e){a(e.message)}finally{c(null)}}};return(0,P.jsxs)(I,{tone:`danger`,children:[(0,P.jsxs)(`div`,{className:`flex flex-wrap gap-2`,children:[(0,P.jsxs)(`button`,{type:`button`,disabled:o!==null,onClick:()=>void d(`here`),className:e(h,`flex-1`),children:[o===`here`?(0,P.jsx)(l,{size:15,className:`animate-spin`}):(0,P.jsx)(E,{size:15}),` `,i(`Sign out`)]}),(0,P.jsxs)(`button`,{type:`button`,disabled:o!==null,onClick:()=>void d(`all`),className:e(h,`flex-1`),children:[o===`all`?(0,P.jsx)(l,{size:15,className:`animate-spin`}):(0,P.jsx)(S,{size:15}),` `,i(`Sign out everywhere`)]})]}),(0,P.jsxs)(`button`,{type:`button`,disabled:o!==null,onClick:()=>void d(`delete`),className:`flex w-full items-center justify-center gap-1.5 rounded-2xl py-2 text-[13px] font-medium text-rose-600 hover:bg-rose-500/10 dark:text-rose-300`,children:[o===`delete`?(0,P.jsx)(l,{size:15,className:`animate-spin`}):(0,P.jsx)(T,{size:15}),` `,i(`Delete the account`)]}),t?.is_model&&(0,P.jsx)(`p`,{className:`text-center text-[11.5px] text-muted`,children:i(`The Cloud model is in use; after signing out, pick another under Connections.`)})]})}export{F as AccountScreen}; \ No newline at end of file +import{E as e,J as t,K as n,Q as r,R as i,Y as a,b as o,f as s,k as c,q as l,x as u}from"./MuseHeader-BDWXHKHT.js";import{A as d,s as f,t as p}from"./StarNudge-B8P2bPEz.js";import{n as m}from"./external-link-CZH-rQLq.js";import{a as h,i as g}from"./Form-B3Ejw5aI.js";import{t as _}from"./clapperboard-C1_tjTS2.js";import{t as v}from"./database-zap-6Cufqig1.js";import{t as y}from"./image-kcW5PNCE.js";import{$ as b,A as x,G as S,J as C,K as w,V as T,ct as E,gt as D,ot as O,t as k,ut as A}from"./index-DKrXW2Qj.js";import{t as j}from"./BackBar-DqcCClHf.js";var M=t(`gift`,[[`path`,{d:`M12 7v14`,key:`1akyts`}],[`path`,{d:`M20 11v8a2 2 0 0 1-2 2H6a2 2 0 0 1-2-2v-8`,key:`1sqzm4`}],[`path`,{d:`M7.5 7a1 1 0 0 1 0-5A4.8 8 0 0 1 12 7a4.8 8 0 0 1 4.5-5 1 1 0 0 1 0 5`,key:`kc0143`}],[`rect`,{x:`3`,y:`7`,width:`18`,height:`4`,rx:`1`,key:`1hberx`}]]),N=r(a(),1),P=o();function F(){let{state:e,toast:t,setTab:r}=s(),i=n(),a=e.hub?.account??null,[o,c]=(0,N.useState)(null),[l,d]=(0,N.useState)(null),[m,h]=(0,N.useState)(null),[g,_]=(0,N.useState)(!1),v=!!a?.signed_in,y=f(),b=async()=>{if(v){_(!0);try{let[e,t,n]=await Promise.all([u.cloudMe(),u.cloudSessions(),u.cloudEvents(40)]);c(e),d(t.sessions),h(n.events)}catch(e){t(e.message)}finally{_(!1)}}};return(0,N.useEffect)(()=>{b()},[v,a?.has_password]),(0,P.jsxs)(`div`,{className:`flex h-full flex-col`,children:[(0,P.jsx)(j,{title:i(`Account`),description:i(v?`nanoMuse Cloud · one account for all your devices`:`Sign in to nanoMuse Cloud`)}),(0,P.jsx)(`div`,{className:`flex-1 overflow-y-auto px-4 pb-8 space-y-4`,children:v?(0,P.jsxs)(P.Fragment,{children:[(0,P.jsx)(L,{account:a,me:o}),o&&(0,P.jsx)(p,{moment:`signed_in`}),o&&(0,P.jsx)(R,{me:o,onChanged:()=>void b()}),o?.invite?.code&&(0,P.jsx)(B,{invite:o.invite}),o&&(0,P.jsx)(H,{me:o}),o&&(0,P.jsx)(z,{me:o}),(0,P.jsx)(W,{account:a,onChanged:()=>void b()}),(0,P.jsx)(G,{sessions:l,loading:g,onChanged:()=>void b()}),m&&m.length>0&&(0,P.jsx)(q,{events:m}),(0,P.jsx)(J,{account:a,onDone:()=>r(`chat`)})]}):(0,P.jsxs)(I,{children:[(0,P.jsx)(`p`,{className:`text-[13.5px] text-muted leading-relaxed`,children:i(`Free. One account for all your devices, with a model and ¥{allowance} of use to start; a code the first time, a password afterwards if you like.`,{allowance:(y.allowance_cny??10).toFixed(0)})}),(0,P.jsx)(k,{onSignedIn:()=>t(i(`Signed in to nanoMuse Cloud.`))})]})})]})}function I({title:t,children:n,tone:r}){return(0,P.jsxs)(`section`,{className:e(`rounded-3xl border p-4 space-y-3 shadow-sm`,r===`danger`?`border-rose-500/25 bg-rose-500/[0.04]`:`border-border/70 bg-surface`),children:[t&&(0,P.jsx)(`h2`,{className:`text-[12px] font-semibold uppercase tracking-wide text-muted`,children:t}),n]})}function L({account:e,me:t}){let r=n(),a=e?.hint??``,o=t?.account.created_at?new Date(t.account.created_at*1e3):null;return(0,P.jsxs)(`section`,{className:`relative overflow-hidden rounded-3xl border border-border/70 bg-surface p-5 shadow-sm`,children:[(0,P.jsx)(`div`,{className:`pointer-events-none absolute -right-16 -top-20 h-48 w-48 rounded-full bg-accent/15 blur-3xl`}),(0,P.jsxs)(`div`,{className:`flex items-center gap-4`,children:[(0,P.jsx)(`div`,{className:`flex h-14 w-14 shrink-0 items-center justify-center rounded-2xl bg-gradient-to-br from-accent to-sky-400 text-[22px] font-bold text-white shadow-md`,children:(a.replace(/[^a-z0-9]/gi,``).slice(0,1)||`n`).toUpperCase()}),(0,P.jsxs)(`div`,{className:`min-w-0 flex-1`,children:[(0,P.jsx)(`div`,{className:`truncate text-[18px] font-semibold tracking-tight`,children:a}),(0,P.jsxs)(`div`,{className:`mt-0.5 flex flex-wrap items-center gap-x-2 gap-y-0.5 text-[12.5px] text-muted`,children:[(0,P.jsx)(`span`,{children:e?.channel===`phone`||e?.channel===`sms`?r(`Mobile number`):r(`E-mail`)}),o&&(0,P.jsxs)(`span`,{children:[`· `,r(`since {date}`,{date:o.toLocaleDateString(i())})]}),t?.account.member&&(0,P.jsxs)(`span`,{className:`inline-flex items-center gap-1 rounded-full bg-emerald-500/12 px-2 py-0.5 text-[11px] font-medium text-emerald-700 dark:text-emerald-300`,children:[(0,P.jsx)(w,{size:11}),` `,r(`Unlimited`)]})]})]})]}),e?.account_id&&(0,P.jsxs)(`div`,{className:`mt-4 flex items-center justify-between gap-3 rounded-2xl bg-surface-2/70 px-3 py-2 text-[12px]`,children:[(0,P.jsx)(`span`,{className:`text-muted`,children:r(`Account id`)}),(0,P.jsx)(`code`,{className:`truncate font-mono text-[11.5px] text-fg/80`,children:e.account_id})]})]})}function R({me:t,onChanged:r}){let i=n(),a=t.spend,o=a.grant??a.daily_cap??0,s=a.grant===void 0?a.today:a.total,c=a.left??(a.unlimited?null:Math.max(0,o-s)),l=!a.unlimited&&o>0,u=l?Math.min(100,Math.round(s/o*100)):0,f=a.usd_cny??0,p=e=>f>0?` ≈ $${(e/f).toFixed(2)}`:``,m=l&&(c??0)<=0,h=l&&!m&&(a.warn??u>=80),g={left:c,grant:o,invite_url:t.invite?.url,invite_bonus_cny:a.invite_bonus_cny??t.invite?.bonus_cny,invitee_bonus_cny:a.invitee_bonus_cny??t.invite?.invitee_bonus_cny,own_key_docs:a.own_key_docs,guidance:a.guidance};return(0,P.jsxs)(I,{title:i(`Free allowance`),children:[(0,P.jsxs)(`div`,{className:`flex items-end justify-between gap-3`,children:[(0,P.jsxs)(`div`,{children:[(0,P.jsx)(`div`,{className:`text-[28px] font-bold tracking-tight leading-none`,children:l?(0,P.jsxs)(P.Fragment,{children:[`¥`,(c??0).toFixed(2),(0,P.jsxs)(`span`,{className:`text-[14px] font-medium text-muted`,children:[` `,i(`left of ¥{grant}`,{grant:o.toFixed(0)})]})]}):(0,P.jsxs)(P.Fragment,{children:[`¥`,s.toFixed(2)]})}),(0,P.jsx)(`div`,{className:`mt-1 text-[12.5px] text-muted`,children:l?i(`¥{spent} used{usd}; the allowance does not reset.`,{spent:s.toFixed(2),usd:p(s)}):i(`No limit on this account.`)})]}),(0,P.jsxs)(`div`,{className:`text-right text-[12.5px] text-muted`,children:[(0,P.jsx)(`div`,{children:i(`All time`)}),(0,P.jsxs)(`div`,{className:`text-[15px] font-semibold text-fg`,children:[`¥`,a.total.toFixed(2)]}),f>0&&(0,P.jsxs)(`div`,{className:`text-[11.5px]`,children:[`≈ $`,(a.total/f).toFixed(2)]})]})]}),l&&(0,P.jsx)(`div`,{className:`h-2 overflow-hidden rounded-full bg-surface-2`,children:(0,P.jsx)(`div`,{className:e(`h-full rounded-full transition-all`,u>=100?`bg-rose-500`:u>=80?`bg-amber-500`:`bg-accent`),style:{width:`${u}%`}})}),l&&(0,P.jsxs)(`p`,{className:`text-[12.5px] text-muted`,children:[i(`¥{allowance} to start, +¥{invite} for each friend you invite, and +¥{invite} for them; after that, your own key keeps the model going.`,{allowance:(a.allowance_cny??10).toFixed(0),invite:(g.invite_bonus_cny??5).toFixed(0)}),` `,!m&&!h&&d(i,{signed_in:!0,channel:t.account.channel,region:t.account.region})]}),(m||h)&&(0,P.jsx)(x,{info:g,exhausted:m,onChanged:r})]})}function z({me:e}){let t=n(),{setTab:r}=s(),i=e.contribute??{on:!1,samples:0};return(0,P.jsx)(I,{title:t(`Data controls`),children:(0,P.jsxs)(`button`,{type:`button`,onClick:()=>{window.location.hash=`data`,r(`you`)},className:`flex w-full items-center gap-3 text-left`,children:[(0,P.jsx)(`span`,{className:`flex h-9 w-9 shrink-0 items-center justify-center rounded-xl bg-surface-2 text-fg`,children:(0,P.jsx)(v,{size:18})}),(0,P.jsxs)(`span`,{className:`min-w-0 flex-1`,children:[(0,P.jsx)(`span`,{className:`block text-[14px] font-medium`,children:t(`Help improve nanoMuse's AI models`)}),(0,P.jsxs)(`span`,{className:`block text-[12.5px] text-muted`,children:[i.on?t(`On`):t(`Off`),i.samples>0&&` · ${t(`{n} turns kept so far`,{n:String(i.samples)})}`]})]}),(0,P.jsx)(`span`,{className:`text-[13px] font-medium text-accent`,children:t(`Open`)})]})})}function B({invite:t}){let r=n(),{toast:i}=s(),a=t.url||`https://nanomuse.cn/web/?invite=${t.code}`,o=t.earned_cny??t.invites*t.bonus_cny,c=async e=>{try{await navigator.clipboard.writeText(e),i(r(`Copied`))}catch{i(e)}},l=async()=>{let e=r(`Try nanoMuse with me, a fully open-source personal agent, free to use. Sign up with my code {code}: {link}`,{code:t.code,link:a}),n=navigator;if(n.share)try{await n.share({text:e});return}catch{}await c(e)};return(0,P.jsxs)(I,{title:r(`Invite a friend`),children:[(0,P.jsx)(`p`,{className:`text-[12.5px] text-muted`,children:r(`Each new person who signs up with your code adds ¥{bonus} to your allowance, and ¥{bonus} to theirs. It never expires.`,{bonus:t.bonus_cny.toFixed(0)})}),(0,P.jsxs)(`div`,{className:`flex items-center justify-between gap-3 rounded-2xl bg-surface-2/70 px-3 py-2`,children:[(0,P.jsxs)(`div`,{children:[(0,P.jsx)(`div`,{className:`text-[11px] text-muted`,children:r(`Your code`)}),(0,P.jsx)(`code`,{className:`font-mono text-[18px] font-semibold tracking-[0.2em]`,children:t.code})]}),(0,P.jsxs)(`button`,{type:`button`,onClick:()=>void c(t.code),className:e(h,`inline-flex items-center gap-1.5`),children:[(0,P.jsx)(D,{size:14}),` `,r(`Copy`)]})]}),(0,P.jsxs)(`div`,{className:`flex gap-2`,children:[(0,P.jsxs)(`button`,{type:`button`,onClick:()=>void l(),className:e(g,`inline-flex flex-1 items-center justify-center gap-1.5 py-2.5`),children:[(0,P.jsx)(C,{size:14}),` `,r(`Share the link`)]}),(0,P.jsxs)(`button`,{type:`button`,onClick:()=>void c(a),className:e(h,`inline-flex items-center gap-1.5`),children:[(0,P.jsx)(M,{size:14}),` `,r(`Copy the link`)]})]}),(0,P.jsxs)(`p`,{className:`text-[12.5px] text-muted`,children:[r(`{n} friends joined`,{n:String(t.invites)}),o>0&&(0,P.jsxs)(P.Fragment,{children:[` · `,r(`¥{amount} added by invitations`,{amount:o.toFixed(0)})]})]})]})}var V={chat:{label:`Chat`,icon:(0,P.jsx)(O,{size:15}),tone:`bg-accent`},image:{label:`Pictures`,icon:(0,P.jsx)(y,{size:15}),tone:`bg-violet-500`},video:{label:`Clips`,icon:(0,P.jsx)(_,{size:15}),tone:`bg-pink-500`},realtime:{label:`Calls`,icon:(0,P.jsx)(b,{size:15}),tone:`bg-emerald-500`}};function H({me:t}){let r=n(),[i,a]=(0,N.useState)(`today`),o=i===`today`?t.usage.today.by_kind:t.usage.total.by_kind,s=t.usage.kinds.length?t.usage.kinds:[`chat`,`image`,`video`,`realtime`],c=new Map(o.map(e=>[e.kind,e])),l=o.reduce((e,t)=>e+t.cost_cny,0),u=t.usage.total.by_model.slice(0,8);return(0,P.jsxs)(I,{title:r(`Usage`),children:[(0,P.jsxs)(`div`,{className:`flex items-center justify-between`,children:[(0,P.jsx)(`p`,{className:`text-[12.5px] text-muted`,children:r(`Every kind of use is counted, not just the chat model.`)}),(0,P.jsx)(`div`,{className:`flex rounded-full bg-surface-2/80 p-0.5 text-[12px] font-medium`,children:[`today`,`total`].map(t=>(0,P.jsx)(`button`,{type:`button`,onClick:()=>a(t),className:e(`rounded-full px-2.5 py-1 transition`,i===t?`bg-surface shadow-sm`:`text-muted`),children:r(t===`today`?`Today`:`All time`)},t))})]}),l>0&&(0,P.jsx)(`div`,{className:`flex h-2.5 overflow-hidden rounded-full bg-surface-2`,children:s.map(t=>{let n=c.get(t);return!n||n.cost_cny<=0?null:(0,P.jsx)(`div`,{className:e(`h-full`,V[t]?.tone??`bg-fg/40`),style:{width:`${n.cost_cny/l*100}%`},title:r(V[t]?.label??t)},t)})}),(0,P.jsx)(`ul`,{className:`grid grid-cols-2 gap-2`,children:s.map(t=>{let n=c.get(t),i=V[t];return(0,P.jsxs)(`li`,{className:`rounded-2xl bg-surface-2/60 p-3`,children:[(0,P.jsxs)(`div`,{className:`flex items-center gap-1.5 text-[12.5px] text-muted`,children:[(0,P.jsx)(`span`,{className:e(`flex h-5 w-5 items-center justify-center rounded-md text-white`,i?.tone??`bg-fg/40`),children:i?.icon}),r(i?.label??t)]}),(0,P.jsxs)(`div`,{className:`mt-1.5 text-[17px] font-semibold tracking-tight`,children:[`¥`,(n?.cost_cny??0).toFixed(2)]}),(0,P.jsx)(`div`,{className:`text-[11.5px] text-muted`,children:n?t===`realtime`?r(`{n} answers · {tokens} tokens`,{n:n.requests,tokens:U(n.prompt_tokens+n.completion_tokens)}):t===`chat`?r(`{n} requests · {tokens} tokens`,{n:n.requests,tokens:U(n.prompt_tokens+n.completion_tokens)}):r(`{n} requests`,{n:n.requests}):r(`Nothing yet`)})]},t)})}),u.length>0&&(0,P.jsxs)(`div`,{children:[(0,P.jsx)(`div`,{className:`mb-1.5 text-[12px] font-medium text-muted`,children:r(`By model, all time`)}),(0,P.jsx)(`ul`,{className:`divide-y divide-border/60 rounded-2xl border border-border/60`,children:u.map(t=>(0,P.jsxs)(`li`,{className:`flex items-center gap-2 px-3 py-2 text-[12.5px]`,children:[(0,P.jsx)(`span`,{className:e(`h-2 w-2 shrink-0 rounded-full`,V[t.kind]?.tone??`bg-fg/40`)}),(0,P.jsx)(`span`,{className:`min-w-0 flex-1 truncate font-mono text-[12px]`,children:t.model}),(0,P.jsx)(`span`,{className:`text-muted`,children:U(t.prompt_tokens+t.completion_tokens)}),(0,P.jsxs)(`span`,{className:`w-16 text-right font-medium`,children:[`¥`,t.cost_cny.toFixed(2)]})]},`${t.model}-${t.kind}`))})]})]})}function U(e){return e>=1e6?`${(e/1e6).toFixed(1)}M`:e>=1e3?`${(e/1e3).toFixed(e>=1e5?0:1)}k`:String(e)}function W({account:t,onChanged:r}){let i=n(),{toast:a}=s(),o=!!t?.has_password,[c,d]=(0,N.useState)(!1),[f,p]=(0,N.useState)(``),[h,g]=(0,N.useState)(``),[_,v]=(0,N.useState)(``),[y,b]=(0,N.useState)(!1),[x,S]=(0,N.useState)(null),C=async(e=!1)=>{if(!(!e&&(h.length<8||h!==_))){b(!0),S(null);try{await u.cloudPassword(e?``:h,o?f:void 0),a(i(e?`Password removed.`:o?`Password changed.`:`Password set.`)),d(!1),p(``),g(``),v(``),r()}catch(e){S(i(e.message))}finally{b(!1)}}};return(0,P.jsxs)(I,{title:i(`Password`),children:[(0,P.jsxs)(`div`,{className:`flex items-center gap-3`,children:[(0,P.jsx)(`span`,{className:e(`flex h-9 w-9 items-center justify-center rounded-xl`,o?`bg-emerald-500/12 text-emerald-600 dark:text-emerald-300`:`bg-surface-2 text-muted`),children:(0,P.jsx)(A,{size:17})}),(0,P.jsxs)(`div`,{className:`min-w-0 flex-1 text-[13.5px]`,children:[(0,P.jsx)(`div`,{className:`font-medium`,children:i(o?`A password is set`:`No password yet`)}),(0,P.jsx)(`div`,{className:`text-[12.5px] text-muted`,children:i(o?`Sign in with it on a new device, or with a code as before.`:`Optional. With one, a new device can sign in without waiting for a code.`)})]}),!c&&(0,P.jsx)(`button`,{type:`button`,onClick:()=>d(!0),className:e(`flex items-center justify-center gap-1.5 rounded-2xl border border-border px-4 py-2.5 text-[14px] font-medium text-muted disabled:opacity-40`,`shrink-0 px-3 py-2 text-[13px]`),children:i(o?`Change`:`Set`)})]}),c&&(0,P.jsxs)(`form`,{className:`space-y-2.5`,onSubmit:e=>{e.preventDefault(),C()},children:[o&&(0,P.jsx)(`input`,{type:`password`,value:f,onChange:e=>p(e.target.value),placeholder:i(`Current password`),autoComplete:`current-password`,className:`w-full rounded-2xl bg-surface-2 px-3.5 py-2.5 text-[14.5px] outline-none focus:ring-2 focus:ring-accent/40`}),(0,P.jsx)(`input`,{type:`password`,value:h,onChange:e=>g(e.target.value),placeholder:i(`New password (8 characters or more)`),autoComplete:`new-password`,autoFocus:!0,className:`w-full rounded-2xl bg-surface-2 px-3.5 py-2.5 text-[14.5px] outline-none focus:ring-2 focus:ring-accent/40`}),(0,P.jsx)(`input`,{type:`password`,value:_,onChange:e=>v(e.target.value),placeholder:i(`Once more`),autoComplete:`new-password`,className:`w-full rounded-2xl bg-surface-2 px-3.5 py-2.5 text-[14.5px] outline-none focus:ring-2 focus:ring-accent/40`}),_&&h!==_&&(0,P.jsx)(`p`,{className:`text-[12px] text-rose-600 dark:text-rose-300`,children:i(`The two do not match.`)}),x&&(0,P.jsx)(`p`,{className:`rounded-2xl bg-rose-500/12 px-3 py-2 text-[12.5px] text-rose-700 dark:text-rose-300`,children:x}),(0,P.jsxs)(`div`,{className:`flex flex-wrap gap-2`,children:[(0,P.jsxs)(`button`,{type:`submit`,disabled:y||h.length<8||h!==_||o&&!f,className:e(`flex items-center justify-center gap-1.5 rounded-2xl bg-accent text-accent-fg px-4 py-2.5 text-[14px] font-medium disabled:opacity-40`,`flex-1`),children:[y?(0,P.jsx)(l,{size:15,className:`animate-spin`}):(0,P.jsx)(m,{size:15}),` `,i(o?`Change password`:`Set password`)]}),o&&(0,P.jsx)(`button`,{type:`button`,disabled:y||!f,onClick:()=>void C(!0),className:`flex items-center justify-center gap-1.5 rounded-2xl border border-border px-4 py-2.5 text-[14px] font-medium text-muted disabled:opacity-40`,children:i(`Remove`)}),(0,P.jsx)(`button`,{type:`button`,onClick:()=>d(!1),className:`flex items-center justify-center gap-1.5 rounded-2xl border border-border px-4 py-2.5 text-[14px] font-medium text-muted disabled:opacity-40`,children:i(`Cancel`)})]})]})]})}function G({sessions:e,loading:t,onChanged:r}){let a=n(),{toast:o}=s(),[d,f]=(0,N.useState)(null),p=async e=>{if(window.confirm(a(`Sign out {device}? It will need to sign in again.`,{device:e.device||e.prefix}))){f(e.prefix);try{await u.cloudRevokeSession(e.prefix),r()}catch(e){o(e.message)}finally{f(null)}}};return(0,P.jsx)(I,{title:a(`Signed in on`),children:e?(0,P.jsx)(`ul`,{className:`divide-y divide-border/60`,children:e.map(e=>(0,P.jsxs)(`li`,{className:`flex items-center gap-3 py-2.5`,children:[(0,P.jsx)(`span`,{className:`flex h-9 w-9 shrink-0 items-center justify-center rounded-xl bg-surface-2 text-fg/70`,children:(0,P.jsx)(S,{size:17})}),(0,P.jsxs)(`div`,{className:`min-w-0 flex-1`,children:[(0,P.jsxs)(`div`,{className:`flex items-center gap-2 text-[13.5px] font-medium`,children:[(0,P.jsx)(`span`,{className:`truncate`,children:e.device||a(`Unnamed device`)}),e.current&&(0,P.jsx)(`span`,{className:`rounded-full bg-accent/12 px-2 py-0.5 text-[10.5px] font-semibold text-accent`,children:a(`This one`)})]}),(0,P.jsxs)(`div`,{className:`truncate text-[12px] text-muted`,children:[e.via===`password`?a(`password`):a(`code`),` · `,a(`since {date}`,{date:new Date(e.created_at*1e3).toLocaleDateString(i())}),e.last_used_at?` · ${a(`used {when}`,{when:c(e.last_used_at)})}`:``]})]}),!e.current&&(0,P.jsx)(`button`,{type:`button`,disabled:d!==null,onClick:()=>void p(e),className:`rounded-full px-3 py-1.5 text-[12.5px] font-medium text-rose-600 hover:bg-rose-500/10 dark:text-rose-300`,children:d===e.prefix?(0,P.jsx)(l,{size:14,className:`animate-spin`}):a(`Sign out`)})]},e.prefix))}):(0,P.jsx)(`div`,{className:`flex justify-center py-3 text-muted`,children:t?(0,P.jsx)(l,{size:18,className:`animate-spin`}):null})})}var K={"account.created":`Account created`,"sign_in.code":`Signed in with a code`,"sign_in.password":`Signed in with the password`,"sign_in.failed":`A sign-in attempt failed`,sign_out:`Signed out`,"sign_out.all":`Signed out everywhere`,"password.set":`Password set`,"password.changed":`Password changed`,"password.cleared":`Password removed`,"budget.refused":`A request was refused: the allowance is used up`,"call.ended":`Call ended`,"upstream.error":`The model provider returned an error`,"credit.granted":`Allowance added`,"pool.set":`Allowance adjusted`,"invite.accepted":`Signed up with a friend's code`,"invite.used":`A friend signed up with your code`,"invite.unknown":`An invite code was not recognised`,"contribute.default":`Data controls: on for new accounts`,"contribute.on":`Data controls: help improve turned on`,"contribute.off":`Data controls: help improve turned off`,"contribute.deleted":`Data controls: kept conversations deleted`,"profile.put":`Agent's name and look saved`,"profile.clear":`Agent's name and look cleared`};function q({events:e}){let t=n(),[r,i]=(0,N.useState)(!1),a=r?e:e.slice(0,6);return(0,P.jsxs)(I,{title:t(`Recent activity`),children:[(0,P.jsx)(`ul`,{className:`space-y-2`,children:a.map((e,n)=>(0,P.jsxs)(`li`,{className:`flex gap-3 text-[12.5px]`,children:[(0,P.jsx)(`span`,{className:`w-[74px] shrink-0 text-muted`,children:c(e.ts)}),(0,P.jsxs)(`span`,{className:`min-w-0 flex-1`,children:[(0,P.jsx)(`span`,{className:`font-medium`,children:t(K[e.kind]??e.kind)}),e.detail&&(0,P.jsx)(`span`,{className:`ml-1.5 break-all text-muted`,children:e.detail})]})]},`${e.ts}-${n}`))}),e.length>6&&(0,P.jsx)(`button`,{type:`button`,onClick:()=>i(e=>!e),className:`text-[12.5px] font-medium text-accent`,children:r?t(`Show less`):t(`Show all {n}`,{n:e.length})})]})}function J({account:t,onDone:r}){let i=n(),{toast:a}=s(),[o,c]=(0,N.useState)(null),d=async e=>{let t=i(e===`here`?`Sign out of nanoMuse Cloud on this device? The hub and the Cloud model stop working here until you sign in again.`:e===`all`?`Sign out on every device, including this one?`:`Delete the account? The relay forgets your identifier, your devices and your usage. This cannot be undone.`);if(window.confirm(t)&&(e!==`delete`||window.confirm(i(`Really delete it?`)))){c(e);try{e===`here`?await u.cloudSignOut():e===`all`?await u.cloudSignOutAll(!0):await u.cloudDelete(),a(i(e===`delete`?`Account deleted.`:`Signed out.`)),r()}catch(e){a(e.message)}finally{c(null)}}};return(0,P.jsxs)(I,{tone:`danger`,children:[(0,P.jsxs)(`div`,{className:`flex flex-wrap gap-2`,children:[(0,P.jsxs)(`button`,{type:`button`,disabled:o!==null,onClick:()=>void d(`here`),className:e(h,`flex-1`),children:[o===`here`?(0,P.jsx)(l,{size:15,className:`animate-spin`}):(0,P.jsx)(E,{size:15}),` `,i(`Sign out`)]}),(0,P.jsxs)(`button`,{type:`button`,disabled:o!==null,onClick:()=>void d(`all`),className:e(h,`flex-1`),children:[o===`all`?(0,P.jsx)(l,{size:15,className:`animate-spin`}):(0,P.jsx)(S,{size:15}),` `,i(`Sign out everywhere`)]})]}),(0,P.jsxs)(`button`,{type:`button`,disabled:o!==null,onClick:()=>void d(`delete`),className:`flex w-full items-center justify-center gap-1.5 rounded-2xl py-2 text-[13px] font-medium text-rose-600 hover:bg-rose-500/10 dark:text-rose-300`,children:[o===`delete`?(0,P.jsx)(l,{size:15,className:`animate-spin`}):(0,P.jsx)(T,{size:15}),` `,i(`Delete the account`)]}),t?.is_model&&(0,P.jsx)(`p`,{className:`text-center text-[11.5px] text-muted`,children:i(`The Cloud model is in use; after signing out, pick another under Connections.`)})]})}export{F as AccountScreen}; \ No newline at end of file diff --git a/nanomuse/server/static/assets/AvatarPicker-gR2knlot.js b/nanomuse/server/static/assets/AvatarPicker-CwYa9V6R.js similarity index 95% rename from nanomuse/server/static/assets/AvatarPicker-gR2knlot.js rename to nanomuse/server/static/assets/AvatarPicker-CwYa9V6R.js index 19d48a512..6cf851ece 100644 --- a/nanomuse/server/static/assets/AvatarPicker-gR2knlot.js +++ b/nanomuse/server/static/assets/AvatarPicker-CwYa9V6R.js @@ -1 +1 @@ -import{E as e,K as t,a as n,b as r,c as i,s as a,u as o}from"./MuseHeader-Pw-NI98v.js";import{n as s}from"./external-link-Xj5fjR8v.js";import{W as c}from"./index-CIdGZ5PB.js";var l=r(),u=[`✨`,`🌙`,`🪐`,`🌿`,`🔥`,`🌊`,`🦉`,`🦊`,`🐙`,`🎯`,`🧭`,`💎`,`🍀`,`🎈`,`🤖`,`🧠`],d=[`#0064d4`,`#7c3aed`,`#0891b2`,`#059669`,`#d97706`,`#dc2626`,`#db2777`,`#4b5563`],f=[{id:`muse`,label:`3D toy (Muse)`},{id:`flat`,label:`Flat`},{id:`clay`,label:`3D clay`},{id:`watercolor`,label:`Watercolour`},{id:`pixel`,label:`Pixel`},{id:`line`,label:`Line`},{id:`sticker`,label:`Sticker`}];function p({value:r,onChange:f,onStudio:p}){let m=t(),h=r.avatar===``,g=!h&&!i(r.avatar)?r.avatar:null,_=`ring-[2.5px] ring-accent ring-offset-2 ring-offset-bg`,v=`relative h-[72px] w-[72px] shrink-0 overflow-hidden rounded-full transition`;return(0,l.jsxs)(`div`,{className:`space-y-3`,children:[(0,l.jsxs)(`div`,{className:`flex flex-wrap gap-3`,children:[(0,l.jsx)(`button`,{type:`button`,"aria-label":m(`The dragon`),"aria-pressed":r.avatar===n,onClick:()=>f({...r,avatar:n}),className:e(v,`bg-[#f1efeb]`,r.avatar===`dragon`?_:`opacity-90 hover:opacity-100`),children:(0,l.jsx)(`img`,{src:a(r.avatar===`dragon`?`happy`:`idle`),alt:``,draggable:!1,className:`h-full w-full object-cover`})}),g&&(0,l.jsx)(`button`,{type:`button`,"aria-label":m(`The face drawn for you`),"aria-pressed":!0,className:e(v,`bg-surface-2`,_),children:(0,l.jsx)(`img`,{src:o(g,`happy`),alt:``,draggable:!1,className:`h-full w-full object-cover`})}),p&&(0,l.jsx)(`button`,{type:`button`,"aria-label":m(`Avatar studio`),onClick:p,className:e(v,`flex items-center justify-center border border-dashed border-border text-accent hover:bg-surface-2`),children:(0,l.jsx)(c,{size:22})}),(0,l.jsx)(`button`,{type:`button`,"aria-label":m(`An emoji instead`),"aria-pressed":h,onClick:()=>f({...r,avatar:``}),className:e(`flex h-[72px] w-[72px] shrink-0 items-center justify-center rounded-full text-[26px] transition`,h?_:`opacity-90 hover:opacity-100`),style:{background:`linear-gradient(135deg, ${r.color}, color-mix(in srgb, ${r.color} 60%, #ffffff))`},children:r.emoji})]}),h&&(0,l.jsxs)(l.Fragment,{children:[(0,l.jsx)(`div`,{className:`grid grid-cols-8 gap-1.5`,children:u.map(t=>(0,l.jsx)(`button`,{type:`button`,onClick:()=>f({...r,emoji:t}),className:e(`flex aspect-square items-center justify-center rounded-2xl bg-surface-2 text-[22px]`,r.emoji===t&&`ring-2 ring-accent`),children:t},t))}),(0,l.jsx)(`div`,{className:`flex gap-2`,children:d.map(e=>(0,l.jsx)(`button`,{type:`button`,"aria-label":e,onClick:()=>f({...r,color:e}),className:`flex h-8 w-8 items-center justify-center rounded-full text-white`,style:{background:e},children:r.color===e&&(0,l.jsx)(s,{size:16})},e))})]})]})}export{f as n,p as r,d as t}; \ No newline at end of file +import{E as e,K as t,a as n,b as r,c as i,s as a,u as o}from"./MuseHeader-BDWXHKHT.js";import{n as s}from"./external-link-CZH-rQLq.js";import{W as c}from"./index-DKrXW2Qj.js";var l=r(),u=[`✨`,`🌙`,`🪐`,`🌿`,`🔥`,`🌊`,`🦉`,`🦊`,`🐙`,`🎯`,`🧭`,`💎`,`🍀`,`🎈`,`🤖`,`🧠`],d=[`#0064d4`,`#7c3aed`,`#0891b2`,`#059669`,`#d97706`,`#dc2626`,`#db2777`,`#4b5563`],f=[{id:`muse`,label:`3D toy (Muse)`},{id:`flat`,label:`Flat`},{id:`clay`,label:`3D clay`},{id:`watercolor`,label:`Watercolour`},{id:`pixel`,label:`Pixel`},{id:`line`,label:`Line`},{id:`sticker`,label:`Sticker`}];function p({value:r,onChange:f,onStudio:p}){let m=t(),h=r.avatar===``,g=!h&&!i(r.avatar)?r.avatar:null,_=`ring-[2.5px] ring-accent ring-offset-2 ring-offset-bg`,v=`relative h-[72px] w-[72px] shrink-0 overflow-hidden rounded-full transition`;return(0,l.jsxs)(`div`,{className:`space-y-3`,children:[(0,l.jsxs)(`div`,{className:`flex flex-wrap gap-3`,children:[(0,l.jsx)(`button`,{type:`button`,"aria-label":m(`The dragon`),"aria-pressed":r.avatar===n,onClick:()=>f({...r,avatar:n}),className:e(v,`bg-[#f1efeb]`,r.avatar===`dragon`?_:`opacity-90 hover:opacity-100`),children:(0,l.jsx)(`img`,{src:a(r.avatar===`dragon`?`happy`:`idle`),alt:``,draggable:!1,className:`h-full w-full object-cover`})}),g&&(0,l.jsx)(`button`,{type:`button`,"aria-label":m(`The face drawn for you`),"aria-pressed":!0,className:e(v,`bg-surface-2`,_),children:(0,l.jsx)(`img`,{src:o(g,`happy`),alt:``,draggable:!1,className:`h-full w-full object-cover`})}),p&&(0,l.jsx)(`button`,{type:`button`,"aria-label":m(`Avatar studio`),onClick:p,className:e(v,`flex items-center justify-center border border-dashed border-border text-accent hover:bg-surface-2`),children:(0,l.jsx)(c,{size:22})}),(0,l.jsx)(`button`,{type:`button`,"aria-label":m(`An emoji instead`),"aria-pressed":h,onClick:()=>f({...r,avatar:``}),className:e(`flex h-[72px] w-[72px] shrink-0 items-center justify-center rounded-full text-[26px] transition`,h?_:`opacity-90 hover:opacity-100`),style:{background:`linear-gradient(135deg, ${r.color}, color-mix(in srgb, ${r.color} 60%, #ffffff))`},children:r.emoji})]}),h&&(0,l.jsxs)(l.Fragment,{children:[(0,l.jsx)(`div`,{className:`grid grid-cols-8 gap-1.5`,children:u.map(t=>(0,l.jsx)(`button`,{type:`button`,onClick:()=>f({...r,emoji:t}),className:e(`flex aspect-square items-center justify-center rounded-2xl bg-surface-2 text-[22px]`,r.emoji===t&&`ring-2 ring-accent`),children:t},t))}),(0,l.jsx)(`div`,{className:`flex gap-2`,children:d.map(e=>(0,l.jsx)(`button`,{type:`button`,"aria-label":e,onClick:()=>f({...r,color:e}),className:`flex h-8 w-8 items-center justify-center rounded-full text-white`,style:{background:e},children:r.color===e&&(0,l.jsx)(s,{size:16})},e))})]})]})}export{f as n,p as r,d as t}; \ No newline at end of file diff --git a/nanomuse/server/static/assets/AvatarStudioScreen-DD2X0R8P.js b/nanomuse/server/static/assets/AvatarStudioScreen-BFsBKlhk.js similarity index 97% rename from nanomuse/server/static/assets/AvatarStudioScreen-DD2X0R8P.js rename to nanomuse/server/static/assets/AvatarStudioScreen-BFsBKlhk.js index 7a2e367df..e7067dda2 100644 --- a/nanomuse/server/static/assets/AvatarStudioScreen-DD2X0R8P.js +++ b/nanomuse/server/static/assets/AvatarStudioScreen-BFsBKlhk.js @@ -1 +1 @@ -import{E as e,K as t,L as n,Q as r,S as i,Y as a,a as o,b as s,c,f as l,l as u,o as d,q as f,r as p,s as m,u as h,x as g}from"./MuseHeader-Pw-NI98v.js";import{C as _,t as v,w as y}from"./StarNudge-DjXecvWj.js";import{n as b}from"./external-link-Xj5fjR8v.js";import{i as x,o as S}from"./Form-DwKuBk1V.js";import{t as ee}from"./refresh-cw-BKgIzslL.js";import{W as C,ht as te}from"./index-CIdGZ5PB.js";import{t as ne}from"./BackBar-Dl56jHZM.js";import{n as w}from"./AvatarPicker-gR2knlot.js";var T=r(a(),1),E=s(),D=[`idle`,`working`,`waiting`,`happy`,`error`],O={idle:`Idle`,working:`Working`,waiting:`Waiting for you`,happy:`Done`,error:`Something went wrong`},re=4,k=`a round, custard-yellow baby dragon with small orange horns and folded little wings`;function A(){let{state:r,setTab:a,toast:s,draft:u,refreshSettings:d}=l(),m=t(),h=r.profile,O=h?.name??`nanoMuse`,[A,oe]=(0,T.useState)(null),[M,se]=(0,T.useState)(``),[N,ce]=(0,T.useState)(`muse`),[P,F]=(0,T.useState)(null),[I,L]=(0,T.useState)(null),[R,z]=(0,T.useState)(!1),[B,V]=(0,T.useState)(``),H=r.studio??A?.current??null,U=H?.stage??``,W=U===`drawing`,G=H?.candidates??[],K=(U===`drawing`||U===`choose`)&&G.length>0,le=()=>g.avatarView().then(oe,e=>s(e.message));(0,T.useEffect)(()=>{le()},[h?.avatar,r.settings?.llm.model,r.connectionsVersion]),(0,T.useEffect)(()=>{U!==`choose`&&F(null)},[U]);let q=async(e,t)=>{L(e),V(``);try{await t()}catch(e){V(e.message)}finally{L(null)}},ue=()=>q(`draw`,async()=>{let e=M.trim()||k,t=await g.avatarBegin(e,``,N);if(t.available===!1)throw Error(y(m,`image`,_(r.hub?.account),n()));t.cost?.cloud===!1&&t.session&&await g.avatarStart(t.session)}),de=()=>q(`reset`,async()=>{await g.updateSettings({profile:{avatar:o}}),await d(),s(m(`Back to the built-in look.`))}),J=A?.face??null,fe=!!h?.avatar&&!c(h.avatar),Y=H&&(U===`posing`||U===`animating`||U===`done`)&&H.face===h?.avatar,pe=Y?Object.keys(H.moods??{}).length:0,me=Y?Object.keys(H.clips??{}).length:0,X=Y?(H.errors??[]).filter(e=>!/clip/.test(e)).length:0,Z=H?.cost??{},Q=Z.clips?m(`{n} pictures and {c} clips`,{n:Z.pictures??8,c:Z.clips}):m(`{n} pictures`,{n:Z.pictures??8}),he=(()=>{if(Z.error)return m(`The cost could not be checked: {error}`,{error:Z.error});if(typeof Z.cny!=`number`)return m(`Checking the cost…`);if(Z.unlimited)return m(`About ¥{cny} for {what}; your account has no limit.`,{cny:Z.cny.toFixed(2),what:Q});let e=typeof Z.left_cny==`number`?Z.left_cny.toFixed(2):`?`;return Z.affordable===!1?m(`About ¥{cny} for {what}, more than the ¥{left} left in your allowance.`,{cny:Z.cny.toFixed(2),what:Q,left:e}):m(`About ¥{cny} for {what}; ¥{left} left in your allowance.`,{cny:Z.cny.toFixed(2),what:Q,left:e})})(),$=e=>w.find(t=>t.id===e)?.label,ge=A?.cloud?`nanoMuse Cloud`:ie(A?.host??``,m);return(0,E.jsxs)(`div`,{className:`flex h-full flex-col`,children:[(0,E.jsx)(ne,{title:m(`Avatar studio`),description:m(`Draw a look with your image model; it moves with what it is doing.`),actions:(0,E.jsxs)(`div`,{className:`relative`,children:[(0,E.jsx)(p,{small:!0,onClick:()=>z(e=>!e),label:m(`More`),expanded:R,children:(0,E.jsx)(te,{size:20})}),R&&(0,E.jsxs)(`div`,{className:`absolute right-0 z-20 mt-1 w-56 overflow-hidden rounded-2xl border border-border/70 bg-surface py-1 text-[14px] shadow-lg`,children:[(0,E.jsx)(j,{label:m(`Name & style`),onClick:()=>{z(!1),a(`you`)}}),(0,E.jsx)(j,{label:m(`Image model`),onClick:()=>{z(!1),a(`connections`)}}),fe&&(0,E.jsxs)(E.Fragment,{children:[(0,E.jsx)(j,{label:m(`Redraw the poses`),onClick:()=>{z(!1),q(`moods`,()=>g.avatarMoods())}}),(0,E.jsx)(j,{label:m(`Back to the built-in look`),danger:!0,onClick:()=>{z(!1),de()}})]})]})]})}),(0,E.jsxs)(`div`,{className:`flex-1 overflow-y-auto px-4 pb-8 space-y-5`,onClick:()=>R&&z(!1),children:[(0,E.jsxs)(`div`,{className:`flex flex-col items-center pt-2 text-center`,children:[(0,E.jsx)(ae,{avatar:h?.avatar,emoji:h?.emoji,color:h?.color,name:O}),J&&(0,E.jsx)(`div`,{className:`mt-0.5 max-w-sm text-[12.5px] text-muted`,children:[J.description,$(J.style)&&m($(J.style))].filter(Boolean).join(` · `)}),Y&&(0,E.jsxs)(`div`,{className:`mt-2.5 flex items-center gap-2 text-[13px] text-muted`,children:[U===`posing`&&(0,E.jsxs)(E.Fragment,{children:[(0,E.jsx)(f,{size:14,className:`animate-spin text-accent`}),(0,E.jsx)(`span`,{children:m(`Drawing the poses… {done}/{total}`,{done:pe,total:D.length})})]}),U===`animating`&&(0,E.jsxs)(E.Fragment,{children:[(0,E.jsx)(f,{size:14,className:`animate-spin text-accent`}),(0,E.jsx)(`span`,{children:m(`The new look is on; making the clips… {done}/{total}`,{done:me,total:re})})]}),U===`done`&&(0,E.jsxs)(E.Fragment,{children:[(0,E.jsx)(`span`,{children:X===0?m(`All five poses are in.`):m(`{done} of {total} poses are in; the rest show the main picture.`,{done:D.length-X,total:D.length})}),X>0&&(0,E.jsx)(`button`,{type:`button`,onClick:()=>void q(`moods`,()=>g.avatarMoods()),className:`font-medium text-accent`,children:m(`Retry`)})]})]})]}),U===`done`&&X===0&&(0,E.jsx)(v,{moment:`new_look`}),(0,E.jsxs)(`section`,{className:`rounded-3xl border border-border/70 bg-surface p-4 shadow-sm space-y-3`,children:[(0,E.jsxs)(`div`,{children:[(0,E.jsx)(`h2`,{className:`text-[17px] font-semibold`,children:m(`Describe a new look`)}),(0,E.jsx)(`p`,{className:`mt-0.5 text-[13px] leading-snug text-muted`,children:m(`One sentence is enough: what it is, what it wears, its air. Pick a style and your image model draws four to choose from.`)})]}),(0,E.jsx)(`textarea`,{value:M,onChange:e=>se(e.target.value),rows:2,maxLength:200,placeholder:m(k),className:`w-full resize-none rounded-2xl bg-surface-2 px-3.5 py-2.5 text-[14.5px] outline-none focus:ring-2 focus:ring-accent/40`}),(0,E.jsx)(`div`,{className:`flex flex-wrap gap-1.5`,children:w.map(t=>(0,E.jsx)(`button`,{type:`button`,onClick:()=>ce(t.id),className:e(`rounded-full px-3 py-1.5 text-[13px] font-medium transition`,N===t.id?`bg-fg text-bg`:`bg-surface-2 text-fg hover:bg-border/60`),children:m(t.label)},t.id))}),(0,E.jsxs)(`button`,{type:`button`,disabled:I!==null||W||A?.available===!1,onClick:()=>void ue(),className:e(x,`w-full rounded-full py-3`),children:[W||I===`draw`?(0,E.jsx)(f,{size:16,className:`animate-spin`}):(0,E.jsx)(C,{size:16}),m(W?`Drawing…`:K||U===`choose`?`Draw four more`:`Draw four`)]}),(0,E.jsxs)(`button`,{type:`button`,onClick:()=>a(`connections`),className:`flex w-full items-center justify-between gap-3 py-1 text-left text-[12.5px] text-muted`,children:[(0,E.jsx)(`span`,{className:`min-w-0 flex-1`,children:A===null?`…`:A.available?m(`Drawn by {provider} · {model}`,{provider:ge,model:A.image_model||`—`}):y(m,`image`,_(r.hub?.account),n())}),(0,E.jsx)(`span`,{className:`shrink-0 font-medium text-accent`,children:m(`Change model`)})]}),B&&(0,E.jsx)(`p`,{className:`text-[13px] text-rose-600 dark:text-rose-300`,children:B})]}),U===`estimate`&&H&&(0,E.jsxs)(`section`,{className:`rounded-3xl border border-accent/50 bg-surface p-4 shadow-sm space-y-3`,children:[(0,E.jsxs)(`div`,{children:[(0,E.jsx)(`h2`,{className:`text-[15px] font-semibold`,children:m(`A new look for {name}`,{name:O})}),(0,E.jsx)(`p`,{className:`mt-0.5 text-[13px] text-muted`,children:H.description})]}),(0,E.jsx)(`p`,{className:`text-[12.5px] text-muted`,children:he}),(0,E.jsxs)(`div`,{className:`flex gap-2`,children:[(0,E.jsxs)(`button`,{type:`button`,disabled:I!==null||typeof Z.cny!=`number`&&!Z.error,onClick:()=>void q(`start`,()=>g.avatarStart(H.session)),className:e(`flex items-center justify-center gap-1.5 rounded-2xl bg-accent text-accent-fg px-4 py-2.5 text-[14px] font-medium disabled:opacity-40`,`rounded-full`),children:[I===`start`?(0,E.jsx)(f,{size:14,className:`animate-spin`}):(0,E.jsx)(C,{size:14}),` `,m(`Draw`)]}),(0,E.jsxs)(`button`,{type:`button`,disabled:I!==null,onClick:()=>void q(`cancel`,()=>g.avatarCancel(H.session)),className:e(`flex items-center justify-center gap-1.5 rounded-2xl border border-border px-4 py-2.5 text-[14px] font-medium text-muted disabled:opacity-40`,`rounded-full`),children:[(0,E.jsx)(S,{size:14}),` `,m(`Not now`)]})]})]}),K&&H&&(0,E.jsxs)(`section`,{className:`space-y-3 px-1`,children:[(0,E.jsxs)(`div`,{children:[(0,E.jsx)(`h2`,{className:`text-[17px] font-semibold`,children:m(`Pick one`)}),(0,E.jsx)(`p`,{className:`mt-0.5 text-[13px] leading-snug text-muted`,children:m(`Draw four more any time; the old ones stay until you do.`)})]}),(0,E.jsx)(`div`,{className:`grid grid-cols-2 gap-3 wide:grid-cols-4`,children:G.map((t,n)=>(0,E.jsxs)(`button`,{type:`button`,disabled:!t||U!==`choose`,onClick:()=>F(e=>e===n?null:n),"aria-label":m(`Candidate {n}`,{n:n+1}),"aria-pressed":P===n,className:e(`relative aspect-square overflow-hidden rounded-[20px] bg-[#f1efeb] transition`,P===n?`ring-[3px] ring-accent`:t&&U===`choose`?`hover:ring-2 hover:ring-accent/60`:``),children:[t?(0,E.jsx)(`img`,{src:i(t),alt:``,draggable:!1,className:`h-full w-full object-cover`}):(0,E.jsx)(`span`,{className:`absolute inset-0 flex items-center justify-center text-muted`,children:W?(0,E.jsx)(f,{size:22,className:`animate-spin`}):(0,E.jsx)(S,{size:18,className:`opacity-50`})}),P===n&&(0,E.jsx)(`span`,{className:`absolute right-2 top-2 flex h-7 w-7 items-center justify-center rounded-full bg-accent text-accent-fg shadow`,children:(0,E.jsx)(b,{size:16})})]},n))}),H.errors&&H.errors.length>0&&U===`choose`&&(0,E.jsx)(`p`,{className:`text-[12.5px] text-rose-600 dark:text-rose-300`,children:m(H.errors[0])}),P!==null&&U===`choose`&&(0,E.jsxs)(`div`,{className:`space-y-1.5 pt-1`,children:[(0,E.jsxs)(`button`,{type:`button`,disabled:I!==null,onClick:()=>void q(`choose`,()=>g.avatarChoose(H.session,P)),className:e(`flex items-center justify-center gap-1.5 rounded-2xl bg-accent text-accent-fg px-4 py-2.5 text-[14px] font-medium disabled:opacity-40`,`w-full rounded-full py-3`),children:[I===`choose`?(0,E.jsx)(f,{size:16,className:`animate-spin`}):(0,E.jsx)(b,{size:16}),` `,m(`Use this one`)]}),(0,E.jsx)(`p`,{className:`text-center text-[12px] leading-snug text-muted`,children:m(`Next, its poses are drawn from it in the background: working, waiting for you, done, something wrong.`)})]}),U===`choose`&&(0,E.jsx)(`button`,{type:`button`,disabled:I!==null,onClick:()=>void q(`cancel`,()=>g.avatarCancel(H.session)),className:`w-full py-1 text-center text-[13px] text-muted`,children:m(`Keep the current look`)})]}),U===`failed`&&H&&(0,E.jsxs)(`section`,{className:`rounded-3xl border border-border/70 bg-surface p-4 shadow-sm space-y-2`,children:[(0,E.jsx)(`h2`,{className:`text-[15px] font-semibold`,children:m(`That did not work`)}),(0,E.jsx)(`p`,{className:`text-[13px] text-muted`,children:m(H.message||`Nothing came back.`)}),(0,E.jsxs)(`button`,{type:`button`,disabled:I!==null,onClick:()=>void q(`retry`,()=>g.avatarStart(H.session)),className:e(`flex items-center justify-center gap-1.5 rounded-2xl border border-border px-4 py-2.5 text-[14px] font-medium text-muted disabled:opacity-40`,`rounded-full`),children:[(0,E.jsx)(ee,{size:14}),` `,m(`Try again`)]})]}),(0,E.jsx)(`p`,{className:`px-1 text-[12px] leading-snug text-muted`,children:m(`The pictures stay in this computer's workspace under avatar/. Each new look asks your provider for eight pictures (four to choose from and four poses) and four short clips where there is a video model.`)}),(0,E.jsx)(`p`,{className:`px-1 text-[12px] leading-snug text-muted`,children:(0,E.jsx)(`button`,{type:`button`,onClick:()=>{u(m(`Change your avatar to `)),a(`chat`)},className:`font-medium text-accent`,children:m(`Or just say it in the chat: “change your avatar to a corgi”.`)})})]})]})}function ie(e,t){return e?/dashscope|aliyuncs/.test(e)?t(`Alibaba Cloud Bailian`):/openai\.com/.test(e)?`OpenAI`:/deepseek/.test(e)?`DeepSeek`:/moonshot/.test(e)?`Moonshot`:/bigmodel|zhipu/.test(e)?t(`Zhipu`):/siliconflow/.test(e)?`SiliconFlow`:/volces|ark/.test(e)?t(`Volcano Ark`):/openrouter/.test(e)?`OpenRouter`:/googleapis/.test(e)?`Gemini`:/x\.ai/.test(e)?`xAI`:/^(127\.0\.0\.1|localhost)/.test(e)?t(`this computer`):e:`—`}function j({label:t,onClick:n,danger:r=!1}){return(0,E.jsx)(`button`,{type:`button`,onClick:n,className:e(`block w-full px-4 py-2.5 text-left hover:bg-surface-2`,r?`text-rose-600 dark:text-rose-300`:``),children:t})}function ae({avatar:e,emoji:n,color:r,name:i}){let a=t(),[o,s]=(0,T.useState)(0),l=D[o%D.length],f=(0,T.useRef)(0);(0,T.useEffect)(()=>(f.current=window.setTimeout(()=>s(e=>(e+1)%D.length),l===`idle`?2600:2e3),()=>window.clearTimeout(f.current)),[o,l]);let p=c(e),g=!p&&e?e:null,_=p?m(l):g?h(g,l):``,v=p?d(l):g?u(g,l):null,[y,b]=(0,T.useState)(()=>new Set),x=v&&!y.has(v)?v:null;return(0,E.jsxs)(E.Fragment,{children:[(0,E.jsx)(`div`,{className:`avatar-pop h-[148px] w-[148px] overflow-hidden rounded-full`,style:_?{background:`#f1efeb`}:{background:`linear-gradient(135deg, ${r??`#0064d4`}, color-mix(in srgb, ${r??`#0064d4`} 60%, #ffffff))`},children:x?(0,E.jsx)(`video`,{src:x,poster:_,autoPlay:!0,loop:!0,muted:!0,playsInline:!0,disablePictureInPicture:!0,onError:()=>b(e=>new Set(e).add(x)),className:`h-full w-full object-cover`},x):_?(0,E.jsx)(`img`,{src:_,alt:``,draggable:!1,className:`h-full w-full object-cover`}):(0,E.jsx)(`span`,{className:`flex h-full w-full items-center justify-center text-[64px] leading-none`,children:n??`✨`})},e),(0,E.jsx)(`div`,{className:`mt-3 text-[20px] font-semibold tracking-tight`,children:i}),(0,E.jsx)(`div`,{className:`mt-1 text-[13px] text-muted`,children:a(O[l])})]})}export{A as AvatarStudioScreen}; \ No newline at end of file +import{E as e,K as t,L as n,Q as r,S as i,Y as a,a as o,b as s,c,f as l,l as u,o as d,q as f,r as p,s as m,u as h,x as g}from"./MuseHeader-BDWXHKHT.js";import{C as _,t as v,w as y}from"./StarNudge-B8P2bPEz.js";import{n as b}from"./external-link-CZH-rQLq.js";import{i as x,o as S}from"./Form-B3Ejw5aI.js";import{t as ee}from"./refresh-cw-qw351CFk.js";import{W as C,ht as te}from"./index-DKrXW2Qj.js";import{t as ne}from"./BackBar-DqcCClHf.js";import{n as w}from"./AvatarPicker-CwYa9V6R.js";var T=r(a(),1),E=s(),D=[`idle`,`working`,`waiting`,`happy`,`error`],O={idle:`Idle`,working:`Working`,waiting:`Waiting for you`,happy:`Done`,error:`Something went wrong`},re=4,k=`a round, custard-yellow baby dragon with small orange horns and folded little wings`;function A(){let{state:r,setTab:a,toast:s,draft:u,refreshSettings:d}=l(),m=t(),h=r.profile,O=h?.name??`nanoMuse`,[A,oe]=(0,T.useState)(null),[M,se]=(0,T.useState)(``),[N,ce]=(0,T.useState)(`muse`),[P,F]=(0,T.useState)(null),[I,L]=(0,T.useState)(null),[R,z]=(0,T.useState)(!1),[B,V]=(0,T.useState)(``),H=r.studio??A?.current??null,U=H?.stage??``,W=U===`drawing`,G=H?.candidates??[],K=(U===`drawing`||U===`choose`)&&G.length>0,le=()=>g.avatarView().then(oe,e=>s(e.message));(0,T.useEffect)(()=>{le()},[h?.avatar,r.settings?.llm.model,r.connectionsVersion]),(0,T.useEffect)(()=>{U!==`choose`&&F(null)},[U]);let q=async(e,t)=>{L(e),V(``);try{await t()}catch(e){V(e.message)}finally{L(null)}},ue=()=>q(`draw`,async()=>{let e=M.trim()||k,t=await g.avatarBegin(e,``,N);if(t.available===!1)throw Error(y(m,`image`,_(r.hub?.account),n()));t.cost?.cloud===!1&&t.session&&await g.avatarStart(t.session)}),de=()=>q(`reset`,async()=>{await g.updateSettings({profile:{avatar:o}}),await d(),s(m(`Back to the built-in look.`))}),J=A?.face??null,fe=!!h?.avatar&&!c(h.avatar),Y=H&&(U===`posing`||U===`animating`||U===`done`)&&H.face===h?.avatar,pe=Y?Object.keys(H.moods??{}).length:0,me=Y?Object.keys(H.clips??{}).length:0,X=Y?(H.errors??[]).filter(e=>!/clip/.test(e)).length:0,Z=H?.cost??{},Q=Z.clips?m(`{n} pictures and {c} clips`,{n:Z.pictures??8,c:Z.clips}):m(`{n} pictures`,{n:Z.pictures??8}),he=(()=>{if(Z.error)return m(`The cost could not be checked: {error}`,{error:Z.error});if(typeof Z.cny!=`number`)return m(`Checking the cost…`);if(Z.unlimited)return m(`About ¥{cny} for {what}; your account has no limit.`,{cny:Z.cny.toFixed(2),what:Q});let e=typeof Z.left_cny==`number`?Z.left_cny.toFixed(2):`?`;return Z.affordable===!1?m(`About ¥{cny} for {what}, more than the ¥{left} left in your allowance.`,{cny:Z.cny.toFixed(2),what:Q,left:e}):m(`About ¥{cny} for {what}; ¥{left} left in your allowance.`,{cny:Z.cny.toFixed(2),what:Q,left:e})})(),$=e=>w.find(t=>t.id===e)?.label,ge=A?.cloud?`nanoMuse Cloud`:ie(A?.host??``,m);return(0,E.jsxs)(`div`,{className:`flex h-full flex-col`,children:[(0,E.jsx)(ne,{title:m(`Avatar studio`),description:m(`Draw a look with your image model; it moves with what it is doing.`),actions:(0,E.jsxs)(`div`,{className:`relative`,children:[(0,E.jsx)(p,{small:!0,onClick:()=>z(e=>!e),label:m(`More`),expanded:R,children:(0,E.jsx)(te,{size:20})}),R&&(0,E.jsxs)(`div`,{className:`absolute right-0 z-20 mt-1 w-56 overflow-hidden rounded-2xl border border-border/70 bg-surface py-1 text-[14px] shadow-lg`,children:[(0,E.jsx)(j,{label:m(`Name & style`),onClick:()=>{z(!1),a(`you`)}}),(0,E.jsx)(j,{label:m(`Image model`),onClick:()=>{z(!1),a(`connections`)}}),fe&&(0,E.jsxs)(E.Fragment,{children:[(0,E.jsx)(j,{label:m(`Redraw the poses`),onClick:()=>{z(!1),q(`moods`,()=>g.avatarMoods())}}),(0,E.jsx)(j,{label:m(`Back to the built-in look`),danger:!0,onClick:()=>{z(!1),de()}})]})]})]})}),(0,E.jsxs)(`div`,{className:`flex-1 overflow-y-auto px-4 pb-8 space-y-5`,onClick:()=>R&&z(!1),children:[(0,E.jsxs)(`div`,{className:`flex flex-col items-center pt-2 text-center`,children:[(0,E.jsx)(ae,{avatar:h?.avatar,emoji:h?.emoji,color:h?.color,name:O}),J&&(0,E.jsx)(`div`,{className:`mt-0.5 max-w-sm text-[12.5px] text-muted`,children:[J.description,$(J.style)&&m($(J.style))].filter(Boolean).join(` · `)}),Y&&(0,E.jsxs)(`div`,{className:`mt-2.5 flex items-center gap-2 text-[13px] text-muted`,children:[U===`posing`&&(0,E.jsxs)(E.Fragment,{children:[(0,E.jsx)(f,{size:14,className:`animate-spin text-accent`}),(0,E.jsx)(`span`,{children:m(`Drawing the poses… {done}/{total}`,{done:pe,total:D.length})})]}),U===`animating`&&(0,E.jsxs)(E.Fragment,{children:[(0,E.jsx)(f,{size:14,className:`animate-spin text-accent`}),(0,E.jsx)(`span`,{children:m(`The new look is on; making the clips… {done}/{total}`,{done:me,total:re})})]}),U===`done`&&(0,E.jsxs)(E.Fragment,{children:[(0,E.jsx)(`span`,{children:X===0?m(`All five poses are in.`):m(`{done} of {total} poses are in; the rest show the main picture.`,{done:D.length-X,total:D.length})}),X>0&&(0,E.jsx)(`button`,{type:`button`,onClick:()=>void q(`moods`,()=>g.avatarMoods()),className:`font-medium text-accent`,children:m(`Retry`)})]})]})]}),U===`done`&&X===0&&(0,E.jsx)(v,{moment:`new_look`}),(0,E.jsxs)(`section`,{className:`rounded-3xl border border-border/70 bg-surface p-4 shadow-sm space-y-3`,children:[(0,E.jsxs)(`div`,{children:[(0,E.jsx)(`h2`,{className:`text-[17px] font-semibold`,children:m(`Describe a new look`)}),(0,E.jsx)(`p`,{className:`mt-0.5 text-[13px] leading-snug text-muted`,children:m(`One sentence is enough: what it is, what it wears, its air. Pick a style and your image model draws four to choose from.`)})]}),(0,E.jsx)(`textarea`,{value:M,onChange:e=>se(e.target.value),rows:2,maxLength:200,placeholder:m(k),className:`w-full resize-none rounded-2xl bg-surface-2 px-3.5 py-2.5 text-[14.5px] outline-none focus:ring-2 focus:ring-accent/40`}),(0,E.jsx)(`div`,{className:`flex flex-wrap gap-1.5`,children:w.map(t=>(0,E.jsx)(`button`,{type:`button`,onClick:()=>ce(t.id),className:e(`rounded-full px-3 py-1.5 text-[13px] font-medium transition`,N===t.id?`bg-fg text-bg`:`bg-surface-2 text-fg hover:bg-border/60`),children:m(t.label)},t.id))}),(0,E.jsxs)(`button`,{type:`button`,disabled:I!==null||W||A?.available===!1,onClick:()=>void ue(),className:e(x,`w-full rounded-full py-3`),children:[W||I===`draw`?(0,E.jsx)(f,{size:16,className:`animate-spin`}):(0,E.jsx)(C,{size:16}),m(W?`Drawing…`:K||U===`choose`?`Draw four more`:`Draw four`)]}),(0,E.jsxs)(`button`,{type:`button`,onClick:()=>a(`connections`),className:`flex w-full items-center justify-between gap-3 py-1 text-left text-[12.5px] text-muted`,children:[(0,E.jsx)(`span`,{className:`min-w-0 flex-1`,children:A===null?`…`:A.available?m(`Drawn by {provider} · {model}`,{provider:ge,model:A.image_model||`—`}):y(m,`image`,_(r.hub?.account),n())}),(0,E.jsx)(`span`,{className:`shrink-0 font-medium text-accent`,children:m(`Change model`)})]}),B&&(0,E.jsx)(`p`,{className:`text-[13px] text-rose-600 dark:text-rose-300`,children:B})]}),U===`estimate`&&H&&(0,E.jsxs)(`section`,{className:`rounded-3xl border border-accent/50 bg-surface p-4 shadow-sm space-y-3`,children:[(0,E.jsxs)(`div`,{children:[(0,E.jsx)(`h2`,{className:`text-[15px] font-semibold`,children:m(`A new look for {name}`,{name:O})}),(0,E.jsx)(`p`,{className:`mt-0.5 text-[13px] text-muted`,children:H.description})]}),(0,E.jsx)(`p`,{className:`text-[12.5px] text-muted`,children:he}),(0,E.jsxs)(`div`,{className:`flex gap-2`,children:[(0,E.jsxs)(`button`,{type:`button`,disabled:I!==null||typeof Z.cny!=`number`&&!Z.error,onClick:()=>void q(`start`,()=>g.avatarStart(H.session)),className:e(`flex items-center justify-center gap-1.5 rounded-2xl bg-accent text-accent-fg px-4 py-2.5 text-[14px] font-medium disabled:opacity-40`,`rounded-full`),children:[I===`start`?(0,E.jsx)(f,{size:14,className:`animate-spin`}):(0,E.jsx)(C,{size:14}),` `,m(`Draw`)]}),(0,E.jsxs)(`button`,{type:`button`,disabled:I!==null,onClick:()=>void q(`cancel`,()=>g.avatarCancel(H.session)),className:e(`flex items-center justify-center gap-1.5 rounded-2xl border border-border px-4 py-2.5 text-[14px] font-medium text-muted disabled:opacity-40`,`rounded-full`),children:[(0,E.jsx)(S,{size:14}),` `,m(`Not now`)]})]})]}),K&&H&&(0,E.jsxs)(`section`,{className:`space-y-3 px-1`,children:[(0,E.jsxs)(`div`,{children:[(0,E.jsx)(`h2`,{className:`text-[17px] font-semibold`,children:m(`Pick one`)}),(0,E.jsx)(`p`,{className:`mt-0.5 text-[13px] leading-snug text-muted`,children:m(`Draw four more any time; the old ones stay until you do.`)})]}),(0,E.jsx)(`div`,{className:`grid grid-cols-2 gap-3 wide:grid-cols-4`,children:G.map((t,n)=>(0,E.jsxs)(`button`,{type:`button`,disabled:!t||U!==`choose`,onClick:()=>F(e=>e===n?null:n),"aria-label":m(`Candidate {n}`,{n:n+1}),"aria-pressed":P===n,className:e(`relative aspect-square overflow-hidden rounded-[20px] bg-[#f1efeb] transition`,P===n?`ring-[3px] ring-accent`:t&&U===`choose`?`hover:ring-2 hover:ring-accent/60`:``),children:[t?(0,E.jsx)(`img`,{src:i(t),alt:``,draggable:!1,className:`h-full w-full object-cover`}):(0,E.jsx)(`span`,{className:`absolute inset-0 flex items-center justify-center text-muted`,children:W?(0,E.jsx)(f,{size:22,className:`animate-spin`}):(0,E.jsx)(S,{size:18,className:`opacity-50`})}),P===n&&(0,E.jsx)(`span`,{className:`absolute right-2 top-2 flex h-7 w-7 items-center justify-center rounded-full bg-accent text-accent-fg shadow`,children:(0,E.jsx)(b,{size:16})})]},n))}),H.errors&&H.errors.length>0&&U===`choose`&&(0,E.jsx)(`p`,{className:`text-[12.5px] text-rose-600 dark:text-rose-300`,children:m(H.errors[0])}),P!==null&&U===`choose`&&(0,E.jsxs)(`div`,{className:`space-y-1.5 pt-1`,children:[(0,E.jsxs)(`button`,{type:`button`,disabled:I!==null,onClick:()=>void q(`choose`,()=>g.avatarChoose(H.session,P)),className:e(`flex items-center justify-center gap-1.5 rounded-2xl bg-accent text-accent-fg px-4 py-2.5 text-[14px] font-medium disabled:opacity-40`,`w-full rounded-full py-3`),children:[I===`choose`?(0,E.jsx)(f,{size:16,className:`animate-spin`}):(0,E.jsx)(b,{size:16}),` `,m(`Use this one`)]}),(0,E.jsx)(`p`,{className:`text-center text-[12px] leading-snug text-muted`,children:m(`Next, its poses are drawn from it in the background: working, waiting for you, done, something wrong.`)})]}),U===`choose`&&(0,E.jsx)(`button`,{type:`button`,disabled:I!==null,onClick:()=>void q(`cancel`,()=>g.avatarCancel(H.session)),className:`w-full py-1 text-center text-[13px] text-muted`,children:m(`Keep the current look`)})]}),U===`failed`&&H&&(0,E.jsxs)(`section`,{className:`rounded-3xl border border-border/70 bg-surface p-4 shadow-sm space-y-2`,children:[(0,E.jsx)(`h2`,{className:`text-[15px] font-semibold`,children:m(`That did not work`)}),(0,E.jsx)(`p`,{className:`text-[13px] text-muted`,children:m(H.message||`Nothing came back.`)}),(0,E.jsxs)(`button`,{type:`button`,disabled:I!==null,onClick:()=>void q(`retry`,()=>g.avatarStart(H.session)),className:e(`flex items-center justify-center gap-1.5 rounded-2xl border border-border px-4 py-2.5 text-[14px] font-medium text-muted disabled:opacity-40`,`rounded-full`),children:[(0,E.jsx)(ee,{size:14}),` `,m(`Try again`)]})]}),(0,E.jsx)(`p`,{className:`px-1 text-[12px] leading-snug text-muted`,children:m(`The pictures stay in this computer's workspace under avatar/. Each new look asks your provider for eight pictures (four to choose from and four poses) and four short clips where there is a video model.`)}),(0,E.jsx)(`p`,{className:`px-1 text-[12px] leading-snug text-muted`,children:(0,E.jsx)(`button`,{type:`button`,onClick:()=>{u(m(`Change your avatar to `)),a(`chat`)},className:`font-medium text-accent`,children:m(`Or just say it in the chat: “change your avatar to a corgi”.`)})})]})]})}function ie(e,t){return e?/dashscope|aliyuncs/.test(e)?t(`Alibaba Cloud Bailian`):/openai\.com/.test(e)?`OpenAI`:/deepseek/.test(e)?`DeepSeek`:/moonshot/.test(e)?`Moonshot`:/bigmodel|zhipu/.test(e)?t(`Zhipu`):/siliconflow/.test(e)?`SiliconFlow`:/volces|ark/.test(e)?t(`Volcano Ark`):/openrouter/.test(e)?`OpenRouter`:/googleapis/.test(e)?`Gemini`:/x\.ai/.test(e)?`xAI`:/^(127\.0\.0\.1|localhost)/.test(e)?t(`this computer`):e:`—`}function j({label:t,onClick:n,danger:r=!1}){return(0,E.jsx)(`button`,{type:`button`,onClick:n,className:e(`block w-full px-4 py-2.5 text-left hover:bg-surface-2`,r?`text-rose-600 dark:text-rose-300`:``),children:t})}function ae({avatar:e,emoji:n,color:r,name:i}){let a=t(),[o,s]=(0,T.useState)(0),l=D[o%D.length],f=(0,T.useRef)(0);(0,T.useEffect)(()=>(f.current=window.setTimeout(()=>s(e=>(e+1)%D.length),l===`idle`?2600:2e3),()=>window.clearTimeout(f.current)),[o,l]);let p=c(e),g=!p&&e?e:null,_=p?m(l):g?h(g,l):``,v=p?d(l):g?u(g,l):null,[y,b]=(0,T.useState)(()=>new Set),x=v&&!y.has(v)?v:null;return(0,E.jsxs)(E.Fragment,{children:[(0,E.jsx)(`div`,{className:`avatar-pop h-[148px] w-[148px] overflow-hidden rounded-full`,style:_?{background:`#f1efeb`}:{background:`linear-gradient(135deg, ${r??`#0064d4`}, color-mix(in srgb, ${r??`#0064d4`} 60%, #ffffff))`},children:x?(0,E.jsx)(`video`,{src:x,poster:_,autoPlay:!0,loop:!0,muted:!0,playsInline:!0,disablePictureInPicture:!0,onError:()=>b(e=>new Set(e).add(x)),className:`h-full w-full object-cover`},x):_?(0,E.jsx)(`img`,{src:_,alt:``,draggable:!1,className:`h-full w-full object-cover`}):(0,E.jsx)(`span`,{className:`flex h-full w-full items-center justify-center text-[64px] leading-none`,children:n??`✨`})},e),(0,E.jsx)(`div`,{className:`mt-3 text-[20px] font-semibold tracking-tight`,children:i}),(0,E.jsx)(`div`,{className:`mt-1 text-[13px] text-muted`,children:a(O[l])})]})}export{A as AvatarStudioScreen}; \ No newline at end of file diff --git a/nanomuse/server/static/assets/BackBar-Dl56jHZM.js b/nanomuse/server/static/assets/BackBar-DqcCClHf.js similarity index 85% rename from nanomuse/server/static/assets/BackBar-Dl56jHZM.js rename to nanomuse/server/static/assets/BackBar-DqcCClHf.js index b084e5e81..6bfff5744 100644 --- a/nanomuse/server/static/assets/BackBar-Dl56jHZM.js +++ b/nanomuse/server/static/assets/BackBar-DqcCClHf.js @@ -1 +1 @@ -import{K as e,b as t,f as n,r}from"./MuseHeader-Pw-NI98v.js";import{Dt as i}from"./index-CIdGZ5PB.js";var a=t();function o({title:t,description:o,actions:s,onBack:c,backLabel:l}){let{setTab:u}=n(),d=e();return(0,a.jsxs)(`header`,{className:`safe-top shrink-0`,children:[(0,a.jsxs)(`div`,{className:`relative flex h-14 items-center justify-center px-3`,children:[(0,a.jsx)(`div`,{className:`absolute left-3 top-1/2 -translate-y-1/2`,children:(0,a.jsx)(r,{small:!0,onClick:c??(()=>u(`chat`)),label:l??d(`Back`),children:(0,a.jsx)(i,{size:20})})}),(0,a.jsx)(`h1`,{className:`max-w-[calc(100%-128px)] truncate text-[17px] font-semibold leading-[22px]`,children:t}),s&&(0,a.jsx)(`div`,{className:`absolute right-3 top-1/2 flex -translate-y-1/2 items-center gap-2`,children:s})]}),o&&(0,a.jsx)(`p`,{className:`px-5 pb-2 text-[13px] leading-[18px] text-muted`,children:o})]})}export{o as t}; \ No newline at end of file +import{K as e,b as t,f as n,r}from"./MuseHeader-BDWXHKHT.js";import{Dt as i}from"./index-DKrXW2Qj.js";var a=t();function o({title:t,description:o,actions:s,onBack:c,backLabel:l}){let{setTab:u}=n(),d=e();return(0,a.jsxs)(`header`,{className:`safe-top shrink-0`,children:[(0,a.jsxs)(`div`,{className:`relative flex h-14 items-center justify-center px-3`,children:[(0,a.jsx)(`div`,{className:`absolute left-3 top-1/2 -translate-y-1/2`,children:(0,a.jsx)(r,{small:!0,onClick:c??(()=>u(`chat`)),label:l??d(`Back`),children:(0,a.jsx)(i,{size:20})})}),(0,a.jsx)(`h1`,{className:`max-w-[calc(100%-128px)] truncate text-[17px] font-semibold leading-[22px]`,children:t}),s&&(0,a.jsx)(`div`,{className:`absolute right-3 top-1/2 flex -translate-y-1/2 items-center gap-2`,children:s})]}),o&&(0,a.jsx)(`p`,{className:`px-5 pb-2 text-[13px] leading-[18px] text-muted`,children:o})]})}export{o as t}; \ No newline at end of file diff --git a/nanomuse/server/static/assets/ChannelsScreen-mBzj7BLf.js b/nanomuse/server/static/assets/ChannelsScreen-Cil6hJ5n.js similarity index 97% rename from nanomuse/server/static/assets/ChannelsScreen-mBzj7BLf.js rename to nanomuse/server/static/assets/ChannelsScreen-Cil6hJ5n.js index c43a8d030..3236de767 100644 --- a/nanomuse/server/static/assets/ChannelsScreen-mBzj7BLf.js +++ b/nanomuse/server/static/assets/ChannelsScreen-Cil6hJ5n.js @@ -1,2 +1,2 @@ -import{E as e,J as t,K as n,Q as r,Y as i,b as a,f as o,q as s,w as c}from"./MuseHeader-Pw-NI98v.js";import{n as l,t as u}from"./external-link-Xj5fjR8v.js";import{a as d,i as f,o as p,r as m}from"./Form-DwKuBk1V.js";import{t as h}from"./refresh-cw-BKgIzslL.js";import{C as g,V as _,Y as v,a as y,at as b,c as x,i as S,l as C,o as w,s as T}from"./index-CIdGZ5PB.js";import{t as E}from"./BackBar-Dl56jHZM.js";var D=t(`qr-code`,[[`rect`,{width:`5`,height:`5`,x:`3`,y:`3`,rx:`1`,key:`1tu5fj`}],[`rect`,{width:`5`,height:`5`,x:`16`,y:`3`,rx:`1`,key:`1v8r4q`}],[`rect`,{width:`5`,height:`5`,x:`3`,y:`16`,rx:`1`,key:`1x03jg`}],[`path`,{d:`M21 16h-3a2 2 0 0 0-2 2v3`,key:`177gqh`}],[`path`,{d:`M21 21v.01`,key:`ents32`}],[`path`,{d:`M12 7v3a2 2 0 0 1-2 2H7`,key:`8crl2c`}],[`path`,{d:`M3 12h.01`,key:`nlz23k`}],[`path`,{d:`M12 3h.01`,key:`n36tog`}],[`path`,{d:`M12 16v.01`,key:`133mhm`}],[`path`,{d:`M16 12h1`,key:`1slzba`}],[`path`,{d:`M21 12v.01`,key:`1lwtk9`}],[`path`,{d:`M12 21v-1`,key:`1880an`}]]),O=r(i(),1),k=(e,t)=>({method:e,body:JSON.stringify(t)}),A=encodeURIComponent,j={view:()=>c(`/api/channels`),update:(e,t)=>c(`/api/channels/${A(e)}`,k(`PUT`,t)),reload:()=>c(`/api/channels/reload`,{method:`POST`}),test:(e,t=``)=>c(`/api/channels/${A(e)}/test`,k(`POST`,{chat_id:t})),approve:e=>c(`/api/channels/pairing/${A(e)}/approve`,{method:`POST`}),deny:e=>c(`/api/channels/pairing/${A(e)}/deny`,{method:`POST`}),setDeliver:(e,t,n)=>c(`/api/channels/${A(e)}/chats/${A(t)}`,k(`PUT`,{deliver:n})),removeChat:(e,t)=>c(`/api/channels/${A(e)}/chats/${A(t)}`,{method:`DELETE`}),loginBegin:(e,t)=>c(`/api/channels/${A(e)}/login`,k(`POST`,{domain:t})),loginPoll:(e,t)=>c(`/api/channels/${A(e)}/login/${A(t)}`),deliver:e=>c(`/api/channels/deliver`,k(`POST`,{text:e}))},M=a(),N={feishu:[`In the Feishu developer console create a custom app and add the Bot capability.`,`Permissions: im:message, im:message.p2p_msg:readonly, im:message.group_at_msg:readonly, im:resource.`,`Events & callbacks: subscription mode Long connection; add im.message.receive_v1; callback mode Long connection; add card.action.trigger.`,`Copy App ID and App Secret from Credentials & Basic Info, then publish a version.`],dingtalk:[`In the DingTalk developer console create an internal app and add the Robot capability.`,`Set the message receive mode to Stream.`,`Copy Client ID (AppKey) and Client Secret (AppSecret) from Credentials & Basic Info.`,`Add the robot send-message permission and publish the version.`],wecom:[`In the WeCom admin console open Intelligent robot and create a robot in API mode with a long connection.`,`Copy the Bot ID and Secret.`,`Add the robot to the chats where it should listen.`],telegram:[`In Telegram talk to @BotFather, send /newbot and copy the token.`,`Direct messages work at once. For a group, add the bot to it; with Group Privacy on it only hears @-mentions and replies.`,`If api.telegram.org is out of reach from this computer, set a proxy below.`]},P={telegram:(0,M.jsx)(v,{size:20})};function F(e,t){let n=t.status.state;return e(n===`off`?`Off`:n===`unconfigured`?`Needs settings`:n===`missing_sdk`?`Not installed`:n===`connecting`?`Connecting…`:n===`connected`?`Connected`:`Error`)}function I({state:t}){return(0,M.jsx)(`span`,{"aria-hidden":!0,className:e(`inline-block h-2 w-2 rounded-full`,t===`connected`?`bg-emerald-500`:t===`error`?`bg-red-500`:t===`connecting`?`bg-amber-400`:`bg-border`)})}function L(){let{toast:e}=o(),t=n(),[r,i]=(0,O.useState)(null),[a,c]=(0,O.useState)(null),l=async()=>{try{i(await j.view()),c(null)}catch(e){c(e.message||`Could not load.`)}};(0,O.useEffect)(()=>{l();let e=window.setInterval(()=>void l(),5e3),t=()=>void l();return window.addEventListener(`focus`,t),()=>{window.clearInterval(e),window.removeEventListener(`focus`,t)}},[]);let u=async(t,n)=>{try{i(await t()),n&&e(n)}catch(t){e(t.message)}};return(0,M.jsxs)(`div`,{className:`flex h-full flex-col`,children:[(0,M.jsx)(E,{title:t(`Chat apps`),description:t(`Talk to your Muse from the chat apps you already use. Nothing needs a public address: each app keeps a long connection open.`)}),(0,M.jsxs)(`div`,{className:`flex-1 overflow-y-auto pb-8`,children:[r===null&&a&&(0,M.jsx)(g,{message:a,onRetry:()=>void l()}),r===null&&!a&&(0,M.jsx)(`div`,{className:`flex justify-center py-10 text-muted`,children:(0,M.jsx)(s,{className:`animate-spin`,size:20})}),r&&r.pending.length>0&&(0,M.jsxs)(M.Fragment,{children:[(0,M.jsx)(x,{children:t(`Waiting for a yes`)}),(0,M.jsx)(y,{children:r.pending.map((e,t)=>(0,M.jsxs)(`div`,{children:[t>0&&(0,M.jsx)(w,{inset:16}),(0,M.jsx)(R,{p:e,label:r.channels.find(t=>t.name===e.channel)?.label??e.channel,onApprove:()=>u(()=>j.approve(e.code)),onDeny:()=>u(()=>j.deny(e.code))})]},e.code))})]}),r?.channels.map(e=>(0,M.jsx)(z,{c:e,run:u,reload:l},e.name)),r&&(0,M.jsx)(S,{children:t(`Each chat is one conversation of your Muse; its replies stream back as they are written.`)})]})]})}function R({p:t,label:r,onApprove:i,onDeny:a}){let o=n(),s=t.sender_name||t.sender_id;return(0,M.jsxs)(`div`,{className:`flex items-center gap-3 px-4 py-3`,children:[(0,M.jsxs)(`div`,{className:`min-w-0 flex-1`,children:[(0,M.jsx)(`p`,{className:`truncate text-[15px]`,children:o(`{name} wrote to the bot. Approve to let them talk to your Muse.`,{name:`${s} · ${r}`})}),(0,M.jsx)(`p`,{className:`text-[13px] text-muted`,children:o(`Code {code}`,{code:t.code})})]}),(0,M.jsxs)(`button`,{type:`button`,className:e(f,`px-3 py-2`),onClick:i,"aria-label":o(`Approve`),children:[(0,M.jsx)(l,{size:16}),` `,o(`Approve`)]}),(0,M.jsx)(`button`,{type:`button`,className:e(d,`px-3 py-2`),onClick:a,"aria-label":o(`Deny`),children:(0,M.jsx)(p,{size:16})})]})}function z({c:t,run:r,reload:i}){let a=n(),{toast:s}=o(),[c,l]=(0,O.useState)(!1),[d,f]=(0,O.useState)({}),[p,m]=(0,O.useState)([]),[g,v]=(0,O.useState)(null),[E,k]=(0,O.useState)(!1),[A,L]=(0,O.useState)(!1),[R,z]=(0,O.useState)(!1),[V,H]=(0,O.useState)(null),[U,W]=(0,O.useState)(``),[G,K]=(0,O.useState)(!1),q=(0,O.useRef)(null),J=Object.keys(d).length>0||g!==null,Y=g??t.allow_from.join(` +import{E as e,J as t,K as n,Q as r,Y as i,b as a,f as o,q as s,w as c}from"./MuseHeader-BDWXHKHT.js";import{n as l,t as u}from"./external-link-CZH-rQLq.js";import{a as d,i as f,o as p,r as m}from"./Form-B3Ejw5aI.js";import{t as h}from"./refresh-cw-qw351CFk.js";import{C as g,V as _,Y as v,a as y,at as b,c as x,i as S,l as C,o as w,s as T}from"./index-DKrXW2Qj.js";import{t as E}from"./BackBar-DqcCClHf.js";var D=t(`qr-code`,[[`rect`,{width:`5`,height:`5`,x:`3`,y:`3`,rx:`1`,key:`1tu5fj`}],[`rect`,{width:`5`,height:`5`,x:`16`,y:`3`,rx:`1`,key:`1v8r4q`}],[`rect`,{width:`5`,height:`5`,x:`3`,y:`16`,rx:`1`,key:`1x03jg`}],[`path`,{d:`M21 16h-3a2 2 0 0 0-2 2v3`,key:`177gqh`}],[`path`,{d:`M21 21v.01`,key:`ents32`}],[`path`,{d:`M12 7v3a2 2 0 0 1-2 2H7`,key:`8crl2c`}],[`path`,{d:`M3 12h.01`,key:`nlz23k`}],[`path`,{d:`M12 3h.01`,key:`n36tog`}],[`path`,{d:`M12 16v.01`,key:`133mhm`}],[`path`,{d:`M16 12h1`,key:`1slzba`}],[`path`,{d:`M21 12v.01`,key:`1lwtk9`}],[`path`,{d:`M12 21v-1`,key:`1880an`}]]),O=r(i(),1),k=(e,t)=>({method:e,body:JSON.stringify(t)}),A=encodeURIComponent,j={view:()=>c(`/api/channels`),update:(e,t)=>c(`/api/channels/${A(e)}`,k(`PUT`,t)),reload:()=>c(`/api/channels/reload`,{method:`POST`}),test:(e,t=``)=>c(`/api/channels/${A(e)}/test`,k(`POST`,{chat_id:t})),approve:e=>c(`/api/channels/pairing/${A(e)}/approve`,{method:`POST`}),deny:e=>c(`/api/channels/pairing/${A(e)}/deny`,{method:`POST`}),setDeliver:(e,t,n)=>c(`/api/channels/${A(e)}/chats/${A(t)}`,k(`PUT`,{deliver:n})),removeChat:(e,t)=>c(`/api/channels/${A(e)}/chats/${A(t)}`,{method:`DELETE`}),loginBegin:(e,t)=>c(`/api/channels/${A(e)}/login`,k(`POST`,{domain:t})),loginPoll:(e,t)=>c(`/api/channels/${A(e)}/login/${A(t)}`),deliver:e=>c(`/api/channels/deliver`,k(`POST`,{text:e}))},M=a(),N={feishu:[`In the Feishu developer console create a custom app and add the Bot capability.`,`Permissions: im:message, im:message.p2p_msg:readonly, im:message.group_at_msg:readonly, im:resource.`,`Events & callbacks: subscription mode Long connection; add im.message.receive_v1; callback mode Long connection; add card.action.trigger.`,`Copy App ID and App Secret from Credentials & Basic Info, then publish a version.`],dingtalk:[`In the DingTalk developer console create an internal app and add the Robot capability.`,`Set the message receive mode to Stream.`,`Copy Client ID (AppKey) and Client Secret (AppSecret) from Credentials & Basic Info.`,`Add the robot send-message permission and publish the version.`],wecom:[`In the WeCom admin console open Intelligent robot and create a robot in API mode with a long connection.`,`Copy the Bot ID and Secret.`,`Add the robot to the chats where it should listen.`],telegram:[`In Telegram talk to @BotFather, send /newbot and copy the token.`,`Direct messages work at once. For a group, add the bot to it; with Group Privacy on it only hears @-mentions and replies.`,`If api.telegram.org is out of reach from this computer, set a proxy below.`]},P={telegram:(0,M.jsx)(v,{size:20})};function F(e,t){let n=t.status.state;return e(n===`off`?`Off`:n===`unconfigured`?`Needs settings`:n===`missing_sdk`?`Not installed`:n===`connecting`?`Connecting…`:n===`connected`?`Connected`:`Error`)}function I({state:t}){return(0,M.jsx)(`span`,{"aria-hidden":!0,className:e(`inline-block h-2 w-2 rounded-full`,t===`connected`?`bg-emerald-500`:t===`error`?`bg-red-500`:t===`connecting`?`bg-amber-400`:`bg-border`)})}function L(){let{toast:e}=o(),t=n(),[r,i]=(0,O.useState)(null),[a,c]=(0,O.useState)(null),l=async()=>{try{i(await j.view()),c(null)}catch(e){c(e.message||`Could not load.`)}};(0,O.useEffect)(()=>{l();let e=window.setInterval(()=>void l(),5e3),t=()=>void l();return window.addEventListener(`focus`,t),()=>{window.clearInterval(e),window.removeEventListener(`focus`,t)}},[]);let u=async(t,n)=>{try{i(await t()),n&&e(n)}catch(t){e(t.message)}};return(0,M.jsxs)(`div`,{className:`flex h-full flex-col`,children:[(0,M.jsx)(E,{title:t(`Chat apps`),description:t(`Talk to your Muse from the chat apps you already use. Nothing needs a public address: each app keeps a long connection open.`)}),(0,M.jsxs)(`div`,{className:`flex-1 overflow-y-auto pb-8`,children:[r===null&&a&&(0,M.jsx)(g,{message:a,onRetry:()=>void l()}),r===null&&!a&&(0,M.jsx)(`div`,{className:`flex justify-center py-10 text-muted`,children:(0,M.jsx)(s,{className:`animate-spin`,size:20})}),r&&r.pending.length>0&&(0,M.jsxs)(M.Fragment,{children:[(0,M.jsx)(x,{children:t(`Waiting for a yes`)}),(0,M.jsx)(y,{children:r.pending.map((e,t)=>(0,M.jsxs)(`div`,{children:[t>0&&(0,M.jsx)(w,{inset:16}),(0,M.jsx)(R,{p:e,label:r.channels.find(t=>t.name===e.channel)?.label??e.channel,onApprove:()=>u(()=>j.approve(e.code)),onDeny:()=>u(()=>j.deny(e.code))})]},e.code))})]}),r?.channels.map(e=>(0,M.jsx)(z,{c:e,run:u,reload:l},e.name)),r&&(0,M.jsx)(S,{children:t(`Each chat is one conversation of your Muse; its replies stream back as they are written.`)})]})]})}function R({p:t,label:r,onApprove:i,onDeny:a}){let o=n(),s=t.sender_name||t.sender_id;return(0,M.jsxs)(`div`,{className:`flex items-center gap-3 px-4 py-3`,children:[(0,M.jsxs)(`div`,{className:`min-w-0 flex-1`,children:[(0,M.jsx)(`p`,{className:`truncate text-[15px]`,children:o(`{name} wrote to the bot. Approve to let them talk to your Muse.`,{name:`${s} · ${r}`})}),(0,M.jsx)(`p`,{className:`text-[13px] text-muted`,children:o(`Code {code}`,{code:t.code})})]}),(0,M.jsxs)(`button`,{type:`button`,className:e(f,`px-3 py-2`),onClick:i,"aria-label":o(`Approve`),children:[(0,M.jsx)(l,{size:16}),` `,o(`Approve`)]}),(0,M.jsx)(`button`,{type:`button`,className:e(d,`px-3 py-2`),onClick:a,"aria-label":o(`Deny`),children:(0,M.jsx)(p,{size:16})})]})}function z({c:t,run:r,reload:i}){let a=n(),{toast:s}=o(),[c,l]=(0,O.useState)(!1),[d,f]=(0,O.useState)({}),[p,m]=(0,O.useState)([]),[g,v]=(0,O.useState)(null),[E,k]=(0,O.useState)(!1),[A,L]=(0,O.useState)(!1),[R,z]=(0,O.useState)(!1),[V,H]=(0,O.useState)(null),[U,W]=(0,O.useState)(``),[G,K]=(0,O.useState)(!1),q=(0,O.useRef)(null),J=Object.keys(d).length>0||g!==null,Y=g??t.allow_from.join(` `),X=async()=>{k(!0);try{let e={},n={};for(let[e,r]of Object.entries(d))(t.fields.find(t=>t.key===e)?.kind!==`secret`||r!==``||p.includes(e))&&(n[e]=r);Object.keys(n).length&&(e.settings=n),g!==null&&(e.allow_from=g.split(/[\n,]/).map(e=>e.trim()).filter(Boolean)),await r(()=>j.update(t.name,e),a(`Saved.`)),f({}),m([]),v(null)}finally{k(!1)}},Z=async()=>{L(!0);try{let e=await j.test(t.name);s(e.detail)}catch(e){s(e.message)}finally{L(!1)}},Q=()=>{q.current!==null&&window.clearTimeout(q.current),q.current=null};(0,O.useEffect)(()=>Q,[]);let $=async()=>{W(``);try{let e=await j.loginBegin(t.name,G?`lark`:`feishu`);H(e);let n=Date.now(),r=async()=>{try{let r=await j.loginPoll(t.name,e.device_code);if(r.status===`succeeded`){H(null),W(a(`The bot was created and is connecting.`)),await i();return}if(r.status===`failed`||Date.now()-n>e.expires_in*1e3){H(null),W(a(`The login did not finish ({error}).`,{error:r.error??`expired`}));return}}catch(e){H(null),W(e.message);return}q.current=window.setTimeout(()=>void r(),Math.max(2,e.interval)*1e3)};q.current=window.setTimeout(()=>void r(),Math.max(2,e.interval)*1e3)}catch(e){s(e.message)}},ee=()=>{Q(),H(null)},te=t.fields.filter(e=>e.required&&(e.kind===`secret`?!e.has_value:!e.value)).map(e=>e.label);return(0,M.jsxs)(M.Fragment,{children:[(0,M.jsx)(x,{children:t.label}),(0,M.jsxs)(y,{children:[(0,M.jsx)(T,{icon:P[t.name]??(0,M.jsx)(b,{size:20}),label:t.label,value:F(a,t),trailing:(0,M.jsx)(I,{state:t.status.state}),onClick:()=>l(e=>!e)}),(0,M.jsx)(w,{}),(0,M.jsx)(C,{label:a(`Switched on`),checked:t.enabled,disabled:!t.sdk_available&&!t.enabled,onChange:e=>void r(()=>j.update(t.name,{enabled:e}))}),t.status.state===`error`&&t.status.detail&&(0,M.jsx)(`p`,{className:`px-4 pb-3 text-[13px] leading-[18px] text-red-600 dark:text-red-400`,children:t.status.detail}),t.status.state===`unconfigured`&&(0,M.jsxs)(`p`,{className:`px-4 pb-3 text-[13px] leading-[18px] text-muted`,children:[a(`Missing`),`: `,t.status.detail||te.join(`, `)]}),!t.sdk_available&&(0,M.jsxs)(`div`,{className:`px-4 pb-3 text-[13px] leading-[18px] text-muted`,children:[a(`Install on the computer running nanoMuse, then switch it on again:`),(0,M.jsx)(`code`,{className:`mt-1 block select-all rounded-lg bg-surface-2 px-2 py-1 text-[12.5px] text-fg`,children:t.install})]}),(c||t.enabled)&&(0,M.jsxs)(M.Fragment,{children:[(0,M.jsx)(w,{inset:16}),(0,M.jsxs)(`div`,{className:`space-y-3 px-4 py-3`,children:[t.fields.map(e=>(0,M.jsx)(B,{f:e,value:d[e.key],onChange:t=>{f(n=>({...n,[e.key]:t})),t!==``&&m(t=>t.filter(t=>t!==e.key))},onClear:()=>{f(t=>({...t,[e.key]:``})),m(t=>t.includes(e.key)?t:[...t,e.key])}},e.key)),(0,M.jsxs)(`label`,{className:`block`,children:[(0,M.jsx)(`span`,{className:`mb-1 block text-[13px] text-muted`,children:a(`In groups, reply`)}),(0,M.jsxs)(`select`,{className:`w-full rounded-2xl bg-surface-2 px-3.5 py-2.5 text-[14.5px] outline-none focus:ring-2 focus:ring-accent/40`,value:t.group_policy,onChange:e=>void r(()=>j.update(t.name,{group_policy:e.target.value})),children:[(0,M.jsx)(`option`,{value:`mention`,children:a(`only when @-mentioned`)}),(0,M.jsx)(`option`,{value:`open`,children:a(`to every message`)})]})]}),(0,M.jsxs)(`label`,{className:`block`,children:[(0,M.jsx)(`span`,{className:`mb-1 block text-[13px] text-muted`,children:a(`Always allowed (ids, one per line)`)}),(0,M.jsx)(`textarea`,{className:e(`w-full rounded-2xl bg-surface-2 px-3.5 py-2.5 text-[14.5px] outline-none focus:ring-2 focus:ring-accent/40`,`min-h-[56px] font-mono text-[13px]`),value:Y,onChange:e=>v(e.target.value),rows:2}),(0,M.jsx)(`span`,{className:`mt-1 block text-[12.5px] leading-[17px] text-muted`,children:a(`People listed here never need a pairing code. A lone * lets anyone in; do that only on a bot nobody else can reach.`)})]}),(0,M.jsxs)(`div`,{className:`flex flex-wrap gap-2`,children:[(0,M.jsx)(`button`,{type:`button`,className:`flex items-center justify-center gap-1.5 rounded-2xl bg-accent text-accent-fg px-4 py-2.5 text-[14px] font-medium disabled:opacity-40`,disabled:!J||E,onClick:()=>void X(),children:a(E?`Saving`:`Save`)}),(0,M.jsxs)(`button`,{type:`button`,className:`flex items-center justify-center gap-1.5 rounded-2xl border border-border px-4 py-2.5 text-[14px] font-medium text-muted disabled:opacity-40`,disabled:A||t.status.state!==`connected`,onClick:()=>void Z(),children:[(0,M.jsx)(h,{size:14,className:A?`animate-spin`:``}),` `,a(A?`Sending`:`Send a test message`)]}),t.name===`feishu`&&!V&&(0,M.jsxs)(`button`,{type:`button`,className:`flex items-center justify-center gap-1.5 rounded-2xl border border-border px-4 py-2.5 text-[14px] font-medium text-muted disabled:opacity-40`,onClick:()=>void $(),children:[(0,M.jsx)(D,{size:14}),` `,a(`Create the bot by QR code`)]}),(0,M.jsx)(`button`,{type:`button`,className:`flex items-center justify-center gap-1.5 rounded-2xl border border-border px-4 py-2.5 text-[14px] font-medium text-muted disabled:opacity-40`,onClick:()=>z(e=>!e),"aria-expanded":R,children:a(`Set up`)})]}),t.name===`feishu`&&!V&&(0,M.jsxs)(`label`,{className:`flex items-center gap-2 text-[13px] text-muted`,children:[(0,M.jsx)(`input`,{type:`checkbox`,checked:G,onChange:e=>K(e.target.checked)}),a(`Lark (international) instead of 飞书`)]}),V&&(0,M.jsxs)(`div`,{className:`rounded-2xl bg-surface-2 p-3 text-center`,children:[V.qr_png?(0,M.jsx)(`img`,{src:`data:image/png;base64,${V.qr_png}`,alt:`QR`,className:`mx-auto h-44 w-44 rounded-lg bg-white p-1`}):null,(0,M.jsx)(`p`,{className:`mt-2 text-[13px] text-muted`,children:a(`Scan with Feishu, confirm the new bot, and the App ID and Secret are saved for you.`)}),(0,M.jsx)(`p`,{className:`text-[13px] text-muted`,children:a(`Waiting for the scan…`)}),(0,M.jsxs)(`div`,{className:`mt-2 flex justify-center gap-2`,children:[(0,M.jsxs)(`a`,{href:V.url,target:`_blank`,rel:`noreferrer`,className:e(`flex items-center justify-center gap-1.5 rounded-2xl border border-border px-4 py-2.5 text-[14px] font-medium text-muted disabled:opacity-40`,`px-3 py-1.5`),children:[(0,M.jsx)(u,{size:14}),` `,a(`Open in Feishu`)]}),(0,M.jsx)(`button`,{type:`button`,className:e(`flex items-center justify-center gap-1.5 rounded-2xl border border-border px-4 py-2.5 text-[14px] font-medium text-muted disabled:opacity-40`,`px-3 py-1.5`),onClick:ee,children:a(`Cancel`)})]})]}),U&&(0,M.jsx)(`p`,{className:`text-[13px] text-muted`,children:U}),R&&(0,M.jsxs)(`div`,{className:`rounded-2xl bg-surface-2 p-3 text-[13.5px] leading-[19px]`,children:[(0,M.jsx)(`ol`,{className:`list-decimal space-y-1 pl-5`,children:(N[t.name]??[]).map(e=>(0,M.jsx)(`li`,{children:a(e)},e))}),(0,M.jsxs)(`p`,{className:`mt-2 text-muted`,children:[a(`Then write to the bot from the app. The first message gets a pairing code; approve it here or run`),` `,(0,M.jsx)(`code`,{className:`rounded bg-surface px-1`,children:`nanomuse channels approve `})]}),t.console_url&&(0,M.jsxs)(`a`,{href:t.console_url,target:`_blank`,rel:`noreferrer`,className:`mt-2 inline-flex items-center gap-1 text-accent underline-offset-2 hover:underline`,children:[(0,M.jsx)(u,{size:14}),` `,a(`Open the console`)]})]})]}),(0,M.jsx)(w,{inset:16}),(0,M.jsx)(`p`,{className:`px-4 pt-3 text-[13px] text-muted`,children:a(`Paired chats`)}),t.paired.length===0?(0,M.jsx)(`p`,{className:`px-4 pb-3 pt-1 text-[13px] leading-[18px] text-muted`,children:a(`Nobody yet. Write to the bot from the app; a pairing code comes back, approve it here.`)}):t.paired.map(e=>(0,M.jsxs)(`div`,{className:`flex items-center`,children:[(0,M.jsx)(`div`,{className:`min-w-0 flex-1`,children:(0,M.jsx)(C,{label:e.sender_name||e.sender_id,value:a(`Deliver here`),checked:e.deliver,onChange:n=>void r(()=>j.setDeliver(t.name,e.sender_id,n))})}),(0,M.jsx)(`button`,{type:`button`,className:`mr-3 rounded-full p-2 text-muted hover:bg-surface-2`,"aria-label":a(`Remove`),onClick:()=>{window.confirm(a(`Remove {name}? They will need a new pairing code.`,{name:e.sender_name||e.sender_id}))&&r(()=>j.removeChat(t.name,e.sender_id))},children:(0,M.jsx)(_,{size:16})})]},e.sender_id))]})]}),(c||t.enabled)&&t.paired.length>0&&(0,M.jsx)(S,{children:a(`Chats with “deliver here” on also get what the Muse does on its own: check-ins, reminders, the results of background work, and the questions it needs answered.`)})]})}function B({f:t,value:r,onChange:i,onClear:a}){let o=n();if(t.kind===`choice`)return(0,M.jsxs)(`label`,{className:`block`,children:[(0,M.jsx)(`span`,{className:`mb-1 block text-[13px] text-muted`,children:t.label}),(0,M.jsx)(`select`,{className:m,value:r??String(t.value??t.default),onChange:e=>i(e.target.value),children:t.choices.map(e=>(0,M.jsx)(`option`,{value:e,children:e},e))}),t.help&&(0,M.jsx)(`span`,{className:`mt-1 block text-[12.5px] text-muted`,children:t.help})]});let s=t.kind===`secret`;return(0,M.jsxs)(`label`,{className:`block`,children:[(0,M.jsxs)(`span`,{className:`mb-1 block text-[13px] text-muted`,children:[t.label,t.required?` *`:``]}),(0,M.jsxs)(`div`,{className:`flex gap-2`,children:[(0,M.jsx)(`input`,{type:s?`password`:`text`,autoComplete:`off`,className:m,value:r??(s?``:String(t.value??``)),placeholder:s&&t.has_value?o(`Set; leave blank to keep`):t.help,onChange:e=>i(e.target.value)}),s&&t.has_value&&(0,M.jsx)(`button`,{type:`button`,className:e(`flex items-center justify-center gap-1.5 rounded-2xl border border-border px-4 py-2.5 text-[14px] font-medium text-muted disabled:opacity-40`,`shrink-0 px-3`),onClick:a,title:o(`Clear the saved value`),"aria-label":o(`Clear the saved value`),children:(0,M.jsx)(p,{size:14})})]}),t.help&&!s&&(0,M.jsx)(`span`,{className:`mt-1 block text-[12.5px] text-muted`,children:t.help})]})}export{L as ChannelsScreen}; \ No newline at end of file diff --git a/nanomuse/server/static/assets/CloudCard-CtVHK0qc.js b/nanomuse/server/static/assets/CloudCard-B2Mi7bjZ.js similarity index 95% rename from nanomuse/server/static/assets/CloudCard-CtVHK0qc.js rename to nanomuse/server/static/assets/CloudCard-B2Mi7bjZ.js index 312716703..2ab13e24b 100644 --- a/nanomuse/server/static/assets/CloudCard-CtVHK0qc.js +++ b/nanomuse/server/static/assets/CloudCard-B2Mi7bjZ.js @@ -1 +1 @@ -import{K as e,Q as t,Y as n,b as r,f as i,q as a,x as o}from"./MuseHeader-Pw-NI98v.js";import{a as s,t as c}from"./Form-DwKuBk1V.js";import{ct as l,l as u,t as d,vt as f}from"./index-CIdGZ5PB.js";var p=t(n(),1),m=r();function h({account:t,onChange:n,compact:r=!1,useAsModel:h=!1}){let{toast:_}=i(),v=e(),[y,b]=(0,p.useState)(r||!t?.signed_in),[x,S]=(0,p.useState)(null),[C,w]=(0,p.useState)(null),T=!!t?.signed_in,E=async()=>{S(`model`),w(null);try{await o.cloudUseAsModel(),_(v(`The Cloud model is in use.`)),n()}catch(e){w(v(e.message))}finally{S(null)}},D=t?.models!==!1,O=async e=>{S(`switch`),w(null);try{await o.cloudModels(e),n()}catch(e){w(v(e.message))}finally{S(null)}},k=async()=>{if(window.confirm(v(`Sign out of nanoMuse Cloud on this device? The hub and the Cloud model stop working here until you sign in again.`))){S(`out`);try{await o.cloudSignOut(),n()}catch(e){_(e.message)}finally{S(null)}}},A=T?{text:v(`Signed in`),tone:`ok`}:{text:v(`Not signed in`),tone:`off`},j=T?t?.is_model?v(`{hint} · model and hub`,{hint:t.hint}):v(`{hint} · hub`,{hint:t?.hint??``}):v(`Free. One account for all your devices, and a model to start with.`);return(0,m.jsx)(c,{icon:(0,m.jsx)(f,{size:20}),title:v(`nanoMuse Cloud`),summary:j,status:A,open:y,onToggle:r?void 0:()=>b(e=>!e),children:T?(0,m.jsxs)(`div`,{className:`space-y-3`,children:[(0,m.jsx)(`p`,{className:`text-[13px] text-muted leading-relaxed`,children:v(`Signed in as {hint}. Your devices meet here; the Cloud model comes with a free allowance.`,{hint:t?.hint??``})}),(0,m.jsx)(`div`,{className:`-mx-4 border-y border-border/60`,children:(0,m.jsx)(u,{label:v(`Use nanoMuse Cloud models`),checked:D,disabled:x!==null,onChange:e=>void O(e)})}),(0,m.jsx)(`p`,{className:`text-[12.5px] text-muted leading-relaxed`,children:v(D?`nanoMuse Cloud is one of the sources for the chat, the hands, pictures and clips; what runs on it comes off your allowance.`:`Off: nothing runs on nanoMuse Cloud unless you choose it yourself. You stay signed in for sync and your devices.`)}),(0,m.jsxs)(`div`,{className:`flex flex-wrap gap-2`,children:[!t?.is_model&&(0,m.jsxs)(`button`,{type:`button`,disabled:x!==null,onClick:()=>void E(),className:`flex items-center justify-center gap-1.5 rounded-2xl bg-accent text-accent-fg px-4 py-2.5 text-[14px] font-medium disabled:opacity-40`,children:[x===`model`?(0,m.jsx)(a,{size:15,className:`animate-spin`}):null,` `,v(`Use the Cloud model`)]}),(0,m.jsxs)(`button`,{type:`button`,disabled:x!==null,onClick:()=>void k(),className:s,children:[(0,m.jsx)(l,{size:15}),` `,v(`Sign out`)]})]}),C&&(0,m.jsx)(g,{text:C})]}):(0,m.jsx)(d,{useAsModel:h,autoFocus:!1,onSignedIn:()=>{_(v(`Signed in to nanoMuse Cloud.`)),n()}})})}function g({text:e}){return(0,m.jsx)(`div`,{className:`rounded-2xl bg-rose-500/12 px-3 py-2 text-[12.5px] text-rose-700 dark:text-rose-300`,children:e})}export{h as t}; \ No newline at end of file +import{K as e,Q as t,Y as n,b as r,f as i,q as a,x as o}from"./MuseHeader-BDWXHKHT.js";import{a as s,t as c}from"./Form-B3Ejw5aI.js";import{ct as l,l as u,t as d,vt as f}from"./index-DKrXW2Qj.js";var p=t(n(),1),m=r();function h({account:t,onChange:n,compact:r=!1,useAsModel:h=!1}){let{toast:_}=i(),v=e(),[y,b]=(0,p.useState)(r||!t?.signed_in),[x,S]=(0,p.useState)(null),[C,w]=(0,p.useState)(null),T=!!t?.signed_in,E=async()=>{S(`model`),w(null);try{await o.cloudUseAsModel(),_(v(`The Cloud model is in use.`)),n()}catch(e){w(v(e.message))}finally{S(null)}},D=t?.models!==!1,O=async e=>{S(`switch`),w(null);try{await o.cloudModels(e),n()}catch(e){w(v(e.message))}finally{S(null)}},k=async()=>{if(window.confirm(v(`Sign out of nanoMuse Cloud on this device? The hub and the Cloud model stop working here until you sign in again.`))){S(`out`);try{await o.cloudSignOut(),n()}catch(e){_(e.message)}finally{S(null)}}},A=T?{text:v(`Signed in`),tone:`ok`}:{text:v(`Not signed in`),tone:`off`},j=T?t?.is_model?v(`{hint} · model and hub`,{hint:t.hint}):v(`{hint} · hub`,{hint:t?.hint??``}):v(`Free. One account for all your devices, and a model to start with.`);return(0,m.jsx)(c,{icon:(0,m.jsx)(f,{size:20}),title:v(`nanoMuse Cloud`),summary:j,status:A,open:y,onToggle:r?void 0:()=>b(e=>!e),children:T?(0,m.jsxs)(`div`,{className:`space-y-3`,children:[(0,m.jsx)(`p`,{className:`text-[13px] text-muted leading-relaxed`,children:v(`Signed in as {hint}. Your devices meet here; the Cloud model comes with a free allowance.`,{hint:t?.hint??``})}),(0,m.jsx)(`div`,{className:`-mx-4 border-y border-border/60`,children:(0,m.jsx)(u,{label:v(`Use nanoMuse Cloud models`),checked:D,disabled:x!==null,onChange:e=>void O(e)})}),(0,m.jsx)(`p`,{className:`text-[12.5px] text-muted leading-relaxed`,children:v(D?`nanoMuse Cloud is one of the sources for the chat, the hands, pictures and clips; what runs on it comes off your allowance.`:`Off: nothing runs on nanoMuse Cloud unless you choose it yourself. You stay signed in for sync and your devices.`)}),(0,m.jsxs)(`div`,{className:`flex flex-wrap gap-2`,children:[!t?.is_model&&(0,m.jsxs)(`button`,{type:`button`,disabled:x!==null,onClick:()=>void E(),className:`flex items-center justify-center gap-1.5 rounded-2xl bg-accent text-accent-fg px-4 py-2.5 text-[14px] font-medium disabled:opacity-40`,children:[x===`model`?(0,m.jsx)(a,{size:15,className:`animate-spin`}):null,` `,v(`Use the Cloud model`)]}),(0,m.jsxs)(`button`,{type:`button`,disabled:x!==null,onClick:()=>void k(),className:s,children:[(0,m.jsx)(l,{size:15}),` `,v(`Sign out`)]})]}),C&&(0,m.jsx)(g,{text:C})]}):(0,m.jsx)(d,{useAsModel:h,autoFocus:!1,onSignedIn:()=>{_(v(`Signed in to nanoMuse Cloud.`)),n()}})})}function g({text:e}){return(0,m.jsx)(`div`,{className:`rounded-2xl bg-rose-500/12 px-3 py-2 text-[12.5px] text-rose-700 dark:text-rose-300`,children:e})}export{h as t}; \ No newline at end of file diff --git a/nanomuse/server/static/assets/CodingScreen-C_tutsx0.js b/nanomuse/server/static/assets/CodingScreen-BulrK8KC.js similarity index 98% rename from nanomuse/server/static/assets/CodingScreen-C_tutsx0.js rename to nanomuse/server/static/assets/CodingScreen-BulrK8KC.js index c7daae17b..efa65914d 100644 --- a/nanomuse/server/static/assets/CodingScreen-C_tutsx0.js +++ b/nanomuse/server/static/assets/CodingScreen-BulrK8KC.js @@ -1,3 +1,3 @@ -import{E as e,J as t,K as n,Q as r,Y as i,b as a,f as o,k as s,q as c,r as l,x as u}from"./MuseHeader-Pw-NI98v.js";import{a as d,i as f,r as p}from"./Form-DwKuBk1V.js";import{t as m}from"./refresh-cw-BKgIzslL.js";import{Ct as h,F as g,H as _,Tt as v,U as y,Z as b,bt as x,it as S,w as C,z as w}from"./index-CIdGZ5PB.js";import{t as T}from"./BackBar-Dl56jHZM.js";var E=t(`folder-open`,[[`path`,{d:`m6 14 1.5-2.9A2 2 0 0 1 9.24 10H20a2 2 0 0 1 1.94 2.5l-1.54 6a2 2 0 0 1-1.95 1.5H4a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h3.9a2 2 0 0 1 1.69.9l.81 1.2a2 2 0 0 0 1.67.9H18a2 2 0 0 1 2 2v2`,key:`usdka0`}]]),D=r(i(),1),O=a(),k={cursor:{label:`Cursor`,tone:`from-slate-700 to-slate-900`,glyph:`C`},codex:{label:`Codex`,tone:`from-emerald-500 to-teal-700`,glyph:`X`},claude:{label:`Claude Code`,tone:`from-orange-400 to-amber-600`,glyph:`A`}};function A(){let{state:t,toast:r}=o(),i=n(),[a,d]=(0,D.useState)(``),[f,p]=(0,D.useState)(null),[h,g]=(0,D.useState)([]),[_,v]=(0,D.useState)(null),[C,w]=(0,D.useState)(``),[A,M]=(0,D.useState)(!1),[F,V]=(0,D.useState)(null),[H,U]=(0,D.useState)(null),[W,G]=(0,D.useState)(null),K=(0,D.useMemo)(()=>(t.hub?.devices??[]).filter(e=>!e.this&&e.online&&e.kind!==`web`&&(e.actions??[]).includes(`coding.sessions`)),[t.hub?.devices]),q=(0,D.useCallback)(async()=>{M(!0),V(null);try{let[e,t]=await Promise.all([u.coding(a),u.codingSessions({device:a,limit:40})]);p(e.agents),g(e.runs??[]),v(t.sessions)}catch(e){V(e.message),p([]),v([])}finally{M(!1)}},[a]);(0,D.useEffect)(()=>{q()},[q]);let J=Object.values(t.codingLive),Y=J.filter(e=>e.run.status!==`running`).length;(0,D.useEffect)(()=>{Y&&q()},[Y]);let X=(_??[]).filter(e=>(!C||e.agent===C)&&(e.messages>0||e.status===`running`)),Z=(f??[]).filter(e=>e.installed),Q=new Set(J.filter(e=>e.run.status===`running`&&(e.run.device??``)===(a?z(K,a):``)).map(e=>e.run.session_id||e.run.asked_session_id));return(0,O.jsxs)(`div`,{className:`flex h-full flex-col`,children:[(0,O.jsx)(T,{title:i(`Coding agents`),description:i(`Cursor, Codex and Claude Code: see what they are doing, and tell them things from anywhere.`),actions:(0,O.jsx)(l,{small:!0,onClick:()=>void q(),label:i(`Refresh`),children:(0,O.jsx)(m,{size:18,className:A?`animate-spin`:``})})}),(0,O.jsxs)(`div`,{className:`flex-1 overflow-y-auto px-4 pb-8 space-y-4`,children:[(K.length>0||a)&&(0,O.jsxs)(`div`,{className:`no-scrollbar -mx-4 flex gap-2 overflow-x-auto px-4`,children:[(0,O.jsx)(R,{active:!a,onClick:()=>d(``),icon:(0,O.jsx)(y,{size:14}),label:t.hub?.device?.name?i(`This one · {name}`,{name:t.hub.device.name}):i(`This computer`)}),K.map(e=>(0,O.jsx)(R,{active:a===e.id,onClick:()=>d(e.id),icon:(0,O.jsx)(S,{size:14}),label:e.name},e.id))]}),f&&(0,O.jsx)(`div`,{className:`grid grid-cols-3 gap-2`,children:f.map(t=>{let n=k[t.id];return(0,O.jsxs)(`button`,{type:`button`,disabled:!t.installed,onClick:()=>w(e=>e===t.id?``:t.id),className:e(`rounded-3xl border p-3 text-left transition`,C===t.id?`border-accent/40 bg-accent/5`:`border-border/70 bg-surface`,!t.installed&&`opacity-45`),children:[(0,O.jsxs)(`div`,{className:`flex items-center justify-between`,children:[(0,O.jsx)(I,{agent:t.id,size:30}),t.running>0&&(0,O.jsxs)(`span`,{className:`flex items-center gap-1 rounded-full bg-emerald-500/12 px-1.5 py-0.5 text-[10.5px] font-semibold text-emerald-700 dark:text-emerald-300`,children:[(0,O.jsx)(`span`,{className:`h-1.5 w-1.5 animate-pulse rounded-full bg-emerald-500`}),` `,t.running]})]}),(0,O.jsx)(`div`,{className:`mt-2 truncate text-[13.5px] font-semibold`,children:n?.label??t.name}),(0,O.jsx)(`div`,{className:`truncate text-[11.5px] text-muted`,children:t.installed?t.cli?t.version||i(`installed`):i(`chats only`):i(`not found`)})]},t.id)})}),F&&(0,O.jsx)(`div`,{className:`rounded-2xl bg-rose-500/12 px-3 py-2 text-[12.5px] text-rose-700 dark:text-rose-300`,children:F}),J.filter(e=>e.run.status===`running`).length>0&&(0,O.jsxs)(`section`,{className:`space-y-2`,children:[(0,O.jsx)(`h2`,{className:`px-1 text-[12px] font-semibold uppercase tracking-wide text-muted`,children:i(`Working now`)}),J.filter(e=>e.run.status===`running`).map(e=>(0,O.jsx)(N,{live:e,onOpen:()=>U({agent:e.run.agent,id:e.run.session_id||e.run.asked_session_id||``})},e.run.id))]}),(0,O.jsxs)(`section`,{className:`space-y-2`,children:[(0,O.jsxs)(`div`,{className:`flex items-center justify-between px-1`,children:[(0,O.jsx)(`h2`,{className:`text-[12px] font-semibold uppercase tracking-wide text-muted`,children:C?i(`{agent} chats`,{agent:k[C]?.label??C}):i(`Recent chats`)}),Z.some(e=>e.cli)&&(0,O.jsxs)(`button`,{type:`button`,onClick:()=>G(C&&Z.find(e=>e.id===C&&e.cli)?C:Z.find(e=>e.cli)?.id??null),className:`flex items-center gap-1 text-[12.5px] font-medium text-accent`,children:[(0,O.jsx)(b,{size:14}),` `,i(`New chat`)]})]}),_===null?(0,O.jsx)(`div`,{className:`flex justify-center py-10 text-muted`,children:(0,O.jsx)(c,{size:20,className:`animate-spin`})}):X.length===0?(0,O.jsx)(`div`,{className:`rounded-3xl border border-dashed border-border/80 px-4 py-8 text-center text-[13.5px] text-muted`,children:f&&f.every(e=>!e.installed)?i(`No coding agent found on this computer. Install Cursor, Codex or Claude Code and their chats appear here.`):i(`No chats yet.`)}):(0,O.jsx)(`ul`,{className:`divide-y divide-border/60 overflow-hidden rounded-3xl border border-border/70 bg-surface`,children:X.map(e=>(0,O.jsx)(`li`,{children:(0,O.jsxs)(`button`,{type:`button`,onClick:()=>U({agent:e.agent,id:e.id}),className:`flex w-full items-center gap-3 px-3.5 py-3 text-left hover:bg-surface-2/60 active:bg-surface-2`,children:[(0,O.jsx)(I,{agent:e.agent,size:34}),(0,O.jsxs)(`span`,{className:`min-w-0 flex-1`,children:[(0,O.jsxs)(`span`,{className:`flex items-center gap-2`,children:[(0,O.jsx)(`span`,{className:`truncate text-[14.5px] font-medium`,children:e.title||i(`Untitled chat`)}),(0,O.jsx)(L,{status:Q.has(e.id)?`running`:e.status})]}),(0,O.jsxs)(`span`,{className:`mt-0.5 flex items-center gap-1.5 truncate text-[12px] text-muted`,children:[e.workspace&&(0,O.jsxs)(`span`,{className:`flex min-w-0 items-center gap-1`,children:[(0,O.jsx)(E,{size:11}),` `,(0,O.jsx)(`span`,{className:`truncate`,children:B(e.workspace)})]}),(0,O.jsxs)(`span`,{children:[`· `,s(e.updated_at)]}),(0,O.jsxs)(`span`,{children:[`· `,i(`{n} messages`,{n:e.messages})]})]})]}),(0,O.jsx)(x,{size:16,className:`shrink-0 text-muted`})]})},`${e.agent}-${e.id}`))})]}),h.filter(e=>e.status!==`running`).length>0&&(0,O.jsxs)(`section`,{className:`space-y-2`,children:[(0,O.jsx)(`h2`,{className:`px-1 text-[12px] font-semibold uppercase tracking-wide text-muted`,children:i(`Sent through nanoMuse`)}),(0,O.jsx)(`ul`,{className:`divide-y divide-border/60 overflow-hidden rounded-3xl border border-border/70 bg-surface`,children:h.filter(e=>e.status!==`running`).slice(0,8).map(e=>(0,O.jsxs)(`li`,{className:`flex items-center gap-3 px-3.5 py-2.5`,children:[(0,O.jsx)(I,{agent:e.agent,size:28}),(0,O.jsxs)(`span`,{className:`min-w-0 flex-1`,children:[(0,O.jsx)(`span`,{className:`block truncate text-[13.5px]`,children:e.text}),(0,O.jsxs)(`span`,{className:`block truncate text-[11.5px] text-muted`,children:[e.status===`done`?i(`done`):e.status===`failed`?i(`failed`):i(`stopped`),` · `,s(e.started_at),e.tools?` · ${i(`{n} steps`,{n:e.tools})}`:``,e.error?` · ${e.error}`:``]})]}),e.session_id&&(0,O.jsx)(`button`,{type:`button`,onClick:()=>U({agent:e.agent,id:e.session_id}),className:`text-[12.5px] font-medium text-accent`,children:i(`Open`)})]},e.id))})]})]}),H&&(0,O.jsx)(j,{agent:H.agent,id:H.id,device:a,deviceLabel:a?z(K,a):``,onClose:()=>U(null)}),W&&(0,O.jsx)(P,{agent:W,agents:Z.filter(e=>e.cli),device:a,onClose:()=>G(null),onStarted:e=>{G(null),r(i(`Sent to {agent}.`,{agent:k[e.agent]?.label??e.agent}))}})]})}function j({agent:t,id:r,device:i,deviceLabel:a,onClose:s}){let{state:l,toast:d}=o(),f=n(),[m,h]=(0,D.useState)(null),[y,b]=(0,D.useState)(null),[x,S]=(0,D.useState)(``),[w,T]=(0,D.useState)(!1),E=(0,D.useRef)(null),A=(0,D.useCallback)(async()=>{try{h(await u.codingSession(t,r,i)),b(null)}catch(e){b(e.message)}},[t,r,i]);(0,D.useEffect)(()=>{A()},[A]);let j=Object.values(l.codingLive).filter(e=>e.run.agent===t&&(e.run.session_id===r||e.run.asked_session_id===r)),N=j.find(e=>e.run.status===`running`),P=j.filter(e=>e.run.status!==`running`).length;(0,D.useEffect)(()=>{P&&A()},[P]),(0,D.useEffect)(()=>{let e=E.current;e&&(e.scrollTop=e.scrollHeight)},[m?.transcript?.length,N?.events.length,N?.current.length]);let L=async()=>{let e=x.trim();if(e&&!w){T(!0);try{await u.codingSend({agent:t,text:e,session_id:r,workspace:m?.workspace??``,device:i}),S(``)}catch(e){d(e.message)}finally{T(!1)}}},R=k[t],z=m?.transcript??[],V=!!m||!!N,H=!!m&&!m.resumable&&!N;return(0,O.jsx)(C,{open:!0,onClose:s,title:(0,O.jsxs)(`span`,{className:`flex items-center gap-2.5`,children:[(0,O.jsx)(I,{agent:t,size:30}),(0,O.jsxs)(`span`,{className:`min-w-0`,children:[(0,O.jsx)(`span`,{className:`block truncate`,children:m?.title||R?.label||t}),(0,O.jsxs)(`span`,{className:`block truncate text-[12px] font-normal text-muted`,children:[a?`${a} · `:``,m?.workspace?B(m.workspace):R?.label,m?.source&&m.source!==`ide`&&m.source!==`cli`?` · ${m.source}`:``]})]})]}),footer:(0,O.jsxs)(O.Fragment,{children:[H&&(0,O.jsx)(`p`,{className:`mb-1.5 px-1 text-[11.5px] leading-snug text-muted`,children:f(`Made in the IDE: your message starts a new chat in the same workspace, with the last exchange quoted.`)}),(0,O.jsxs)(`form`,{className:`flex items-end gap-2`,onSubmit:e=>{e.preventDefault(),L()},children:[(0,O.jsx)(`textarea`,{value:x,onChange:e=>S(e.target.value),onKeyDown:e=>{e.key===`Enter`&&!e.shiftKey&&(e.preventDefault(),L())},rows:1,disabled:!V||!!N,placeholder:N?f(`{agent} is working…`,{agent:R?.label??t}):m?H?f(`Continue in a new chat…`):f(`Tell {agent}…`,{agent:R?.label??t}):`…`,className:e(p,`max-h-32 min-h-[44px] resize-none py-2.5`)}),N?(0,O.jsx)(`button`,{type:`button`,onClick:()=>void u.codingStop(N.run.id,i).catch(e=>d(e.message)),"aria-label":f(`Stop`),className:`flex h-11 w-11 shrink-0 items-center justify-center rounded-full bg-rose-500 text-white`,children:(0,O.jsx)(_,{size:16})}):(0,O.jsx)(`button`,{type:`submit`,disabled:!x.trim()||w||!V,"aria-label":f(`Send`),className:`flex h-11 w-11 shrink-0 items-center justify-center rounded-full bg-accent text-white disabled:opacity-40`,children:w?(0,O.jsx)(c,{size:16,className:`animate-spin`}):(0,O.jsx)(v,{size:18})})]})]}),children:(0,O.jsxs)(`div`,{ref:E,className:`space-y-2.5 py-1`,children:[y&&(0,O.jsx)(`div`,{className:`rounded-2xl bg-rose-500/12 px-3 py-2 text-[12.5px] text-rose-700 dark:text-rose-300`,children:y}),!m&&!y&&(0,O.jsx)(`div`,{className:`flex justify-center py-10 text-muted`,children:(0,O.jsx)(c,{size:20,className:`animate-spin`})}),z.map((e,n)=>(0,O.jsx)(F,{who:e.role===`user`?`you`:`agent`,agent:t,children:e.role===`user`?(0,O.jsx)(`span`,{className:`whitespace-pre-wrap`,children:e.text}):(0,O.jsx)(g,{text:e.text})},n)),j.filter(e=>!(e.run.status===`done`&&(e.run.resumed||!e.run.asked_session_id)&&z.some(t=>t.role===`user`&&t.text.trim()===e.run.text.trim()))).map(e=>(0,O.jsx)(M,{live:e,agent:t,hideFinishedText:z.length>0&&e.run.status===`done`},e.run.id)),m&&z.length===0&&j.length===0&&(0,O.jsx)(`p`,{className:`py-6 text-center text-[13px] text-muted`,children:f(`Nothing readable in this chat yet.`)})]})})}function M({live:e,agent:t,hideFinishedText:r}){let i=n(),{run:a,events:o,current:s}=e,l=o.filter(e=>e.kind===`tool`),u=k[t];return(0,O.jsxs)(O.Fragment,{children:[(0,O.jsx)(F,{who:`you`,agent:t,badge:i(`via nanoMuse`),children:(0,O.jsx)(`span`,{className:`whitespace-pre-wrap`,children:a.text})}),(l.length>0||a.status===`running`)&&(0,O.jsxs)(`div`,{className:`mx-1 rounded-2xl border border-border/60 bg-surface-2/40 px-3 py-2 text-[12.5px]`,children:[(0,O.jsxs)(`div`,{className:`flex items-center gap-1.5 font-medium text-fg/80`,children:[a.status===`running`?(0,O.jsx)(c,{size:13,className:`animate-spin text-accent`}):(0,O.jsx)(w,{size:13,className:`text-muted`}),a.status===`running`?i(`{agent} is working…`,{agent:u?.label??t}):i(`{n} steps`,{n:l.length}),a.device&&(0,O.jsxs)(`span`,{className:`ml-auto flex items-center gap-1 text-muted`,children:[(0,O.jsx)(S,{size:11}),` `,a.device]})]}),l.length>0&&(0,O.jsx)(`ul`,{className:`mt-1.5 max-h-28 space-y-0.5 overflow-y-auto font-mono text-[11.5px] text-muted`,children:l.slice(-12).map((e,t)=>(0,O.jsx)(`li`,{className:`truncate`,children:e.text},t))})]}),(s||a.output&&!r)&&(0,O.jsxs)(F,{who:`agent`,agent:t,children:[(0,O.jsx)(g,{text:a.status===`running`?(a.output?a.output+` +import{E as e,J as t,K as n,Q as r,Y as i,b as a,f as o,k as s,q as c,r as l,x as u}from"./MuseHeader-BDWXHKHT.js";import{a as d,i as f,r as p}from"./Form-B3Ejw5aI.js";import{t as m}from"./refresh-cw-qw351CFk.js";import{Ct as h,F as g,H as _,Tt as v,U as y,Z as b,bt as x,it as S,w as C,z as w}from"./index-DKrXW2Qj.js";import{t as T}from"./BackBar-DqcCClHf.js";var E=t(`folder-open`,[[`path`,{d:`m6 14 1.5-2.9A2 2 0 0 1 9.24 10H20a2 2 0 0 1 1.94 2.5l-1.54 6a2 2 0 0 1-1.95 1.5H4a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h3.9a2 2 0 0 1 1.69.9l.81 1.2a2 2 0 0 0 1.67.9H18a2 2 0 0 1 2 2v2`,key:`usdka0`}]]),D=r(i(),1),O=a(),k={cursor:{label:`Cursor`,tone:`from-slate-700 to-slate-900`,glyph:`C`},codex:{label:`Codex`,tone:`from-emerald-500 to-teal-700`,glyph:`X`},claude:{label:`Claude Code`,tone:`from-orange-400 to-amber-600`,glyph:`A`}};function A(){let{state:t,toast:r}=o(),i=n(),[a,d]=(0,D.useState)(``),[f,p]=(0,D.useState)(null),[h,g]=(0,D.useState)([]),[_,v]=(0,D.useState)(null),[C,w]=(0,D.useState)(``),[A,M]=(0,D.useState)(!1),[F,V]=(0,D.useState)(null),[H,U]=(0,D.useState)(null),[W,G]=(0,D.useState)(null),K=(0,D.useMemo)(()=>(t.hub?.devices??[]).filter(e=>!e.this&&e.online&&e.kind!==`web`&&(e.actions??[]).includes(`coding.sessions`)),[t.hub?.devices]),q=(0,D.useCallback)(async()=>{M(!0),V(null);try{let[e,t]=await Promise.all([u.coding(a),u.codingSessions({device:a,limit:40})]);p(e.agents),g(e.runs??[]),v(t.sessions)}catch(e){V(e.message),p([]),v([])}finally{M(!1)}},[a]);(0,D.useEffect)(()=>{q()},[q]);let J=Object.values(t.codingLive),Y=J.filter(e=>e.run.status!==`running`).length;(0,D.useEffect)(()=>{Y&&q()},[Y]);let X=(_??[]).filter(e=>(!C||e.agent===C)&&(e.messages>0||e.status===`running`)),Z=(f??[]).filter(e=>e.installed),Q=new Set(J.filter(e=>e.run.status===`running`&&(e.run.device??``)===(a?z(K,a):``)).map(e=>e.run.session_id||e.run.asked_session_id));return(0,O.jsxs)(`div`,{className:`flex h-full flex-col`,children:[(0,O.jsx)(T,{title:i(`Coding agents`),description:i(`Cursor, Codex and Claude Code: see what they are doing, and tell them things from anywhere.`),actions:(0,O.jsx)(l,{small:!0,onClick:()=>void q(),label:i(`Refresh`),children:(0,O.jsx)(m,{size:18,className:A?`animate-spin`:``})})}),(0,O.jsxs)(`div`,{className:`flex-1 overflow-y-auto px-4 pb-8 space-y-4`,children:[(K.length>0||a)&&(0,O.jsxs)(`div`,{className:`no-scrollbar -mx-4 flex gap-2 overflow-x-auto px-4`,children:[(0,O.jsx)(R,{active:!a,onClick:()=>d(``),icon:(0,O.jsx)(y,{size:14}),label:t.hub?.device?.name?i(`This one · {name}`,{name:t.hub.device.name}):i(`This computer`)}),K.map(e=>(0,O.jsx)(R,{active:a===e.id,onClick:()=>d(e.id),icon:(0,O.jsx)(S,{size:14}),label:e.name},e.id))]}),f&&(0,O.jsx)(`div`,{className:`grid grid-cols-3 gap-2`,children:f.map(t=>{let n=k[t.id];return(0,O.jsxs)(`button`,{type:`button`,disabled:!t.installed,onClick:()=>w(e=>e===t.id?``:t.id),className:e(`rounded-3xl border p-3 text-left transition`,C===t.id?`border-accent/40 bg-accent/5`:`border-border/70 bg-surface`,!t.installed&&`opacity-45`),children:[(0,O.jsxs)(`div`,{className:`flex items-center justify-between`,children:[(0,O.jsx)(I,{agent:t.id,size:30}),t.running>0&&(0,O.jsxs)(`span`,{className:`flex items-center gap-1 rounded-full bg-emerald-500/12 px-1.5 py-0.5 text-[10.5px] font-semibold text-emerald-700 dark:text-emerald-300`,children:[(0,O.jsx)(`span`,{className:`h-1.5 w-1.5 animate-pulse rounded-full bg-emerald-500`}),` `,t.running]})]}),(0,O.jsx)(`div`,{className:`mt-2 truncate text-[13.5px] font-semibold`,children:n?.label??t.name}),(0,O.jsx)(`div`,{className:`truncate text-[11.5px] text-muted`,children:t.installed?t.cli?t.version||i(`installed`):i(`chats only`):i(`not found`)})]},t.id)})}),F&&(0,O.jsx)(`div`,{className:`rounded-2xl bg-rose-500/12 px-3 py-2 text-[12.5px] text-rose-700 dark:text-rose-300`,children:F}),J.filter(e=>e.run.status===`running`).length>0&&(0,O.jsxs)(`section`,{className:`space-y-2`,children:[(0,O.jsx)(`h2`,{className:`px-1 text-[12px] font-semibold uppercase tracking-wide text-muted`,children:i(`Working now`)}),J.filter(e=>e.run.status===`running`).map(e=>(0,O.jsx)(N,{live:e,onOpen:()=>U({agent:e.run.agent,id:e.run.session_id||e.run.asked_session_id||``})},e.run.id))]}),(0,O.jsxs)(`section`,{className:`space-y-2`,children:[(0,O.jsxs)(`div`,{className:`flex items-center justify-between px-1`,children:[(0,O.jsx)(`h2`,{className:`text-[12px] font-semibold uppercase tracking-wide text-muted`,children:C?i(`{agent} chats`,{agent:k[C]?.label??C}):i(`Recent chats`)}),Z.some(e=>e.cli)&&(0,O.jsxs)(`button`,{type:`button`,onClick:()=>G(C&&Z.find(e=>e.id===C&&e.cli)?C:Z.find(e=>e.cli)?.id??null),className:`flex items-center gap-1 text-[12.5px] font-medium text-accent`,children:[(0,O.jsx)(b,{size:14}),` `,i(`New chat`)]})]}),_===null?(0,O.jsx)(`div`,{className:`flex justify-center py-10 text-muted`,children:(0,O.jsx)(c,{size:20,className:`animate-spin`})}):X.length===0?(0,O.jsx)(`div`,{className:`rounded-3xl border border-dashed border-border/80 px-4 py-8 text-center text-[13.5px] text-muted`,children:f&&f.every(e=>!e.installed)?i(`No coding agent found on this computer. Install Cursor, Codex or Claude Code and their chats appear here.`):i(`No chats yet.`)}):(0,O.jsx)(`ul`,{className:`divide-y divide-border/60 overflow-hidden rounded-3xl border border-border/70 bg-surface`,children:X.map(e=>(0,O.jsx)(`li`,{children:(0,O.jsxs)(`button`,{type:`button`,onClick:()=>U({agent:e.agent,id:e.id}),className:`flex w-full items-center gap-3 px-3.5 py-3 text-left hover:bg-surface-2/60 active:bg-surface-2`,children:[(0,O.jsx)(I,{agent:e.agent,size:34}),(0,O.jsxs)(`span`,{className:`min-w-0 flex-1`,children:[(0,O.jsxs)(`span`,{className:`flex items-center gap-2`,children:[(0,O.jsx)(`span`,{className:`truncate text-[14.5px] font-medium`,children:e.title||i(`Untitled chat`)}),(0,O.jsx)(L,{status:Q.has(e.id)?`running`:e.status})]}),(0,O.jsxs)(`span`,{className:`mt-0.5 flex items-center gap-1.5 truncate text-[12px] text-muted`,children:[e.workspace&&(0,O.jsxs)(`span`,{className:`flex min-w-0 items-center gap-1`,children:[(0,O.jsx)(E,{size:11}),` `,(0,O.jsx)(`span`,{className:`truncate`,children:B(e.workspace)})]}),(0,O.jsxs)(`span`,{children:[`· `,s(e.updated_at)]}),(0,O.jsxs)(`span`,{children:[`· `,i(`{n} messages`,{n:e.messages})]})]})]}),(0,O.jsx)(x,{size:16,className:`shrink-0 text-muted`})]})},`${e.agent}-${e.id}`))})]}),h.filter(e=>e.status!==`running`).length>0&&(0,O.jsxs)(`section`,{className:`space-y-2`,children:[(0,O.jsx)(`h2`,{className:`px-1 text-[12px] font-semibold uppercase tracking-wide text-muted`,children:i(`Sent through nanoMuse`)}),(0,O.jsx)(`ul`,{className:`divide-y divide-border/60 overflow-hidden rounded-3xl border border-border/70 bg-surface`,children:h.filter(e=>e.status!==`running`).slice(0,8).map(e=>(0,O.jsxs)(`li`,{className:`flex items-center gap-3 px-3.5 py-2.5`,children:[(0,O.jsx)(I,{agent:e.agent,size:28}),(0,O.jsxs)(`span`,{className:`min-w-0 flex-1`,children:[(0,O.jsx)(`span`,{className:`block truncate text-[13.5px]`,children:e.text}),(0,O.jsxs)(`span`,{className:`block truncate text-[11.5px] text-muted`,children:[e.status===`done`?i(`done`):e.status===`failed`?i(`failed`):i(`stopped`),` · `,s(e.started_at),e.tools?` · ${i(`{n} steps`,{n:e.tools})}`:``,e.error?` · ${e.error}`:``]})]}),e.session_id&&(0,O.jsx)(`button`,{type:`button`,onClick:()=>U({agent:e.agent,id:e.session_id}),className:`text-[12.5px] font-medium text-accent`,children:i(`Open`)})]},e.id))})]})]}),H&&(0,O.jsx)(j,{agent:H.agent,id:H.id,device:a,deviceLabel:a?z(K,a):``,onClose:()=>U(null)}),W&&(0,O.jsx)(P,{agent:W,agents:Z.filter(e=>e.cli),device:a,onClose:()=>G(null),onStarted:e=>{G(null),r(i(`Sent to {agent}.`,{agent:k[e.agent]?.label??e.agent}))}})]})}function j({agent:t,id:r,device:i,deviceLabel:a,onClose:s}){let{state:l,toast:d}=o(),f=n(),[m,h]=(0,D.useState)(null),[y,b]=(0,D.useState)(null),[x,S]=(0,D.useState)(``),[w,T]=(0,D.useState)(!1),E=(0,D.useRef)(null),A=(0,D.useCallback)(async()=>{try{h(await u.codingSession(t,r,i)),b(null)}catch(e){b(e.message)}},[t,r,i]);(0,D.useEffect)(()=>{A()},[A]);let j=Object.values(l.codingLive).filter(e=>e.run.agent===t&&(e.run.session_id===r||e.run.asked_session_id===r)),N=j.find(e=>e.run.status===`running`),P=j.filter(e=>e.run.status!==`running`).length;(0,D.useEffect)(()=>{P&&A()},[P]),(0,D.useEffect)(()=>{let e=E.current;e&&(e.scrollTop=e.scrollHeight)},[m?.transcript?.length,N?.events.length,N?.current.length]);let L=async()=>{let e=x.trim();if(e&&!w){T(!0);try{await u.codingSend({agent:t,text:e,session_id:r,workspace:m?.workspace??``,device:i}),S(``)}catch(e){d(e.message)}finally{T(!1)}}},R=k[t],z=m?.transcript??[],V=!!m||!!N,H=!!m&&!m.resumable&&!N;return(0,O.jsx)(C,{open:!0,onClose:s,title:(0,O.jsxs)(`span`,{className:`flex items-center gap-2.5`,children:[(0,O.jsx)(I,{agent:t,size:30}),(0,O.jsxs)(`span`,{className:`min-w-0`,children:[(0,O.jsx)(`span`,{className:`block truncate`,children:m?.title||R?.label||t}),(0,O.jsxs)(`span`,{className:`block truncate text-[12px] font-normal text-muted`,children:[a?`${a} · `:``,m?.workspace?B(m.workspace):R?.label,m?.source&&m.source!==`ide`&&m.source!==`cli`?` · ${m.source}`:``]})]})]}),footer:(0,O.jsxs)(O.Fragment,{children:[H&&(0,O.jsx)(`p`,{className:`mb-1.5 px-1 text-[11.5px] leading-snug text-muted`,children:f(`Made in the IDE: your message starts a new chat in the same workspace, with the last exchange quoted.`)}),(0,O.jsxs)(`form`,{className:`flex items-end gap-2`,onSubmit:e=>{e.preventDefault(),L()},children:[(0,O.jsx)(`textarea`,{value:x,onChange:e=>S(e.target.value),onKeyDown:e=>{e.key===`Enter`&&!e.shiftKey&&(e.preventDefault(),L())},rows:1,disabled:!V||!!N,placeholder:N?f(`{agent} is working…`,{agent:R?.label??t}):m?H?f(`Continue in a new chat…`):f(`Tell {agent}…`,{agent:R?.label??t}):`…`,className:e(p,`max-h-32 min-h-[44px] resize-none py-2.5`)}),N?(0,O.jsx)(`button`,{type:`button`,onClick:()=>void u.codingStop(N.run.id,i).catch(e=>d(e.message)),"aria-label":f(`Stop`),className:`flex h-11 w-11 shrink-0 items-center justify-center rounded-full bg-rose-500 text-white`,children:(0,O.jsx)(_,{size:16})}):(0,O.jsx)(`button`,{type:`submit`,disabled:!x.trim()||w||!V,"aria-label":f(`Send`),className:`flex h-11 w-11 shrink-0 items-center justify-center rounded-full bg-accent text-white disabled:opacity-40`,children:w?(0,O.jsx)(c,{size:16,className:`animate-spin`}):(0,O.jsx)(v,{size:18})})]})]}),children:(0,O.jsxs)(`div`,{ref:E,className:`space-y-2.5 py-1`,children:[y&&(0,O.jsx)(`div`,{className:`rounded-2xl bg-rose-500/12 px-3 py-2 text-[12.5px] text-rose-700 dark:text-rose-300`,children:y}),!m&&!y&&(0,O.jsx)(`div`,{className:`flex justify-center py-10 text-muted`,children:(0,O.jsx)(c,{size:20,className:`animate-spin`})}),z.map((e,n)=>(0,O.jsx)(F,{who:e.role===`user`?`you`:`agent`,agent:t,children:e.role===`user`?(0,O.jsx)(`span`,{className:`whitespace-pre-wrap`,children:e.text}):(0,O.jsx)(g,{text:e.text})},n)),j.filter(e=>!(e.run.status===`done`&&(e.run.resumed||!e.run.asked_session_id)&&z.some(t=>t.role===`user`&&t.text.trim()===e.run.text.trim()))).map(e=>(0,O.jsx)(M,{live:e,agent:t,hideFinishedText:z.length>0&&e.run.status===`done`},e.run.id)),m&&z.length===0&&j.length===0&&(0,O.jsx)(`p`,{className:`py-6 text-center text-[13px] text-muted`,children:f(`Nothing readable in this chat yet.`)})]})})}function M({live:e,agent:t,hideFinishedText:r}){let i=n(),{run:a,events:o,current:s}=e,l=o.filter(e=>e.kind===`tool`),u=k[t];return(0,O.jsxs)(O.Fragment,{children:[(0,O.jsx)(F,{who:`you`,agent:t,badge:i(`via nanoMuse`),children:(0,O.jsx)(`span`,{className:`whitespace-pre-wrap`,children:a.text})}),(l.length>0||a.status===`running`)&&(0,O.jsxs)(`div`,{className:`mx-1 rounded-2xl border border-border/60 bg-surface-2/40 px-3 py-2 text-[12.5px]`,children:[(0,O.jsxs)(`div`,{className:`flex items-center gap-1.5 font-medium text-fg/80`,children:[a.status===`running`?(0,O.jsx)(c,{size:13,className:`animate-spin text-accent`}):(0,O.jsx)(w,{size:13,className:`text-muted`}),a.status===`running`?i(`{agent} is working…`,{agent:u?.label??t}):i(`{n} steps`,{n:l.length}),a.device&&(0,O.jsxs)(`span`,{className:`ml-auto flex items-center gap-1 text-muted`,children:[(0,O.jsx)(S,{size:11}),` `,a.device]})]}),l.length>0&&(0,O.jsx)(`ul`,{className:`mt-1.5 max-h-28 space-y-0.5 overflow-y-auto font-mono text-[11.5px] text-muted`,children:l.slice(-12).map((e,t)=>(0,O.jsx)(`li`,{className:`truncate`,children:e.text},t))})]}),(s||a.output&&!r)&&(0,O.jsxs)(F,{who:`agent`,agent:t,children:[(0,O.jsx)(g,{text:a.status===`running`?(a.output?a.output+` `:``)+s:a.output}),a.status===`running`&&(0,O.jsx)(`span`,{className:`ml-1 inline-block h-3.5 w-1 animate-pulse bg-accent align-middle`})]}),a.status===`failed`&&(0,O.jsx)(`div`,{className:`mx-1 rounded-2xl bg-rose-500/12 px-3 py-2 text-[12.5px] text-rose-700 dark:text-rose-300`,children:a.error||i(`failed`)}),a.status===`stopped`&&(0,O.jsx)(`div`,{className:`mx-1 text-center text-[12px] text-muted`,children:i(`stopped`)}),!a.resumed&&a.asked_session_id&&a.status!==`running`&&(0,O.jsx)(`div`,{className:`mx-1 text-center text-[12px] text-muted`,children:i(`Continued as a new chat: the agent could not reopen the old one.`)})]})}function N({live:e,onOpen:t}){let r=n(),{run:i,events:a,current:o}=e,s=[...a].reverse().find(e=>e.kind===`tool`);return(0,O.jsxs)(`button`,{type:`button`,onClick:t,className:`flex w-full items-center gap-3 rounded-3xl border border-accent/25 bg-accent/5 px-3.5 py-3 text-left`,children:[(0,O.jsx)(I,{agent:i.agent,size:34}),(0,O.jsxs)(`span`,{className:`min-w-0 flex-1`,children:[(0,O.jsx)(`span`,{className:`block truncate text-[14px] font-medium`,children:i.text}),(0,O.jsxs)(`span`,{className:`mt-0.5 flex items-center gap-1.5 truncate text-[12px] text-muted`,children:[(0,O.jsx)(c,{size:11,className:`animate-spin text-accent`}),(0,O.jsx)(`span`,{className:`truncate`,children:o.slice(-80)||s?.text||r(`starting…`)})]})]}),i.device&&(0,O.jsx)(S,{size:14,className:`shrink-0 text-muted`})]})}function P({agent:t,agents:r,device:i,onClose:a,onStarted:s}){let{toast:l}=o(),m=n(),[h,g]=(0,D.useState)(t),[_,y]=(0,D.useState)(``),[b,x]=(0,D.useState)(``),[S,w]=(0,D.useState)(!1),[T,E]=(0,D.useState)([]);(0,D.useEffect)(()=>{u.codingSessions({agent:h,device:i,limit:30}).then(e=>E(Array.from(new Set(e.sessions.map(e=>e.workspace).filter(Boolean))).slice(0,6))).catch(()=>E([]))},[h,i]);let A=async()=>{if(b.trim()&&!S){w(!0);try{s(await u.codingSend({agent:h,text:b.trim(),workspace:_.trim(),device:i}))}catch(e){l(e.message)}finally{w(!1)}}};return(0,O.jsx)(C,{open:!0,onClose:a,title:m(`New chat`),footer:(0,O.jsxs)(`button`,{type:`button`,disabled:!b.trim()||S,onClick:()=>void A(),className:e(f,`w-full py-3`),children:[S?(0,O.jsx)(c,{size:15,className:`animate-spin`}):(0,O.jsx)(v,{size:15}),` `,m(`Send to {agent}`,{agent:k[h]?.label??h})]}),children:(0,O.jsxs)(`div`,{className:`space-y-4 py-1`,children:[(0,O.jsx)(`div`,{className:`grid grid-cols-3 gap-1 rounded-2xl bg-surface-2/70 p-1 text-[13px] font-medium`,children:r.map(t=>(0,O.jsxs)(`button`,{type:`button`,onClick:()=>g(t.id),className:e(`flex items-center justify-center gap-1.5 rounded-xl px-2 py-2 transition`,h===t.id?`bg-surface text-fg shadow-sm`:`text-muted`),children:[(0,O.jsx)(I,{agent:t.id,size:18}),` `,k[t.id]?.label??t.name]},t.id))}),(0,O.jsxs)(`div`,{children:[(0,O.jsx)(`label`,{className:`text-[12px] text-muted`,children:m(`Project folder`)}),(0,O.jsx)(`input`,{value:_,onChange:e=>y(e.target.value),placeholder:`/home/you/project`,className:e(p,`mt-1 font-mono text-[13px]`)}),T.length>0&&(0,O.jsx)(`div`,{className:`mt-2 flex flex-wrap gap-1.5`,children:T.map(t=>(0,O.jsx)(`button`,{type:`button`,onClick:()=>y(t),className:e(`rounded-full border px-2.5 py-1 text-[12px]`,_===t?`border-accent/40 bg-accent/10 text-accent`:`border-border text-muted`),children:B(t)},t))})]}),(0,O.jsxs)(`div`,{children:[(0,O.jsx)(`label`,{className:`text-[12px] text-muted`,children:m(`What to do`)}),(0,O.jsx)(`textarea`,{value:b,onChange:e=>x(e.target.value),rows:4,autoFocus:!0,placeholder:m(`Add tests for the parser and run them`),className:e(p,`mt-1 resize-none`)})]}),(0,O.jsx)(`p`,{className:`text-[12px] text-muted`,children:m(`The agent runs on that computer with its own permissions; nanoMuse only carries the message and brings the answer back.`)}),(0,O.jsx)(`button`,{type:`button`,onClick:a,className:e(d,`w-full`),children:m(`Cancel`)})]})})}function F({who:t,agent:n,badge:r,children:i}){return(0,O.jsxs)(`div`,{className:e(`flex`,t===`you`?`justify-end`:`justify-start`),children:[t===`agent`&&(0,O.jsx)(I,{agent:n,size:24,className:`mr-2 mt-1 shrink-0`}),(0,O.jsxs)(`div`,{className:e(`max-w-[86%] rounded-3xl px-3.5 py-2 text-[14px] leading-relaxed`,t===`you`?`rounded-br-lg bg-bubble-user text-bubble-user-fg`:`rounded-bl-lg bg-surface-2`),children:[r&&(0,O.jsx)(`div`,{className:`mb-0.5 text-[10.5px] font-semibold uppercase tracking-wide text-fg/45`,children:r}),(0,O.jsx)(`div`,{className:`md break-words`,children:i})]})]})}function I({agent:t,size:n=28,className:r}){let i=k[t];return(0,O.jsx)(`span`,{className:e(`flex shrink-0 items-center justify-center rounded-xl bg-gradient-to-br font-bold text-white shadow-sm`,i?.tone??`from-slate-400 to-slate-600`,r),style:{width:n,height:n,fontSize:Math.round(n*.46)},"aria-hidden":!0,children:i?.glyph??(0,O.jsx)(h,{size:Math.round(n*.55)})})}function L({status:e}){let t=n();return e===`running`?(0,O.jsxs)(`span`,{className:`flex shrink-0 items-center gap-1 rounded-full bg-emerald-500/12 px-2 py-0.5 text-[10.5px] font-semibold text-emerald-700 dark:text-emerald-300`,children:[(0,O.jsx)(`span`,{className:`h-1.5 w-1.5 animate-pulse rounded-full bg-emerald-500`}),` `,t(`working`)]}):e===`active`?(0,O.jsx)(`span`,{className:`h-2 w-2 shrink-0 rounded-full bg-accent`,title:t(`active`)}):null}function R({active:t,onClick:n,icon:r,label:i}){return(0,O.jsxs)(`button`,{type:`button`,onClick:n,className:e(`flex shrink-0 items-center gap-1.5 rounded-full border px-3 py-1.5 text-[12.5px] font-medium transition`,t?`border-fg bg-fg text-bg`:`border-border bg-surface text-fg/75`),children:[r,` `,i]})}function z(e,t){return e.find(e=>e.id===t)?.name??t}function B(e){let t=e.replace(/[\\/]+$/,``).split(/[\\/]/);return t[t.length-1]||e}export{A as CodingScreen}; \ No newline at end of file diff --git a/nanomuse/server/static/assets/ConnectionsScreen-CMt7GOff.js b/nanomuse/server/static/assets/ConnectionsScreen-CMt7GOff.js deleted file mode 100644 index 5c97b83c3..000000000 --- a/nanomuse/server/static/assets/ConnectionsScreen-CMt7GOff.js +++ /dev/null @@ -1 +0,0 @@ -import{A as e,E as t,J as n,K as r,L as i,Q as a,Y as o,b as s,f as c,q as l,x as u}from"./MuseHeader-Pw-NI98v.js";import{C as d,O as f,S as p,b as m,f as h,g,h as _,k as v,m as y,v as b,w as x,x as S}from"./StarNudge-DjXecvWj.js";import{n as C,t as w}from"./external-link-Xj5fjR8v.js";import{a as T,c as E,i as D,r as O,s as k,t as A}from"./Form-DwKuBk1V.js";import{t as j}from"./clapperboard-BokpXv9J.js";import{t as M}from"./image-crWy0a06.js";import{t as N}from"./plug-Bj_5EEV3.js";import{t as P}from"./refresh-cw-BKgIzslL.js";import{Ct as F,E as I,G as L,N as ee,P as te,T as R,V as z,X as B,Z as V,j as H,lt as U,pt as ne,st as re,ut as ie,xt as ae}from"./index-CIdGZ5PB.js";import{t as oe}from"./BackBar-Dl56jHZM.js";import{t as se}from"./CloudCard-CtVHK0qc.js";var ce=n(`brain-circuit`,[[`path`,{d:`M12 5a3 3 0 1 0-5.997.125 4 4 0 0 0-2.526 5.77 4 4 0 0 0 .556 6.588A4 4 0 1 0 12 18Z`,key:`l5xja`}],[`path`,{d:`M9 13a4.5 4.5 0 0 0 3-4`,key:`10igwf`}],[`path`,{d:`M6.003 5.125A3 3 0 0 0 6.401 6.5`,key:`105sqy`}],[`path`,{d:`M3.477 10.896a4 4 0 0 1 .585-.396`,key:`ql3yin`}],[`path`,{d:`M6 18a4 4 0 0 1-1.967-.516`,key:`2e4loj`}],[`path`,{d:`M12 13h4`,key:`1ku699`}],[`path`,{d:`M12 18h6a2 2 0 0 1 2 2v1`,key:`105ag5`}],[`path`,{d:`M12 8h8`,key:`1lhi5i`}],[`path`,{d:`M16 8V5a2 2 0 0 1 2-2`,key:`u6izg6`}],[`circle`,{cx:`16`,cy:`13`,r:`.5`,key:`ry7gng`}],[`circle`,{cx:`18`,cy:`3`,r:`.5`,key:`1aiba7`}],[`circle`,{cx:`20`,cy:`21`,r:`.5`,key:`yhc1fs`}],[`circle`,{cx:`20`,cy:`8`,r:`.5`,key:`1e43v0`}]]),W=n(`contact`,[[`path`,{d:`M16 2v2`,key:`scm5qe`}],[`path`,{d:`M7 22v-2a2 2 0 0 1 2-2h6a2 2 0 0 1 2 2v2`,key:`1waht3`}],[`path`,{d:`M8 2v2`,key:`pbkmx`}],[`circle`,{cx:`12`,cy:`11`,r:`3`,key:`itu57m`}],[`rect`,{x:`3`,y:`4`,width:`18`,height:`18`,rx:`2`,key:`12vinp`}]]),le=n(`eye-off`,[[`path`,{d:`M10.733 5.076a10.744 10.744 0 0 1 11.205 6.575 1 1 0 0 1 0 .696 10.747 10.747 0 0 1-1.444 2.49`,key:`ct8e1f`}],[`path`,{d:`M14.084 14.158a3 3 0 0 1-4.242-4.242`,key:`151rxh`}],[`path`,{d:`M17.479 17.499a10.75 10.75 0 0 1-15.417-5.151 1 1 0 0 1 0-.696 10.75 10.75 0 0 1 4.446-5.143`,key:`13bj9a`}],[`path`,{d:`m2 2 20 20`,key:`1ooewy`}]]),ue=n(`eye`,[[`path`,{d:`M2.062 12.348a1 1 0 0 1 0-.696 10.75 10.75 0 0 1 19.876 0 1 1 0 0 1 0 .696 10.75 10.75 0 0 1-19.876 0`,key:`1nclc0`}],[`circle`,{cx:`12`,cy:`12`,r:`3`,key:`1v7zrd`}]]),de=n(`unplug`,[[`path`,{d:`m19 5 3-3`,key:`yk6iyv`}],[`path`,{d:`m2 22 3-3`,key:`19mgm9`}],[`path`,{d:`M6.3 20.3a2.4 2.4 0 0 0 3.4 0L12 18l-6-6-2.3 2.3a2.4 2.4 0 0 0 0 3.4Z`,key:`goz73y`}],[`path`,{d:`M7.5 13.5 10 11`,key:`7xgeeb`}],[`path`,{d:`M10.5 16.5 13 14`,key:`10btkg`}],[`path`,{d:`m12 6 6 6 2.3-2.3a2.4 2.4 0 0 0 0-3.4l-2.6-2.6a2.4 2.4 0 0 0-3.4 0Z`,key:`1snsnr`}]]),fe=n(`upload`,[[`path`,{d:`M12 3v12`,key:`1x0j5s`}],[`path`,{d:`m17 8-5-5-5 5`,key:`7q97r8`}],[`path`,{d:`M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4`,key:`ih7n3h`}]]),G=a(o(),1);function pe(e,t){let n=t.trim().toLowerCase();return!n||e.id.toLowerCase().includes(n)||e.name.toLowerCase().includes(n)}function me(e,t){let n=e.default&&e.rows.some(t=>t.id===e.default)?e.default:e.rows.find(e=>e.recommended)?.id,r=t&&t.group===e.key?t.id:void 0,i=[];for(let t of[n,r]){if(!t||i.some(e=>e.id===t))continue;let n=e.rows.find(e=>e.id===t);n&&i.push(n)}return[...i,...e.rows.filter(e=>!i.includes(e))]}function he(e){return e.reduce((e,t)=>e+t.rows.length,0)}function ge(e){return he(e)>8}function _e(e,{current:t,query:n=``,expanded:r}={}){let i=n.trim().length>0,a=[];for(let o of e){let e=me(o,t);if(i){let t=e.filter(e=>pe(e,n));t.length&&a.push({key:o.key,label:o.label,rows:t,more:0});continue}e.length>8&&!r?.has(o.key)?a.push({key:o.key,label:o.label,rows:e.slice(0,8),more:e.length-8}):a.push({key:o.key,label:o.label,rows:e,more:0})}return a}var K=s(),q=`flex w-full items-center gap-2 rounded-xl px-3 py-2 text-left text-[14px] hover:bg-surface-2 focus:bg-surface-2 focus:outline-none`;function ve({label:e,text:n,heads:i=[],headValue:a,tail:o,groups:s,current:c,disabled:l,onHead:u,onPick:d,onTail:f,rowText:p}){let m=r(),[h,g]=(0,G.useState)(!1),[_,v]=(0,G.useState)(``),[y,b]=(0,G.useState)(()=>new Set),[x,S]=(0,G.useState)(!1),w=(0,G.useRef)(null),T=(0,G.useRef)(null),D=ge(s),k=(0,G.useCallback)((e=!1)=>{g(!1),v(``),b(new Set),S(e)},[]);(0,G.useEffect)(()=>{!h&&x&&(S(!1),w.current?.focus())},[h,x]),(0,G.useEffect)(()=>{if(!h)return;let e=e=>{let t=e.target;T.current?.contains(t)||w.current?.contains(t)||k()},t=e=>{e.key===`Escape`&&(e.stopPropagation(),k(!0))};return document.addEventListener(`pointerdown`,e,!0),document.addEventListener(`keydown`,t,!0),()=>{document.removeEventListener(`pointerdown`,e,!0),document.removeEventListener(`keydown`,t,!0)}},[h,k]),(0,G.useEffect)(()=>{h&&T.current&&(T.current.querySelector(`input`)??T.current.querySelector(`[aria-selected="true"]`)??T.current.querySelector(`[data-row]`))?.focus()},[h]);let A=e=>{if(e.key!==`ArrowDown`&&e.key!==`ArrowUp`)return;let t=[...e.currentTarget.closest(`[role="listbox"]`)?.querySelectorAll(`[data-row]`)??[]];if(!t.length)return;e.preventDefault();let n=t.indexOf(e.target);t[e.key===`ArrowDown`?n<0?0:Math.min(t.length-1,n+1):n<0?t.length-1:Math.max(0,n-1)]?.focus()},j=_e(s,{current:c,query:_,expanded:y}),M=_.trim().length>0,N=(e,n,r,i,a)=>(0,K.jsxs)(`button`,{type:`button`,role:`option`,"aria-selected":n,"data-row":``,title:a,onClick:i,onKeyDown:A,className:t(q,n&&`text-accent font-medium`),children:[(0,K.jsx)(`span`,{className:`min-w-0 flex-1 truncate`,children:r}),n&&(0,K.jsx)(C,{size:15,className:`shrink-0`})]},e);return(0,K.jsxs)(`div`,{className:`relative`,children:[(0,K.jsxs)(`button`,{ref:w,type:`button`,disabled:l,"aria-label":e,"aria-haspopup":`listbox`,"aria-expanded":h,title:n,onClick:()=>h?k():g(!0),className:t(O,`flex items-center gap-2 text-left text-fg disabled:opacity-50`),children:[(0,K.jsx)(`span`,{className:`min-w-0 flex-1 truncate`,children:n}),(0,K.jsx)(E,{size:16,className:`shrink-0 text-muted`})]}),h&&(0,K.jsxs)(`div`,{ref:T,role:`listbox`,"aria-label":e,className:`absolute left-0 right-0 top-full z-30 mt-1 flex max-h-[60vh] flex-col overflow-hidden rounded-2xl border border-border bg-surface p-1.5 shadow-xl`,children:[i.length>0&&(0,K.jsx)(`div`,{className:`mb-1 flex flex-col border-b border-border pb-1`,children:i.map(e=>N(`head:${e.value}`,a===e.value,e.label,()=>{u?.(e.value),k(!0)}))}),D&&(0,K.jsxs)(`label`,{className:`mb-1.5 flex items-center gap-2 rounded-xl bg-surface-2 px-3 py-2 text-muted focus-within:ring-2 focus-within:ring-accent/40`,children:[(0,K.jsx)(B,{size:15,className:`shrink-0`}),(0,K.jsx)(`input`,{type:`search`,value:_,onChange:e=>v(e.target.value),onKeyDown:A,placeholder:m(`Search models`),"aria-label":m(`Search models`),autoComplete:`off`,spellCheck:!1,className:`min-w-0 flex-1 bg-transparent text-[14px] text-fg outline-none placeholder:text-muted`})]}),(0,K.jsxs)(`div`,{className:`min-h-0 flex-1 overflow-y-auto`,children:[M&&j.length===0&&(0,K.jsx)(`div`,{className:`px-3 py-2.5 text-[13.5px] text-muted`,children:m(`No model matches`)}),j.map(e=>(0,K.jsxs)(`div`,{role:`group`,"aria-label":e.label,className:`[&+&]:mt-1.5`,children:[(0,K.jsx)(`div`,{className:`truncate px-3 pb-0.5 pt-1.5 text-[11px] font-semibold uppercase tracking-wide text-muted`,children:e.label}),e.rows.map(t=>N(`${e.key}:${t.id}`,c?.group===e.key&&c.id===t.id,p?p(t):t.name,()=>{d(e.key,t),k(!0)},t.id)),e.more>0&&(0,K.jsx)(`button`,{type:`button`,"data-row":``,onKeyDown:A,onClick:()=>b(t=>new Set([...t,e.key])),className:t(q,`text-[13px] text-accent`),children:m(`Show {n} more`,{n:e.more})})]},e.key))]}),o&&!M&&(0,K.jsx)(`div`,{className:`mt-1 border-t border-border pt-1`,children:N(`tail`,!1,o,()=>{f?.(),k(!0)})})]})]})}var ye=`nanomuse_cloud`,be=`{{vault:NANOMUSE_CLOUD_KEY}}`,xe=`custom`,J=[`openai`,`openai_responses`];function Y(e){try{return new URL(e).hostname.toLowerCase()}catch{return``}}function X(e,t,n=h){if(e&&!J.includes(e))return n.find(t=>t.id===e)??null;let r=Y(t);if(!r)return null;let i=e=>[e.base_url,e.base_url_global].map(e=>Y(e??``)).filter(Boolean);return n.find(e=>i(e).includes(r))||(n.find(e=>i(e).some(e=>{let t=e.indexOf(`.`);return t>0&&r.endsWith(e.slice(t))}))??null)}function Se(e,t,n=``,r=h){if(e===`nanomuse_cloud`)return`nanoMuse Cloud`;if(e===`chatgpt`)return`ChatGPT`;let i=r.find(t=>t.id===e);return i&&e!==`custom`?S(i,t):Y(n)||e}function Ce(e,t,n=h){if(!e.effective_provider)return``;let r=Se(e.effective_provider,t,e.base_url,n);return e.effective_model?`${r} · ${e.effective_model}`:r}function we(e,t,n,r=h){let i=e.effective_model??``;if(!i)return``;let a=(e,t)=>Se(X(e,t,r)?.id??(J.includes(e)?`custom`:e),n,t,r),o;return o=e.effective_source===`cloud`?`nanoMuse Cloud`:e.effective_source===`gui`&&(e.provider_id||e.base_url||!J.includes(e.provider||`openai`))?e.provider_id?Se(e.provider_id,n,e.base_url,r):a(e.provider,e.base_url):t.cloud?`nanoMuse Cloud`:a(t.provider,t.base_url),`${o} · ${i}`}function Te(e,t){let n=t.list??h,r=[];t.signedIn&&r.push({value:ye,label:`nanoMuse Cloud`,group:`cloud`,needsKey:!1,entry:null});let i=t.chat.cloud?null:X(t.chat.provider,t.chat.base_url,n);i&&i.capabilities.includes(e)&&r.push({value:i.id,label:S(i,t.locale),group:`chat`,needsKey:!1,entry:i});for(let a of p(t.region,e,n))a.id!==i?.id&&r.push({value:a.id,label:S(a,t.locale),group:`add`,needsKey:!0,entry:a});return r.push({value:xe,label:``,group:`add`,needsKey:!1,entry:null}),r}function Ee(e,t){return e.configured?t&&e.base_url&&Y(e.base_url)===Y(t)?ye:e.provider_id||`custom`:``}var De=`nanomuse_cloud`;function Oe(){let{state:e}=c(),[t,n]=(0,G.useState)(null),[i,a]=(0,G.useState)(null),o=e.profile?.name??`nanoMuse`,s=r(),d=(0,G.useCallback)(async()=>{try{n(await u.connections()),a(null)}catch(e){a(s(e.message))}},[s]);return(0,G.useEffect)(()=>{d()},[d,e.connectionsVersion]),(0,K.jsxs)(`div`,{className:`flex h-full flex-col`,children:[(0,K.jsx)(oe,{title:s(`Connections`),description:s(`What {name} can reach; keys stay in the vault on this machine.`,{name:o})}),(0,K.jsxs)(`div`,{className:`flex-1 overflow-y-auto px-4 pb-8 space-y-4`,children:[i&&(0,K.jsx)(`div`,{className:`rounded-2xl bg-rose-500/12 text-rose-700 dark:text-rose-300 p-3 text-[13.5px]`,children:i}),!t&&!i&&(0,K.jsx)(`div`,{className:`flex justify-center py-10 text-muted`,children:(0,K.jsx)(l,{className:`animate-spin`,size:20})}),t&&(0,K.jsxs)(K.Fragment,{children:[(0,K.jsx)(Z,{data:t,onChange:d}),t.image&&(0,K.jsx)(ke,{slot:`image`,data:t,onChange:d}),t.video&&(0,K.jsx)(ke,{slot:`video`,data:t,onChange:d}),(0,K.jsx)(se,{account:e.hub?.account??null,onChange:d}),t.embeddings.memory_enabled&&(0,K.jsx)(Ae,{data:t,onChange:d}),(0,K.jsx)(je,{data:t,onChange:d}),(0,K.jsx)(Ne,{data:t,onChange:d}),(0,K.jsx)(Fe,{data:t,onChange:d}),(0,K.jsx)(Ie,{data:t,onChange:d}),(0,K.jsx)(Q,{data:t,onChange:d}),(0,K.jsx)(Le,{data:t,onChange:d}),(0,K.jsx)(Re,{data:t,onChange:d}),(0,K.jsx)(ze,{data:t,onChange:d})]})]})]})}function Z({data:e,onChange:n,compact:a}){let{toast:o,state:s}=c(),p=r(),[m,g]=(0,G.useState)(!!a),j=e.providers,M=!!s.hub?.account?.any_model,P=Object.entries(j).find(([t,n])=>t!==`custom`&&n.base_url&&e.llm.base_url.startsWith(n.base_url)&&n.provider===e.llm.provider)?.[0]??Object.entries(j).find(([t,n])=>t!==`custom`&&n.base_url&&e.llm.base_url.startsWith(n.base_url))?.[0]??(e.llm.base_url?`custom`:`deepseek`),[I,L]=(0,G.useState)(P),[R,z]=(0,G.useState)(e.llm.model),[B,V]=(0,G.useState)(e.llm.base_url),[H,ne]=(0,G.useState)(``),[re,ie]=(0,G.useState)(!1),[ae,oe]=(0,G.useState)(!1),[se,ce]=(0,G.useState)(e.llm.key_source===`none`&&!!j[P]?.key_optional),[W,de]=(0,G.useState)(e.llm.tool_mode||`auto`),[fe,pe]=(0,G.useState)(e.llm.proxy??``),[me,he]=(0,G.useState)(!1),[ge,_e]=(0,G.useState)(!1),[q,ye]=(0,G.useState)(null),[be,xe]=(0,G.useState)(!1),[J,Y]=(0,G.useState)(e.gui?.model??``),[X,Se]=(0,G.useState)({list:j[P]?.models??[],image:[],video:[],menu:[],catalog:[],imageCatalog:[],videoCatalog:[],vision:[],gui:j[P]?.gui_models??[],source:`catalogue`}),[Ce,Te]=(0,G.useState)(!1),[Ee,Oe]=(0,G.useState)(!1);(0,G.useEffect)(()=>{z(e.llm.model),V(e.llm.base_url),de(e.llm.tool_mode||`auto`),pe(e.llm.proxy??``),he(!1),Y(e.gui?.model??``),L(P)},[e.llm,e.gui?.model]);let Z=j[I],ke=I===`custom`||!Z?.base_url?B:Z.base_url;(0,G.useEffect)(()=>{if(!m)return;let e=!0,t=setTimeout(()=>{Se(e=>({...e,source:`loading`})),u.llmModels({preset:I,base_url:ke,api_key:H||void 0}).then(t=>{e&&(Se({list:t.models,image:t.image_models??[],video:t.video_models??[],menu:t.menu??[],catalog:t.catalog??[],imageCatalog:t.image_catalog??[],videoCatalog:t.video_catalog??[],vision:t.vision??[],gui:t.gui??j[I]?.gui_models??[],source:t.source}),t.source===`live`&&t.models.length&&!Ce&&z(e=>t.models.includes(e)?e:t.models[0]))}).catch(()=>e&&Se({list:Z?.models??[],image:[],video:[],menu:[],catalog:[],imageCatalog:[],videoCatalog:[],vision:[],gui:Z?.gui_models??[],source:`catalogue`}))},H?600:150);return()=>{e=!1,clearTimeout(t)}},[m,I,ke,H]);let Ae=t=>{L(t);let n=j[t];n&&(n.base_url?V(n.base_url):j[I]?.base_url&&V(``),(!R||Object.values(j).some(e=>e.models?.includes(R)))&&n.models?.length&&!n.models.includes(R)&&z(n.models[0]),Se({list:n.models??[],image:[],video:[],menu:[],catalog:[],imageCatalog:[],videoCatalog:[],vision:[],gui:n.gui_models??[],source:`catalogue`}),(!e.gui?.model||Object.values(j).some(t=>t.gui_model===e.gui?.model))&&Y(n.cloud?``:n.gui_model??``),Oe(!1),Te(!1),ce(!1))};(0,G.useEffect)(()=>{let e=ee();e&&j[e]&&(g(!0),Ae(e))},[]);let je=!!Z?.no_key||se&&!!Z?.key_optional,Me=e.llm.cloud?{text:p(`Your account's model`),tone:`ok`}:e.llm.key_source===`none`&&!j[P]?.no_key&&!j[P]?.key_optional?{text:p(`No key yet`),tone:`warn`}:e.llm.key_source===`missing`?{text:p(`Key missing from vault`),tone:`warn`}:{text:e.llm.key_source===`vault`?p(`Key in vault`):e.llm.key_source===`config`?p(`Key from config`):p(`No key needed`),tone:`ok`},Ne=async()=>{_e(!0),ye(null);try{Z?.cloud?await u.cloudUseAsModel(R.trim()):await u.setLLM({provider:Z?.provider??`openai`,model:R.trim(),base_url:ke.trim(),tool_mode:W,api_key:H||(je?``:null),proxy:me&&e.llm.proxy!==void 0?fe.trim():null}),J.trim()!==(e.gui?.model??``)&&await u.setGui({model:J.trim()}),ne(``),b(),o(p(`Model saved`)),n(),a||g(!1)}catch(e){o(e.message)}finally{_e(!1)}},Pe=async()=>{xe(!0);try{ye(await u.testLLM())}catch(e){ye({ok:!1,error:e.message})}finally{xe(!1)}},Fe=[{id:`cloud`,title:p(`Your account`),ids:[]},{id:`openai`,title:p(`OpenAI-compatible · Chat Completions`),ids:[]},{id:`responses`,title:p(`Responses API`),ids:[]},{id:`local`,title:p(`Local or your own endpoint`),ids:[]}];for(let[e,t]of Object.entries(j))(Fe.find(e=>e.id===(t.group??`openai`))??Fe[0]).ids.push(e);for(let e of Fe)e.ids=v(e.ids,j,s.hub?.account);let Ie=I===`custom`||!Z?.base_url,Q=Z?.cloud?null:h.find(e=>e.id===y(I))??null,Le=d(s.hub?.account),Re=i(),ze=e=>!!Q&&!Q.user_capabilities&&!Q.capabilities.includes(e),Ve=j[De],Ge=Z?.cloud?X.gui[0]??Z.gui_model??``:Q&&!Q.user_capabilities?Q.capabilities.includes(`vision`)?Q.defaults.hands||R.trim():Ve?.gui_model??R.trim():R.trim(),Ke=!Z?.cloud&&ze(`vision`)&&!!Ve,qe=e.gui?we(e.gui,e.llm,Re):``,Je=Array.from(new Set([...Z?.cloud?X.gui:[],...Z?.gui_model?[Z.gui_model]:[],...X.list.filter(e=>X.vision.includes(e)||f(e)===!0)])).filter(Boolean),Ye=Z?.cloud?`nanoMuse Cloud`:Q?S(Q,Re):We(ke)||I,Xe=Z?.cloud?X.gui[0]??Z.gui_model??``:Q?.defaults.hands??Z?.gui_model??``,Ze=[{key:`hands`,label:Ye,rows:Je.map(e=>({id:e,name:e})),...Xe?{default:Xe}:{}}],Qe=Ie&&/^https?:\/\/[^/]+\/?$/.test(B.trim());return(0,K.jsxs)(A,{icon:(0,K.jsx)(F,{size:19}),title:p(`Chat model`),summary:e.llm.cloud?`nanoMuse Cloud · ${e.llm.model||`—`}`:`${e.llm.model||`—`}${e.llm.base_url?` · ${We(e.llm.base_url)}`:``}`,status:Me,open:m,onToggle:a?void 0:()=>g(!m),children:[(0,K.jsx)($,{label:p(`Provider`),children:(0,K.jsxs)(`div`,{className:`space-y-2.5`,children:[Fe.filter(e=>e.ids.length).map(e=>(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`div`,{className:`mb-1 text-[11px] uppercase tracking-wide text-muted`,children:e.title}),(0,K.jsx)(`div`,{className:`flex flex-wrap gap-1.5`,children:e.ids.map(e=>{let n=j[e];return(0,K.jsxs)(`button`,{type:`button`,onClick:()=>Ae(e),className:t(`rounded-2xl px-3 py-1.5 text-left border leading-tight`,I===e?`border-accent bg-accent/10 text-accent`:`border-border text-muted`),children:[(0,K.jsx)(`span`,{className:t(`block text-[13px]`,I===e&&`font-medium`),children:n.label}),n.subtitle&&(0,K.jsx)(`span`,{className:`block text-[10.5px] opacity-80`,children:p(n.subtitle)})]},e)})})]},e.id)),Q&&(0,K.jsxs)(`p`,{className:`text-[12px] text-muted`,children:[(0,K.jsx)(`span`,{className:`font-medium text-fg`,children:S(Q,Re)}),` · `,_(p,Q.capabilities),`. `,Re===`zh-CN`?Q.note_zh:Q.note]}),(0,K.jsxs)(`div`,{children:[(0,K.jsxs)(`button`,{type:`button`,onClick:()=>oe(!ae),className:`inline-flex items-center gap-1.5 text-[12.5px] text-accent`,children:[(0,K.jsx)(U,{size:13}),` `,p(`Or sign in with a ChatGPT plan`),` `,ae?(0,K.jsx)(k,{size:13}):(0,K.jsx)(E,{size:13})]}),ae&&(0,K.jsx)(`div`,{className:`mt-2`,children:(0,K.jsx)(te,{compact:!0,onChanged:()=>{n()}})})]})]})}),Ie&&(0,K.jsx)($,{label:p(`Base URL`),hint:p(Qe?`/v1 is added when the URL has no path.`:`The endpoint that serves /chat/completions, for example http://127.0.0.1:8000/v1.`),children:(0,K.jsx)(`input`,{value:B,onChange:e=>V(e.target.value),className:`w-full rounded-2xl bg-surface-2 px-3.5 py-2.5 text-[14.5px] outline-none focus:ring-2 focus:ring-accent/40`,placeholder:`https://host/v1`,inputMode:`url`,autoCapitalize:`off`})}),(0,K.jsxs)($,{label:p(`Chat model`),hint:Z?.cloud&&M&&X.catalog.length?p(`{n} models your account may use: the menu first, then everything else the provider lists under the Cloud key. Pick one; the ones beyond the menu are priced as the dearest menu model of their kind.`,{n:X.list.length}):Z?.cloud&&M?p(`Your account may name any model the provider has, not only these: type its id (a chat model here, a picture or clip model below) and it goes through as typed.`):X.source===`live`?p(`{n} models from the endpoint`,{n:X.list.length}):X.source===`loading`?p(`Asking the endpoint…`):X.list.length?p(`Could not list the endpoint's models; these are the usual ones.`):void 0,children:[Z?.cloud&&X.catalog.length>0&&!Ee&&(!R||X.list.includes(R))?(0,K.jsxs)(`select`,{value:R,onChange:e=>{if(e.target.value===Be){Oe(!0);return}z(e.target.value),Te(!0)},className:t(O,`text-fg`),children:[!R&&(0,K.jsx)(`option`,{value:``,children:p(`model name`)}),(0,K.jsx)(`optgroup`,{label:p(`Menu`),children:X.menu.map(e=>(0,K.jsx)(`option`,{value:e,children:X.vision.includes(e)?`${e} · ${p(`reads pictures`)}`:e},e))}),(0,K.jsx)(`optgroup`,{label:p(`More models on your account`),children:X.catalog.map(e=>(0,K.jsx)(`option`,{value:e,children:X.vision.includes(e)?`${e} · ${p(`reads pictures`)}`:e},e))}),(0,K.jsx)(`option`,{value:Be,children:p(`Type a model id…`)})]}):(0,K.jsxs)(K.Fragment,{children:[(0,K.jsx)(`input`,{list:`om-models`,value:R,onChange:e=>{z(e.target.value),Te(!0)},className:O,placeholder:p(`model name`),autoCapitalize:`off`,autoCorrect:`off`,autoFocus:Ee}),(0,K.jsx)(`datalist`,{id:`om-models`,children:X.list.map(e=>(0,K.jsx)(`option`,{value:e},e))}),Z?.cloud&&X.catalog.length>0&&(0,K.jsx)(`button`,{type:`button`,className:`mt-1.5 text-[12px] text-accent`,onClick:()=>{Oe(!1),X.list.includes(R)||z(X.menu[0]??X.list[0]??``)},children:p(`Pick from the list`)})]}),X.list.length>0&&(0,K.jsx)(`div`,{className:`mt-1.5 flex flex-wrap gap-1.5`,children:(X.menu.length?X.menu:X.list).slice(0,8).map(e=>(0,K.jsx)(`button`,{type:`button`,onClick:()=>z(e),className:t(`rounded-full px-2.5 py-1 text-[12px] border`,R===e?`border-accent bg-accent/10 text-accent font-medium`:`border-border text-muted`),children:e},e))})]}),(0,K.jsxs)($,{label:p(`Hands model`),hint:Z?.cloud?p(`The model that looks at screens when the hands run: the phone, this computer, a page the browser cannot read. Your account's hands model is {model}; the chat model above is a different pick.`,{model:Ge||`—`}):Ke?p(`The model that looks at screens when the hands run. This provider has no model that sees, so the hands use your account's, {model}, unless you pick one here.`,{model:Ge||`—`}):p(`The model that looks at screens when the hands run: a small, fast one that takes pictures, on the same endpoint and key. Default: this provider's own hands model.`),children:[(0,K.jsx)(ve,{label:p(`Hands model`),text:J?`${Ye} · ${J}`:p(`Automatic`),heads:[{value:``,label:p(`Automatic`)}],headValue:J?void 0:``,groups:Ze,current:J?{group:`hands`,id:J}:void 0,onHead:()=>Y(``),onPick:(e,t)=>Y(t.id)}),qe&&(0,K.jsx)(`p`,{className:`mt-1.5 text-[12px] text-muted`,children:p(`Currently {value}`,{value:qe})}),!Z?.cloud&&R.trim()&&!J&&f(R.trim())===!1&&(0,K.jsx)(`div`,{className:`mt-1.5 text-[12px] text-amber-700 dark:text-amber-300`,children:p(`{model} does not take pictures, so the hands would be blind with it. Pick a model that sees for them.`,{model:R.trim()})}),ze(`vision`)&&!Ke&&(0,K.jsxs)(`div`,{className:`mt-1.5 text-[12px] text-amber-700 dark:text-amber-300`,children:[x(p,`vision`,Le,Re),` `,(0,K.jsx)(He,{})]})]}),!Z?.no_key&&(0,K.jsxs)($,{label:p(`API key`),hint:se&&Z?.key_optional?p(`No key will be sent.`):e.llm.key_source===`vault`&&I===P?p(`A key is in the vault. Leave blank to keep it.`):p(`Stored encrypted in the vault as LLM_API_KEY.`),children:[(0,K.jsxs)(`div`,{className:`relative`,children:[(0,K.jsx)(`input`,{type:re?`text`:`password`,value:H,onChange:e=>ne(e.target.value),disabled:se&&!!Z?.key_optional,className:t(`w-full rounded-2xl bg-surface-2 px-3.5 py-2.5 text-[14.5px] outline-none focus:ring-2 focus:ring-accent/40`,`pr-10 disabled:opacity-50`),placeholder:e.llm.key_source===`vault`&&I===P?`••••••••`:Z?.key_hint||`sk-…`,autoComplete:`off`,autoCapitalize:`off`,spellCheck:!1}),(0,K.jsx)(`button`,{type:`button`,onClick:()=>ie(!re),"aria-label":p(re?`Hide key`:`Show key`),className:`absolute right-2 top-1/2 -translate-y-1/2 rounded-full p-1.5 text-muted`,children:re?(0,K.jsx)(le,{size:16}):(0,K.jsx)(ue,{size:16})})]}),(0,K.jsxs)(`div`,{className:`mt-1.5 flex items-center justify-between gap-2 text-[12px]`,children:[Z?.key_url?(0,K.jsxs)(`a`,{href:Z.key_url,target:`_blank`,rel:`noreferrer`,className:`inline-flex items-center gap-1 text-accent`,children:[p(`Get a key from {vendor}`,{vendor:Z.label}),` `,(0,K.jsx)(w,{size:12})]}):(0,K.jsx)(`span`,{}),Z?.key_optional&&(0,K.jsxs)(`label`,{className:`inline-flex items-center gap-1.5 text-muted`,children:[(0,K.jsx)(`input`,{type:`checkbox`,checked:se,onChange:e=>ce(e.target.checked),className:`accent-accent`}),` `,p(`No key`)]})]})]}),(0,K.jsx)($,{label:p(`Tool calling`),hint:p(`Auto uses the API's function calling and falls back to describing tools in the prompt when the endpoint rejects them. Prompt: for endpoints that silently ignore tools.`),children:(0,K.jsx)(`div`,{className:`flex gap-1.5`,children:[`auto`,`native`,`prompt`].map(e=>(0,K.jsx)(`button`,{type:`button`,onClick:()=>de(e),className:t(`rounded-full px-3 py-1.5 text-[13px] border`,W===e?`border-accent bg-accent/10 text-accent font-medium`:`border-border text-muted`),children:e},e))})}),!Z?.cloud&&e.llm.proxy!==void 0&&(0,K.jsx)($,{label:p(`Proxy (optional)`),hint:p(`Only this provider's requests go through it. nanoMuse Cloud never does.`),children:(0,K.jsx)(`input`,{className:`w-full rounded-2xl bg-surface-2 px-3.5 py-2.5 text-[14.5px] outline-none focus:ring-2 focus:ring-accent/40`,value:fe,onChange:e=>{pe(e.target.value),he(!0)},onFocus:()=>fe.includes(`••••`)&&!me&&pe(``),onBlur:()=>!me&&pe(e.llm.proxy??``),placeholder:`http://host:port / socks5://host:port`,autoComplete:`off`,spellCheck:!1})}),(0,K.jsxs)(`div`,{className:`flex gap-2 pt-1`,children:[(0,K.jsxs)(`button`,{type:`button`,disabled:ge||!R.trim()||Ie&&!B.trim(),onClick:()=>void Ne(),className:D,children:[ge?(0,K.jsx)(l,{size:16,className:`animate-spin`}):(0,K.jsx)(C,{size:16}),` `,p(`Save`)]}),(0,K.jsxs)(`button`,{type:`button`,disabled:be,onClick:()=>void Pe(),className:T,children:[be?(0,K.jsx)(l,{size:16,className:`animate-spin`}):(0,K.jsx)(N,{size:16}),` `,p(`Test`)]})]}),q&&(0,K.jsx)(Ue,{result:q,okText:p(`Replied "{reply}" in {ms} ms`,{reply:q.reply??``,ms:q.ms??0})})]})}function ke({slot:e,data:n,onChange:a}){let{toast:o,state:s}=c(),f=r(),p=n[e],h=e,v=s.hub?.account??null,y=!!v?.signed_in,T=d(v),E=i(),k=n.providers[De]?.base_url??``,N=Te(h,{signedIn:y,chat:{provider:n.llm.provider,base_url:n.llm.base_url,cloud:!!n.llm.cloud},region:T,locale:E}),P=Ee(p,k),[F,I]=(0,G.useState)(!1),[L,ee]=(0,G.useState)(P),[te,R]=(0,G.useState)(p.model),[z,B]=(0,G.useState)(p.base_url),[H,U]=(0,G.useState)(``),[ne,re]=(0,G.useState)(!1),[ie,ae]=(0,G.useState)(!1),[oe,se]=(0,G.useState)({list:[],more:[],source:`catalogue`});(0,G.useEffect)(()=>{ee(P),R(p.model),B(p.base_url),U(``)},[p]);let ce=N.find(e=>e.value===L)??null,W=ce?.entry??null,de=W?g(W,T):null,fe=L===`nanomuse_cloud`?k:L===`custom`?z.trim():de?.base_url??``,pe=P===L&&P!==``&&(p.key_source===`vault`||p.key_source===`config`),me=!!ce?.needsKey&&!H&&!pe,he=L===`nanomuse_cloud`?oe.list[0]??``:W?.defaults[e]??``;(0,G.useEffect)(()=>{if(!F||!L||L!==`nanomuse_cloud`&&!fe){se({list:[],more:[],source:`catalogue`});return}let t=!0,n=setTimeout(()=>{se(e=>({...e,source:`loading`})),u.llmModels(L===`nanomuse_cloud`?{preset:De}:{preset:W?m(W.id):``,base_url:fe,api_key:H||void 0}).then(n=>{if(!t)return;let r=(e===`image`?n.image_models:n.video_models)??[],i=(e===`image`?n.image_catalog:n.video_catalog)??[];se({list:r.filter(e=>!i.includes(e)),more:i,source:n.source})}).catch(()=>t&&se({list:[],more:[],source:`catalogue`}))},H?600:150);return()=>{t=!1,clearTimeout(n)}},[F,L,fe,H]);let ge=f(e===`image`?`Making pictures`:`Making clips`),_e=f(e===`image`?`Portraits of your Muse.`:`Short clips of your Muse.`),q=Ce(p,E),ve=x(f,h,T,E),ye=p.effective_provider?p.effective_source===`cloud`?{text:f(`Your account`),tone:`ok`}:p.effective_source===`chat`?{text:f(`The chat model's provider`),tone:`ok`}:{text:f(`Your key`),tone:`ok`}:{text:f(`Not set up`),tone:`warn`},xe=async()=>{ae(!0);try{L?L===`nanomuse_cloud`?await u.setMedia(e,{provider:`openai`,base_url:k,model:te.trim(),api_key:be}):L===`custom`?await u.setMedia(e,{provider:`openai`,base_url:z.trim(),model:te.trim(),api_key:H||null}):await u.setMedia(e,{provider:L,base_url:``,model:te.trim(),api_key:H||(ce?.group===`chat`?``:null)}):await u.setMedia(e,{provider:``,model:``,base_url:``,api_key:``}),U(``),b(),o(f(`Saved`)),a(),I(!1)}catch(e){o(e.message)}finally{ae(!1)}},J=e=>f(e===`cloud`?`Your account`:e===`chat`?`The chat model's provider`:`Add a provider`),Y=[`cloud`,`chat`,`add`].map(e=>({g:e,items:N.filter(t=>t.group===e)})).filter(e=>e.items.length),X=e===`image`?`IMAGE_API_KEY`:`VIDEO_API_KEY`;return(0,K.jsxs)(A,{icon:e===`image`?(0,K.jsx)(M,{size:19}):(0,K.jsx)(j,{size:19}),title:ge,summary:q||ve,status:ye,open:F,onToggle:()=>I(!F),children:[(0,K.jsx)(`p`,{className:`text-[12.5px] text-muted`,children:_e}),(0,K.jsxs)($,{label:f(`Provider`),hint:!q&&!L?ve:void 0,children:[(0,K.jsxs)(`select`,{value:L,onChange:e=>{ee(e.target.value),R(``),U(``)},className:t(O,`text-fg`),children:[(0,K.jsx)(`option`,{value:``,children:f(`Automatic`)}),Y.map(({g:e,items:t})=>(0,K.jsx)(`optgroup`,{label:J(e),children:t.map(e=>(0,K.jsx)(`option`,{value:e.value,children:e.value===`custom`?f(`Other OpenAI-compatible endpoint`):e.label},e.value))},e))]}),q&&(0,K.jsx)(`p`,{className:`mt-1.5 text-[12px] text-muted`,children:f(`Currently {value}`,{value:q})}),!q&&!L&&(0,K.jsxs)(`button`,{type:`button`,className:`mt-1.5 inline-flex items-center gap-1 text-[12.5px] text-accent`,onClick:()=>ee(N.find(e=>e.group===`add`)?.value??``),children:[(0,K.jsx)(V,{size:13}),` `,f(`Add a provider`)]}),W&&(0,K.jsxs)(`p`,{className:`mt-1.5 text-[12px] text-muted`,children:[(0,K.jsx)(`span`,{className:`font-medium text-fg`,children:S(W,E)}),` · `,_(f,W.capabilities),`. `,E===`zh-CN`?W.note_zh:W.note]})]}),L===`custom`&&(0,K.jsx)($,{label:f(`Base URL`),hint:f(`The endpoint that serves /images/generations, for example https://host/v1.`),children:(0,K.jsx)(`input`,{value:z,onChange:e=>B(e.target.value),className:`w-full rounded-2xl bg-surface-2 px-3.5 py-2.5 text-[14.5px] outline-none focus:ring-2 focus:ring-accent/40`,placeholder:`https://host/v1`,inputMode:`url`,autoCapitalize:`off`})}),L&&(0,K.jsx)(Ve,{label:f(e===`image`?`Picture model`:`Clip model`),provider:L===`nanomuse_cloud`?`nanoMuse Cloud`:L===`custom`?We(z)||f(`Other OpenAI-compatible endpoint`):ce?.label??L,value:te,options:oe.list,more:oe.more,onChange:R,other:L!==`nanomuse_cloud`||!!v?.any_model,placeholder:he||void 0}),L&&L!==`nanomuse_cloud`&&ce?.group!==`chat`&&(0,K.jsxs)($,{label:f(`API key`),hint:pe?f(`A key is in the vault. Leave blank to keep it.`):f(`Stored encrypted in the vault as {name}.`,{name:X}),children:[(0,K.jsxs)(`div`,{className:`relative`,children:[(0,K.jsx)(`input`,{type:ne?`text`:`password`,value:H,onChange:e=>U(e.target.value),className:t(`w-full rounded-2xl bg-surface-2 px-3.5 py-2.5 text-[14.5px] outline-none focus:ring-2 focus:ring-accent/40`,`pr-10`),placeholder:pe?`••••••••`:W?.key_hint||`sk-…`,autoComplete:`off`,autoCapitalize:`off`,spellCheck:!1}),(0,K.jsx)(`button`,{type:`button`,onClick:()=>re(!ne),"aria-label":f(ne?`Hide key`:`Show key`),className:`absolute right-2 top-1/2 -translate-y-1/2 rounded-full p-1.5 text-muted`,children:ne?(0,K.jsx)(le,{size:16}):(0,K.jsx)(ue,{size:16})})]}),de?.key_url&&(0,K.jsxs)(`a`,{href:de.key_url,target:`_blank`,rel:`noreferrer`,className:`mt-1.5 inline-flex items-center gap-1 text-[12px] text-accent`,children:[f(`Get a key from {vendor}`,{vendor:W?S(W,E):``}),` `,(0,K.jsx)(w,{size:12})]})]}),ce?.group===`chat`&&(0,K.jsx)(`p`,{className:`text-[12px] text-muted`,children:f(`Uses the chat model's key.`)}),(0,K.jsx)(`div`,{className:`flex gap-2 pt-1`,children:(0,K.jsxs)(`button`,{type:`button`,disabled:ie||me||L===`custom`&&!z.trim(),onClick:()=>void xe(),className:D,children:[ie?(0,K.jsx)(l,{size:16,className:`animate-spin`}):(0,K.jsx)(C,{size:16}),` `,f(`Save`)]})})]})}function Ae({data:e,onChange:n}){let{toast:i}=c(),a=r(),o=e.embeddings,[s,d]=(0,G.useState)(!1),[f,p]=(0,G.useState)(o.mode),[m,h]=(0,G.useState)(!!o.base_url),[g,_]=(0,G.useState)(o.base_url),[v,y]=(0,G.useState)(o.model),[b,x]=(0,G.useState)(``),[S,w]=(0,G.useState)(!1),[E,O]=(0,G.useState)(null),[k,j]=(0,G.useState)(!1);(0,G.useEffect)(()=>{p(o.mode),h(!!o.base_url),_(o.base_url),y(o.model)},[e.embeddings]);let M=o.mode===`off`?{text:a(`Off`),tone:`off`}:o.available===!0?{text:a(`On`),tone:`ok`}:o.available===!1?{text:o.mode===`on`?a(`Not reachable`):a(`By keyword`),tone:`warn`}:{text:a(`Not tried yet`),tone:`off`},P=o.mode===`off`?a(`Keyword recall only`):o.available===!0?a(`{model} · {n} of {total} memories indexed`,{model:o.model||o.default_model,n:o.indexed,total:o.total}):o.available===!1?o.reason:a(`{model} at {host}`,{model:o.model||o.default_model,host:We(o.effective_base_url)}),F=async()=>{w(!0),O(null);try{await u.setEmbeddings({mode:f,base_url:m?g.trim():``,model:v.trim(),api_key:m?b||void 0:``}),x(``),i(a(`Saved`)),n()}catch(e){i(e.message)}finally{w(!1)}},I=async()=>{j(!0);try{O(await u.testEmbeddings()),n()}catch(e){O({ok:!1,error:e.message})}finally{j(!1)}},L=e=>t(`rounded-full px-3 py-1.5 text-[13px] border`,e?`border-accent bg-accent/10 text-accent font-medium`:`border-border text-muted`);return(0,K.jsxs)(A,{icon:(0,K.jsx)(ce,{size:19}),title:a(`Recall by meaning`),summary:P,status:M,open:s,onToggle:()=>d(!s),children:[(0,K.jsx)(`p`,{className:`text-[12.5px] text-muted leading-snug`,children:a(`Memories are embedded once and a message finds the ones that mean the same thing, in any language: “写邮件给房东” finds “the landlord is Bob Li”. Keyword recall stays; the two are fused.`)}),(0,K.jsx)($,{label:a(`Mode`),hint:a(`Auto uses the model's endpoint when it has embeddings and falls back to keywords when it does not. On insists and warns. Off: keywords only.`),children:(0,K.jsx)(`div`,{className:`flex gap-1.5`,children:[`auto`,`on`,`off`].map(e=>(0,K.jsx)(`button`,{type:`button`,onClick:()=>p(e),className:L(f===e),children:a(e===`auto`?`Auto`:e===`on`?`On`:`Off`)},e))})}),f!==`off`&&(0,K.jsxs)(K.Fragment,{children:[(0,K.jsx)($,{label:a(`Endpoint`),hint:a(m?`Any OpenAI-compatible /embeddings: Ollama with an embedding model pulled, OpenAI, a gateway.`:`The model's endpoint and key. DeepSeek has no embeddings; pick another endpoint.`),children:(0,K.jsxs)(`div`,{className:`flex gap-1.5`,children:[(0,K.jsx)(`button`,{type:`button`,onClick:()=>h(!1),className:L(!m),children:a(`Same as the model`)}),(0,K.jsx)(`button`,{type:`button`,onClick:()=>{h(!0),g||_(`http://127.0.0.1:11434/v1`)},className:L(m),children:a(`Another endpoint`)})]})}),m&&(0,K.jsxs)(K.Fragment,{children:[(0,K.jsx)($,{label:a(`Base URL`),children:(0,K.jsx)(`input`,{value:g,onChange:e=>_(e.target.value),className:`w-full rounded-2xl bg-surface-2 px-3.5 py-2.5 text-[14.5px] outline-none focus:ring-2 focus:ring-accent/40`,placeholder:`http://127.0.0.1:11434/v1`,inputMode:`url`})}),(0,K.jsx)($,{label:a(`API key`),hint:o.key_source===`vault`?a(`A key is in the vault. Leave blank to keep it.`):a(`Stored encrypted in the vault as EMBEDDINGS_API_KEY. Ollama needs none.`),children:(0,K.jsx)(`input`,{type:`password`,value:b,onChange:e=>x(e.target.value),className:`w-full rounded-2xl bg-surface-2 px-3.5 py-2.5 text-[14.5px] outline-none focus:ring-2 focus:ring-accent/40`,placeholder:o.key_source===`vault`?`••••••••`:`sk-…`,autoComplete:`off`})})]}),(0,K.jsx)($,{label:a(`Embedding model`),hint:a(`Blank uses the endpoint's default: {model}. On Ollama: ollama pull qwen3-embedding:0.6b (reads Chinese and English).`,{model:o.default_model}),children:(0,K.jsx)(`input`,{value:v,onChange:e=>y(e.target.value),className:`w-full rounded-2xl bg-surface-2 px-3.5 py-2.5 text-[14.5px] outline-none focus:ring-2 focus:ring-accent/40`,placeholder:o.default_model,autoComplete:`off`})})]}),(0,K.jsxs)(`div`,{className:`flex gap-2 pt-1`,children:[(0,K.jsxs)(`button`,{type:`button`,disabled:S||m&&!/^https?:\/\//.test(g.trim()),onClick:()=>void F(),className:D,children:[S?(0,K.jsx)(l,{size:16,className:`animate-spin`}):(0,K.jsx)(C,{size:16}),` `,a(`Save`)]}),(0,K.jsxs)(`button`,{type:`button`,disabled:k||o.mode===`off`,onClick:()=>void I(),className:T,children:[k?(0,K.jsx)(l,{size:16,className:`animate-spin`}):(0,K.jsx)(N,{size:16}),` `,a(`Test`)]})]}),E&&(0,K.jsx)(Ue,{result:E,okText:a(`{model} · {dims} dims · {n} memories indexed · {ms} ms`,{model:E.model??``,dims:E.dims??0,n:E.indexed??0,ms:E.ms??0})})]})}function je({data:e,onChange:n}){let{toast:i}=c(),a=r(),o=e.search,[s,d]=(0,G.useState)(!1),[f,p]=(0,G.useState)(o.provider),[m,h]=(0,G.useState)(o.base_url),[g,_]=(0,G.useState)(``),[v,y]=(0,G.useState)(!1),[b,x]=(0,G.useState)(null),[S,w]=(0,G.useState)(!1);(0,G.useEffect)(()=>{p(o.provider),h(o.base_url)},[e.search]);let E=o.providers.find(e=>e.id===o.provider),O=o.providers.find(e=>e.id===f),k=!!O?.needs_key,j=o.configured?{text:a(`On`),tone:`ok`}:{text:a(`Not set up`),tone:`warn`},M=o.configured?o.provider===`searxng`?a(`{provider} at {host}`,{provider:E?.label??o.provider,host:We(o.base_url)}):E?.label??o.provider:a(`{provider} needs {what}; searches use DuckDuckGo until then`,{provider:E?.label??o.provider,what:E?.needs_key?a(`a key`):a(`an instance URL`)}),P=async()=>{y(!0),x(null);try{await u.setSearch({provider:f,base_url:f===`searxng`?m.trim():``,api_key:k?g||void 0:``}),_(``),i(a(`Saved`)),n()}catch(e){i(e.message)}finally{y(!1)}},F=async()=>{w(!0);try{x(await u.testSearch())}catch(e){x({ok:!1,error:e.message})}finally{w(!1)}},I=e=>t(`rounded-full px-3 py-1.5 text-[13px] border`,e?`border-accent bg-accent/10 text-accent font-medium`:`border-border text-muted`),L=f!==`searxng`||/^https?:\/\//.test(m.trim());return(0,K.jsxs)(A,{icon:(0,K.jsx)(B,{size:19}),title:a(`Web search`),summary:M,status:j,open:s,onToggle:()=>d(!s),children:[(0,K.jsx)(`p`,{className:`text-[12.5px] text-muted leading-snug`,children:a(`DuckDuckGo needs nothing, but it is scraped and rate-limits now and then. For searches that always work, use a provider with an API. Whichever you pick, a failed search falls back to DuckDuckGo with a note.`)}),(0,K.jsx)($,{label:a(`Provider`),children:(0,K.jsx)(`div`,{className:`flex flex-wrap gap-1.5`,children:o.providers.map(e=>(0,K.jsx)(`button`,{type:`button`,onClick:()=>p(e.id),className:I(f===e.id),children:e.label},e.id))})}),k&&(0,K.jsxs)($,{label:a(`API key`),hint:o.key_source===`vault`&&o.provider===f?a(`A key is in the vault. Leave blank to keep it.`):a(`Stored encrypted in the vault as SEARCH_API_KEY.`),children:[(0,K.jsx)(`input`,{type:`password`,value:g,onChange:e=>_(e.target.value),className:`w-full rounded-2xl bg-surface-2 px-3.5 py-2.5 text-[14.5px] outline-none focus:ring-2 focus:ring-accent/40`,placeholder:o.key_source===`vault`&&o.provider===f?`••••••••`:`…`,autoComplete:`off`}),O?.keys_url&&(0,K.jsx)(`a`,{href:O.keys_url,target:`_blank`,rel:`noreferrer`,className:`mt-1 inline-block text-[12px] text-accent`,children:a(`Get a key from {label}`,{label:O.label})})]}),f===`searxng`&&(0,K.jsx)($,{label:a(`Instance URL`),hint:a(`A SearXNG you run, with the JSON format enabled in its settings.`),children:(0,K.jsx)(`input`,{value:m,onChange:e=>h(e.target.value),className:`w-full rounded-2xl bg-surface-2 px-3.5 py-2.5 text-[14.5px] outline-none focus:ring-2 focus:ring-accent/40`,placeholder:`http://127.0.0.1:8080`,inputMode:`url`})}),(0,K.jsxs)(`div`,{className:`flex gap-2 pt-1`,children:[(0,K.jsxs)(`button`,{type:`button`,disabled:v||!L,onClick:()=>void P(),className:D,children:[v?(0,K.jsx)(l,{size:16,className:`animate-spin`}):(0,K.jsx)(C,{size:16}),` `,a(`Save`)]}),(0,K.jsxs)(`button`,{type:`button`,disabled:S,onClick:()=>void F(),className:T,children:[S?(0,K.jsx)(l,{size:16,className:`animate-spin`}):(0,K.jsx)(N,{size:16}),` `,a(`Test`)]})]}),b&&(0,K.jsx)(Ue,{result:b,okText:a(`{provider} · {n} results · {ms} ms`,{provider:b.provider??``,n:b.results??0,ms:b.ms??0})})]})}var Me=[{id:`gmail`,label:`Gmail`,imap:`imap.gmail.com`,smtp:`smtp.gmail.com`,port:587,starttls:!0},{id:`outlook`,label:`Outlook`,imap:`outlook.office365.com`,smtp:`smtp.office365.com`,port:587,starttls:!0},{id:`icloud`,label:`iCloud`,imap:`imap.mail.me.com`,smtp:`smtp.mail.me.com`,port:587,starttls:!0},{id:`qq`,label:`QQ`,imap:`imap.qq.com`,smtp:`smtp.qq.com`,port:587,starttls:!0},{id:`163`,label:`163`,imap:`imap.163.com`,smtp:`smtp.163.com`,port:465,starttls:!1},{id:`fastmail`,label:`Fastmail`,imap:`imap.fastmail.com`,smtp:`smtp.fastmail.com`,port:587,starttls:!0}];function Ne({data:e,onChange:n,compact:i}){let{toast:a}=c(),o=r(),s=e.email,[d,f]=(0,G.useState)(!!i),[p,m]=(0,G.useState)(s.address),[h,g]=(0,G.useState)(``),[_,v]=(0,G.useState)(s.imap_host),[y,b]=(0,G.useState)(s.imap_port),[x,S]=(0,G.useState)(s.smtp_host),[C,w]=(0,G.useState)(s.smtp_port),[T,E]=(0,G.useState)(s.smtp_starttls),[k,j]=(0,G.useState)(null),[M,P]=(0,G.useState)(null);(0,G.useEffect)(()=>{m(s.address),v(s.imap_host),b(s.imap_port),S(s.smtp_host),w(s.smtp_port),E(s.smtp_starttls)},[s]);let F=e=>{v(e.imap),b(993),S(e.smtp),w(e.port),E(e.starttls)},I=async()=>{j(`save`),P(null);try{await u.setEmail({enabled:!0,address:p.trim(),password:h||void 0,imap_host:_.trim(),imap_port:y,smtp_host:x.trim(),smtp_port:C,smtp_starttls:T}),g(``);let e=await u.testEmail();P(e),a(e.ok?o(`Email connected`):o(`Saved, but the test failed`)),n()}catch(e){a(e.message)}finally{j(null)}},L=async()=>{j(`off`);try{await u.disconnectEmail(),P(null),a(o(`Email disconnected`)),n()}catch(e){a(e.message)}finally{j(null)}},ee=s.enabled&&s.configured?{text:o(`Connected`),tone:`ok`}:s.enabled?{text:o(`Incomplete`),tone:`warn`}:{text:o(`Not connected`),tone:`off`};return(0,K.jsxs)(A,{icon:(0,K.jsx)(re,{size:19}),title:o(`Email`),summary:s.configured&&s.enabled?`${s.address} · ${o(`reads and sends`)}`:o(`Read your inbox, draft and send mail`),status:ee,open:d,onToggle:i?void 0:()=>f(!d),children:[(0,K.jsx)(`p`,{className:`text-[12.5px] text-muted -mt-1`,children:o(`Reading is a moderate action; sending always asks you first. Use an app password where your provider offers one.`)}),(0,K.jsx)($,{label:o(`Provider`),children:(0,K.jsx)(`div`,{className:`flex flex-wrap gap-1.5`,children:Me.map(e=>(0,K.jsx)(`button`,{type:`button`,onClick:()=>F(e),className:t(`rounded-full px-3 py-1.5 text-[13px] border`,_===e.imap?`border-accent bg-accent/10 text-accent font-medium`:`border-border text-muted`),children:e.label},e.id))})}),(0,K.jsx)($,{label:o(`Address`),children:(0,K.jsx)(`input`,{value:p,onChange:e=>m(e.target.value),className:O,placeholder:`you@example.com`,inputMode:`email`,autoComplete:`off`})}),(0,K.jsx)($,{label:o(`Password`),hint:s.password_set?o(`A password is in the vault. Leave blank to keep it.`):o(`Stored encrypted in the vault as EMAIL_PASSWORD.`),children:(0,K.jsx)(`input`,{type:`password`,value:h,onChange:e=>g(e.target.value),className:O,placeholder:s.password_set?`••••••••`:o(`app password`),autoComplete:`off`})}),(0,K.jsxs)(`div`,{className:`grid grid-cols-[1fr_84px] gap-2`,children:[(0,K.jsx)($,{label:o(`IMAP server`),children:(0,K.jsx)(`input`,{value:_,onChange:e=>v(e.target.value),className:O,placeholder:`imap.example.com`})}),(0,K.jsx)($,{label:o(`Port`),children:(0,K.jsx)(`input`,{type:`number`,value:y,onChange:e=>b(Number(e.target.value)),className:O})}),(0,K.jsx)($,{label:o(`SMTP server`),children:(0,K.jsx)(`input`,{value:x,onChange:e=>S(e.target.value),className:O,placeholder:`smtp.example.com`})}),(0,K.jsx)($,{label:o(`Port`),children:(0,K.jsx)(`input`,{type:`number`,value:C,onChange:e=>w(Number(e.target.value)),className:O})})]}),(0,K.jsxs)(`label`,{className:`flex items-center gap-2 text-[13.5px]`,children:[(0,K.jsx)(`input`,{type:`checkbox`,checked:T,onChange:e=>E(e.target.checked),className:`accent-[var(--om-accent)]`}),` `,o(`STARTTLS for SMTP (off for port 465)`)]}),(0,K.jsxs)(`div`,{className:`flex gap-2 pt-1`,children:[(0,K.jsxs)(`button`,{type:`button`,disabled:k!==null||!p.trim()||!_.trim()||!x.trim()||!h&&!s.password_set,onClick:()=>void I(),className:D,children:[k===`save`?(0,K.jsx)(l,{size:16,className:`animate-spin`}):(0,K.jsx)(N,{size:16}),` `,s.configured?o(`Save & test`):o(`Connect`)]}),s.enabled&&(0,K.jsxs)(`button`,{type:`button`,disabled:k!==null,onClick:()=>void L(),className:`flex items-center justify-center gap-1.5 rounded-2xl border border-border px-4 py-2.5 text-[14px] font-medium text-muted disabled:opacity-40`,children:[k===`off`?(0,K.jsx)(l,{size:16,className:`animate-spin`}):(0,K.jsx)(de,{size:16}),` `,o(`Disconnect`)]})]}),M&&(0,K.jsx)(Ue,{result:M,okText:o(`Signed in · {n} messages in the inbox`,{n:M.inbox??`?`})})]})}var Pe=[{id:`google`,label:`Google`,hint:`Settings → your calendar → Integrate calendar → Secret address in iCal format`},{id:`outlook`,label:`Outlook`,hint:`Settings → Calendar → Shared calendars → Publish a calendar → ICS link`},{id:`icloud`,label:`iCloud`,hint:`Share Calendar → Public Calendar → copy the webcal:// link`},{id:`fastmail`,label:`Fastmail`,hint:`Settings → Calendars → Export → Calendar URL`},{id:`file`,label:`.ics file`,hint:`A path on the machine where nanoMuse runs, for example ~/calendar.ics`}];function Fe({data:n,onChange:i,compact:a}){let{toast:o}=c(),s=r(),d=n.calendar,[f,p]=(0,G.useState)(!!a),[m,h]=(0,G.useState)(!1),[g,_]=(0,G.useState)(``),[v,y]=(0,G.useState)(``),[b,x]=(0,G.useState)(null),[S,w]=(0,G.useState)(d.day_start),[E,k]=(0,G.useState)(d.day_end),[j,M]=(0,G.useState)(null),[F,I]=(0,G.useState)(null);(0,G.useEffect)(()=>{w(d.day_start),k(d.day_end)},[d.day_start,d.day_end]);let L=async()=>{M(`add`),I(null);try{let e=await u.addCalendarFeed(g.trim(),v.trim());if(e.error)o(s(`Added, but it could not be read: {error}`,{error:e.error}));else{let t=e.feeds.find(e=>e.name===g.trim());o(`${s(`Calendar connected`)} · ${U(t?.events??0)}`),_(``),y(``),h(!1)}i()}catch(e){o(e.message)}finally{M(null)}},ee=async e=>{M(e);try{await u.removeCalendarFeed(e),i()}catch(e){o(e.message)}finally{M(null)}},te=async()=>{M(`hours`);try{await u.setCalendar({day_start:S,day_end:E}),o(s(`Saved`)),i()}catch(e){o(e.message)}finally{M(null)}},R=async()=>{M(`test`);try{I(await u.testCalendar()),i()}catch(e){o(e.message)}finally{M(null)}},B=d.feeds.reduce((e,t)=>e+t.events,0),H=d.feeds.filter(e=>e.error).length,U=e=>e===1?s(`1 event`):s(`{n} events`,{n:e}),ne=d.configured?H?{text:s(`{n} not reading`,{n:H}),tone:`warn`}:{text:s(`Connected`),tone:`ok`}:{text:s(`Not connected`),tone:`off`};return(0,K.jsxs)(A,{icon:(0,K.jsx)(ae,{size:19}),title:s(`Calendar`),summary:d.configured?d.feeds.length===1?`${d.feeds[0].name} · ${U(B)}`:`${s(`{n} calendars`,{n:d.feeds.length})} · ${U(B)}`:s(`Your agenda, free time, and events it can draft`),status:ne,open:f,onToggle:a?void 0:()=>p(!f),children:[(0,K.jsx)(`p`,{className:`text-[12.5px] text-muted -mt-1`,children:s(`Reads your calendar from its private .ics link; the link stays in the vault. It never changes your calendar; an event it proposes comes as a file you add with a tap.`)}),d.feeds.length>0&&(0,K.jsx)(`ul`,{className:`space-y-1.5`,children:d.feeds.map(n=>(0,K.jsxs)(`li`,{className:`flex items-center gap-2.5 rounded-2xl bg-surface-2/60 px-3 py-2`,children:[(0,K.jsx)(`span`,{className:t(`h-2 w-2 rounded-full`,n.error?`bg-rose-500`:n.fetched_at?`bg-emerald-500`:`bg-amber-500`)}),(0,K.jsxs)(`div`,{className:`min-w-0 flex-1`,children:[(0,K.jsx)(`div`,{className:`text-[13.5px] font-medium truncate`,children:n.name}),(0,K.jsxs)(`div`,{className:`text-[11.5px] text-muted truncate`,children:[n.error?n.error:n.fetched_at?`${U(n.events)} · ${s(`read {when}`,{when:e(n.fetched_at)})}`:s(`not read yet`),!n.from_app&&` · ${s(`from config.toml`)}`]})]}),n.from_app&&(0,K.jsx)(`button`,{type:`button`,"aria-label":s(`Remove`),disabled:j===n.name,onClick:()=>void ee(n.name),className:`p-1.5 rounded-full text-muted hover:bg-surface-2`,children:j===n.name?(0,K.jsx)(l,{size:15,className:`animate-spin`}):(0,K.jsx)(z,{size:15})})]},n.name))}),m?(0,K.jsxs)(`div`,{className:`space-y-2.5 rounded-2xl border border-border/70 p-3`,children:[(0,K.jsxs)($,{label:s(`Where is the link?`),children:[(0,K.jsx)(`div`,{className:`flex flex-wrap gap-1.5`,children:Pe.map(e=>(0,K.jsx)(`button`,{type:`button`,onClick:()=>x(b===e.id?null:e.id),className:t(`rounded-full px-3 py-1.5 text-[13px] border`,b===e.id?`border-accent bg-accent/10 text-accent font-medium`:`border-border text-muted`),children:s(e.label)},e.id))}),b&&(0,K.jsx)(`div`,{className:`mt-1.5 text-[11.5px] text-muted leading-snug`,children:s(Pe.find(e=>e.id===b).hint)})]}),(0,K.jsx)($,{label:s(`Name`),children:(0,K.jsx)(`input`,{value:g,onChange:e=>_(e.target.value),className:O,placeholder:s(`Work`)})}),(0,K.jsx)($,{label:s(`Private .ics link or file path`),hint:s(`Stored encrypted in the vault as CALENDAR_{name}.`,{name:g.trim().toUpperCase().replace(/[^A-Z0-9]+/g,`_`).replace(/^_+|_+$/g,``)||`NAME`})+` `+s(`nanoMuse fetches whatever address you put here, from this machine; only paste links you trust.`),children:(0,K.jsx)(`input`,{value:v,onChange:e=>y(e.target.value),className:O,placeholder:`https://calendar.google.com/calendar/ical/…/basic.ics`,inputMode:`url`,autoComplete:`off`})}),(0,K.jsxs)(`div`,{className:`flex gap-2`,children:[(0,K.jsxs)(`button`,{type:`button`,disabled:j===`add`||!g.trim()||!v.trim(),onClick:()=>void L(),className:D,children:[j===`add`?(0,K.jsx)(l,{size:16,className:`animate-spin`}):(0,K.jsx)(N,{size:16}),` `,s(`Connect`)]}),(0,K.jsx)(`button`,{type:`button`,onClick:()=>h(!1),className:T,children:s(`Cancel`)})]})]}):(0,K.jsxs)(`button`,{type:`button`,onClick:()=>h(!0),className:T,children:[(0,K.jsx)(V,{size:16}),` `,s(`Add a calendar`)]}),d.configured&&(0,K.jsxs)(K.Fragment,{children:[(0,K.jsx)($,{label:s(`Working hours`),hint:s(`Free time is looked for inside these hours.`),children:(0,K.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,K.jsx)(`input`,{type:`time`,value:S,onChange:e=>w(e.target.value),className:t(`w-full rounded-2xl bg-surface-2 px-3.5 py-2.5 text-[14.5px] outline-none focus:ring-2 focus:ring-accent/40`,`w-auto`)}),(0,K.jsx)(`span`,{className:`text-muted`,children:`–`}),(0,K.jsx)(`input`,{type:`time`,value:E,onChange:e=>k(e.target.value),className:t(`w-full rounded-2xl bg-surface-2 px-3.5 py-2.5 text-[14.5px] outline-none focus:ring-2 focus:ring-accent/40`,`w-auto`)}),(S!==d.day_start||E!==d.day_end)&&(0,K.jsx)(`button`,{type:`button`,disabled:j===`hours`,onClick:()=>void te(),className:t(`flex items-center justify-center gap-1.5 rounded-2xl bg-accent text-accent-fg px-4 py-2.5 text-[14px] font-medium disabled:opacity-40`,`px-3`),"aria-label":s(`Save`),children:j===`hours`?(0,K.jsx)(l,{size:16,className:`animate-spin`}):(0,K.jsx)(C,{size:16})})]})}),(0,K.jsxs)(`button`,{type:`button`,disabled:j===`test`,onClick:()=>void R(),className:`flex items-center justify-center gap-1.5 rounded-2xl border border-border px-4 py-2.5 text-[14px] font-medium text-muted disabled:opacity-40`,children:[j===`test`?(0,K.jsx)(l,{size:16,className:`animate-spin`}):(0,K.jsx)(P,{size:16}),` `,s(`Read again`)]}),F&&(0,K.jsx)(Ue,{result:F,okText:d.feeds.length===1?U(F.events??0):`${U(F.events??0)} · ${s(`{n} calendars`,{n:d.feeds.length})}`})]})]})}function Ie({data:n,onChange:i,compact:a}){let{toast:o}=c(),s=r(),d=n.contacts,[f,p]=(0,G.useState)(!!a),[m,h]=(0,G.useState)(!1),[g,_]=(0,G.useState)(``),[v,y]=(0,G.useState)(``),[b,x]=(0,G.useState)(null),[S,C]=(0,G.useState)(null),[w,E]=(0,G.useState)(``),[k,j]=(0,G.useState)(null),M=(0,G.useRef)(null),F=e=>e===1?s(`1 person`):s(`{n} people`,{n:e}),I=(e,t)=>{if(e.error)o(s(`Added, but it could not be read: {error}`,{error:e.error}));else{let n=e.sources.find(e=>e.name===t);o(`${s(`Address book connected`)} · ${F(n?.contacts??0)}`),_(``),y(``),h(!1)}i()},L=async()=>{x(`add`),C(null);try{I(await u.addContactsSource(g.trim(),v.trim()),g.trim())}catch(e){o(e.message)}finally{x(null)}},ee=async e=>{x(`upload`),C(null);try{let t=(g.trim()||e.name.replace(/\.vcf$/i,``)||`Imported`).slice(0,40);I(await u.importContacts(t,await e.text()),t)}catch(e){o(e.message)}finally{x(null),M.current&&(M.current.value=``)}},te=async e=>{x(e);try{await u.removeContactsSource(e),i()}catch(e){o(e.message)}finally{x(null)}},R=async()=>{x(`test`);try{C(await u.testContacts()),i()}catch(e){o(e.message)}finally{x(null)}};(0,G.useEffect)(()=>{if(!w.trim()){j(null);return}let e=setTimeout(()=>{u.contacts(w.trim(),5).then(e=>j(e.people)).catch(()=>j([]))},250);return()=>clearTimeout(e)},[w]);let H=d.sources.filter(e=>e.error).length,U=d.enabled?d.configured?H?{text:s(`{n} not reading`,{n:H}),tone:`warn`}:{text:s(`Connected`),tone:`ok`}:{text:s(`Not connected`),tone:`off`}:{text:s(`Off`),tone:`off`};return(0,K.jsxs)(A,{icon:(0,K.jsx)(W,{size:19}),title:s(`Contacts`),summary:d.configured?d.sources.length===0?`${F(d.count)} · ${s(`told to it in chat`)}`:`${F(d.count)} · ${d.sources.length===1?d.sources[0].name:s(`{n} address books`,{n:d.sources.length})}`:s(`Who is who, so it never guesses an address`),status:U,open:f,onToggle:a?void 0:()=>p(!f),children:[(0,K.jsx)(`p`,{className:`text-[12.5px] text-muted -mt-1`,children:s(`Import a .vcf export from Google Contacts, iCloud, Outlook or your phone, or paste a link to one. People you mention in chat go into its own book. It looks people up before writing to them and warns when an address is unknown.`)}),(d.sources.length>0||d.own>0)&&(0,K.jsxs)(`ul`,{className:`space-y-1.5`,children:[d.own>0&&(0,K.jsxs)(`li`,{className:`flex items-center gap-2.5 rounded-2xl bg-surface-2/60 px-3 py-2`,children:[(0,K.jsx)(`span`,{className:`h-2 w-2 rounded-full bg-emerald-500`}),(0,K.jsxs)(`div`,{className:`min-w-0 flex-1`,children:[(0,K.jsx)(`div`,{className:`text-[13.5px] font-medium truncate`,children:s(`My contacts`)}),(0,K.jsx)(`div`,{className:`text-[11.5px] text-muted truncate`,children:`${F(d.own)} · ${s(`added in chat`)}`})]})]}),d.sources.map(n=>(0,K.jsxs)(`li`,{className:`flex items-center gap-2.5 rounded-2xl bg-surface-2/60 px-3 py-2`,children:[(0,K.jsx)(`span`,{className:t(`h-2 w-2 rounded-full`,n.error?`bg-rose-500`:n.fetched_at?`bg-emerald-500`:`bg-amber-500`)}),(0,K.jsxs)(`div`,{className:`min-w-0 flex-1`,children:[(0,K.jsx)(`div`,{className:`text-[13.5px] font-medium truncate`,children:n.name}),(0,K.jsxs)(`div`,{className:`text-[11.5px] text-muted truncate`,children:[n.error?n.error:n.fetched_at?`${F(n.contacts)} · ${s(`read {when}`,{when:e(n.fetched_at)})}`:s(`not read yet`),!n.from_app&&` · ${s(`from config.toml`)}`]})]}),n.from_app&&(0,K.jsx)(`button`,{type:`button`,"aria-label":s(`Remove`),disabled:b===n.name,onClick:()=>void te(n.name),className:`p-1.5 rounded-full text-muted hover:bg-surface-2`,children:b===n.name?(0,K.jsx)(l,{size:15,className:`animate-spin`}):(0,K.jsx)(z,{size:15})})]},n.name))]}),m?(0,K.jsxs)(`div`,{className:`space-y-2.5 rounded-2xl border border-border/70 p-3`,children:[(0,K.jsx)($,{label:s(`Name`),children:(0,K.jsx)(`input`,{value:g,onChange:e=>_(e.target.value),className:O,placeholder:s(`iPhone`)})}),(0,K.jsxs)($,{label:s(`A .vcf file from your phone or computer`),hint:s(`Google Contacts: Export → vCard. iPhone: Contacts → select all → Share → Save to Files. Outlook: People → Manage → Export.`),children:[(0,K.jsx)(`input`,{ref:M,type:`file`,accept:`.vcf,text/vcard,text/x-vcard`,className:`hidden`,onChange:e=>e.target.files?.[0]&&void ee(e.target.files[0])}),(0,K.jsxs)(`button`,{type:`button`,disabled:b===`upload`,onClick:()=>M.current?.click(),className:T,children:[b===`upload`?(0,K.jsx)(l,{size:16,className:`animate-spin`}):(0,K.jsx)(fe,{size:16}),` `,s(`Choose a .vcf file`)]})]}),(0,K.jsx)($,{label:s(`Or a link / path to one`),hint:s(`A link is stored encrypted in the vault as CONTACTS_{name}.`,{name:g.trim().toUpperCase().replace(/[^A-Z0-9]+/g,`_`).replace(/^_+|_+$/g,``)||`NAME`})+` `+s(`nanoMuse fetches whatever address you put here, from this machine; only paste links you trust.`),children:(0,K.jsx)(`input`,{value:v,onChange:e=>y(e.target.value),className:O,placeholder:`https://… /contacts.vcf`,inputMode:`url`,autoComplete:`off`})}),(0,K.jsxs)(`div`,{className:`flex gap-2`,children:[(0,K.jsxs)(`button`,{type:`button`,disabled:b===`add`||!g.trim()||!v.trim(),onClick:()=>void L(),className:D,children:[b===`add`?(0,K.jsx)(l,{size:16,className:`animate-spin`}):(0,K.jsx)(N,{size:16}),` `,s(`Connect`)]}),(0,K.jsx)(`button`,{type:`button`,onClick:()=>h(!1),className:T,children:s(`Cancel`)})]})]}):(0,K.jsxs)(`button`,{type:`button`,onClick:()=>h(!0),className:T,children:[(0,K.jsx)(V,{size:16}),` `,s(`Add an address book`)]}),d.configured&&(0,K.jsxs)(K.Fragment,{children:[(0,K.jsxs)(`div`,{className:`relative`,children:[(0,K.jsx)(B,{size:15,className:`absolute left-3 top-1/2 -translate-y-1/2 text-muted`}),(0,K.jsx)(`input`,{value:w,onChange:e=>E(e.target.value),className:t(`w-full rounded-2xl bg-surface-2 px-3.5 py-2.5 text-[14.5px] outline-none focus:ring-2 focus:ring-accent/40`,`pl-9`),placeholder:s(`Find someone, as the agent would`),autoComplete:`off`})]}),k!==null&&(0,K.jsxs)(`ul`,{className:`space-y-1`,children:[k.length===0&&(0,K.jsx)(`li`,{className:`text-[12.5px] text-muted px-1`,children:s(`No one matches.`)}),k.map(e=>(0,K.jsxs)(`li`,{className:`rounded-2xl bg-surface-2/60 px-3 py-2`,children:[(0,K.jsxs)(`div`,{className:`text-[13.5px] font-medium`,children:[e.name,e.org&&(0,K.jsxs)(`span`,{className:`text-muted font-normal`,children:[` · `,e.org]})]}),(0,K.jsx)(`div`,{className:`text-[12px] text-muted break-words`,children:[...e.emails,...e.phones].join(` · `)})]},e.id))]}),d.sources.length>0&&(0,K.jsxs)(`button`,{type:`button`,disabled:b===`test`,onClick:()=>void R(),className:`flex items-center justify-center gap-1.5 rounded-2xl border border-border px-4 py-2.5 text-[14px] font-medium text-muted disabled:opacity-40`,children:[b===`test`?(0,K.jsx)(l,{size:16,className:`animate-spin`}):(0,K.jsx)(P,{size:16}),` `,s(`Read again`)]}),S&&(0,K.jsx)(Ue,{result:S,okText:F(S.contacts??0)})]})]})}function Q({data:e,onChange:n}){let{toast:i}=c(),a=r(),o=e.browser,[s,l]=(0,G.useState)(!1),d=async()=>{l(!0);try{await u.setBrowser(!o.enabled),n()}catch(e){i(e.message)}finally{l(!1)}};return(0,K.jsx)(A,{icon:(0,K.jsx)(ne,{size:19}),title:a(`Browser`),summary:o.available?a(`Open pages, click, fill forms, screenshot`):a(`Playwright is not installed on the server`),status:o.enabled&&o.available?{text:a(`On`),tone:`ok`}:o.enabled?{text:a(`Unavailable`),tone:`warn`}:{text:a(`Off`),tone:`off`},open:!1,trailing:(0,K.jsx)(`button`,{type:`button`,role:`switch`,"aria-checked":o.enabled,disabled:s,onClick:()=>void d(),className:t(`relative h-7 w-12 shrink-0 rounded-full transition`,o.enabled?`bg-accent`:`bg-surface-2 border border-border`),children:(0,K.jsx)(`span`,{className:t(`absolute top-0.5 h-6 w-6 rounded-full bg-white shadow transition`,o.enabled?`left-[22px]`:`left-0.5`)})}),children:!o.available&&(0,K.jsxs)(`p`,{className:`text-[12.5px] text-muted`,children:[a(`Install it where the server runs:`),` `,(0,K.jsx)(`code`,{className:`rounded bg-surface-2 px-1`,children:`pip install "nanomuse[browser]" && playwright install chromium`})]})})}function Le({data:e,onChange:n}){let{toast:i}=c(),a=r(),o=e.gui,[s,d]=(0,G.useState)(!1),[f,p]=(0,G.useState)(!1),[m,h]=(0,G.useState)(o.model),[g,_]=(0,G.useState)(o.base_url),[v,y]=(0,G.useState)(``),[b,x]=(0,G.useState)(null);(0,G.useEffect)(()=>{h(o.model),_(o.base_url)},[o.model,o.base_url]);let S=async()=>{p(!0);try{await u.setGui({enabled:!o.enabled}),n()}catch(e){i(e.message)}finally{p(!1)}},w=async()=>{p(!0),x(null);try{await u.setGui({model:m.trim(),base_url:g.trim(),...v?{api_key:v.trim()}:{}}),y(``),n(),x(await u.testGui())}catch(e){i(e.message)}finally{p(!1)}},T=o.phone,[E,k]=(0,G.useState)(R),j=(0,G.useRef)(E);(0,G.useEffect)(()=>{if(!s)return;let e=()=>{let e=R();e!==j.current&&(j.current=e,k(e),setTimeout(n,400))};return e(),document.addEventListener(`visibilitychange`,e),window.addEventListener(`focus`,e),()=>{document.removeEventListener(`visibilitychange`,e),window.removeEventListener(`focus`,e)}},[s,n]);let M=T.connected?a(`{name} is connected`,{name:T.device?.name??a(`A phone`)}):o.enabled?a(`No phone connected. Open the app on the phone`):a(`Tap, type and swipe in the apps on your phone`);return(0,K.jsxs)(A,{icon:(0,K.jsx)(L,{size:19}),title:a(`Phone`),summary:M,status:o.enabled&&T.connected?{text:a(`On`),tone:`ok`}:o.enabled?{text:a(`Waiting`),tone:`warn`}:{text:a(`Off`),tone:`off`},open:s,onToggle:()=>d(e=>!e),children:[(0,K.jsxs)(`div`,{className:`flex items-center justify-between gap-3`,children:[(0,K.jsxs)(`div`,{className:`text-[13px] leading-snug`,children:[(0,K.jsx)(`div`,{className:`font-medium`,children:a(`Operate the phone`)}),(0,K.jsx)(`div`,{className:`text-[12px] text-muted`,children:a(`When on, the agent can read the screen and act in the apps on the connected phone: 12306, WeChat, Alipay… It asks before paying, sending or deleting.`)})]}),(0,K.jsx)(`button`,{type:`button`,role:`switch`,"aria-checked":o.enabled,disabled:f,onClick:()=>void S(),className:t(`relative h-7 w-12 shrink-0 rounded-full transition`,o.enabled?`bg-accent`:`bg-surface-2 border border-border`),children:(0,K.jsx)(`span`,{className:t(`absolute top-0.5 h-6 w-6 rounded-full bg-white shadow transition`,o.enabled?`left-[22px]`:`left-0.5`)})})]}),E!==null&&(0,K.jsxs)(`div`,{className:`rounded-2xl bg-surface-2 px-3 py-2.5 text-[12.5px] leading-snug space-y-1.5`,children:[(0,K.jsxs)(`div`,{className:`flex items-center justify-between gap-3`,children:[(0,K.jsx)(`span`,{className:`font-medium`,children:a(`This phone`)}),(0,K.jsx)(`span`,{className:t(`rounded-full px-2 py-0.5 text-[11px] font-medium`,E===`on`&&`bg-emerald-500/12 text-emerald-700 dark:text-emerald-300`,E===`off`&&`bg-amber-500/15 text-amber-700 dark:text-amber-300`,E===`unsupported`&&`bg-surface text-muted`),children:a(E===`on`?`Ready`:E===`off`?`Not yet`:`Not on this Android`)})]}),E===`unsupported`&&(0,K.jsx)(`div`,{className:`text-muted`,children:a(`Operating the screen needs Android 11 or newer; this phone can still be used for everything else.`)}),E===`off`&&(0,K.jsxs)(K.Fragment,{children:[(0,K.jsx)(`div`,{className:`text-muted`,children:a(`Turn on the nanoMuse accessibility service; that is how it sees the screen and taps for you, only while a task runs, with a Stop button on screen.`)}),(0,K.jsxs)(`div`,{className:`flex flex-wrap gap-2 pt-0.5`,children:[(0,K.jsx)(`button`,{type:`button`,onClick:()=>I()?.openAccessibilitySettings?.(),className:`rounded-full bg-accent px-3 py-1.5 text-[12.5px] font-medium text-white`,children:a(`Open Accessibility settings`)}),(0,K.jsx)(`button`,{type:`button`,onClick:()=>I()?.openAppSettings?.(),className:`rounded-full border border-border px-3 py-1.5 text-[12.5px]`,children:a(`App settings`)})]}),(0,K.jsx)(`div`,{className:`text-muted`,children:a(`Greyed out with “Restricted setting”? Android 13+ does that for apps installed from a download: in App settings tap ⋮ → Allow restricted settings, then come back.`)})]}),E===`on`&&(0,K.jsx)(`div`,{className:`text-muted`,children:a(`Android may switch the service off after an update or a battery clean-up; if the phone stops answering, come back here.`)})]}),T.connected&&T.device&&(0,K.jsxs)(`div`,{className:`rounded-2xl bg-surface-2 px-3 py-2 text-[12.5px] text-muted`,children:[a(`{name} ({platform}), {n} apps`,{name:T.device.name,platform:T.device.platform,n:String(T.device.apps)}),T.last_screen&&(0,K.jsxs)(K.Fragment,{children:[` `,`·`,` `,a(`last seen in {app}`,{app:T.last_screen.app_name||T.last_screen.app})]})]}),(0,K.jsx)(`div`,{className:`text-[12px] text-muted leading-snug`,children:a(`The operator's model looks at screens step by step: a small, fast model that takes pictures. The Hands model row under Chat model picks one on the same endpoint and key; the fields here are for a different endpoint. Empty = {model}.`,{model:o.default_model||a(`the chat model`)})}),(0,K.jsx)($,{label:a(`Model`),children:(0,K.jsx)(`input`,{value:m,onChange:e=>h(e.target.value),placeholder:o.default_model||a(`same as the chat model`),className:O})}),(0,K.jsx)($,{label:a(`Base URL`),children:(0,K.jsx)(`input`,{value:g,onChange:e=>_(e.target.value),placeholder:a(`same as the chat model`),className:O})}),(0,K.jsx)($,{label:a(`API key`),hint:o.key_source===`vault`?a(`A key is in the vault; leave empty to keep it.`):o.key_source===`config`?a(`Set in config.toml.`):a(`Leave empty to use the main model's key.`),children:(0,K.jsx)(`input`,{type:`password`,value:v,onChange:e=>y(e.target.value),placeholder:`sk-…`,className:O,autoComplete:`off`})}),(0,K.jsxs)(`button`,{type:`button`,disabled:f,onClick:()=>void w(),className:D,children:[f?(0,K.jsx)(l,{size:16,className:`animate-spin`}):(0,K.jsx)(C,{size:16}),a(`Save and test`)]}),b&&(0,K.jsx)(Ue,{result:b,okText:a(`The operator's model answers.`)})]})}function Re({data:e,onChange:n}){let{toast:i}=c(),a=r(),[o,s]=(0,G.useState)(!1),[d,f]=(0,G.useState)(!1),[p,m]=(0,G.useState)(``),[h,g]=(0,G.useState)(``),[_,v]=(0,G.useState)(``),[y,b]=(0,G.useState)(`moderate`),[x,S]=(0,G.useState)(null),C=async()=>{S(`add`);try{let e=h.trim().split(/\s+/).filter(Boolean);await u.addMCP({name:p.trim(),command:e[0]??null,args:e.slice(1),url:_.trim()||null,risk:y}),m(``),g(``),v(``),f(!1),i(a(`Server connected`)),n()}catch(e){i(e.message)}finally{S(null)}},w=async e=>{S(e);try{await u.removeMCP(e),n()}catch(e){i(e.message)}finally{S(null)}},E=e.mcp.filter(e=>e.connected).length,k=(e.shared??[]).filter(e=>e.enabled&&!e.here),j=e=>{m(e.id),v(e.url),g(``),f(!0),s(!0)};return(0,K.jsxs)(A,{icon:(0,K.jsx)(N,{size:19}),title:a(`MCP servers`),summary:e.mcp.length?a(`{n} of {total} connected · {tools} tools`,{n:E,total:e.mcp.length,tools:e.mcp.reduce((e,t)=>e+t.tools,0)}):a(`Add tools from any Model Context Protocol server`),status:e.mcp.length?{text:a(`{n} on`,{n:E}),tone:E?`ok`:`warn`}:{text:a(`None`),tone:`off`},open:o,onToggle:()=>s(!o),children:[e.mcp.length>0&&(0,K.jsx)(`ul`,{className:`space-y-1.5`,children:e.mcp.map(e=>(0,K.jsxs)(`li`,{className:`flex items-center gap-2.5 rounded-2xl bg-surface-2/60 px-3 py-2`,children:[(0,K.jsx)(`span`,{className:t(`h-2 w-2 rounded-full`,e.connected?`bg-emerald-500`:`bg-rose-500`)}),(0,K.jsxs)(`div`,{className:`min-w-0 flex-1`,children:[(0,K.jsx)(`div`,{className:`text-[13.5px] font-medium truncate`,children:e.builtin?a(`This phone`):e.name}),(0,K.jsxs)(`div`,{className:`text-[11.5px] text-muted truncate`,children:[e.builtin?a(`clipboard, notifications, calendar, contacts, location, alarms, photos`):e.url??[e.command,...e.args].join(` `),` ·`,` `,a(`{n} tools`,{n:e.tools}),` · `,a(e.risk),!e.from_app&&!e.builtin&&` · ${a(`from config.toml`)}`]})]}),e.from_app&&(0,K.jsx)(`button`,{type:`button`,"aria-label":a(`Remove`),disabled:x===e.name,onClick:()=>void w(e.name),className:`p-1.5 rounded-full text-muted hover:bg-surface-2`,children:x===e.name?(0,K.jsx)(l,{size:15,className:`animate-spin`}):(0,K.jsx)(z,{size:15})})]},e.name))}),k.length>0&&(0,K.jsx)(`ul`,{className:`space-y-1.5`,children:k.map(e=>(0,K.jsxs)(`li`,{className:`flex items-center gap-2.5 rounded-2xl border border-dashed border-border/70 px-3 py-2`,children:[(0,K.jsx)(`span`,{className:`h-2 w-2 rounded-full bg-border`}),(0,K.jsxs)(`div`,{className:`min-w-0 flex-1`,children:[(0,K.jsx)(`div`,{className:`text-[13.5px] font-medium truncate`,children:e.label||e.id}),(0,K.jsxs)(`div`,{className:`text-[11.5px] text-muted truncate`,children:[a(`Connected on {device}; sign in here to use it on this device`,{device:e.device||e.device_id}),e.url?` · ${e.url}`:``]})]}),e.url&&(0,K.jsx)(`button`,{type:`button`,onClick:()=>j(e),className:t(`flex items-center justify-center gap-1.5 rounded-2xl border border-border px-4 py-2.5 text-[14px] font-medium text-muted disabled:opacity-40`,`py-1.5 text-[12.5px]`),children:a(`Sign in here`)})]},`${e.device_id}:${e.id}`))}),d?(0,K.jsxs)(`div`,{className:`space-y-2.5 rounded-2xl border border-border/70 p-3`,children:[(0,K.jsx)($,{label:a(`Name`),children:(0,K.jsx)(`input`,{value:p,onChange:e=>m(e.target.value),className:O,placeholder:`filesystem`})}),(0,K.jsx)($,{label:a(`Command`),hint:a(`Run locally over stdio, for example: npx -y @modelcontextprotocol/server-filesystem ./workspace`),children:(0,K.jsx)(`input`,{value:h,onChange:e=>g(e.target.value),className:O,placeholder:`npx -y @modelcontextprotocol/server-…`})}),(0,K.jsx)($,{label:a(`or URL`),hint:a(`A remote server over Streamable HTTP.`),children:(0,K.jsx)(`input`,{value:_,onChange:e=>v(e.target.value),className:O,placeholder:`https://host/mcp`,inputMode:`url`})}),(0,K.jsx)($,{label:a(`Risk of its tools`),hint:a(`Decides when the Sentinel asks you before a call.`),children:(0,K.jsx)(`div`,{className:`flex gap-1.5`,children:[`safe`,`moderate`,`high`].map(e=>(0,K.jsx)(`button`,{type:`button`,onClick:()=>b(e),className:t(`rounded-full px-3 py-1.5 text-[13px] border`,y===e?`border-accent bg-accent/10 text-accent font-medium`:`border-border text-muted`),children:a(e)},e))})}),(0,K.jsxs)(`div`,{className:`flex gap-2`,children:[(0,K.jsxs)(`button`,{type:`button`,disabled:x===`add`||!p.trim()||!(h.trim()||_.trim()),onClick:()=>void C(),className:D,children:[x===`add`?(0,K.jsx)(l,{size:16,className:`animate-spin`}):(0,K.jsx)(N,{size:16}),` `,a(`Connect`)]}),(0,K.jsx)(`button`,{type:`button`,onClick:()=>f(!1),className:T,children:a(`Cancel`)})]})]}):(0,K.jsxs)(`button`,{type:`button`,onClick:()=>f(!0),className:T,children:[(0,K.jsx)(V,{size:16}),` `,a(`Add a server`)]})]})}function ze({data:e,onChange:n}){let{toast:i}=c(),a=r(),[o,s]=(0,G.useState)(!1),[d,f]=(0,G.useState)(``),[p,m]=(0,G.useState)(``),[h,g]=(0,G.useState)(null),_=async()=>{g(`add`);try{await u.vaultSet(d.trim(),p),f(``),m(``),i(a(`Stored in the vault`)),n()}catch(e){i(e.message)}finally{g(null)}},v=async e=>{g(e);try{await u.vaultDelete(e),n()}catch(e){i(e.message)}finally{g(null)}};return(0,K.jsxs)(A,{icon:(0,K.jsx)(ie,{size:19}),title:a(`Vault`),summary:e.vault.length?a(`{n} secrets · encrypted on your machine`,{n:e.vault.length}):a(`Encrypted secrets the model never sees`),status:{text:`${e.vault.length}`,tone:`off`},open:o,onToggle:()=>s(!o),children:[(0,K.jsxs)(`p`,{className:`text-[12.5px] text-muted -mt-1`,children:[a(`Refer to a secret as`),` `,(0,K.jsx)(`code`,{className:`rounded bg-surface-2 px-1`,children:`{{vault:NAME}}`}),` `,a(`in a tool call or config: the value is filled in after the Sentinel approves and is redacted from everything the model reads.`)]}),e.vault.length>0&&(0,K.jsx)(`ul`,{className:`flex flex-wrap gap-1.5`,children:e.vault.map(e=>(0,K.jsxs)(`li`,{className:`flex items-center gap-1 rounded-full bg-surface-2 pl-3 pr-1 py-1 text-[12.5px] font-mono`,children:[e,(0,K.jsx)(`button`,{type:`button`,"aria-label":a(`Delete {name}`,{name:e}),disabled:h===e,onClick:()=>void v(e),className:`p-1 rounded-full text-muted hover:text-rose-500`,children:h===e?(0,K.jsx)(l,{size:13,className:`animate-spin`}):(0,K.jsx)(z,{size:13})})]},e))}),(0,K.jsxs)(`div`,{className:`grid grid-cols-[1fr_1fr_auto] gap-2 items-end`,children:[(0,K.jsx)($,{label:a(`Name`),children:(0,K.jsx)(`input`,{value:d,onChange:e=>f(e.target.value.toUpperCase().replace(/[^A-Z0-9_.-]/g,`_`)),className:t(O,`font-mono`),placeholder:`GITHUB_TOKEN`})}),(0,K.jsx)($,{label:a(`Value`),children:(0,K.jsx)(`input`,{type:`password`,value:p,onChange:e=>m(e.target.value),className:O,placeholder:a(`secret`),autoComplete:`off`})}),(0,K.jsx)(`button`,{type:`button`,disabled:h===`add`||!d||!p,onClick:()=>void _(),className:t(D,`px-3`),"aria-label":a(`Store`),children:h===`add`?(0,K.jsx)(l,{size:16,className:`animate-spin`}):(0,K.jsx)(V,{size:16})})]})]})}var Be=`\0other`;function Ve({label:e,provider:n,value:i,options:a,more:o=[],onChange:s,other:c=!0,placeholder:l}){let u=r(),d=a.includes(i)||o.includes(i),[f,p]=(0,G.useState)(!1),m=l?u(`Automatic · {model}`,{model:l}):u(`Automatic`),h=e=>e.map(e=>({id:e,name:e})),g=o.length?[{key:`menu`,label:u(`Menu`),rows:h(a),...l?{default:l}:{}},{key:`more`,label:u(`More models on your account`),rows:h(o)}]:[{key:`list`,label:n,rows:h(a),...l?{default:l}:{}}],_=i&&d?{group:a.includes(i)?g[0].key:`more`,id:i}:void 0;return(0,K.jsxs)(`div`,{className:`block text-[12.5px] text-muted`,children:[(0,K.jsx)(`span`,{className:`block mb-1`,children:e}),(a.length||o.length)&&(d||!i)&&!f?(0,K.jsx)(ve,{label:e,text:i?`${n} · ${i}`:m,heads:[{value:``,label:m}],headValue:i?void 0:``,groups:g,current:_,onHead:()=>s(``),onPick:(e,t)=>s(t.id),tail:c?u(`Other model…`):void 0,onTail:()=>{p(!0),s(``)}}):(0,K.jsx)(`input`,{value:i,onChange:e=>s(e.target.value),placeholder:m,"aria-label":e,className:t(O,`text-fg`),spellCheck:!1})]})}function He(){let e=r();return(0,K.jsxs)(`a`,{href:H,target:`_blank`,rel:`noopener noreferrer`,className:`inline-flex items-center gap-0.5 text-accent`,children:[e(`How`),` `,(0,K.jsx)(w,{size:11})]})}function $({label:e,hint:t,children:n}){return(0,K.jsxs)(`div`,{children:[(0,K.jsx)(`label`,{className:`text-[12px] text-muted`,children:e}),(0,K.jsx)(`div`,{className:`mt-1`,children:n}),t&&(0,K.jsx)(`div`,{className:`mt-1 text-[11.5px] text-muted leading-snug`,children:t})]})}function Ue({result:e,okText:n}){let i=r(),[a,o]=(0,G.useState)(!1),s=!e.ok&&e.detail&&e.detail!==e.error?e.detail:null;return(0,K.jsxs)(`div`,{className:t(`rounded-2xl px-3 py-2 text-[12.5px]`,e.ok?`bg-emerald-500/12 text-emerald-700 dark:text-emerald-300`:`bg-rose-500/12 text-rose-700 dark:text-rose-300`),children:[e.ok?n:i(e.error??`The model provider did not answer.`),s&&(0,K.jsxs)(K.Fragment,{children:[` `,(0,K.jsx)(`button`,{type:`button`,onClick:()=>o(e=>!e),className:`underline decoration-dotted underline-offset-2 opacity-70 hover:opacity-100`,children:i(a?`Hide details`:`Details`)}),a&&(0,K.jsx)(`div`,{className:`mt-1.5 break-all font-mono text-[11px] opacity-80`,children:s})]})]})}function We(e){try{return new URL(e).host}catch{return e}}export{Fe as CalendarCard,Oe as ConnectionsScreen,Ie as ContactsCard,Ne as EmailCard,Z as ModelCard}; \ No newline at end of file diff --git a/nanomuse/server/static/assets/ConnectionsScreen-DzFdAyKl.js b/nanomuse/server/static/assets/ConnectionsScreen-DzFdAyKl.js new file mode 100644 index 000000000..2227a3d74 --- /dev/null +++ b/nanomuse/server/static/assets/ConnectionsScreen-DzFdAyKl.js @@ -0,0 +1 @@ +import{A as e,E as t,J as n,K as r,L as i,Q as a,Y as o,b as s,f as c,q as l,x as u}from"./MuseHeader-BDWXHKHT.js";import{C as d,O as f,S as p,b as m,f as h,g,h as _,k as v,m as y,v as b,w as x,x as S}from"./StarNudge-B8P2bPEz.js";import{n as C,t as w}from"./external-link-CZH-rQLq.js";import{a as T,c as E,i as D,r as O,s as k,t as A}from"./Form-B3Ejw5aI.js";import{t as j}from"./clapperboard-C1_tjTS2.js";import{t as M}from"./image-kcW5PNCE.js";import{t as N}from"./plug-Cn-mgW7a.js";import{t as P}from"./refresh-cw-qw351CFk.js";import{Ct as F,E as I,G as L,N as ee,P as R,T as te,V as z,X as B,Z as ne,j as V,lt as re,pt as H,st as ie,ut as ae,xt as oe}from"./index-DKrXW2Qj.js";import{t as se}from"./BackBar-DqcCClHf.js";import{t as ce}from"./CloudCard-B2Mi7bjZ.js";var le=n(`brain-circuit`,[[`path`,{d:`M12 5a3 3 0 1 0-5.997.125 4 4 0 0 0-2.526 5.77 4 4 0 0 0 .556 6.588A4 4 0 1 0 12 18Z`,key:`l5xja`}],[`path`,{d:`M9 13a4.5 4.5 0 0 0 3-4`,key:`10igwf`}],[`path`,{d:`M6.003 5.125A3 3 0 0 0 6.401 6.5`,key:`105sqy`}],[`path`,{d:`M3.477 10.896a4 4 0 0 1 .585-.396`,key:`ql3yin`}],[`path`,{d:`M6 18a4 4 0 0 1-1.967-.516`,key:`2e4loj`}],[`path`,{d:`M12 13h4`,key:`1ku699`}],[`path`,{d:`M12 18h6a2 2 0 0 1 2 2v1`,key:`105ag5`}],[`path`,{d:`M12 8h8`,key:`1lhi5i`}],[`path`,{d:`M16 8V5a2 2 0 0 1 2-2`,key:`u6izg6`}],[`circle`,{cx:`16`,cy:`13`,r:`.5`,key:`ry7gng`}],[`circle`,{cx:`18`,cy:`3`,r:`.5`,key:`1aiba7`}],[`circle`,{cx:`20`,cy:`21`,r:`.5`,key:`yhc1fs`}],[`circle`,{cx:`20`,cy:`8`,r:`.5`,key:`1e43v0`}]]),ue=n(`contact`,[[`path`,{d:`M16 2v2`,key:`scm5qe`}],[`path`,{d:`M7 22v-2a2 2 0 0 1 2-2h6a2 2 0 0 1 2 2v2`,key:`1waht3`}],[`path`,{d:`M8 2v2`,key:`pbkmx`}],[`circle`,{cx:`12`,cy:`11`,r:`3`,key:`itu57m`}],[`rect`,{x:`3`,y:`4`,width:`18`,height:`18`,rx:`2`,key:`12vinp`}]]),de=n(`eye-off`,[[`path`,{d:`M10.733 5.076a10.744 10.744 0 0 1 11.205 6.575 1 1 0 0 1 0 .696 10.747 10.747 0 0 1-1.444 2.49`,key:`ct8e1f`}],[`path`,{d:`M14.084 14.158a3 3 0 0 1-4.242-4.242`,key:`151rxh`}],[`path`,{d:`M17.479 17.499a10.75 10.75 0 0 1-15.417-5.151 1 1 0 0 1 0-.696 10.75 10.75 0 0 1 4.446-5.143`,key:`13bj9a`}],[`path`,{d:`m2 2 20 20`,key:`1ooewy`}]]),fe=n(`eye`,[[`path`,{d:`M2.062 12.348a1 1 0 0 1 0-.696 10.75 10.75 0 0 1 19.876 0 1 1 0 0 1 0 .696 10.75 10.75 0 0 1-19.876 0`,key:`1nclc0`}],[`circle`,{cx:`12`,cy:`12`,r:`3`,key:`1v7zrd`}]]),U=n(`unplug`,[[`path`,{d:`m19 5 3-3`,key:`yk6iyv`}],[`path`,{d:`m2 22 3-3`,key:`19mgm9`}],[`path`,{d:`M6.3 20.3a2.4 2.4 0 0 0 3.4 0L12 18l-6-6-2.3 2.3a2.4 2.4 0 0 0 0 3.4Z`,key:`goz73y`}],[`path`,{d:`M7.5 13.5 10 11`,key:`7xgeeb`}],[`path`,{d:`M10.5 16.5 13 14`,key:`10btkg`}],[`path`,{d:`m12 6 6 6 2.3-2.3a2.4 2.4 0 0 0 0-3.4l-2.6-2.6a2.4 2.4 0 0 0-3.4 0Z`,key:`1snsnr`}]]),W=n(`upload`,[[`path`,{d:`M12 3v12`,key:`1x0j5s`}],[`path`,{d:`m17 8-5-5-5 5`,key:`7q97r8`}],[`path`,{d:`M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4`,key:`ih7n3h`}]]),G=a(o(),1);function pe(e,t){let n=t.trim().toLowerCase();return!n||e.id.toLowerCase().includes(n)||e.name.toLowerCase().includes(n)}function K(e,t){let n=e.default&&e.rows.some(t=>t.id===e.default)?e.default:e.rows.find(e=>e.recommended)?.id,r=t&&t.group===e.key?t.id:void 0,i=[];for(let t of[n,r]){if(!t||i.some(e=>e.id===t))continue;let n=e.rows.find(e=>e.id===t);n&&i.push(n)}return[...i,...e.rows.filter(e=>!i.includes(e))]}function me(e){return e.reduce((e,t)=>e+t.rows.length,0)}function he(e){return me(e)>8}function ge(e,{current:t,query:n=``,expanded:r}={}){let i=n.trim().length>0,a=[];for(let o of e){let e=K(o,t);if(i){let t=e.filter(e=>pe(e,n));t.length&&a.push({key:o.key,label:o.label,rows:t,more:0});continue}e.length>8&&!r?.has(o.key)?a.push({key:o.key,label:o.label,rows:e.slice(0,8),more:e.length-8}):a.push({key:o.key,label:o.label,rows:e,more:0})}return a}var q=s(),_e=`flex w-full items-center gap-2 rounded-xl px-3 py-2 text-left text-[14px] hover:bg-surface-2 focus:bg-surface-2 focus:outline-none`;function ve({label:e,text:n,heads:i=[],headValue:a,tail:o,groups:s,current:c,disabled:l,onHead:u,onPick:d,onTail:f,rowText:p}){let m=r(),[h,g]=(0,G.useState)(!1),[_,v]=(0,G.useState)(``),[y,b]=(0,G.useState)(()=>new Set),[x,S]=(0,G.useState)(!1),w=(0,G.useRef)(null),T=(0,G.useRef)(null),D=he(s),k=(0,G.useCallback)((e=!1)=>{g(!1),v(``),b(new Set),S(e)},[]);(0,G.useEffect)(()=>{!h&&x&&(S(!1),w.current?.focus())},[h,x]),(0,G.useEffect)(()=>{if(!h)return;let e=e=>{let t=e.target;T.current?.contains(t)||w.current?.contains(t)||k()},t=e=>{e.key===`Escape`&&(e.stopPropagation(),k(!0))};return document.addEventListener(`pointerdown`,e,!0),document.addEventListener(`keydown`,t,!0),()=>{document.removeEventListener(`pointerdown`,e,!0),document.removeEventListener(`keydown`,t,!0)}},[h,k]),(0,G.useEffect)(()=>{h&&T.current&&(T.current.querySelector(`input`)??T.current.querySelector(`[aria-selected="true"]`)??T.current.querySelector(`[data-row]`))?.focus()},[h]);let A=e=>{if(e.key!==`ArrowDown`&&e.key!==`ArrowUp`)return;let t=[...e.currentTarget.closest(`[role="listbox"]`)?.querySelectorAll(`[data-row]`)??[]];if(!t.length)return;e.preventDefault();let n=t.indexOf(e.target);t[e.key===`ArrowDown`?n<0?0:Math.min(t.length-1,n+1):n<0?t.length-1:Math.max(0,n-1)]?.focus()},j=ge(s,{current:c,query:_,expanded:y}),M=_.trim().length>0,N=(e,n,r,i,a)=>(0,q.jsxs)(`button`,{type:`button`,role:`option`,"aria-selected":n,"data-row":``,title:a,onClick:i,onKeyDown:A,className:t(_e,n&&`text-accent font-medium`),children:[(0,q.jsx)(`span`,{className:`min-w-0 flex-1 truncate`,children:r}),n&&(0,q.jsx)(C,{size:15,className:`shrink-0`})]},e);return(0,q.jsxs)(`div`,{className:`relative`,children:[(0,q.jsxs)(`button`,{ref:w,type:`button`,disabled:l,"aria-label":e,"aria-haspopup":`listbox`,"aria-expanded":h,title:n,onClick:()=>h?k():g(!0),className:t(O,`flex items-center gap-2 text-left text-fg disabled:opacity-50`),children:[(0,q.jsx)(`span`,{className:`min-w-0 flex-1 truncate`,children:n}),(0,q.jsx)(E,{size:16,className:`shrink-0 text-muted`})]}),h&&(0,q.jsxs)(`div`,{ref:T,role:`listbox`,"aria-label":e,className:`absolute left-0 right-0 top-full z-30 mt-1 flex max-h-[60vh] flex-col overflow-hidden rounded-2xl border border-border bg-surface p-1.5 shadow-xl`,children:[i.length>0&&(0,q.jsx)(`div`,{className:`mb-1 flex flex-col border-b border-border pb-1`,children:i.map(e=>N(`head:${e.value}`,a===e.value,e.label,()=>{u?.(e.value),k(!0)}))}),D&&(0,q.jsxs)(`label`,{className:`mb-1.5 flex items-center gap-2 rounded-xl bg-surface-2 px-3 py-2 text-muted focus-within:ring-2 focus-within:ring-accent/40`,children:[(0,q.jsx)(B,{size:15,className:`shrink-0`}),(0,q.jsx)(`input`,{type:`search`,value:_,onChange:e=>v(e.target.value),onKeyDown:A,placeholder:m(`Search models`),"aria-label":m(`Search models`),autoComplete:`off`,spellCheck:!1,className:`min-w-0 flex-1 bg-transparent text-[14px] text-fg outline-none placeholder:text-muted`})]}),(0,q.jsxs)(`div`,{className:`min-h-0 flex-1 overflow-y-auto`,children:[M&&j.length===0&&(0,q.jsx)(`div`,{className:`px-3 py-2.5 text-[13.5px] text-muted`,children:m(`No model matches`)}),j.map(e=>(0,q.jsxs)(`div`,{role:`group`,"aria-label":e.label,className:`[&+&]:mt-1.5`,children:[(0,q.jsx)(`div`,{className:`truncate px-3 pb-0.5 pt-1.5 text-[11px] font-semibold uppercase tracking-wide text-muted`,children:e.label}),e.rows.map(t=>N(`${e.key}:${t.id}`,c?.group===e.key&&c.id===t.id,p?p(t):t.name,()=>{d(e.key,t),k(!0)},t.id)),e.more>0&&(0,q.jsx)(`button`,{type:`button`,"data-row":``,onKeyDown:A,onClick:()=>b(t=>new Set([...t,e.key])),className:t(_e,`text-[13px] text-accent`),children:m(`Show {n} more`,{n:e.more})})]},e.key))]}),o&&!M&&(0,q.jsx)(`div`,{className:`mt-1 border-t border-border pt-1`,children:N(`tail`,!1,o,()=>{f?.(),k(!0)})})]})]})}var ye=`nanomuse_cloud`,be=`{{vault:NANOMUSE_CLOUD_KEY}}`,xe=`custom`,Se=`endpoint:`,Ce=[`openai`,`openai_responses`];function we(e){try{return new URL(e).hostname.toLowerCase()}catch{return``}}function Te(e){return Se+e}function Ee(e){return e.startsWith(`endpoint:`)&&e.length>9?e.slice(9):null}function De(e){if(e.label.trim())return e.label.trim();try{return new URL(e.base_url).host}catch{return e.base_url}}function J(e,t){return e?t.find(t=>t.id===e)??null:null}function Oe(e,t=``){return e.filter(e=>e.id!==t&&e.models.length).map(e=>({key:Te(e.id),label:De(e),rows:e.models.filter(e=>f(e)!==!1).map(e=>({id:e,name:e}))})).filter(e=>e.rows.length)}function ke(e,t,n=h){if(e&&!Ce.includes(e))return n.find(t=>t.id===e)??null;let r=we(t);if(!r)return null;let i=e=>[e.base_url,e.base_url_global].map(e=>we(e??``)).filter(Boolean);return n.find(e=>i(e).includes(r))||(n.find(e=>i(e).some(e=>{let t=e.indexOf(`.`);return t>0&&r.endsWith(e.slice(t))}))??null)}function Ae(e,t,n=``,r=h){if(e===`nanomuse_cloud`)return`nanoMuse Cloud`;if(e===`chatgpt`)return`ChatGPT`;let i=r.find(t=>t.id===e);return i&&e!==`custom`?S(i,t):we(n)||e}function je(e,t,n=h,r=[]){if(!e.effective_provider)return``;let i=J(e.endpoint,r),a=i?De(i):Ae(e.effective_provider,t,e.base_url,n);return e.effective_model?`${a} · ${e.effective_model}`:a}function Me(e,t,n,r=h,i=[]){let a=e.effective_model??``;if(!a)return``;let o=(e,t)=>Ae(ke(e,t,r)?.id??(Ce.includes(e)?`custom`:e),n,t,r),s,c=J(e.endpoint,i),l=J(t.endpoint,i);return s=e.effective_source===`cloud`?`nanoMuse Cloud`:e.effective_source===`gui`&&c?De(c):e.effective_source===`gui`&&(e.provider_id||e.base_url||!Ce.includes(e.provider||`openai`))?e.provider_id?Ae(e.provider_id,n,e.base_url,r):o(e.provider,e.base_url):t.cloud?`nanoMuse Cloud`:l?De(l):o(t.provider,t.base_url),`${s} · ${a}`}function Y(e,t){let n=t.list??h,r=[];t.signedIn&&r.push({value:ye,label:`nanoMuse Cloud`,group:`cloud`,needsKey:!1,entry:null});let i=t.chat.cloud?null:ke(t.chat.provider,t.chat.base_url,n);i&&i.capabilities.includes(e)&&r.push({value:i.id,label:S(i,t.locale),group:`chat`,needsKey:!1,entry:i});for(let e of t.endpoints??[])r.push({value:Te(e.id),label:De(e),group:`endpoints`,needsKey:!1,entry:null});for(let a of p(t.region,e,n))a.id!==i?.id&&r.push({value:a.id,label:S(a,t.locale),group:`add`,needsKey:!0,entry:a});return r.push({value:xe,label:``,group:`add`,needsKey:!1,entry:null}),r}function Ne(e,t){return e.configured?t&&e.base_url&&we(e.base_url)===we(t)?ye:e.endpoint?Te(e.endpoint):e.provider_id||`custom`:``}var Pe=`nanomuse_cloud`,Fe=`add-endpoint`;function Ie(){let{state:e}=c(),[t,n]=(0,G.useState)(null),[i,a]=(0,G.useState)(null),o=e.profile?.name??`nanoMuse`,s=r(),d=(0,G.useCallback)(async()=>{try{n(await u.connections()),a(null)}catch(e){a(s(e.message))}},[s]);return(0,G.useEffect)(()=>{d()},[d,e.connectionsVersion]),(0,q.jsxs)(`div`,{className:`flex h-full flex-col`,children:[(0,q.jsx)(se,{title:s(`Connections`),description:s(`What {name} can reach; keys stay in the vault on this machine.`,{name:o})}),(0,q.jsxs)(`div`,{className:`flex-1 overflow-y-auto px-4 pb-8 space-y-4`,children:[i&&(0,q.jsx)(`div`,{className:`rounded-2xl bg-rose-500/12 text-rose-700 dark:text-rose-300 p-3 text-[13.5px]`,children:i}),!t&&!i&&(0,q.jsx)(`div`,{className:`flex justify-center py-10 text-muted`,children:(0,q.jsx)(l,{className:`animate-spin`,size:20})}),t&&(0,q.jsxs)(q.Fragment,{children:[(0,q.jsx)(Le,{data:t,onChange:d}),t.image&&(0,q.jsx)(Ve,{slot:`image`,data:t,onChange:d}),t.video&&(0,q.jsx)(Ve,{slot:`video`,data:t,onChange:d}),(0,q.jsx)(ce,{account:e.hub?.account??null,onChange:d}),t.embeddings.memory_enabled&&(0,q.jsx)(X,{data:t,onChange:d}),(0,q.jsx)(Z,{data:t,onChange:d}),(0,q.jsx)(Ue,{data:t,onChange:d}),(0,q.jsx)(Ge,{data:t,onChange:d}),(0,q.jsx)(Ke,{data:t,onChange:d}),(0,q.jsx)(qe,{data:t,onChange:d}),(0,q.jsx)(Je,{data:t,onChange:d}),(0,q.jsx)(Ye,{data:t,onChange:d}),(0,q.jsx)(Xe,{data:t,onChange:d})]})]})]})}function Le({data:e,onChange:n,compact:a}){let{toast:o,state:s}=c(),p=r(),[m,g]=(0,G.useState)(!!a),T=e.providers,D=e.endpoints??[],O=e.endpoints!==void 0,j=D.find(t=>t.id===e.llm.endpoint)??null,M=!!s.hub?.account?.any_model,P=(j?Te(j.id):null)??Object.entries(T).find(([t,n])=>t!==`custom`&&n.base_url&&e.llm.base_url.startsWith(n.base_url)&&n.provider===e.llm.provider)?.[0]??Object.entries(T).find(([t,n])=>t!==`custom`&&n.base_url&&e.llm.base_url.startsWith(n.base_url))?.[0]??(e.llm.base_url?`custom`:`deepseek`),I=e=>{if(e===Fe)return{label:p(`Add an endpoint`),subtitle:T.custom?.subtitle,group:`local`,provider:`openai`,base_url:``,key_optional:!0};let t=Ee(e);if(!t)return T[e];let n=D.find(e=>e.id===t);return n?{label:De(n),group:`local`,provider:`openai`,base_url:n.base_url,models:n.models,no_key:!0}:void 0},[L,te]=(0,G.useState)(P),z=(0,G.useRef)(``),[B,V]=(0,G.useState)(e.llm.model),[H,ie]=(0,G.useState)(e.llm.base_url),[ae,oe]=(0,G.useState)(``),[se,ce]=(0,G.useState)(!1),[le,ue]=(0,G.useState)(!1),[U,W]=(0,G.useState)(e.llm.key_source===`none`&&!!T[P]?.key_optional),[pe,K]=(0,G.useState)(e.llm.tool_mode||`auto`),[me,he]=(0,G.useState)(e.llm.proxy??``),[ge,_e]=(0,G.useState)(!1),[ye,be]=(0,G.useState)(!1),[xe,Se]=(0,G.useState)(null),[Ce,we]=(0,G.useState)(!1),[J,ke]=(0,G.useState)(e.gui?.model??``),[Ae,je]=(0,G.useState)(e.gui?.endpoint??``),[Y,Ne]=(0,G.useState)({list:I(P)?.models??[],image:[],video:[],menu:[],catalog:[],imageCatalog:[],videoCatalog:[],vision:[],gui:T[P]?.gui_models??[],source:`catalogue`}),[Ie,Le]=(0,G.useState)(!1),[Re,Ve]=(0,G.useState)(!1);(0,G.useEffect)(()=>{V(e.llm.model),ie(e.llm.base_url),K(e.llm.tool_mode||`auto`),he(e.llm.proxy??``),_e(!1),ke(e.gui?.model??``),je(e.gui?.endpoint??``);let t=D.find(e=>e.id===z.current);if(t){z.current=``,te(Te(t.id)),ie(t.base_url),t.models.includes(e.llm.model)||V(t.models[0]??``),Le(!1);return}te(P)},[e.llm,e.gui?.model,e.gui?.endpoint,e.endpoints]);let X=I(L),Z=D.find(e=>Te(e.id)===L)??null,He=L===Fe,Ue=L===`custom`||!X?.base_url?H:X.base_url;(0,G.useEffect)(()=>{if(!m||He)return;let e=!0,t=setTimeout(()=>{Ne(e=>({...e,source:`loading`})),u.llmModels(Z?{endpoint:Z.id}:{preset:L,base_url:Ue,api_key:ae||void 0}).then(t=>{e&&(Ne({list:t.models,image:t.image_models??[],video:t.video_models??[],menu:t.menu??[],catalog:t.catalog??[],imageCatalog:t.image_catalog??[],videoCatalog:t.video_catalog??[],vision:t.vision??[],gui:t.gui??T[L]?.gui_models??[],source:t.source}),t.source===`live`&&t.models.length&&!Ie&&V(e=>t.models.includes(e)?e:t.models[0]))}).catch(()=>e&&Ne({list:X?.models??[],image:[],video:[],menu:[],catalog:[],imageCatalog:[],videoCatalog:[],vision:[],gui:X?.gui_models??[],source:`catalogue`}))},ae?600:150);return()=>{e=!1,clearTimeout(t)}},[m,L,Ue,ae]);let We=t=>{te(t);let n=I(t);n&&(n.base_url?ie(n.base_url):X?.base_url&&ie(``),(!B||Object.values(T).some(e=>e.models?.includes(B))||D.some(e=>e.models.includes(B)))&&n.models?.length&&!n.models.includes(B)&&V(n.models[0]),Ne({list:n.models??[],image:[],video:[],menu:[],catalog:[],imageCatalog:[],videoCatalog:[],vision:[],gui:n.gui_models??[],source:`catalogue`}),(!e.gui?.model||Object.values(T).some(t=>t.gui_model===e.gui?.model))&&ke(n.cloud?``:n.gui_model??``),Ve(!1),Le(!1),W(!1))};(0,G.useEffect)(()=>{let e=ee();e&&T[e]&&(g(!0),We(e))},[]);let Ge=!!X?.no_key||U&&!!X?.key_optional,Ke=e.llm.cloud?{text:p(`Your account's model`),tone:`ok`}:e.llm.key_source===`none`&&j?{text:p(`No key`),tone:`ok`}:e.llm.key_source===`none`&&!T[P]?.no_key&&!T[P]?.key_optional?{text:p(`No key yet`),tone:`warn`}:e.llm.key_source===`missing`?{text:p(`Key missing from vault`),tone:`warn`}:{text:e.llm.key_source===`vault`?p(`Key in vault`):e.llm.key_source===`config`?p(`Key from config`):p(`No key needed`),tone:`ok`},qe=async()=>{be(!0),Se(null);try{X?.cloud?await u.cloudUseAsModel(B.trim()):Z?await u.setLLM({endpoint:Z.id,model:B.trim(),tool_mode:pe,proxy:ge&&e.llm.proxy!==void 0?me.trim():null}):await u.setLLM({provider:X?.provider??`openai`,model:B.trim(),base_url:Ue.trim(),tool_mode:pe,api_key:ae||(Ge?``:null),proxy:ge&&e.llm.proxy!==void 0?me.trim():null});let t={model:e.gui?.model??``,endpoint:e.gui?.endpoint??``};(J.trim()!==t.model||Ae!==t.endpoint)&&(Ae?await u.setGui({endpoint:Ae,model:J.trim()}):t.endpoint?await u.setGui({model:J.trim(),provider:``,base_url:``,api_key:``}):await u.setGui({model:J.trim()})),oe(``),b(),o(p(`Model saved`)),n(),a||g(!1)}catch(e){o(e.message)}finally{be(!1)}},Je=async()=>{we(!0);try{Se(await u.testLLM())}catch(e){Se({ok:!1,error:e.message})}finally{we(!1)}},Ye=[{id:`cloud`,title:p(`Your account`),ids:[]},{id:`openai`,title:p(`OpenAI-compatible · Chat Completions`),ids:[]},{id:`responses`,title:p(`Responses API`),ids:[]},{id:`local`,title:p(`Local or your own endpoint`),ids:[]}];for(let[e,t]of Object.entries(T))(Ye.find(e=>e.id===(t.group??`openai`))??Ye[0]).ids.push(e);for(let e of Ye)e.ids=v(e.ids,T,s.hub?.account);let Xe=Ye.find(e=>e.id===`local`);if(Xe){let e=Xe.ids.filter(e=>e!==`custom`||!O||P===`custom`);Xe.ids=[...D.map(e=>Te(e.id)),...e,...O?[Fe]:[]]}let Qe=!Z&&!He&&(L===`custom`||!X?.base_url),$=X?.cloud||Z||He?null:h.find(e=>e.id===y(L))??null,nt=d(s.hub?.account),rt=i(),it=e=>!!$&&!$.user_capabilities&&!$.capabilities.includes(e),at=T[Pe],ot=X?.cloud?Y.gui[0]??X.gui_model??``:$&&!$.user_capabilities?$.capabilities.includes(`vision`)?$.defaults.hands||B.trim():at?.gui_model??B.trim():B.trim(),st=!X?.cloud&&it(`vision`)&&!!at,ct=e.gui?Me(e.gui,e.llm,rt,h,D):``,lt=Array.from(new Set([...X?.cloud?Y.gui:[],...X?.gui_model?[X.gui_model]:[],...Y.list.filter(e=>Y.vision.includes(e)||f(e)===!0)])).filter(Boolean),ut=X?.cloud?`nanoMuse Cloud`:Z?De(Z):$?S($,rt):tt(Ue)||L,dt=X?.cloud?Y.gui[0]??X.gui_model??``:$?.defaults.hands??X?.gui_model??``,ft=[{key:`hands`,label:ut,rows:lt.map(e=>({id:e,name:e})),...dt?{default:dt}:{}},...Oe(D,Z?.id??``)],pt=Ae&&Ae!==Z?.id?Te(Ae):`hands`,mt=D.find(e=>e.id===Ae)??null,ht=J?`${pt===`hands`?ut:mt?De(mt):``} · ${J}`:p(`Automatic`),gt=Qe&&/^https?:\/\/[^/]+\/?$/.test(H.trim());return(0,q.jsxs)(A,{icon:(0,q.jsx)(F,{size:19}),title:p(`Chat model`),summary:e.llm.cloud?`nanoMuse Cloud · ${e.llm.model||`—`}`:j?`${e.llm.model||`—`} · ${De(j)}`:`${e.llm.model||`—`}${e.llm.base_url?` · ${tt(e.llm.base_url)}`:``}`,status:Ke,open:m,onToggle:a?void 0:()=>g(!m),children:[(0,q.jsx)(Q,{label:p(`Provider`),children:(0,q.jsxs)(`div`,{className:`space-y-2.5`,children:[Ye.filter(e=>e.ids.length).map(e=>(0,q.jsxs)(`div`,{children:[(0,q.jsx)(`div`,{className:`mb-1 text-[11px] uppercase tracking-wide text-muted`,children:e.title}),(0,q.jsx)(`div`,{className:`flex flex-wrap gap-1.5`,children:e.ids.map(e=>{let n=I(e);if(!n)return null;let r=D.find(t=>Te(t.id)===e),i=r?tt(r.base_url)===n.label?void 0:tt(r.base_url):n.subtitle?p(n.subtitle):void 0;return(0,q.jsxs)(`button`,{type:`button`,onClick:()=>We(e),className:t(`rounded-2xl px-3 py-1.5 text-left border leading-tight`,L===e?`border-accent bg-accent/10 text-accent`:`border-border text-muted`),children:[(0,q.jsxs)(`span`,{className:t(`block text-[13px]`,L===e&&`font-medium`,e===Fe&&`inline-flex items-center gap-1`),children:[e===Fe&&(0,q.jsx)(ne,{size:13}),n.label]}),i&&(0,q.jsx)(`span`,{className:`block text-[10.5px] opacity-80`,children:i})]},e)})})]},e.id)),$&&(0,q.jsxs)(`p`,{className:`text-[12px] text-muted`,children:[(0,q.jsx)(`span`,{className:`font-medium text-fg`,children:S($,rt)}),` · `,_(p,$.capabilities),`. `,rt===`zh-CN`?$.note_zh:$.note]}),(0,q.jsxs)(`div`,{children:[(0,q.jsxs)(`button`,{type:`button`,onClick:()=>ue(!le),className:`inline-flex items-center gap-1.5 text-[12.5px] text-accent`,children:[(0,q.jsx)(re,{size:13}),` `,p(`Or sign in with a ChatGPT plan`),` `,le?(0,q.jsx)(k,{size:13}):(0,q.jsx)(E,{size:13})]}),le&&(0,q.jsx)(`div`,{className:`mt-2`,children:(0,q.jsx)(R,{compact:!0,onChanged:()=>{n()}})})]})]})}),He&&(0,q.jsx)(ze,{onAdded:e=>{z.current=e.id,b(),n()}}),Z&&(0,q.jsx)(Q,{label:p(`Endpoint`),children:(0,q.jsx)(Be,{endpoint:Z,onChange:()=>{b(),n()},onModels:e=>{Ne(t=>({...t,list:e,source:`live`})),e.length&&!Ie&&!e.includes(B)&&V(e[0])}})}),Qe&&(0,q.jsx)(Q,{label:p(`Base URL`),hint:p(gt?`/v1 is added when the URL has no path.`:`The endpoint that serves /chat/completions, for example http://127.0.0.1:8000/v1.`),children:(0,q.jsx)(`input`,{value:H,onChange:e=>ie(e.target.value),className:`w-full rounded-2xl bg-surface-2 px-3.5 py-2.5 text-[14.5px] outline-none focus:ring-2 focus:ring-accent/40`,placeholder:`https://host/v1`,inputMode:`url`,autoCapitalize:`off`})}),!He&&(0,q.jsxs)(Q,{label:p(`Chat model`),hint:X?.cloud&&M&&Y.catalog.length?p(`{n} models your account may use: the menu first, then everything else the provider lists under the Cloud key. Pick one; the ones beyond the menu are priced as the dearest menu model of their kind.`,{n:Y.list.length}):X?.cloud&&M?p(`Your account may name any model the provider has, not only these: type its id (a chat model here, a picture or clip model below) and it goes through as typed.`):Y.source===`live`?p(`{n} models from the endpoint`,{n:Y.list.length}):Y.source===`loading`?p(`Asking the endpoint…`):Y.list.length&&Z?p(`{n} models saved with this endpoint`,{n:Y.list.length}):Y.list.length?p(`Could not list the endpoint's models; these are the usual ones.`):void 0,children:[X?.cloud&&Y.catalog.length>0&&!Re&&(!B||Y.list.includes(B))?(0,q.jsxs)(`select`,{value:B,onChange:e=>{if(e.target.value===Ze){Ve(!0);return}V(e.target.value),Le(!0)},className:t(`w-full rounded-2xl bg-surface-2 px-3.5 py-2.5 text-[14.5px] outline-none focus:ring-2 focus:ring-accent/40`,`text-fg`),children:[!B&&(0,q.jsx)(`option`,{value:``,children:p(`model name`)}),(0,q.jsx)(`optgroup`,{label:p(`Menu`),children:Y.menu.map(e=>(0,q.jsx)(`option`,{value:e,children:Y.vision.includes(e)?`${e} · ${p(`reads pictures`)}`:e},e))}),(0,q.jsx)(`optgroup`,{label:p(`More models on your account`),children:Y.catalog.map(e=>(0,q.jsx)(`option`,{value:e,children:Y.vision.includes(e)?`${e} · ${p(`reads pictures`)}`:e},e))}),(0,q.jsx)(`option`,{value:Ze,children:p(`Type a model id…`)})]}):(0,q.jsxs)(q.Fragment,{children:[(0,q.jsx)(`input`,{list:`om-models`,value:B,onChange:e=>{V(e.target.value),Le(!0)},className:`w-full rounded-2xl bg-surface-2 px-3.5 py-2.5 text-[14.5px] outline-none focus:ring-2 focus:ring-accent/40`,placeholder:p(`model name`),autoCapitalize:`off`,autoCorrect:`off`,autoFocus:Re}),(0,q.jsx)(`datalist`,{id:`om-models`,children:Y.list.map(e=>(0,q.jsx)(`option`,{value:e},e))}),X?.cloud&&Y.catalog.length>0&&(0,q.jsx)(`button`,{type:`button`,className:`mt-1.5 text-[12px] text-accent`,onClick:()=>{Ve(!1),Y.list.includes(B)||V(Y.menu[0]??Y.list[0]??``)},children:p(`Pick from the list`)})]}),Y.list.length>0&&(0,q.jsx)(`div`,{className:`mt-1.5 flex flex-wrap gap-1.5`,children:(Y.menu.length?Y.menu:Y.list).slice(0,8).map(e=>(0,q.jsx)(`button`,{type:`button`,onClick:()=>V(e),className:t(`rounded-full px-2.5 py-1 text-[12px] border`,B===e?`border-accent bg-accent/10 text-accent font-medium`:`border-border text-muted`),children:e},e))})]}),!He&&(0,q.jsxs)(Q,{label:p(`Hands model`),hint:X?.cloud?p(`The model that looks at screens when the hands run: the phone, this computer, a page the browser cannot read. Your account's hands model is {model}; the chat model above is a different pick.`,{model:ot||`—`}):st?p(`The model that looks at screens when the hands run. This provider has no model that sees, so the hands use your account's, {model}, unless you pick one here.`,{model:ot||`—`}):D.length>+!!Z?p(`The model that looks at screens when the hands run: a small, fast one that takes pictures. Pick one of this provider's, or one from another endpoint of your list, which then lends its address and key.`):p(`The model that looks at screens when the hands run: a small, fast one that takes pictures, on the same endpoint and key. Default: this provider's own hands model.`),children:[(0,q.jsx)(ve,{label:p(`Hands model`),text:ht,heads:[{value:``,label:p(`Automatic`)}],headValue:J?void 0:``,groups:ft,current:J?{group:pt,id:J}:void 0,onHead:()=>{ke(``),je(``)},onPick:(e,t)=>{ke(t.id),je(Ee(e)??``)}}),ct&&(0,q.jsx)(`p`,{className:`mt-1.5 text-[12px] text-muted`,children:p(`Currently {value}`,{value:ct})}),!X?.cloud&&B.trim()&&!J&&f(B.trim())===!1&&(0,q.jsx)(`div`,{className:`mt-1.5 text-[12px] text-amber-700 dark:text-amber-300`,children:p(`{model} does not take pictures, so the hands would be blind with it. Pick a model that sees for them.`,{model:B.trim()})}),it(`vision`)&&!st&&(0,q.jsxs)(`div`,{className:`mt-1.5 text-[12px] text-amber-700 dark:text-amber-300`,children:[x(p,`vision`,nt,rt),` `,(0,q.jsx)($e,{})]})]}),!X?.no_key&&!He&&(0,q.jsxs)(Q,{label:p(`API key`),hint:U&&X?.key_optional?p(`No key will be sent.`):e.llm.key_source===`vault`&&L===P?p(`A key is in the vault. Leave blank to keep it.`):p(`Stored encrypted in the vault as LLM_API_KEY.`),children:[(0,q.jsxs)(`div`,{className:`relative`,children:[(0,q.jsx)(`input`,{type:se?`text`:`password`,value:ae,onChange:e=>oe(e.target.value),disabled:U&&!!X?.key_optional,className:t(`w-full rounded-2xl bg-surface-2 px-3.5 py-2.5 text-[14.5px] outline-none focus:ring-2 focus:ring-accent/40`,`pr-10 disabled:opacity-50`),placeholder:e.llm.key_source===`vault`&&L===P?`••••••••`:X?.key_hint||`sk-…`,autoComplete:`off`,autoCapitalize:`off`,spellCheck:!1}),(0,q.jsx)(`button`,{type:`button`,onClick:()=>ce(!se),"aria-label":p(se?`Hide key`:`Show key`),className:`absolute right-2 top-1/2 -translate-y-1/2 rounded-full p-1.5 text-muted`,children:se?(0,q.jsx)(de,{size:16}):(0,q.jsx)(fe,{size:16})})]}),(0,q.jsxs)(`div`,{className:`mt-1.5 flex items-center justify-between gap-2 text-[12px]`,children:[X?.key_url?(0,q.jsxs)(`a`,{href:X.key_url,target:`_blank`,rel:`noreferrer`,className:`inline-flex items-center gap-1 text-accent`,children:[p(`Get a key from {vendor}`,{vendor:X.label}),` `,(0,q.jsx)(w,{size:12})]}):(0,q.jsx)(`span`,{}),X?.key_optional&&(0,q.jsxs)(`label`,{className:`inline-flex items-center gap-1.5 text-muted`,children:[(0,q.jsx)(`input`,{type:`checkbox`,checked:U,onChange:e=>W(e.target.checked),className:`accent-accent`}),` `,p(`No key`)]})]})]}),!He&&(0,q.jsx)(Q,{label:p(`Tool calling`),hint:p(`Auto uses the API's function calling and falls back to describing tools in the prompt when the endpoint rejects them. Prompt: for endpoints that silently ignore tools.`),children:(0,q.jsx)(`div`,{className:`flex gap-1.5`,children:[`auto`,`native`,`prompt`].map(e=>(0,q.jsx)(`button`,{type:`button`,onClick:()=>K(e),className:t(`rounded-full px-3 py-1.5 text-[13px] border`,pe===e?`border-accent bg-accent/10 text-accent font-medium`:`border-border text-muted`),children:e},e))})}),!X?.cloud&&!He&&e.llm.proxy!==void 0&&(0,q.jsx)(Q,{label:p(`Proxy (optional)`),hint:p(`Only this provider's requests go through it. nanoMuse Cloud never does.`),children:(0,q.jsx)(`input`,{className:`w-full rounded-2xl bg-surface-2 px-3.5 py-2.5 text-[14.5px] outline-none focus:ring-2 focus:ring-accent/40`,value:me,onChange:e=>{he(e.target.value),_e(!0)},onFocus:()=>me.includes(`••••`)&&!ge&&he(``),onBlur:()=>!ge&&he(e.llm.proxy??``),placeholder:`http://host:port / socks5://host:port`,autoComplete:`off`,spellCheck:!1})}),!He&&(0,q.jsxs)(`div`,{className:`flex gap-2 pt-1`,children:[(0,q.jsxs)(`button`,{type:`button`,disabled:ye||!B.trim()||Qe&&!H.trim(),onClick:()=>void qe(),className:`flex items-center justify-center gap-1.5 rounded-2xl bg-accent text-accent-fg px-4 py-2.5 text-[14px] font-medium disabled:opacity-40`,children:[ye?(0,q.jsx)(l,{size:16,className:`animate-spin`}):(0,q.jsx)(C,{size:16}),` `,p(`Save`)]}),(0,q.jsxs)(`button`,{type:`button`,disabled:Ce,onClick:()=>void Je(),className:`flex items-center justify-center gap-1.5 rounded-2xl border border-border px-4 py-2.5 text-[14px] font-medium text-muted disabled:opacity-40`,children:[Ce?(0,q.jsx)(l,{size:16,className:`animate-spin`}):(0,q.jsx)(N,{size:16}),` `,p(`Test`)]})]}),xe&&(0,q.jsx)(et,{result:xe,okText:p(`Replied "{reply}" in {ms} ms`,{reply:xe.reply??``,ms:xe.ms??0})})]})}var Re={chat:`the chat model`,hands:`the hands`,image:`pictures`,video:`clips`};function ze({onAdded:e}){let n=r(),{toast:i}=c(),[a,o]=(0,G.useState)(``),[s,d]=(0,G.useState)(``),[f,p]=(0,G.useState)(``),[m,h]=(0,G.useState)(!1),[g,_]=(0,G.useState)(!1),[v,y]=(0,G.useState)(``),[b,x]=(0,G.useState)(null),[S,C]=(0,G.useState)(!1),w=/^https?:\/\/[^/]+\/?$/.test(s.trim()),T=async()=>{C(!0),x(null);try{let t=await u.addEndpoint({label:a.trim(),base_url:s.trim(),api_key:g?``:f,models:v});i(n(`Endpoint added`)),e(t)}catch(e){x(n(e.message))}finally{C(!1)}};return(0,q.jsxs)(`div`,{className:`space-y-3 rounded-2xl border border-border p-3`,children:[(0,q.jsx)(`p`,{className:`text-[12.5px] text-muted leading-snug`,children:n(`An endpoint joins your list with its own key and stays there; add as many as you use. Pick one as the chat model, or use its models for the hands, pictures and clips.`)}),(0,q.jsx)(Q,{label:n(`Name (optional)`),hint:n(`How the endpoint reads in the lists; its host when left empty.`),children:(0,q.jsx)(`input`,{value:a,onChange:e=>o(e.target.value),className:O,placeholder:n(`for example: my gateway`),autoCapitalize:`off`})}),(0,q.jsx)(Q,{label:n(`Base URL`),hint:n(w?`/v1 is added when the URL has no path.`:`The endpoint that serves /chat/completions, for example http://127.0.0.1:8000/v1.`),children:(0,q.jsx)(`input`,{value:s,onChange:e=>d(e.target.value),className:O,placeholder:`https://host/v1`,inputMode:`url`,autoCapitalize:`off`})}),(0,q.jsxs)(Q,{label:n(`API key`),hint:n(g?`No key will be sent.`:`Stored encrypted in the vault under this endpoint's own name.`),children:[(0,q.jsxs)(`div`,{className:`relative`,children:[(0,q.jsx)(`input`,{type:m?`text`:`password`,value:f,onChange:e=>p(e.target.value),disabled:g,className:t(O,`pr-10 disabled:opacity-50`),placeholder:`sk-…`,autoComplete:`off`,autoCapitalize:`off`,spellCheck:!1}),(0,q.jsx)(`button`,{type:`button`,onClick:()=>h(!m),"aria-label":n(m?`Hide key`:`Show key`),className:`absolute right-2 top-1/2 -translate-y-1/2 rounded-full p-1.5 text-muted`,children:m?(0,q.jsx)(de,{size:16}):(0,q.jsx)(fe,{size:16})})]}),(0,q.jsxs)(`label`,{className:`mt-1.5 inline-flex items-center gap-1.5 text-[12px] text-muted`,children:[(0,q.jsx)(`input`,{type:`checkbox`,checked:g,onChange:e=>_(e.target.checked),className:`accent-accent`}),` `,n(`No key`)]})]}),(0,q.jsx)(Q,{label:n(`Models (optional)`),hint:n(`Leave empty when the endpoint lists its models at /models. Otherwise type their ids, separated by commas.`),children:(0,q.jsx)(`input`,{value:v,onChange:e=>y(e.target.value),className:O,placeholder:`model-a, model-b`,autoCapitalize:`off`,autoCorrect:`off`,spellCheck:!1})}),b&&(0,q.jsx)(`div`,{className:`rounded-2xl bg-rose-500/12 px-3 py-2 text-[12.5px] text-rose-700 dark:text-rose-300`,children:b}),(0,q.jsxs)(`button`,{type:`button`,disabled:S||!s.trim(),onClick:()=>void T(),className:D,children:[S?(0,q.jsx)(l,{size:16,className:`animate-spin`}):(0,q.jsx)(ne,{size:16}),` `,n(`Add endpoint`)]})]})}function Be({endpoint:e,onChange:n,onModels:a}){let o=r(),{toast:s}=c(),[d,f]=(0,G.useState)(``),[p,m]=(0,G.useState)(e.label),[h,g]=(0,G.useState)(``),[_,v]=(0,G.useState)(!1),[y,b]=(0,G.useState)(!1),[x,S]=(0,G.useState)(e.models.join(`, `)),[C,w]=(0,G.useState)(!1),[T,E]=(0,G.useState)(null),D=e.models.join(`, `);(0,G.useEffect)(()=>{m(e.label),S(D),f(``),g(``),b(!1),E(null)},[e.id,e.label,D]);let O=async(e,t)=>{w(!0),E(null);try{await e(),t&&s(t),f(``),n()}catch(e){E(o(e.message))}finally{w(!1)}},k=async()=>{w(!0),E(null);try{let t=await u.refreshEndpointModels(e.id);t.source===`live`?(a(t.models),s(o(`{n} models from the endpoint`,{n:t.models.length})),n()):E(o(`The endpoint did not list its models; the saved list stands.`)+(t.error?` ${o(t.error)}`:``))}catch(e){E(o(e.message))}finally{w(!1)}},A=e.key_source===`vault`?o(`Key in vault`):e.key_source===`config`?o(`Key from config`):e.key_source===`missing`?o(`Key missing from vault`):o(`No key`),j=e.slots.map(e=>o(Re[e])).join(i()===`zh-CN`?`、`:`, `),M=e.slots.includes(`chat`),N=`text-[12.5px] text-accent disabled:opacity-50`;return(0,q.jsxs)(`div`,{className:`space-y-2 rounded-2xl border border-border p-3 text-[13px]`,children:[(0,q.jsxs)(`div`,{children:[(0,q.jsx)(`span`,{className:`font-medium text-fg`,children:De(e)}),(0,q.jsxs)(`span`,{className:`text-muted`,children:[` · `,tt(e.base_url)]})]}),(0,q.jsxs)(`div`,{className:`text-[12px] text-muted`,children:[A,` · `,o(`{n} models`,{n:e.models.length}),j?` · ${o(`Used by {slots}`,{slots:j})}`:``]}),d===``&&(0,q.jsxs)(`div`,{className:`flex flex-wrap gap-x-3 gap-y-1`,children:[(0,q.jsx)(`button`,{type:`button`,className:N,disabled:C,onClick:()=>f(`rename`),children:o(`Rename`)}),(0,q.jsx)(`button`,{type:`button`,className:N,disabled:C,onClick:()=>f(`key`),children:o(`Change key`)}),(0,q.jsx)(`button`,{type:`button`,className:N,disabled:C,onClick:()=>f(`models`),children:o(`Edit models`)}),(0,q.jsxs)(`button`,{type:`button`,className:N,disabled:C,onClick:()=>void k(),children:[C?(0,q.jsx)(l,{size:12,className:`inline animate-spin`}):(0,q.jsx)(P,{size:12,className:`inline`}),` `,o(`Ask for its models`)]}),(0,q.jsx)(`button`,{type:`button`,className:t(N,`text-rose-600 dark:text-rose-300`),disabled:C,onClick:()=>f(`remove`),children:o(`Remove`)})]}),d===`rename`&&(0,q.jsxs)(`div`,{className:`space-y-2`,children:[(0,q.jsx)(`input`,{value:p,onChange:e=>m(e.target.value),className:`w-full rounded-2xl bg-surface-2 px-3.5 py-2.5 text-[14.5px] outline-none focus:ring-2 focus:ring-accent/40`,placeholder:tt(e.base_url),autoCapitalize:`off`,"aria-label":o(`Name`)}),(0,q.jsxs)(`div`,{className:`flex gap-2`,children:[(0,q.jsx)(`button`,{type:`button`,disabled:C,className:`flex items-center justify-center gap-1.5 rounded-2xl bg-accent text-accent-fg px-4 py-2.5 text-[14px] font-medium disabled:opacity-40`,onClick:()=>void O(()=>u.updateEndpoint(e.id,{label:p.trim()}),o(`Endpoint renamed`)),children:o(`Save`)}),(0,q.jsx)(`button`,{type:`button`,className:`flex items-center justify-center gap-1.5 rounded-2xl border border-border px-4 py-2.5 text-[14px] font-medium text-muted disabled:opacity-40`,onClick:()=>f(``),children:o(`Cancel`)})]})]}),d===`key`&&(0,q.jsxs)(`div`,{className:`space-y-2`,children:[(0,q.jsxs)(`div`,{className:`relative`,children:[(0,q.jsx)(`input`,{type:_?`text`:`password`,value:h,onChange:e=>g(e.target.value),disabled:y,className:t(`w-full rounded-2xl bg-surface-2 px-3.5 py-2.5 text-[14.5px] outline-none focus:ring-2 focus:ring-accent/40`,`pr-10 disabled:opacity-50`),placeholder:e.key_source===`vault`?`••••••••`:`sk-…`,"aria-label":o(`API key`),autoComplete:`off`,autoCapitalize:`off`,spellCheck:!1}),(0,q.jsx)(`button`,{type:`button`,onClick:()=>v(!_),"aria-label":o(_?`Hide key`:`Show key`),className:`absolute right-2 top-1/2 -translate-y-1/2 rounded-full p-1.5 text-muted`,children:_?(0,q.jsx)(de,{size:16}):(0,q.jsx)(fe,{size:16})})]}),(0,q.jsxs)(`label`,{className:`inline-flex items-center gap-1.5 text-[12px] text-muted`,children:[(0,q.jsx)(`input`,{type:`checkbox`,checked:y,onChange:e=>b(e.target.checked),className:`accent-accent`}),` `,o(`No key`)]}),(0,q.jsxs)(`div`,{className:`flex gap-2`,children:[(0,q.jsx)(`button`,{type:`button`,disabled:C||!y&&!h.trim(),className:`flex items-center justify-center gap-1.5 rounded-2xl bg-accent text-accent-fg px-4 py-2.5 text-[14px] font-medium disabled:opacity-40`,onClick:()=>void O(()=>u.updateEndpoint(e.id,{api_key:y?``:h.trim()}),o(`Key saved`)),children:o(`Save`)}),(0,q.jsx)(`button`,{type:`button`,className:`flex items-center justify-center gap-1.5 rounded-2xl border border-border px-4 py-2.5 text-[14px] font-medium text-muted disabled:opacity-40`,onClick:()=>f(``),children:o(`Cancel`)})]})]}),d===`models`&&(0,q.jsxs)(`div`,{className:`space-y-2`,children:[(0,q.jsx)(`input`,{value:x,onChange:e=>S(e.target.value),className:`w-full rounded-2xl bg-surface-2 px-3.5 py-2.5 text-[14.5px] outline-none focus:ring-2 focus:ring-accent/40`,placeholder:`model-a, model-b`,"aria-label":o(`Models`),autoCapitalize:`off`,autoCorrect:`off`,spellCheck:!1}),(0,q.jsx)(`div`,{className:`text-[12px] text-muted`,children:o(`The ids of the models this endpoint serves, separated by commas; what it lists at /models is added after them.`)}),(0,q.jsxs)(`div`,{className:`flex gap-2`,children:[(0,q.jsx)(`button`,{type:`button`,disabled:C,className:`flex items-center justify-center gap-1.5 rounded-2xl bg-accent text-accent-fg px-4 py-2.5 text-[14px] font-medium disabled:opacity-40`,onClick:()=>void O(()=>u.updateEndpoint(e.id,{models:x}),o(`Models saved`)),children:o(`Save`)}),(0,q.jsx)(`button`,{type:`button`,className:`flex items-center justify-center gap-1.5 rounded-2xl border border-border px-4 py-2.5 text-[14px] font-medium text-muted disabled:opacity-40`,onClick:()=>f(``),children:o(`Cancel`)})]})]}),d===`remove`&&(0,q.jsxs)(`div`,{className:`space-y-2`,children:[(0,q.jsx)(`div`,{className:`text-[12.5px] text-muted`,children:o(M?`The chat model answers through this endpoint; pick another chat model first.`:`Its key goes with it, and the hands, pictures or clips set on it go back to automatic.`)}),(0,q.jsxs)(`div`,{className:`flex gap-2`,children:[(0,q.jsxs)(`button`,{type:`button`,disabled:C||M,className:t(`flex items-center justify-center gap-1.5 rounded-2xl bg-accent text-accent-fg px-4 py-2.5 text-[14px] font-medium disabled:opacity-40`,`bg-rose-600 hover:bg-rose-600/90`),onClick:()=>void O(()=>u.removeEndpoint(e.id),o(`Endpoint removed`)),children:[(0,q.jsx)(z,{size:16}),` `,o(`Remove`)]}),(0,q.jsx)(`button`,{type:`button`,className:`flex items-center justify-center gap-1.5 rounded-2xl border border-border px-4 py-2.5 text-[14px] font-medium text-muted disabled:opacity-40`,onClick:()=>f(``),children:o(`Cancel`)})]})]}),T&&(0,q.jsx)(`div`,{className:`rounded-2xl bg-rose-500/12 px-3 py-2 text-[12.5px] text-rose-700 dark:text-rose-300`,children:T})]})}function Ve({slot:e,data:n,onChange:a}){let{toast:o,state:s}=c(),f=r(),p=n[e],v=e,y=s.hub?.account??null,T=!!y?.signed_in,E=d(y),k=i(),N=n.providers[Pe]?.base_url??``,P=n.endpoints??[],F=Y(v,{signedIn:T,chat:{provider:n.llm.provider,base_url:n.llm.base_url,cloud:!!n.llm.cloud},region:E,locale:k,endpoints:P}),I=Ne(p,N),[L,ee]=(0,G.useState)(!1),[R,te]=(0,G.useState)(I),[z,B]=(0,G.useState)(p.model),[V,re]=(0,G.useState)(p.base_url),[H,ie]=(0,G.useState)(``),[ae,oe]=(0,G.useState)(!1),[se,ce]=(0,G.useState)(!1),[le,ue]=(0,G.useState)({list:[],more:[],source:`catalogue`});(0,G.useEffect)(()=>{te(I),B(p.model),re(p.base_url),ie(``)},[p]);let U=F.find(e=>e.value===R)??null,W=U?.entry??null,pe=W?g(W,E):null,K=P.find(e=>Te(e.id)===R)??null,me=R===`nanomuse_cloud`?N:K?K.base_url:R===`custom`?V.trim():pe?.base_url??``,he=I===R&&I!==``&&(p.key_source===`vault`||p.key_source===`config`),ge=!!U?.needsKey&&!H&&!he,_e=R===`nanomuse_cloud`?le.list[0]??``:W?.defaults[e]??``;(0,G.useEffect)(()=>{if(!L||!R||R!==`nanomuse_cloud`&&!me){ue({list:[],more:[],source:`catalogue`});return}let t=!0,n=setTimeout(()=>{ue(e=>({...e,source:`loading`})),u.llmModels(R===`nanomuse_cloud`?{preset:Pe}:K?{endpoint:K.id}:{preset:W?m(W.id):``,base_url:me,api_key:H||void 0}).then(n=>{if(!t)return;let r=(e===`image`?n.image_models:n.video_models)??[],i=(e===`image`?n.image_catalog:n.video_catalog)??[];ue({list:r.filter(e=>!i.includes(e)),more:i,source:n.source})}).catch(()=>t&&ue({list:[],more:[],source:`catalogue`}))},H?600:150);return()=>{t=!1,clearTimeout(n)}},[L,R,me,H]);let ve=f(e===`image`?`Making pictures`:`Making clips`),ye=f(e===`image`?`Portraits of your Muse.`:`Short clips of your Muse.`),xe=je(p,k,h,P),Se=x(f,v,E,k),Ce=p.effective_provider?p.effective_source===`cloud`?{text:f(`Your account`),tone:`ok`}:p.effective_source===`chat`?{text:f(`The chat model's provider`),tone:`ok`}:{text:f(`Your key`),tone:`ok`}:{text:f(`Not set up`),tone:`warn`},we=async()=>{ce(!0);try{R?R===`nanomuse_cloud`?await u.setMedia(e,{provider:`openai`,base_url:N,model:z.trim(),api_key:be}):K?await u.setMedia(e,{endpoint:K.id,model:z.trim()}):R===`custom`?await u.setMedia(e,{provider:`openai`,base_url:V.trim(),model:z.trim(),api_key:H||null}):await u.setMedia(e,{provider:R,base_url:``,model:z.trim(),api_key:H||(U?.group===`chat`?``:null)}):await u.setMedia(e,{provider:``,model:``,base_url:``,api_key:``}),ie(``),b(),o(f(`Saved`)),a(),ee(!1)}catch(e){o(e.message)}finally{ce(!1)}},Ee=e=>f(e===`cloud`?`Your account`:e===`chat`?`The chat model's provider`:e===`endpoints`?`Your endpoints`:`Add a provider`),De=[`cloud`,`chat`,`endpoints`,`add`].map(e=>({g:e,items:F.filter(t=>t.group===e)})).filter(e=>e.items.length),J=e===`image`?`IMAGE_API_KEY`:`VIDEO_API_KEY`;return(0,q.jsxs)(A,{icon:e===`image`?(0,q.jsx)(M,{size:19}):(0,q.jsx)(j,{size:19}),title:ve,summary:xe||Se,status:Ce,open:L,onToggle:()=>ee(!L),children:[(0,q.jsx)(`p`,{className:`text-[12.5px] text-muted`,children:ye}),(0,q.jsxs)(Q,{label:f(`Provider`),hint:!xe&&!R?Se:void 0,children:[(0,q.jsxs)(`select`,{value:R,onChange:e=>{te(e.target.value),B(``),ie(``)},className:t(O,`text-fg`),children:[(0,q.jsx)(`option`,{value:``,children:f(`Automatic`)}),De.map(({g:e,items:t})=>(0,q.jsx)(`optgroup`,{label:Ee(e),children:t.map(e=>(0,q.jsx)(`option`,{value:e.value,children:e.value===`custom`?f(`Other OpenAI-compatible endpoint`):e.label},e.value))},e))]}),xe&&(0,q.jsx)(`p`,{className:`mt-1.5 text-[12px] text-muted`,children:f(`Currently {value}`,{value:xe})}),!xe&&!R&&(0,q.jsxs)(`button`,{type:`button`,className:`mt-1.5 inline-flex items-center gap-1 text-[12.5px] text-accent`,onClick:()=>te(F.find(e=>e.group===`add`)?.value??``),children:[(0,q.jsx)(ne,{size:13}),` `,f(`Add a provider`)]}),W&&(0,q.jsxs)(`p`,{className:`mt-1.5 text-[12px] text-muted`,children:[(0,q.jsx)(`span`,{className:`font-medium text-fg`,children:S(W,k)}),` · `,_(f,W.capabilities),`. `,k===`zh-CN`?W.note_zh:W.note]})]}),R===`custom`&&(0,q.jsx)(Q,{label:f(`Base URL`),hint:f(`The endpoint that serves /images/generations, for example https://host/v1.`),children:(0,q.jsx)(`input`,{value:V,onChange:e=>re(e.target.value),className:`w-full rounded-2xl bg-surface-2 px-3.5 py-2.5 text-[14.5px] outline-none focus:ring-2 focus:ring-accent/40`,placeholder:`https://host/v1`,inputMode:`url`,autoCapitalize:`off`})}),R&&(0,q.jsx)(Qe,{label:f(e===`image`?`Picture model`:`Clip model`),provider:R===`nanomuse_cloud`?`nanoMuse Cloud`:R===`custom`?tt(V)||f(`Other OpenAI-compatible endpoint`):U?.label??R,value:z,options:le.list,more:le.more,onChange:B,other:R!==`nanomuse_cloud`||!!y?.any_model,placeholder:_e||void 0}),R&&R!==`nanomuse_cloud`&&U?.group!==`chat`&&!K&&(0,q.jsxs)(Q,{label:f(`API key`),hint:he?f(`A key is in the vault. Leave blank to keep it.`):f(`Stored encrypted in the vault as {name}.`,{name:J}),children:[(0,q.jsxs)(`div`,{className:`relative`,children:[(0,q.jsx)(`input`,{type:ae?`text`:`password`,value:H,onChange:e=>ie(e.target.value),className:t(`w-full rounded-2xl bg-surface-2 px-3.5 py-2.5 text-[14.5px] outline-none focus:ring-2 focus:ring-accent/40`,`pr-10`),placeholder:he?`••••••••`:W?.key_hint||`sk-…`,autoComplete:`off`,autoCapitalize:`off`,spellCheck:!1}),(0,q.jsx)(`button`,{type:`button`,onClick:()=>oe(!ae),"aria-label":f(ae?`Hide key`:`Show key`),className:`absolute right-2 top-1/2 -translate-y-1/2 rounded-full p-1.5 text-muted`,children:ae?(0,q.jsx)(de,{size:16}):(0,q.jsx)(fe,{size:16})})]}),pe?.key_url&&(0,q.jsxs)(`a`,{href:pe.key_url,target:`_blank`,rel:`noreferrer`,className:`mt-1.5 inline-flex items-center gap-1 text-[12px] text-accent`,children:[f(`Get a key from {vendor}`,{vendor:W?S(W,k):``}),` `,(0,q.jsx)(w,{size:12})]})]}),U?.group===`chat`&&(0,q.jsx)(`p`,{className:`text-[12px] text-muted`,children:f(`Uses the chat model's key.`)}),K&&(0,q.jsx)(`p`,{className:`text-[12px] text-muted`,children:f(`Uses the key saved with this endpoint.`)}),(0,q.jsx)(`div`,{className:`flex gap-2 pt-1`,children:(0,q.jsxs)(`button`,{type:`button`,disabled:se||ge||R===`custom`&&!V.trim(),onClick:()=>void we(),className:D,children:[se?(0,q.jsx)(l,{size:16,className:`animate-spin`}):(0,q.jsx)(C,{size:16}),` `,f(`Save`)]})})]})}function X({data:e,onChange:n}){let{toast:i}=c(),a=r(),o=e.embeddings,[s,d]=(0,G.useState)(!1),[f,p]=(0,G.useState)(o.mode),[m,h]=(0,G.useState)(!!o.base_url),[g,_]=(0,G.useState)(o.base_url),[v,y]=(0,G.useState)(o.model),[b,x]=(0,G.useState)(``),[S,w]=(0,G.useState)(!1),[E,O]=(0,G.useState)(null),[k,j]=(0,G.useState)(!1);(0,G.useEffect)(()=>{p(o.mode),h(!!o.base_url),_(o.base_url),y(o.model)},[e.embeddings]);let M=o.mode===`off`?{text:a(`Off`),tone:`off`}:o.available===!0?{text:a(`On`),tone:`ok`}:o.available===!1?{text:o.mode===`on`?a(`Not reachable`):a(`By keyword`),tone:`warn`}:{text:a(`Not tried yet`),tone:`off`},P=o.mode===`off`?a(`Keyword recall only`):o.available===!0?a(`{model} · {n} of {total} memories indexed`,{model:o.model||o.default_model,n:o.indexed,total:o.total}):o.available===!1?o.reason:a(`{model} at {host}`,{model:o.model||o.default_model,host:tt(o.effective_base_url)}),F=async()=>{w(!0),O(null);try{await u.setEmbeddings({mode:f,base_url:m?g.trim():``,model:v.trim(),api_key:m?b||void 0:``}),x(``),i(a(`Saved`)),n()}catch(e){i(e.message)}finally{w(!1)}},I=async()=>{j(!0);try{O(await u.testEmbeddings()),n()}catch(e){O({ok:!1,error:e.message})}finally{j(!1)}},L=e=>t(`rounded-full px-3 py-1.5 text-[13px] border`,e?`border-accent bg-accent/10 text-accent font-medium`:`border-border text-muted`);return(0,q.jsxs)(A,{icon:(0,q.jsx)(le,{size:19}),title:a(`Recall by meaning`),summary:P,status:M,open:s,onToggle:()=>d(!s),children:[(0,q.jsx)(`p`,{className:`text-[12.5px] text-muted leading-snug`,children:a(`Memories are embedded once and a message finds the ones that mean the same thing, in any language: “写邮件给房东” finds “the landlord is Bob Li”. Keyword recall stays; the two are fused.`)}),(0,q.jsx)(Q,{label:a(`Mode`),hint:a(`Auto uses the model's endpoint when it has embeddings and falls back to keywords when it does not. On insists and warns. Off: keywords only.`),children:(0,q.jsx)(`div`,{className:`flex gap-1.5`,children:[`auto`,`on`,`off`].map(e=>(0,q.jsx)(`button`,{type:`button`,onClick:()=>p(e),className:L(f===e),children:a(e===`auto`?`Auto`:e===`on`?`On`:`Off`)},e))})}),f!==`off`&&(0,q.jsxs)(q.Fragment,{children:[(0,q.jsx)(Q,{label:a(`Endpoint`),hint:a(m?`Any OpenAI-compatible /embeddings: Ollama with an embedding model pulled, OpenAI, a gateway.`:`The model's endpoint and key. DeepSeek has no embeddings; pick another endpoint.`),children:(0,q.jsxs)(`div`,{className:`flex gap-1.5`,children:[(0,q.jsx)(`button`,{type:`button`,onClick:()=>h(!1),className:L(!m),children:a(`Same as the model`)}),(0,q.jsx)(`button`,{type:`button`,onClick:()=>{h(!0),g||_(`http://127.0.0.1:11434/v1`)},className:L(m),children:a(`Another endpoint`)})]})}),m&&(0,q.jsxs)(q.Fragment,{children:[(0,q.jsx)(Q,{label:a(`Base URL`),children:(0,q.jsx)(`input`,{value:g,onChange:e=>_(e.target.value),className:`w-full rounded-2xl bg-surface-2 px-3.5 py-2.5 text-[14.5px] outline-none focus:ring-2 focus:ring-accent/40`,placeholder:`http://127.0.0.1:11434/v1`,inputMode:`url`})}),(0,q.jsx)(Q,{label:a(`API key`),hint:o.key_source===`vault`?a(`A key is in the vault. Leave blank to keep it.`):a(`Stored encrypted in the vault as EMBEDDINGS_API_KEY. Ollama needs none.`),children:(0,q.jsx)(`input`,{type:`password`,value:b,onChange:e=>x(e.target.value),className:`w-full rounded-2xl bg-surface-2 px-3.5 py-2.5 text-[14.5px] outline-none focus:ring-2 focus:ring-accent/40`,placeholder:o.key_source===`vault`?`••••••••`:`sk-…`,autoComplete:`off`})})]}),(0,q.jsx)(Q,{label:a(`Embedding model`),hint:a(`Blank uses the endpoint's default: {model}. On Ollama: ollama pull qwen3-embedding:0.6b (reads Chinese and English).`,{model:o.default_model}),children:(0,q.jsx)(`input`,{value:v,onChange:e=>y(e.target.value),className:`w-full rounded-2xl bg-surface-2 px-3.5 py-2.5 text-[14.5px] outline-none focus:ring-2 focus:ring-accent/40`,placeholder:o.default_model,autoComplete:`off`})})]}),(0,q.jsxs)(`div`,{className:`flex gap-2 pt-1`,children:[(0,q.jsxs)(`button`,{type:`button`,disabled:S||m&&!/^https?:\/\//.test(g.trim()),onClick:()=>void F(),className:D,children:[S?(0,q.jsx)(l,{size:16,className:`animate-spin`}):(0,q.jsx)(C,{size:16}),` `,a(`Save`)]}),(0,q.jsxs)(`button`,{type:`button`,disabled:k||o.mode===`off`,onClick:()=>void I(),className:T,children:[k?(0,q.jsx)(l,{size:16,className:`animate-spin`}):(0,q.jsx)(N,{size:16}),` `,a(`Test`)]})]}),E&&(0,q.jsx)(et,{result:E,okText:a(`{model} · {dims} dims · {n} memories indexed · {ms} ms`,{model:E.model??``,dims:E.dims??0,n:E.indexed??0,ms:E.ms??0})})]})}function Z({data:e,onChange:n}){let{toast:i}=c(),a=r(),o=e.search,[s,d]=(0,G.useState)(!1),[f,p]=(0,G.useState)(o.provider),[m,h]=(0,G.useState)(o.base_url),[g,_]=(0,G.useState)(``),[v,y]=(0,G.useState)(!1),[b,x]=(0,G.useState)(null),[S,w]=(0,G.useState)(!1);(0,G.useEffect)(()=>{p(o.provider),h(o.base_url)},[e.search]);let E=o.providers.find(e=>e.id===o.provider),O=o.providers.find(e=>e.id===f),k=!!O?.needs_key,j=o.configured?{text:a(`On`),tone:`ok`}:{text:a(`Not set up`),tone:`warn`},M=o.configured?o.provider===`searxng`?a(`{provider} at {host}`,{provider:E?.label??o.provider,host:tt(o.base_url)}):E?.label??o.provider:a(`{provider} needs {what}; searches use DuckDuckGo until then`,{provider:E?.label??o.provider,what:E?.needs_key?a(`a key`):a(`an instance URL`)}),P=async()=>{y(!0),x(null);try{await u.setSearch({provider:f,base_url:f===`searxng`?m.trim():``,api_key:k?g||void 0:``}),_(``),i(a(`Saved`)),n()}catch(e){i(e.message)}finally{y(!1)}},F=async()=>{w(!0);try{x(await u.testSearch())}catch(e){x({ok:!1,error:e.message})}finally{w(!1)}},I=e=>t(`rounded-full px-3 py-1.5 text-[13px] border`,e?`border-accent bg-accent/10 text-accent font-medium`:`border-border text-muted`),L=f!==`searxng`||/^https?:\/\//.test(m.trim());return(0,q.jsxs)(A,{icon:(0,q.jsx)(B,{size:19}),title:a(`Web search`),summary:M,status:j,open:s,onToggle:()=>d(!s),children:[(0,q.jsx)(`p`,{className:`text-[12.5px] text-muted leading-snug`,children:a(`DuckDuckGo needs nothing, but it is scraped and rate-limits now and then. For searches that always work, use a provider with an API. Whichever you pick, a failed search falls back to DuckDuckGo with a note.`)}),(0,q.jsx)(Q,{label:a(`Provider`),children:(0,q.jsx)(`div`,{className:`flex flex-wrap gap-1.5`,children:o.providers.map(e=>(0,q.jsx)(`button`,{type:`button`,onClick:()=>p(e.id),className:I(f===e.id),children:e.label},e.id))})}),k&&(0,q.jsxs)(Q,{label:a(`API key`),hint:o.key_source===`vault`&&o.provider===f?a(`A key is in the vault. Leave blank to keep it.`):a(`Stored encrypted in the vault as SEARCH_API_KEY.`),children:[(0,q.jsx)(`input`,{type:`password`,value:g,onChange:e=>_(e.target.value),className:`w-full rounded-2xl bg-surface-2 px-3.5 py-2.5 text-[14.5px] outline-none focus:ring-2 focus:ring-accent/40`,placeholder:o.key_source===`vault`&&o.provider===f?`••••••••`:`…`,autoComplete:`off`}),O?.keys_url&&(0,q.jsx)(`a`,{href:O.keys_url,target:`_blank`,rel:`noreferrer`,className:`mt-1 inline-block text-[12px] text-accent`,children:a(`Get a key from {label}`,{label:O.label})})]}),f===`searxng`&&(0,q.jsx)(Q,{label:a(`Instance URL`),hint:a(`A SearXNG you run, with the JSON format enabled in its settings.`),children:(0,q.jsx)(`input`,{value:m,onChange:e=>h(e.target.value),className:`w-full rounded-2xl bg-surface-2 px-3.5 py-2.5 text-[14.5px] outline-none focus:ring-2 focus:ring-accent/40`,placeholder:`http://127.0.0.1:8080`,inputMode:`url`})}),(0,q.jsxs)(`div`,{className:`flex gap-2 pt-1`,children:[(0,q.jsxs)(`button`,{type:`button`,disabled:v||!L,onClick:()=>void P(),className:D,children:[v?(0,q.jsx)(l,{size:16,className:`animate-spin`}):(0,q.jsx)(C,{size:16}),` `,a(`Save`)]}),(0,q.jsxs)(`button`,{type:`button`,disabled:S,onClick:()=>void F(),className:T,children:[S?(0,q.jsx)(l,{size:16,className:`animate-spin`}):(0,q.jsx)(N,{size:16}),` `,a(`Test`)]})]}),b&&(0,q.jsx)(et,{result:b,okText:a(`{provider} · {n} results · {ms} ms`,{provider:b.provider??``,n:b.results??0,ms:b.ms??0})})]})}var He=[{id:`gmail`,label:`Gmail`,imap:`imap.gmail.com`,smtp:`smtp.gmail.com`,port:587,starttls:!0},{id:`outlook`,label:`Outlook`,imap:`outlook.office365.com`,smtp:`smtp.office365.com`,port:587,starttls:!0},{id:`icloud`,label:`iCloud`,imap:`imap.mail.me.com`,smtp:`smtp.mail.me.com`,port:587,starttls:!0},{id:`qq`,label:`QQ`,imap:`imap.qq.com`,smtp:`smtp.qq.com`,port:587,starttls:!0},{id:`163`,label:`163`,imap:`imap.163.com`,smtp:`smtp.163.com`,port:465,starttls:!1},{id:`fastmail`,label:`Fastmail`,imap:`imap.fastmail.com`,smtp:`smtp.fastmail.com`,port:587,starttls:!0}];function Ue({data:e,onChange:n,compact:i}){let{toast:a}=c(),o=r(),s=e.email,[d,f]=(0,G.useState)(!!i),[p,m]=(0,G.useState)(s.address),[h,g]=(0,G.useState)(``),[_,v]=(0,G.useState)(s.imap_host),[y,b]=(0,G.useState)(s.imap_port),[x,S]=(0,G.useState)(s.smtp_host),[C,w]=(0,G.useState)(s.smtp_port),[T,E]=(0,G.useState)(s.smtp_starttls),[k,j]=(0,G.useState)(null),[M,P]=(0,G.useState)(null);(0,G.useEffect)(()=>{m(s.address),v(s.imap_host),b(s.imap_port),S(s.smtp_host),w(s.smtp_port),E(s.smtp_starttls)},[s]);let F=e=>{v(e.imap),b(993),S(e.smtp),w(e.port),E(e.starttls)},I=async()=>{j(`save`),P(null);try{await u.setEmail({enabled:!0,address:p.trim(),password:h||void 0,imap_host:_.trim(),imap_port:y,smtp_host:x.trim(),smtp_port:C,smtp_starttls:T}),g(``);let e=await u.testEmail();P(e),a(e.ok?o(`Email connected`):o(`Saved, but the test failed`)),n()}catch(e){a(e.message)}finally{j(null)}},L=async()=>{j(`off`);try{await u.disconnectEmail(),P(null),a(o(`Email disconnected`)),n()}catch(e){a(e.message)}finally{j(null)}},ee=s.enabled&&s.configured?{text:o(`Connected`),tone:`ok`}:s.enabled?{text:o(`Incomplete`),tone:`warn`}:{text:o(`Not connected`),tone:`off`};return(0,q.jsxs)(A,{icon:(0,q.jsx)(ie,{size:19}),title:o(`Email`),summary:s.configured&&s.enabled?`${s.address} · ${o(`reads and sends`)}`:o(`Read your inbox, draft and send mail`),status:ee,open:d,onToggle:i?void 0:()=>f(!d),children:[(0,q.jsx)(`p`,{className:`text-[12.5px] text-muted -mt-1`,children:o(`Reading is a moderate action; sending always asks you first. Use an app password where your provider offers one.`)}),(0,q.jsx)(Q,{label:o(`Provider`),children:(0,q.jsx)(`div`,{className:`flex flex-wrap gap-1.5`,children:He.map(e=>(0,q.jsx)(`button`,{type:`button`,onClick:()=>F(e),className:t(`rounded-full px-3 py-1.5 text-[13px] border`,_===e.imap?`border-accent bg-accent/10 text-accent font-medium`:`border-border text-muted`),children:e.label},e.id))})}),(0,q.jsx)(Q,{label:o(`Address`),children:(0,q.jsx)(`input`,{value:p,onChange:e=>m(e.target.value),className:O,placeholder:`you@example.com`,inputMode:`email`,autoComplete:`off`})}),(0,q.jsx)(Q,{label:o(`Password`),hint:s.password_set?o(`A password is in the vault. Leave blank to keep it.`):o(`Stored encrypted in the vault as EMAIL_PASSWORD.`),children:(0,q.jsx)(`input`,{type:`password`,value:h,onChange:e=>g(e.target.value),className:O,placeholder:s.password_set?`••••••••`:o(`app password`),autoComplete:`off`})}),(0,q.jsxs)(`div`,{className:`grid grid-cols-[1fr_84px] gap-2`,children:[(0,q.jsx)(Q,{label:o(`IMAP server`),children:(0,q.jsx)(`input`,{value:_,onChange:e=>v(e.target.value),className:O,placeholder:`imap.example.com`})}),(0,q.jsx)(Q,{label:o(`Port`),children:(0,q.jsx)(`input`,{type:`number`,value:y,onChange:e=>b(Number(e.target.value)),className:O})}),(0,q.jsx)(Q,{label:o(`SMTP server`),children:(0,q.jsx)(`input`,{value:x,onChange:e=>S(e.target.value),className:O,placeholder:`smtp.example.com`})}),(0,q.jsx)(Q,{label:o(`Port`),children:(0,q.jsx)(`input`,{type:`number`,value:C,onChange:e=>w(Number(e.target.value)),className:O})})]}),(0,q.jsxs)(`label`,{className:`flex items-center gap-2 text-[13.5px]`,children:[(0,q.jsx)(`input`,{type:`checkbox`,checked:T,onChange:e=>E(e.target.checked),className:`accent-[var(--om-accent)]`}),` `,o(`STARTTLS for SMTP (off for port 465)`)]}),(0,q.jsxs)(`div`,{className:`flex gap-2 pt-1`,children:[(0,q.jsxs)(`button`,{type:`button`,disabled:k!==null||!p.trim()||!_.trim()||!x.trim()||!h&&!s.password_set,onClick:()=>void I(),className:D,children:[k===`save`?(0,q.jsx)(l,{size:16,className:`animate-spin`}):(0,q.jsx)(N,{size:16}),` `,s.configured?o(`Save & test`):o(`Connect`)]}),s.enabled&&(0,q.jsxs)(`button`,{type:`button`,disabled:k!==null,onClick:()=>void L(),className:`flex items-center justify-center gap-1.5 rounded-2xl border border-border px-4 py-2.5 text-[14px] font-medium text-muted disabled:opacity-40`,children:[k===`off`?(0,q.jsx)(l,{size:16,className:`animate-spin`}):(0,q.jsx)(U,{size:16}),` `,o(`Disconnect`)]})]}),M&&(0,q.jsx)(et,{result:M,okText:o(`Signed in · {n} messages in the inbox`,{n:M.inbox??`?`})})]})}var We=[{id:`google`,label:`Google`,hint:`Settings → your calendar → Integrate calendar → Secret address in iCal format`},{id:`outlook`,label:`Outlook`,hint:`Settings → Calendar → Shared calendars → Publish a calendar → ICS link`},{id:`icloud`,label:`iCloud`,hint:`Share Calendar → Public Calendar → copy the webcal:// link`},{id:`fastmail`,label:`Fastmail`,hint:`Settings → Calendars → Export → Calendar URL`},{id:`file`,label:`.ics file`,hint:`A path on the machine where nanoMuse runs, for example ~/calendar.ics`}];function Ge({data:n,onChange:i,compact:a}){let{toast:o}=c(),s=r(),d=n.calendar,[f,p]=(0,G.useState)(!!a),[m,h]=(0,G.useState)(!1),[g,_]=(0,G.useState)(``),[v,y]=(0,G.useState)(``),[b,x]=(0,G.useState)(null),[S,w]=(0,G.useState)(d.day_start),[E,k]=(0,G.useState)(d.day_end),[j,M]=(0,G.useState)(null),[F,I]=(0,G.useState)(null);(0,G.useEffect)(()=>{w(d.day_start),k(d.day_end)},[d.day_start,d.day_end]);let L=async()=>{M(`add`),I(null);try{let e=await u.addCalendarFeed(g.trim(),v.trim());if(e.error)o(s(`Added, but it could not be read: {error}`,{error:e.error}));else{let t=e.feeds.find(e=>e.name===g.trim());o(`${s(`Calendar connected`)} · ${re(t?.events??0)}`),_(``),y(``),h(!1)}i()}catch(e){o(e.message)}finally{M(null)}},ee=async e=>{M(e);try{await u.removeCalendarFeed(e),i()}catch(e){o(e.message)}finally{M(null)}},R=async()=>{M(`hours`);try{await u.setCalendar({day_start:S,day_end:E}),o(s(`Saved`)),i()}catch(e){o(e.message)}finally{M(null)}},te=async()=>{M(`test`);try{I(await u.testCalendar()),i()}catch(e){o(e.message)}finally{M(null)}},B=d.feeds.reduce((e,t)=>e+t.events,0),V=d.feeds.filter(e=>e.error).length,re=e=>e===1?s(`1 event`):s(`{n} events`,{n:e}),H=d.configured?V?{text:s(`{n} not reading`,{n:V}),tone:`warn`}:{text:s(`Connected`),tone:`ok`}:{text:s(`Not connected`),tone:`off`};return(0,q.jsxs)(A,{icon:(0,q.jsx)(oe,{size:19}),title:s(`Calendar`),summary:d.configured?d.feeds.length===1?`${d.feeds[0].name} · ${re(B)}`:`${s(`{n} calendars`,{n:d.feeds.length})} · ${re(B)}`:s(`Your agenda, free time, and events it can draft`),status:H,open:f,onToggle:a?void 0:()=>p(!f),children:[(0,q.jsx)(`p`,{className:`text-[12.5px] text-muted -mt-1`,children:s(`Reads your calendar from its private .ics link; the link stays in the vault. It never changes your calendar; an event it proposes comes as a file you add with a tap.`)}),d.feeds.length>0&&(0,q.jsx)(`ul`,{className:`space-y-1.5`,children:d.feeds.map(n=>(0,q.jsxs)(`li`,{className:`flex items-center gap-2.5 rounded-2xl bg-surface-2/60 px-3 py-2`,children:[(0,q.jsx)(`span`,{className:t(`h-2 w-2 rounded-full`,n.error?`bg-rose-500`:n.fetched_at?`bg-emerald-500`:`bg-amber-500`)}),(0,q.jsxs)(`div`,{className:`min-w-0 flex-1`,children:[(0,q.jsx)(`div`,{className:`text-[13.5px] font-medium truncate`,children:n.name}),(0,q.jsxs)(`div`,{className:`text-[11.5px] text-muted truncate`,children:[n.error?n.error:n.fetched_at?`${re(n.events)} · ${s(`read {when}`,{when:e(n.fetched_at)})}`:s(`not read yet`),!n.from_app&&` · ${s(`from config.toml`)}`]})]}),n.from_app&&(0,q.jsx)(`button`,{type:`button`,"aria-label":s(`Remove`),disabled:j===n.name,onClick:()=>void ee(n.name),className:`p-1.5 rounded-full text-muted hover:bg-surface-2`,children:j===n.name?(0,q.jsx)(l,{size:15,className:`animate-spin`}):(0,q.jsx)(z,{size:15})})]},n.name))}),m?(0,q.jsxs)(`div`,{className:`space-y-2.5 rounded-2xl border border-border/70 p-3`,children:[(0,q.jsxs)(Q,{label:s(`Where is the link?`),children:[(0,q.jsx)(`div`,{className:`flex flex-wrap gap-1.5`,children:We.map(e=>(0,q.jsx)(`button`,{type:`button`,onClick:()=>x(b===e.id?null:e.id),className:t(`rounded-full px-3 py-1.5 text-[13px] border`,b===e.id?`border-accent bg-accent/10 text-accent font-medium`:`border-border text-muted`),children:s(e.label)},e.id))}),b&&(0,q.jsx)(`div`,{className:`mt-1.5 text-[11.5px] text-muted leading-snug`,children:s(We.find(e=>e.id===b).hint)})]}),(0,q.jsx)(Q,{label:s(`Name`),children:(0,q.jsx)(`input`,{value:g,onChange:e=>_(e.target.value),className:O,placeholder:s(`Work`)})}),(0,q.jsx)(Q,{label:s(`Private .ics link or file path`),hint:s(`Stored encrypted in the vault as CALENDAR_{name}.`,{name:g.trim().toUpperCase().replace(/[^A-Z0-9]+/g,`_`).replace(/^_+|_+$/g,``)||`NAME`})+` `+s(`nanoMuse fetches whatever address you put here, from this machine; only paste links you trust.`),children:(0,q.jsx)(`input`,{value:v,onChange:e=>y(e.target.value),className:O,placeholder:`https://calendar.google.com/calendar/ical/…/basic.ics`,inputMode:`url`,autoComplete:`off`})}),(0,q.jsxs)(`div`,{className:`flex gap-2`,children:[(0,q.jsxs)(`button`,{type:`button`,disabled:j===`add`||!g.trim()||!v.trim(),onClick:()=>void L(),className:D,children:[j===`add`?(0,q.jsx)(l,{size:16,className:`animate-spin`}):(0,q.jsx)(N,{size:16}),` `,s(`Connect`)]}),(0,q.jsx)(`button`,{type:`button`,onClick:()=>h(!1),className:T,children:s(`Cancel`)})]})]}):(0,q.jsxs)(`button`,{type:`button`,onClick:()=>h(!0),className:T,children:[(0,q.jsx)(ne,{size:16}),` `,s(`Add a calendar`)]}),d.configured&&(0,q.jsxs)(q.Fragment,{children:[(0,q.jsx)(Q,{label:s(`Working hours`),hint:s(`Free time is looked for inside these hours.`),children:(0,q.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,q.jsx)(`input`,{type:`time`,value:S,onChange:e=>w(e.target.value),className:t(`w-full rounded-2xl bg-surface-2 px-3.5 py-2.5 text-[14.5px] outline-none focus:ring-2 focus:ring-accent/40`,`w-auto`)}),(0,q.jsx)(`span`,{className:`text-muted`,children:`–`}),(0,q.jsx)(`input`,{type:`time`,value:E,onChange:e=>k(e.target.value),className:t(`w-full rounded-2xl bg-surface-2 px-3.5 py-2.5 text-[14.5px] outline-none focus:ring-2 focus:ring-accent/40`,`w-auto`)}),(S!==d.day_start||E!==d.day_end)&&(0,q.jsx)(`button`,{type:`button`,disabled:j===`hours`,onClick:()=>void R(),className:t(`flex items-center justify-center gap-1.5 rounded-2xl bg-accent text-accent-fg px-4 py-2.5 text-[14px] font-medium disabled:opacity-40`,`px-3`),"aria-label":s(`Save`),children:j===`hours`?(0,q.jsx)(l,{size:16,className:`animate-spin`}):(0,q.jsx)(C,{size:16})})]})}),(0,q.jsxs)(`button`,{type:`button`,disabled:j===`test`,onClick:()=>void te(),className:`flex items-center justify-center gap-1.5 rounded-2xl border border-border px-4 py-2.5 text-[14px] font-medium text-muted disabled:opacity-40`,children:[j===`test`?(0,q.jsx)(l,{size:16,className:`animate-spin`}):(0,q.jsx)(P,{size:16}),` `,s(`Read again`)]}),F&&(0,q.jsx)(et,{result:F,okText:d.feeds.length===1?re(F.events??0):`${re(F.events??0)} · ${s(`{n} calendars`,{n:d.feeds.length})}`})]})]})}function Ke({data:n,onChange:i,compact:a}){let{toast:o}=c(),s=r(),d=n.contacts,[f,p]=(0,G.useState)(!!a),[m,h]=(0,G.useState)(!1),[g,_]=(0,G.useState)(``),[v,y]=(0,G.useState)(``),[b,x]=(0,G.useState)(null),[S,C]=(0,G.useState)(null),[w,E]=(0,G.useState)(``),[k,j]=(0,G.useState)(null),M=(0,G.useRef)(null),F=e=>e===1?s(`1 person`):s(`{n} people`,{n:e}),I=(e,t)=>{if(e.error)o(s(`Added, but it could not be read: {error}`,{error:e.error}));else{let n=e.sources.find(e=>e.name===t);o(`${s(`Address book connected`)} · ${F(n?.contacts??0)}`),_(``),y(``),h(!1)}i()},L=async()=>{x(`add`),C(null);try{I(await u.addContactsSource(g.trim(),v.trim()),g.trim())}catch(e){o(e.message)}finally{x(null)}},ee=async e=>{x(`upload`),C(null);try{let t=(g.trim()||e.name.replace(/\.vcf$/i,``)||`Imported`).slice(0,40);I(await u.importContacts(t,await e.text()),t)}catch(e){o(e.message)}finally{x(null),M.current&&(M.current.value=``)}},R=async e=>{x(e);try{await u.removeContactsSource(e),i()}catch(e){o(e.message)}finally{x(null)}},te=async()=>{x(`test`);try{C(await u.testContacts()),i()}catch(e){o(e.message)}finally{x(null)}};(0,G.useEffect)(()=>{if(!w.trim()){j(null);return}let e=setTimeout(()=>{u.contacts(w.trim(),5).then(e=>j(e.people)).catch(()=>j([]))},250);return()=>clearTimeout(e)},[w]);let V=d.sources.filter(e=>e.error).length,re=d.enabled?d.configured?V?{text:s(`{n} not reading`,{n:V}),tone:`warn`}:{text:s(`Connected`),tone:`ok`}:{text:s(`Not connected`),tone:`off`}:{text:s(`Off`),tone:`off`};return(0,q.jsxs)(A,{icon:(0,q.jsx)(ue,{size:19}),title:s(`Contacts`),summary:d.configured?d.sources.length===0?`${F(d.count)} · ${s(`told to it in chat`)}`:`${F(d.count)} · ${d.sources.length===1?d.sources[0].name:s(`{n} address books`,{n:d.sources.length})}`:s(`Who is who, so it never guesses an address`),status:re,open:f,onToggle:a?void 0:()=>p(!f),children:[(0,q.jsx)(`p`,{className:`text-[12.5px] text-muted -mt-1`,children:s(`Import a .vcf export from Google Contacts, iCloud, Outlook or your phone, or paste a link to one. People you mention in chat go into its own book. It looks people up before writing to them and warns when an address is unknown.`)}),(d.sources.length>0||d.own>0)&&(0,q.jsxs)(`ul`,{className:`space-y-1.5`,children:[d.own>0&&(0,q.jsxs)(`li`,{className:`flex items-center gap-2.5 rounded-2xl bg-surface-2/60 px-3 py-2`,children:[(0,q.jsx)(`span`,{className:`h-2 w-2 rounded-full bg-emerald-500`}),(0,q.jsxs)(`div`,{className:`min-w-0 flex-1`,children:[(0,q.jsx)(`div`,{className:`text-[13.5px] font-medium truncate`,children:s(`My contacts`)}),(0,q.jsx)(`div`,{className:`text-[11.5px] text-muted truncate`,children:`${F(d.own)} · ${s(`added in chat`)}`})]})]}),d.sources.map(n=>(0,q.jsxs)(`li`,{className:`flex items-center gap-2.5 rounded-2xl bg-surface-2/60 px-3 py-2`,children:[(0,q.jsx)(`span`,{className:t(`h-2 w-2 rounded-full`,n.error?`bg-rose-500`:n.fetched_at?`bg-emerald-500`:`bg-amber-500`)}),(0,q.jsxs)(`div`,{className:`min-w-0 flex-1`,children:[(0,q.jsx)(`div`,{className:`text-[13.5px] font-medium truncate`,children:n.name}),(0,q.jsxs)(`div`,{className:`text-[11.5px] text-muted truncate`,children:[n.error?n.error:n.fetched_at?`${F(n.contacts)} · ${s(`read {when}`,{when:e(n.fetched_at)})}`:s(`not read yet`),!n.from_app&&` · ${s(`from config.toml`)}`]})]}),n.from_app&&(0,q.jsx)(`button`,{type:`button`,"aria-label":s(`Remove`),disabled:b===n.name,onClick:()=>void R(n.name),className:`p-1.5 rounded-full text-muted hover:bg-surface-2`,children:b===n.name?(0,q.jsx)(l,{size:15,className:`animate-spin`}):(0,q.jsx)(z,{size:15})})]},n.name))]}),m?(0,q.jsxs)(`div`,{className:`space-y-2.5 rounded-2xl border border-border/70 p-3`,children:[(0,q.jsx)(Q,{label:s(`Name`),children:(0,q.jsx)(`input`,{value:g,onChange:e=>_(e.target.value),className:O,placeholder:s(`iPhone`)})}),(0,q.jsxs)(Q,{label:s(`A .vcf file from your phone or computer`),hint:s(`Google Contacts: Export → vCard. iPhone: Contacts → select all → Share → Save to Files. Outlook: People → Manage → Export.`),children:[(0,q.jsx)(`input`,{ref:M,type:`file`,accept:`.vcf,text/vcard,text/x-vcard`,className:`hidden`,onChange:e=>e.target.files?.[0]&&void ee(e.target.files[0])}),(0,q.jsxs)(`button`,{type:`button`,disabled:b===`upload`,onClick:()=>M.current?.click(),className:T,children:[b===`upload`?(0,q.jsx)(l,{size:16,className:`animate-spin`}):(0,q.jsx)(W,{size:16}),` `,s(`Choose a .vcf file`)]})]}),(0,q.jsx)(Q,{label:s(`Or a link / path to one`),hint:s(`A link is stored encrypted in the vault as CONTACTS_{name}.`,{name:g.trim().toUpperCase().replace(/[^A-Z0-9]+/g,`_`).replace(/^_+|_+$/g,``)||`NAME`})+` `+s(`nanoMuse fetches whatever address you put here, from this machine; only paste links you trust.`),children:(0,q.jsx)(`input`,{value:v,onChange:e=>y(e.target.value),className:O,placeholder:`https://… /contacts.vcf`,inputMode:`url`,autoComplete:`off`})}),(0,q.jsxs)(`div`,{className:`flex gap-2`,children:[(0,q.jsxs)(`button`,{type:`button`,disabled:b===`add`||!g.trim()||!v.trim(),onClick:()=>void L(),className:D,children:[b===`add`?(0,q.jsx)(l,{size:16,className:`animate-spin`}):(0,q.jsx)(N,{size:16}),` `,s(`Connect`)]}),(0,q.jsx)(`button`,{type:`button`,onClick:()=>h(!1),className:T,children:s(`Cancel`)})]})]}):(0,q.jsxs)(`button`,{type:`button`,onClick:()=>h(!0),className:T,children:[(0,q.jsx)(ne,{size:16}),` `,s(`Add an address book`)]}),d.configured&&(0,q.jsxs)(q.Fragment,{children:[(0,q.jsxs)(`div`,{className:`relative`,children:[(0,q.jsx)(B,{size:15,className:`absolute left-3 top-1/2 -translate-y-1/2 text-muted`}),(0,q.jsx)(`input`,{value:w,onChange:e=>E(e.target.value),className:t(`w-full rounded-2xl bg-surface-2 px-3.5 py-2.5 text-[14.5px] outline-none focus:ring-2 focus:ring-accent/40`,`pl-9`),placeholder:s(`Find someone, as the agent would`),autoComplete:`off`})]}),k!==null&&(0,q.jsxs)(`ul`,{className:`space-y-1`,children:[k.length===0&&(0,q.jsx)(`li`,{className:`text-[12.5px] text-muted px-1`,children:s(`No one matches.`)}),k.map(e=>(0,q.jsxs)(`li`,{className:`rounded-2xl bg-surface-2/60 px-3 py-2`,children:[(0,q.jsxs)(`div`,{className:`text-[13.5px] font-medium`,children:[e.name,e.org&&(0,q.jsxs)(`span`,{className:`text-muted font-normal`,children:[` · `,e.org]})]}),(0,q.jsx)(`div`,{className:`text-[12px] text-muted break-words`,children:[...e.emails,...e.phones].join(` · `)})]},e.id))]}),d.sources.length>0&&(0,q.jsxs)(`button`,{type:`button`,disabled:b===`test`,onClick:()=>void te(),className:`flex items-center justify-center gap-1.5 rounded-2xl border border-border px-4 py-2.5 text-[14px] font-medium text-muted disabled:opacity-40`,children:[b===`test`?(0,q.jsx)(l,{size:16,className:`animate-spin`}):(0,q.jsx)(P,{size:16}),` `,s(`Read again`)]}),S&&(0,q.jsx)(et,{result:S,okText:F(S.contacts??0)})]})]})}function qe({data:e,onChange:n}){let{toast:i}=c(),a=r(),o=e.browser,[s,l]=(0,G.useState)(!1),d=async()=>{l(!0);try{await u.setBrowser(!o.enabled),n()}catch(e){i(e.message)}finally{l(!1)}};return(0,q.jsx)(A,{icon:(0,q.jsx)(H,{size:19}),title:a(`Browser`),summary:o.available?a(`Open pages, click, fill forms, screenshot`):a(`Playwright is not installed on the server`),status:o.enabled&&o.available?{text:a(`On`),tone:`ok`}:o.enabled?{text:a(`Unavailable`),tone:`warn`}:{text:a(`Off`),tone:`off`},open:!1,trailing:(0,q.jsx)(`button`,{type:`button`,role:`switch`,"aria-checked":o.enabled,disabled:s,onClick:()=>void d(),className:t(`relative h-7 w-12 shrink-0 rounded-full transition`,o.enabled?`bg-accent`:`bg-surface-2 border border-border`),children:(0,q.jsx)(`span`,{className:t(`absolute top-0.5 h-6 w-6 rounded-full bg-white shadow transition`,o.enabled?`left-[22px]`:`left-0.5`)})}),children:!o.available&&(0,q.jsxs)(`p`,{className:`text-[12.5px] text-muted`,children:[a(`Install it where the server runs:`),` `,(0,q.jsx)(`code`,{className:`rounded bg-surface-2 px-1`,children:`pip install "nanomuse[browser]" && playwright install chromium`})]})})}function Je({data:e,onChange:n}){let{toast:i}=c(),a=r(),o=e.gui,[s,d]=(0,G.useState)(!1),[f,p]=(0,G.useState)(!1),[m,h]=(0,G.useState)(o.model),[g,_]=(0,G.useState)(o.base_url),[v,y]=(0,G.useState)(``),[b,x]=(0,G.useState)(null);(0,G.useEffect)(()=>{h(o.model),_(o.base_url)},[o.model,o.base_url]);let S=async()=>{p(!0);try{await u.setGui({enabled:!o.enabled}),n()}catch(e){i(e.message)}finally{p(!1)}},w=async()=>{p(!0),x(null);try{await u.setGui({model:m.trim(),base_url:g.trim(),...v?{api_key:v.trim()}:{}}),y(``),n(),x(await u.testGui())}catch(e){i(e.message)}finally{p(!1)}},T=o.phone,[E,k]=(0,G.useState)(te),j=(0,G.useRef)(E);(0,G.useEffect)(()=>{if(!s)return;let e=()=>{let e=te();e!==j.current&&(j.current=e,k(e),setTimeout(n,400))};return e(),document.addEventListener(`visibilitychange`,e),window.addEventListener(`focus`,e),()=>{document.removeEventListener(`visibilitychange`,e),window.removeEventListener(`focus`,e)}},[s,n]);let M=T.connected?a(`{name} is connected`,{name:T.device?.name??a(`A phone`)}):o.enabled?a(`No phone connected. Open the app on the phone`):a(`Tap, type and swipe in the apps on your phone`);return(0,q.jsxs)(A,{icon:(0,q.jsx)(L,{size:19}),title:a(`Phone`),summary:M,status:o.enabled&&T.connected?{text:a(`On`),tone:`ok`}:o.enabled?{text:a(`Waiting`),tone:`warn`}:{text:a(`Off`),tone:`off`},open:s,onToggle:()=>d(e=>!e),children:[(0,q.jsxs)(`div`,{className:`flex items-center justify-between gap-3`,children:[(0,q.jsxs)(`div`,{className:`text-[13px] leading-snug`,children:[(0,q.jsx)(`div`,{className:`font-medium`,children:a(`Operate the phone`)}),(0,q.jsx)(`div`,{className:`text-[12px] text-muted`,children:a(`When on, the agent can read the screen and act in the apps on the connected phone: 12306, WeChat, Alipay… It asks before paying, sending or deleting.`)})]}),(0,q.jsx)(`button`,{type:`button`,role:`switch`,"aria-checked":o.enabled,disabled:f,onClick:()=>void S(),className:t(`relative h-7 w-12 shrink-0 rounded-full transition`,o.enabled?`bg-accent`:`bg-surface-2 border border-border`),children:(0,q.jsx)(`span`,{className:t(`absolute top-0.5 h-6 w-6 rounded-full bg-white shadow transition`,o.enabled?`left-[22px]`:`left-0.5`)})})]}),E!==null&&(0,q.jsxs)(`div`,{className:`rounded-2xl bg-surface-2 px-3 py-2.5 text-[12.5px] leading-snug space-y-1.5`,children:[(0,q.jsxs)(`div`,{className:`flex items-center justify-between gap-3`,children:[(0,q.jsx)(`span`,{className:`font-medium`,children:a(`This phone`)}),(0,q.jsx)(`span`,{className:t(`rounded-full px-2 py-0.5 text-[11px] font-medium`,E===`on`&&`bg-emerald-500/12 text-emerald-700 dark:text-emerald-300`,E===`off`&&`bg-amber-500/15 text-amber-700 dark:text-amber-300`,E===`unsupported`&&`bg-surface text-muted`),children:a(E===`on`?`Ready`:E===`off`?`Not yet`:`Not on this Android`)})]}),E===`unsupported`&&(0,q.jsx)(`div`,{className:`text-muted`,children:a(`Operating the screen needs Android 11 or newer; this phone can still be used for everything else.`)}),E===`off`&&(0,q.jsxs)(q.Fragment,{children:[(0,q.jsx)(`div`,{className:`text-muted`,children:a(`Turn on the nanoMuse accessibility service; that is how it sees the screen and taps for you, only while a task runs, with a Stop button on screen.`)}),(0,q.jsxs)(`div`,{className:`flex flex-wrap gap-2 pt-0.5`,children:[(0,q.jsx)(`button`,{type:`button`,onClick:()=>I()?.openAccessibilitySettings?.(),className:`rounded-full bg-accent px-3 py-1.5 text-[12.5px] font-medium text-white`,children:a(`Open Accessibility settings`)}),(0,q.jsx)(`button`,{type:`button`,onClick:()=>I()?.openAppSettings?.(),className:`rounded-full border border-border px-3 py-1.5 text-[12.5px]`,children:a(`App settings`)})]}),(0,q.jsx)(`div`,{className:`text-muted`,children:a(`Greyed out with “Restricted setting”? Android 13+ does that for apps installed from a download: in App settings tap ⋮ → Allow restricted settings, then come back.`)})]}),E===`on`&&(0,q.jsx)(`div`,{className:`text-muted`,children:a(`Android may switch the service off after an update or a battery clean-up; if the phone stops answering, come back here.`)})]}),T.connected&&T.device&&(0,q.jsxs)(`div`,{className:`rounded-2xl bg-surface-2 px-3 py-2 text-[12.5px] text-muted`,children:[a(`{name} ({platform}), {n} apps`,{name:T.device.name,platform:T.device.platform,n:String(T.device.apps)}),T.last_screen&&(0,q.jsxs)(q.Fragment,{children:[` `,`·`,` `,a(`last seen in {app}`,{app:T.last_screen.app_name||T.last_screen.app})]})]}),(0,q.jsx)(`div`,{className:`text-[12px] text-muted leading-snug`,children:a(`The operator's model looks at screens step by step: a small, fast model that takes pictures. The Hands model row under Chat model picks one on the same endpoint and key; the fields here are for a different endpoint. Empty = {model}.`,{model:o.default_model||a(`the chat model`)})}),(0,q.jsx)(Q,{label:a(`Model`),children:(0,q.jsx)(`input`,{value:m,onChange:e=>h(e.target.value),placeholder:o.default_model||a(`same as the chat model`),className:O})}),(0,q.jsx)(Q,{label:a(`Base URL`),children:(0,q.jsx)(`input`,{value:g,onChange:e=>_(e.target.value),placeholder:a(`same as the chat model`),className:O})}),(0,q.jsx)(Q,{label:a(`API key`),hint:o.key_source===`vault`?a(`A key is in the vault; leave empty to keep it.`):o.key_source===`config`?a(`Set in config.toml.`):a(`Leave empty to use the main model's key.`),children:(0,q.jsx)(`input`,{type:`password`,value:v,onChange:e=>y(e.target.value),placeholder:`sk-…`,className:O,autoComplete:`off`})}),(0,q.jsxs)(`button`,{type:`button`,disabled:f,onClick:()=>void w(),className:D,children:[f?(0,q.jsx)(l,{size:16,className:`animate-spin`}):(0,q.jsx)(C,{size:16}),a(`Save and test`)]}),b&&(0,q.jsx)(et,{result:b,okText:a(`The operator's model answers.`)})]})}function Ye({data:e,onChange:n}){let{toast:i}=c(),a=r(),[o,s]=(0,G.useState)(!1),[d,f]=(0,G.useState)(!1),[p,m]=(0,G.useState)(``),[h,g]=(0,G.useState)(``),[_,v]=(0,G.useState)(``),[y,b]=(0,G.useState)(`moderate`),[x,S]=(0,G.useState)(null),C=async()=>{S(`add`);try{let e=h.trim().split(/\s+/).filter(Boolean);await u.addMCP({name:p.trim(),command:e[0]??null,args:e.slice(1),url:_.trim()||null,risk:y}),m(``),g(``),v(``),f(!1),i(a(`Server connected`)),n()}catch(e){i(e.message)}finally{S(null)}},w=async e=>{S(e);try{await u.removeMCP(e),n()}catch(e){i(e.message)}finally{S(null)}},E=e.mcp.filter(e=>e.connected).length,k=(e.shared??[]).filter(e=>e.enabled&&!e.here),j=e=>{m(e.id),v(e.url),g(``),f(!0),s(!0)};return(0,q.jsxs)(A,{icon:(0,q.jsx)(N,{size:19}),title:a(`MCP servers`),summary:e.mcp.length?a(`{n} of {total} connected · {tools} tools`,{n:E,total:e.mcp.length,tools:e.mcp.reduce((e,t)=>e+t.tools,0)}):a(`Add tools from any Model Context Protocol server`),status:e.mcp.length?{text:a(`{n} on`,{n:E}),tone:E?`ok`:`warn`}:{text:a(`None`),tone:`off`},open:o,onToggle:()=>s(!o),children:[e.mcp.length>0&&(0,q.jsx)(`ul`,{className:`space-y-1.5`,children:e.mcp.map(e=>(0,q.jsxs)(`li`,{className:`flex items-center gap-2.5 rounded-2xl bg-surface-2/60 px-3 py-2`,children:[(0,q.jsx)(`span`,{className:t(`h-2 w-2 rounded-full`,e.connected?`bg-emerald-500`:`bg-rose-500`)}),(0,q.jsxs)(`div`,{className:`min-w-0 flex-1`,children:[(0,q.jsx)(`div`,{className:`text-[13.5px] font-medium truncate`,children:e.builtin?a(`This phone`):e.name}),(0,q.jsxs)(`div`,{className:`text-[11.5px] text-muted truncate`,children:[e.builtin?a(`clipboard, notifications, calendar, contacts, location, alarms, photos`):e.url??[e.command,...e.args].join(` `),` ·`,` `,a(`{n} tools`,{n:e.tools}),` · `,a(e.risk),!e.from_app&&!e.builtin&&` · ${a(`from config.toml`)}`]})]}),e.from_app&&(0,q.jsx)(`button`,{type:`button`,"aria-label":a(`Remove`),disabled:x===e.name,onClick:()=>void w(e.name),className:`p-1.5 rounded-full text-muted hover:bg-surface-2`,children:x===e.name?(0,q.jsx)(l,{size:15,className:`animate-spin`}):(0,q.jsx)(z,{size:15})})]},e.name))}),k.length>0&&(0,q.jsx)(`ul`,{className:`space-y-1.5`,children:k.map(e=>(0,q.jsxs)(`li`,{className:`flex items-center gap-2.5 rounded-2xl border border-dashed border-border/70 px-3 py-2`,children:[(0,q.jsx)(`span`,{className:`h-2 w-2 rounded-full bg-border`}),(0,q.jsxs)(`div`,{className:`min-w-0 flex-1`,children:[(0,q.jsx)(`div`,{className:`text-[13.5px] font-medium truncate`,children:e.label||e.id}),(0,q.jsxs)(`div`,{className:`text-[11.5px] text-muted truncate`,children:[a(`Connected on {device}; sign in here to use it on this device`,{device:e.device||e.device_id}),e.url?` · ${e.url}`:``]})]}),e.url&&(0,q.jsx)(`button`,{type:`button`,onClick:()=>j(e),className:t(`flex items-center justify-center gap-1.5 rounded-2xl border border-border px-4 py-2.5 text-[14px] font-medium text-muted disabled:opacity-40`,`py-1.5 text-[12.5px]`),children:a(`Sign in here`)})]},`${e.device_id}:${e.id}`))}),d?(0,q.jsxs)(`div`,{className:`space-y-2.5 rounded-2xl border border-border/70 p-3`,children:[(0,q.jsx)(Q,{label:a(`Name`),children:(0,q.jsx)(`input`,{value:p,onChange:e=>m(e.target.value),className:O,placeholder:`filesystem`})}),(0,q.jsx)(Q,{label:a(`Command`),hint:a(`Run locally over stdio, for example: npx -y @modelcontextprotocol/server-filesystem ./workspace`),children:(0,q.jsx)(`input`,{value:h,onChange:e=>g(e.target.value),className:O,placeholder:`npx -y @modelcontextprotocol/server-…`})}),(0,q.jsx)(Q,{label:a(`or URL`),hint:a(`A remote server over Streamable HTTP.`),children:(0,q.jsx)(`input`,{value:_,onChange:e=>v(e.target.value),className:O,placeholder:`https://host/mcp`,inputMode:`url`})}),(0,q.jsx)(Q,{label:a(`Risk of its tools`),hint:a(`Decides when the Sentinel asks you before a call.`),children:(0,q.jsx)(`div`,{className:`flex gap-1.5`,children:[`safe`,`moderate`,`high`].map(e=>(0,q.jsx)(`button`,{type:`button`,onClick:()=>b(e),className:t(`rounded-full px-3 py-1.5 text-[13px] border`,y===e?`border-accent bg-accent/10 text-accent font-medium`:`border-border text-muted`),children:a(e)},e))})}),(0,q.jsxs)(`div`,{className:`flex gap-2`,children:[(0,q.jsxs)(`button`,{type:`button`,disabled:x===`add`||!p.trim()||!(h.trim()||_.trim()),onClick:()=>void C(),className:D,children:[x===`add`?(0,q.jsx)(l,{size:16,className:`animate-spin`}):(0,q.jsx)(N,{size:16}),` `,a(`Connect`)]}),(0,q.jsx)(`button`,{type:`button`,onClick:()=>f(!1),className:T,children:a(`Cancel`)})]})]}):(0,q.jsxs)(`button`,{type:`button`,onClick:()=>f(!0),className:T,children:[(0,q.jsx)(ne,{size:16}),` `,a(`Add a server`)]})]})}function Xe({data:e,onChange:n}){let{toast:i}=c(),a=r(),[o,s]=(0,G.useState)(!1),[d,f]=(0,G.useState)(``),[p,m]=(0,G.useState)(``),[h,g]=(0,G.useState)(null),_=async()=>{g(`add`);try{await u.vaultSet(d.trim(),p),f(``),m(``),i(a(`Stored in the vault`)),n()}catch(e){i(e.message)}finally{g(null)}},v=async e=>{g(e);try{await u.vaultDelete(e),n()}catch(e){i(e.message)}finally{g(null)}};return(0,q.jsxs)(A,{icon:(0,q.jsx)(ae,{size:19}),title:a(`Vault`),summary:e.vault.length?a(`{n} secrets · encrypted on your machine`,{n:e.vault.length}):a(`Encrypted secrets the model never sees`),status:{text:`${e.vault.length}`,tone:`off`},open:o,onToggle:()=>s(!o),children:[(0,q.jsxs)(`p`,{className:`text-[12.5px] text-muted -mt-1`,children:[a(`Refer to a secret as`),` `,(0,q.jsx)(`code`,{className:`rounded bg-surface-2 px-1`,children:`{{vault:NAME}}`}),` `,a(`in a tool call or config: the value is filled in after the Sentinel approves and is redacted from everything the model reads.`)]}),e.vault.length>0&&(0,q.jsx)(`ul`,{className:`flex flex-wrap gap-1.5`,children:e.vault.map(e=>(0,q.jsxs)(`li`,{className:`flex items-center gap-1 rounded-full bg-surface-2 pl-3 pr-1 py-1 text-[12.5px] font-mono`,children:[e,(0,q.jsx)(`button`,{type:`button`,"aria-label":a(`Delete {name}`,{name:e}),disabled:h===e,onClick:()=>void v(e),className:`p-1 rounded-full text-muted hover:text-rose-500`,children:h===e?(0,q.jsx)(l,{size:13,className:`animate-spin`}):(0,q.jsx)(z,{size:13})})]},e))}),(0,q.jsxs)(`div`,{className:`grid grid-cols-[1fr_1fr_auto] gap-2 items-end`,children:[(0,q.jsx)(Q,{label:a(`Name`),children:(0,q.jsx)(`input`,{value:d,onChange:e=>f(e.target.value.toUpperCase().replace(/[^A-Z0-9_.-]/g,`_`)),className:t(O,`font-mono`),placeholder:`GITHUB_TOKEN`})}),(0,q.jsx)(Q,{label:a(`Value`),children:(0,q.jsx)(`input`,{type:`password`,value:p,onChange:e=>m(e.target.value),className:O,placeholder:a(`secret`),autoComplete:`off`})}),(0,q.jsx)(`button`,{type:`button`,disabled:h===`add`||!d||!p,onClick:()=>void _(),className:t(D,`px-3`),"aria-label":a(`Store`),children:h===`add`?(0,q.jsx)(l,{size:16,className:`animate-spin`}):(0,q.jsx)(ne,{size:16})})]})]})}var Ze=`\0other`;function Qe({label:e,provider:n,value:i,options:a,more:o=[],onChange:s,other:c=!0,placeholder:l}){let u=r(),d=a.includes(i)||o.includes(i),[f,p]=(0,G.useState)(!1),m=l?u(`Automatic · {model}`,{model:l}):u(`Automatic`),h=e=>e.map(e=>({id:e,name:e})),g=o.length?[{key:`menu`,label:u(`Menu`),rows:h(a),...l?{default:l}:{}},{key:`more`,label:u(`More models on your account`),rows:h(o)}]:[{key:`list`,label:n,rows:h(a),...l?{default:l}:{}}],_=i&&d?{group:a.includes(i)?g[0].key:`more`,id:i}:void 0;return(0,q.jsxs)(`div`,{className:`block text-[12.5px] text-muted`,children:[(0,q.jsx)(`span`,{className:`block mb-1`,children:e}),(a.length||o.length)&&(d||!i)&&!f?(0,q.jsx)(ve,{label:e,text:i?`${n} · ${i}`:m,heads:[{value:``,label:m}],headValue:i?void 0:``,groups:g,current:_,onHead:()=>s(``),onPick:(e,t)=>s(t.id),tail:c?u(`Other model…`):void 0,onTail:()=>{p(!0),s(``)}}):(0,q.jsx)(`input`,{value:i,onChange:e=>s(e.target.value),placeholder:m,"aria-label":e,className:t(O,`text-fg`),spellCheck:!1})]})}function $e(){let e=r();return(0,q.jsxs)(`a`,{href:V,target:`_blank`,rel:`noopener noreferrer`,className:`inline-flex items-center gap-0.5 text-accent`,children:[e(`How`),` `,(0,q.jsx)(w,{size:11})]})}function Q({label:e,hint:t,children:n}){return(0,q.jsxs)(`div`,{children:[(0,q.jsx)(`label`,{className:`text-[12px] text-muted`,children:e}),(0,q.jsx)(`div`,{className:`mt-1`,children:n}),t&&(0,q.jsx)(`div`,{className:`mt-1 text-[11.5px] text-muted leading-snug`,children:t})]})}function et({result:e,okText:n}){let i=r(),[a,o]=(0,G.useState)(!1),s=!e.ok&&e.detail&&e.detail!==e.error?e.detail:null;return(0,q.jsxs)(`div`,{className:t(`rounded-2xl px-3 py-2 text-[12.5px]`,e.ok?`bg-emerald-500/12 text-emerald-700 dark:text-emerald-300`:`bg-rose-500/12 text-rose-700 dark:text-rose-300`),children:[e.ok?n:i(e.error??`The model provider did not answer.`),s&&(0,q.jsxs)(q.Fragment,{children:[` `,(0,q.jsx)(`button`,{type:`button`,onClick:()=>o(e=>!e),className:`underline decoration-dotted underline-offset-2 opacity-70 hover:opacity-100`,children:i(a?`Hide details`:`Details`)}),a&&(0,q.jsx)(`div`,{className:`mt-1.5 break-all font-mono text-[11px] opacity-80`,children:s})]})]})}function tt(e){try{return new URL(e).host}catch{return e}}export{Ge as CalendarCard,Ie as ConnectionsScreen,Ke as ContactsCard,Ue as EmailCard,Le as ModelCard}; \ No newline at end of file diff --git a/nanomuse/server/static/assets/DevicesScreen-g6FUY327.js b/nanomuse/server/static/assets/DevicesScreen-Cox4s7Rb.js similarity index 97% rename from nanomuse/server/static/assets/DevicesScreen-g6FUY327.js rename to nanomuse/server/static/assets/DevicesScreen-Cox4s7Rb.js index 64daca63e..7af454551 100644 --- a/nanomuse/server/static/assets/DevicesScreen-g6FUY327.js +++ b/nanomuse/server/static/assets/DevicesScreen-Cox4s7Rb.js @@ -1 +1 @@ -import{A as e,E as t,J as n,K as r,Q as i,Y as a,b as o,f as s,x as c}from"./MuseHeader-Pw-NI98v.js";import{n as l}from"./external-link-Xj5fjR8v.js";import{o as u}from"./Form-DwKuBk1V.js";import{t as d}from"./refresh-cw-BKgIzslL.js";import{G as f,H as p,a as m,at as h,et as g,ft as _,ht as v,i as y,l as b,o as x,pt as S,s as C}from"./index-CIdGZ5PB.js";import{t as w}from"./BackBar-Dl56jHZM.js";import{t as T}from"./CloudCard-CtVHK0qc.js";var E=n(`laptop`,[[`path`,{d:`M18 5a2 2 0 0 1 2 2v8.526a2 2 0 0 0 .212.897l1.068 2.127a1 1 0 0 1-.9 1.45H3.62a1 1 0 0 1-.9-1.45l1.068-2.127A2 2 0 0 0 4 15.526V7a2 2 0 0 1 2-2z`,key:`1pdavp`}],[`path`,{d:`M20.054 15.987H3.946`,key:`14rxg9`}]]),D=n(`wifi`,[[`path`,{d:`M12 20h.01`,key:`zekei9`}],[`path`,{d:`M2 8.82a15 15 0 0 1 20 0`,key:`dnpr2z`}],[`path`,{d:`M5 12.859a10 10 0 0 1 14 0`,key:`1x1e6c`}],[`path`,{d:`M8.5 16.429a5 5 0 0 1 7 0`,key:`1bycff`}]]),O=i(a(),1),k=o(),A=`https://nanomuse.cn/dl/`;function j(){let{state:e,dispatch:n,openThread:i,setTab:a,toast:o}=s(),l=r(),u=e.hub,f=e.hands,[p,m]=(0,O.useState)(!1),h=async()=>{try{let[e,t]=await Promise.all([c.hub(),c.hands()]);n({type:`ws`,msg:{kind:`hub`,hub:e}}),n({type:`ws`,msg:{kind:`hands_state`,hands:t}})}catch{}};(0,O.useEffect)(()=>{h()},[]);let g=async()=>{m(!0),await h(),m(!1)},_=async e=>{try{let t=await c.askDevice(e.id);n({type:`ws`,msg:{kind:`thread`,thread:t.thread}}),i(t.thread.id),a(`chat`)}catch(e){o(e.message)}},v=e=>{window.confirm(l(`Forget {name}? It can join again by signing in.`,{name:e.name}))&&c.forgetDevice(e.id).then(e=>n({type:`ws`,msg:{kind:`hub`,hub:e}})).catch(e=>o(e.message))},y=(u?.devices??[]).filter(e=>!e.this&&e.kind!==`web`),b=!!u?.account.signed_in,x=u?.state===`connected`,S=y.length+(u&&x?1:0),C=y.filter(e=>e.online).length+(u&&x?1:0);return(0,k.jsxs)(`div`,{className:`flex h-full flex-col`,children:[(0,k.jsx)(w,{title:l(`Devices`),actions:(0,k.jsx)(`button`,{type:`button`,onClick:()=>void g(),"aria-label":l(`Refresh`),title:l(`Refresh`),className:`flex h-9 w-9 items-center justify-center rounded-full text-muted hover:bg-surface-2 hover:text-fg`,children:(0,k.jsx)(d,{size:17,className:t(p&&`animate-spin`)})})}),(0,k.jsxs)(`div`,{className:`@container flex-1 overflow-y-auto pb-8`,children:[(0,k.jsxs)(`div`,{className:`px-5 pb-4 pt-1`,children:[(0,k.jsx)(`p`,{className:`text-[14px] leading-[20px] text-muted`,children:l(`Every device signed in to your account is a Muse of its own, on the same conversations. Type @ and a device's name in the chat to hand it work; a computer lends its hands.`)}),u&&b&&S>0&&(0,k.jsxs)(`p`,{className:`mt-1.5 text-[12.5px] font-medium uppercase tracking-wide text-muted/80`,children:[S===1?l(`1 device`):l(`{n} devices`,{n:S}),` · `,l(`{n} online`,{n:C})]})]}),(0,k.jsx)(`div`,{className:`px-4 pb-3`,children:(0,k.jsx)(T,{account:u?.account??null,onChange:()=>void h()})}),u&&(0,k.jsxs)(`div`,{className:`px-4`,children:[(0,k.jsx)(M,{children:l(`This device`)}),(0,k.jsx)(H,{hub:u,hands:f??void 0,onChange:()=>void h()})]}),(0,k.jsxs)(`div`,{className:`px-4 pt-4`,children:[(0,k.jsx)(M,{children:l(`Other devices`)}),y.length===0?(0,k.jsx)(G,{hub:u??void 0,signedIn:b}):(0,k.jsx)(`div`,{className:`grid grid-cols-1 gap-3 @2xl:grid-cols-2`,children:y.map(e=>(0,k.jsx)(U,{device:e,onAsk:()=>void _(e),onForget:()=>v(e)},e.id))}),(0,k.jsx)(`p`,{className:`px-1 pt-3 text-[12.5px] leading-[18px] text-muted`,children:l(`A chat addressed to a device runs there; you see every step here and answer its approvals.`)})]}),f&&!f.reason?.includes(`phone`)&&(0,k.jsxs)(`div`,{className:`pt-4`,children:[(0,k.jsx)(`div`,{className:`px-4`,children:(0,k.jsx)(M,{children:l(`Hands`)})}),(0,k.jsx)(K,{hands:f,onChange:()=>void h()})]})]})]})}function M({children:e}){return(0,k.jsx)(`p`,{className:`px-1 pb-2 text-[12.5px] font-medium uppercase tracking-wide text-muted/80`,children:e})}function N({children:e}){return(0,k.jsx)(`p`,{className:`px-4 pb-3 text-[12.5px] leading-[18px] text-muted`,children:e})}function P({children:e,className:n}){return(0,k.jsx)(`div`,{className:t(`relative rounded-2xl border border-border/70 bg-surface p-4`,n),children:e})}function F({kind:e,online:n}){return(0,k.jsx)(`span`,{className:t(`flex h-11 w-11 shrink-0 items-center justify-center rounded-xl`,n?`bg-accent/10 text-accent`:`bg-surface-2 text-muted`),"aria-hidden":!0,children:q(e,22)})}function I({online:e}){return(0,k.jsx)(`span`,{"aria-hidden":!0,className:t(`inline-block h-2 w-2 shrink-0 rounded-full`,e?`bg-[#2fb344]`:`bg-muted/35`)})}function L(e){if(e==null||e===``)return``;let t=typeof e==`number`?e:/^\d+(\.\d+)?$/.test(e)?Number(e):NaN;return Number.isFinite(t)?new Date(t*1e3).toISOString():String(e)}function R(t,n){let r=L(t.last_seen),i=e(r);return t.online?r&&Date.now()-new Date(r).getTime()<12e4?`${n(`Online`)} · ${n(`just now`)}`:n(`Online`):i?n(`Last seen {when}`,{when:i}):n(`Offline`)}function z(e,t,n=[]){let r=new Set(e??[]),i=[...n];return r.has(`task`)&&i.push(t(`Tasks`)),r.has(`shell`)&&i.push(t(`Commands`)),(r.has(`files`)||r.has(`file.get`)||r.has(`file.put`))&&i.push(t(`Files`)),r.has(`screen`)&&i.push(t(`Screenshot`)),r.has(`open`)&&i.push(t(`Open links`)),[...r].some(e=>e.startsWith(`coding.`))&&i.push(t(`Coding agents`)),r.has(`notify`)&&i.push(t(`Notifications`)),i}function B({items:e}){return e.length===0?null:(0,k.jsx)(`div`,{className:`flex flex-wrap gap-1.5`,children:e.map(e=>(0,k.jsx)(`span`,{className:`rounded-full bg-surface-2 px-2.5 py-1 text-[12px] font-medium text-fg/80`,children:e},e))})}function V(e){return[e.os||``,e.version||``].filter(Boolean).join(` · `)}function H({hub:e,hands:t,onChange:n}){let{dispatch:i,toast:a}=s(),o=r(),[d,f]=(0,O.useState)(!1),[p,m]=(0,O.useState)(e.device.name),[h,_]=(0,O.useState)(!1),v=e.account.signed_in,y=e.state===`connected`,S=e.devices.find(e=>e.this),C=async e=>{_(!0);try{let t=await c.updateHub(e);i({type:`ws`,msg:{kind:`hub`,hub:t}}),n()}catch(e){a(e.message)}finally{_(!1)}},w=v?e.enabled?y?o(`Online`):e.state===`refused`?o(`Refused`):o(`Connecting…`):o(`Off`):o(`Signed out`),T=z(e.device.actions,o,t?.enabled&&t.available?[o(`Hands`)]:[]);return(0,k.jsxs)(P,{children:[(0,k.jsxs)(`div`,{className:`flex items-start gap-3.5`,children:[(0,k.jsx)(F,{kind:e.device.kind,online:y}),(0,k.jsxs)(`div`,{className:`min-w-0 flex-1`,children:[d?(0,k.jsxs)(`form`,{className:`flex items-center gap-2`,onSubmit:e=>{e.preventDefault(),p.trim()&&C({name:p.trim()}).then(()=>f(!1))},children:[(0,k.jsx)(`input`,{value:p,onChange:e=>m(e.target.value),maxLength:60,autoFocus:!0,"aria-label":o(`This device's name`),placeholder:o(`A name your other devices will see`),className:`h-9 min-w-0 flex-1 rounded-xl bg-surface-2 px-3 text-[15px] outline-none focus:ring-2 focus:ring-accent/40`}),(0,k.jsx)(`button`,{type:`submit`,disabled:h||!p.trim(),"aria-label":o(`Save`),className:`flex h-9 w-9 items-center justify-center rounded-full bg-accent text-accent-fg disabled:opacity-40`,children:(0,k.jsx)(l,{size:16})}),(0,k.jsx)(`button`,{type:`button`,onClick:()=>f(!1),"aria-label":o(`Cancel`),className:`flex h-9 w-9 items-center justify-center rounded-full bg-surface-2 text-muted`,children:(0,k.jsx)(u,{size:16})})]}):(0,k.jsxs)(`div`,{className:`flex items-center gap-1.5`,children:[(0,k.jsx)(`span`,{className:`truncate text-[16px] font-semibold leading-[22px]`,children:e.device.name}),(0,k.jsx)(`button`,{type:`button`,onClick:()=>{m(e.device.name),f(!0)},"aria-label":o(`Rename this device`),title:o(`Rename this device`),className:`flex h-7 w-7 shrink-0 items-center justify-center rounded-full text-muted hover:bg-surface-2 hover:text-fg`,children:(0,k.jsx)(g,{size:13})})]}),(0,k.jsxs)(`p`,{className:`mt-0.5 flex items-center gap-1.5 text-[13px] leading-[18px] text-muted`,children:[(0,k.jsx)(I,{online:y}),(0,k.jsx)(`span`,{className:`truncate`,children:[w,V(S??{})].filter(Boolean).join(` · `)})]}),T.length>0&&(0,k.jsx)(`div`,{className:`mt-3`,children:(0,k.jsx)(B,{items:T})})]})]}),(0,k.jsxs)(`div`,{className:`-mx-4 -mb-2 mt-4 border-t border-border/60`,children:[(0,k.jsx)(b,{label:o(`Join the hub`),checked:e.enabled&&v,disabled:!v||h,onChange:e=>void C({enabled:e})}),(0,k.jsx)(N,{children:o(v?`Reachable by your other devices while this runs.`:`Sign in first.`)}),(0,k.jsx)(x,{inset:16}),(0,k.jsx)(b,{label:o(`My other devices may operate it`),checked:e.remote_control,disabled:h,onChange:e=>void C({remote_control:e})}),(0,k.jsx)(N,{children:o(`They can run commands, read files and see its screen here; each step still goes through the Sentinel.`)})]}),(e.state===`refused`||e.state===`disconnected`)&&e.detail&&(0,k.jsx)(`div`,{className:`mt-3 rounded-xl bg-amber-500/12 px-3 py-2 text-[12.5px] text-amber-700 dark:text-amber-300`,children:e.detail})]})}function U({device:e,onAsk:t,onForget:n}){let i=r(),a=z(e.actions,i),o=e.online&&(e.actions??[]).includes(`task`);return(0,k.jsxs)(P,{className:`flex flex-col gap-3`,children:[(0,k.jsxs)(`div`,{className:`flex items-start gap-3.5`,children:[(0,k.jsx)(F,{kind:e.kind,online:e.online}),(0,k.jsxs)(`div`,{className:`min-w-0 flex-1`,children:[(0,k.jsx)(`p`,{className:`truncate text-[16px] font-semibold leading-[22px]`,children:e.name}),(0,k.jsxs)(`p`,{className:`mt-0.5 flex items-center gap-1.5 text-[13px] leading-[18px] text-muted`,children:[(0,k.jsx)(I,{online:e.online}),(0,k.jsx)(`span`,{className:`truncate`,children:[R(e,i),V(e)].filter(Boolean).join(` · `)})]})]}),(0,k.jsx)(W,{label:i(`More about {name}`,{name:e.name}),items:[{label:i(`Forget this device`),onClick:n,danger:!0}]})]}),(0,k.jsx)(B,{items:a}),o&&(0,k.jsx)(`p`,{className:`text-[12.5px] leading-[18px] text-muted`,children:i(`Type @{name} in the chat to hand it work.`,{name:e.name})}),e.online&&(0,k.jsxs)(`button`,{type:`button`,onClick:t,className:`flex h-9 w-fit items-center gap-1.5 rounded-full bg-accent/10 px-3.5 text-[13.5px] font-medium text-accent hover:bg-accent/15`,children:[(0,k.jsx)(h,{size:14}),` `,i(`Ask`)]})]})}function W({label:e,items:n}){let[r,i]=(0,O.useState)(!1),a=(0,O.useRef)(null);return(0,O.useEffect)(()=>{if(!r)return;let e=e=>{a.current?.contains(e.target)||i(!1)},t=e=>{e.key===`Escape`&&i(!1)};return window.addEventListener(`pointerdown`,e),window.addEventListener(`keydown`,t),()=>{window.removeEventListener(`pointerdown`,e),window.removeEventListener(`keydown`,t)}},[r]),(0,k.jsxs)(`div`,{ref:a,className:`relative -mr-1.5 -mt-1`,children:[(0,k.jsx)(`button`,{type:`button`,onClick:()=>i(e=>!e),"aria-label":e,"aria-haspopup":`menu`,"aria-expanded":r,className:`flex h-8 w-8 items-center justify-center rounded-full text-muted hover:bg-surface-2 hover:text-fg`,children:(0,k.jsx)(v,{size:18})}),r&&(0,k.jsx)(`ul`,{role:`menu`,className:`absolute right-0 top-9 z-30 min-w-[180px] overflow-hidden rounded-2xl border border-border bg-surface py-1 shadow-xl`,children:n.map(e=>(0,k.jsx)(`li`,{children:(0,k.jsx)(`button`,{type:`button`,role:`menuitem`,onClick:()=>{i(!1),e.onClick()},className:t(`w-full px-4 py-2.5 text-left text-[14px] hover:bg-surface-2`,e.danger&&`text-red-600 dark:text-red-400`),children:e.label})},e.label))})]})}function G({hub:e,signedIn:t}){let n=r(),i=t&&e?.state===`connected`;return(0,k.jsxs)(P,{className:`flex flex-col gap-3`,children:[(0,k.jsxs)(`div`,{className:`flex items-start gap-3.5`,children:[(0,k.jsx)(`span`,{className:`flex h-11 w-11 shrink-0 items-center justify-center rounded-xl bg-surface-2 text-muted`,"aria-hidden":!0,children:(0,k.jsx)(f,{size:22})}),(0,k.jsxs)(`div`,{className:`min-w-0 flex-1`,children:[(0,k.jsx)(`p`,{className:`text-[15px] font-semibold leading-[20px]`,children:n(i?`Add a device`:`No other device yet`)}),(0,k.jsx)(`p`,{className:`mt-1 text-[13px] leading-[18px] text-muted`,children:t?i?e?.account.hint?n(`Install nanoMuse on your phone, Mac or PC and sign in as {hint}; it appears here on its own.`,{hint:e.account.hint}):n(`Install nanoMuse on your phone, Mac or PC and sign in with the same account; it appears here on its own.`):J(e?.state??``,n):n(`Sign in above to see them.`)})]})]}),i&&(0,k.jsx)(`a`,{href:A,target:`_blank`,rel:`noopener noreferrer`,className:`flex h-9 w-fit items-center gap-1.5 rounded-full bg-accent/10 px-3.5 text-[13.5px] font-medium text-accent hover:bg-accent/15`,children:n(`Get the apps`)})]})}function K({hands:e,onChange:n}){let{dispatch:i,toast:a,state:o}=s(),l=r(),[u,d]=(0,O.useState)(!1),f=o.profile?.name??`nanoMuse`,h=async e=>{d(!0);try{let t=await c.setHands(e);i({type:`ws`,msg:{kind:`hands_state`,hands:t}}),n()}catch(e){a(e.message)}finally{d(!1)}},g=e.task_active?l(`Working`):e.enabled?e.available?l(`On`):l(`Unavailable`):l(`Off`);return(0,k.jsxs)(k.Fragment,{children:[(0,k.jsxs)(m,{className:`border border-border/70`,children:[(0,k.jsx)(b,{icon:(0,k.jsx)(_,{size:22}),label:l(`Hands on this computer`),value:g,checked:e.enabled,disabled:u,onChange:e=>void h({enabled:e})}),(0,k.jsx)(y,{className:`pb-3 pt-0`,children:e.task_active?e.task_text||l(`On the screen now`):e.available?l(`It looks at a screenshot and clicks by position; paying, sending and deleting ask you first.`):e.reason||l(`Nothing can drive this screen yet.`)}),(0,k.jsx)(x,{inset:16}),(0,k.jsxs)(`div`,{className:`flex items-center gap-2 px-4 py-3 text-[13px] text-muted`,children:[(0,k.jsxs)(`span`,{children:[l(`Driver`),`:`]}),[`auto`,`desktop`,`pyautogui`,`xdotool`].map(n=>(0,k.jsx)(`button`,{type:`button`,disabled:u,onClick:()=>void h({backend:n}),className:t(`rounded-full px-2.5 py-1`,(e.backend??`auto`)===n||n===`auto`&&!e.backend?`bg-fg text-bg`:`bg-surface-2 text-fg`),children:n},n))]}),(e.device?.platform===`darwin`||e.window?.available)&&(0,k.jsxs)(k.Fragment,{children:[(0,k.jsx)(x,{inset:16}),(0,k.jsxs)(`div`,{className:`flex flex-wrap items-center gap-2 px-4 py-3 text-[13px] text-muted`,children:[(0,k.jsxs)(`span`,{children:[l(`Where`),`:`]}),[`auto`,`window`,`screen`].map(n=>(0,k.jsx)(`button`,{type:`button`,disabled:u,onClick:()=>void h({mode:n}),className:t(`rounded-full px-2.5 py-1`,(e.mode??`auto`)===n?`bg-fg text-bg`:`bg-surface-2 text-fg`),children:l(n===`auto`?`Auto`:n===`window`?`One window`:`Whole screen`)},n))]}),(0,k.jsx)(y,{className:`pb-3 pt-0`,children:e.window?.active&&e.window.app?l(`Working in {app}'s window; the mouse stays yours.`,{app:e.window.app}):e.window?.reason&&(e.mode??`auto`)!==`screen`?l(`On the whole screen for now: {reason}`,{reason:e.window.reason}):l(`One window: the hands work inside the app they were given, send clicks and keys to it alone and leave your mouse alone. Whole screen: the system mouse, like other platforms. Auto picks one window as soon as an app is named.`)})]}),e.task_active&&(0,k.jsxs)(k.Fragment,{children:[(0,k.jsx)(x,{inset:16}),(0,k.jsx)(C,{icon:(0,k.jsx)(p,{size:18,fill:`currentColor`}),label:l(`Stop the hands`),onClick:()=>void c.stopHands().catch(e=>a(e.message)),chevron:!1})]})]}),e.enabled&&e.device?.platform===`darwin`&&(0,k.jsx)(y,{children:l(`On a Mac, allow nanoMuse under System Settings → Privacy & Security → Accessibility and Screen Recording when macOS asks; without them clicks do nothing and the screenshot is black. The first action in each app asks you once ("Let {name} use Safari?") and the answer is kept under Permissions.`,{name:f})})]})}function q(e,t=18){switch(e){case`phone`:return(0,k.jsx)(f,{size:t});case`computer`:return(0,k.jsx)(E,{size:t});case`web`:return(0,k.jsx)(S,{size:t});default:return(0,k.jsx)(D,{size:t})}}function J(e,t){switch(e){case`connected`:return t(`On the hub`);case`connecting`:case`disconnected`:return t(`Connecting to the hub…`);case`refused`:return t(`The hub refused this device. Sign in again.`);case`signed_out`:return t(`Not signed in.`);case`off`:case`stopped`:return t(`The hub is off on this device.`);default:return e}}export{j as DevicesScreen}; \ No newline at end of file +import{A as e,E as t,J as n,K as r,Q as i,Y as a,b as o,f as s,x as c}from"./MuseHeader-BDWXHKHT.js";import{n as l}from"./external-link-CZH-rQLq.js";import{o as u}from"./Form-B3Ejw5aI.js";import{t as d}from"./refresh-cw-qw351CFk.js";import{G as f,H as p,a as m,at as h,et as g,ft as _,ht as v,i as y,l as b,o as x,pt as S,s as C}from"./index-DKrXW2Qj.js";import{t as w}from"./BackBar-DqcCClHf.js";import{t as T}from"./CloudCard-B2Mi7bjZ.js";var E=n(`laptop`,[[`path`,{d:`M18 5a2 2 0 0 1 2 2v8.526a2 2 0 0 0 .212.897l1.068 2.127a1 1 0 0 1-.9 1.45H3.62a1 1 0 0 1-.9-1.45l1.068-2.127A2 2 0 0 0 4 15.526V7a2 2 0 0 1 2-2z`,key:`1pdavp`}],[`path`,{d:`M20.054 15.987H3.946`,key:`14rxg9`}]]),D=n(`wifi`,[[`path`,{d:`M12 20h.01`,key:`zekei9`}],[`path`,{d:`M2 8.82a15 15 0 0 1 20 0`,key:`dnpr2z`}],[`path`,{d:`M5 12.859a10 10 0 0 1 14 0`,key:`1x1e6c`}],[`path`,{d:`M8.5 16.429a5 5 0 0 1 7 0`,key:`1bycff`}]]),O=i(a(),1),k=o(),A=`https://nanomuse.cn/dl/`;function j(){let{state:e,dispatch:n,openThread:i,setTab:a,toast:o}=s(),l=r(),u=e.hub,f=e.hands,[p,m]=(0,O.useState)(!1),h=async()=>{try{let[e,t]=await Promise.all([c.hub(),c.hands()]);n({type:`ws`,msg:{kind:`hub`,hub:e}}),n({type:`ws`,msg:{kind:`hands_state`,hands:t}})}catch{}};(0,O.useEffect)(()=>{h()},[]);let g=async()=>{m(!0),await h(),m(!1)},_=async e=>{try{let t=await c.askDevice(e.id);n({type:`ws`,msg:{kind:`thread`,thread:t.thread}}),i(t.thread.id),a(`chat`)}catch(e){o(e.message)}},v=e=>{window.confirm(l(`Forget {name}? It can join again by signing in.`,{name:e.name}))&&c.forgetDevice(e.id).then(e=>n({type:`ws`,msg:{kind:`hub`,hub:e}})).catch(e=>o(e.message))},y=(u?.devices??[]).filter(e=>!e.this&&e.kind!==`web`),b=!!u?.account.signed_in,x=u?.state===`connected`,S=y.length+(u&&x?1:0),C=y.filter(e=>e.online).length+(u&&x?1:0);return(0,k.jsxs)(`div`,{className:`flex h-full flex-col`,children:[(0,k.jsx)(w,{title:l(`Devices`),actions:(0,k.jsx)(`button`,{type:`button`,onClick:()=>void g(),"aria-label":l(`Refresh`),title:l(`Refresh`),className:`flex h-9 w-9 items-center justify-center rounded-full text-muted hover:bg-surface-2 hover:text-fg`,children:(0,k.jsx)(d,{size:17,className:t(p&&`animate-spin`)})})}),(0,k.jsxs)(`div`,{className:`@container flex-1 overflow-y-auto pb-8`,children:[(0,k.jsxs)(`div`,{className:`px-5 pb-4 pt-1`,children:[(0,k.jsx)(`p`,{className:`text-[14px] leading-[20px] text-muted`,children:l(`Every device signed in to your account is a Muse of its own, on the same conversations. Type @ and a device's name in the chat to hand it work; a computer lends its hands.`)}),u&&b&&S>0&&(0,k.jsxs)(`p`,{className:`mt-1.5 text-[12.5px] font-medium uppercase tracking-wide text-muted/80`,children:[S===1?l(`1 device`):l(`{n} devices`,{n:S}),` · `,l(`{n} online`,{n:C})]})]}),(0,k.jsx)(`div`,{className:`px-4 pb-3`,children:(0,k.jsx)(T,{account:u?.account??null,onChange:()=>void h()})}),u&&(0,k.jsxs)(`div`,{className:`px-4`,children:[(0,k.jsx)(M,{children:l(`This device`)}),(0,k.jsx)(H,{hub:u,hands:f??void 0,onChange:()=>void h()})]}),(0,k.jsxs)(`div`,{className:`px-4 pt-4`,children:[(0,k.jsx)(M,{children:l(`Other devices`)}),y.length===0?(0,k.jsx)(G,{hub:u??void 0,signedIn:b}):(0,k.jsx)(`div`,{className:`grid grid-cols-1 gap-3 @2xl:grid-cols-2`,children:y.map(e=>(0,k.jsx)(U,{device:e,onAsk:()=>void _(e),onForget:()=>v(e)},e.id))}),(0,k.jsx)(`p`,{className:`px-1 pt-3 text-[12.5px] leading-[18px] text-muted`,children:l(`A chat addressed to a device runs there; you see every step here and answer its approvals.`)})]}),f&&!f.reason?.includes(`phone`)&&(0,k.jsxs)(`div`,{className:`pt-4`,children:[(0,k.jsx)(`div`,{className:`px-4`,children:(0,k.jsx)(M,{children:l(`Hands`)})}),(0,k.jsx)(K,{hands:f,onChange:()=>void h()})]})]})]})}function M({children:e}){return(0,k.jsx)(`p`,{className:`px-1 pb-2 text-[12.5px] font-medium uppercase tracking-wide text-muted/80`,children:e})}function N({children:e}){return(0,k.jsx)(`p`,{className:`px-4 pb-3 text-[12.5px] leading-[18px] text-muted`,children:e})}function P({children:e,className:n}){return(0,k.jsx)(`div`,{className:t(`relative rounded-2xl border border-border/70 bg-surface p-4`,n),children:e})}function F({kind:e,online:n}){return(0,k.jsx)(`span`,{className:t(`flex h-11 w-11 shrink-0 items-center justify-center rounded-xl`,n?`bg-accent/10 text-accent`:`bg-surface-2 text-muted`),"aria-hidden":!0,children:q(e,22)})}function I({online:e}){return(0,k.jsx)(`span`,{"aria-hidden":!0,className:t(`inline-block h-2 w-2 shrink-0 rounded-full`,e?`bg-[#2fb344]`:`bg-muted/35`)})}function L(e){if(e==null||e===``)return``;let t=typeof e==`number`?e:/^\d+(\.\d+)?$/.test(e)?Number(e):NaN;return Number.isFinite(t)?new Date(t*1e3).toISOString():String(e)}function R(t,n){let r=L(t.last_seen),i=e(r);return t.online?r&&Date.now()-new Date(r).getTime()<12e4?`${n(`Online`)} · ${n(`just now`)}`:n(`Online`):i?n(`Last seen {when}`,{when:i}):n(`Offline`)}function z(e,t,n=[]){let r=new Set(e??[]),i=[...n];return r.has(`task`)&&i.push(t(`Tasks`)),r.has(`shell`)&&i.push(t(`Commands`)),(r.has(`files`)||r.has(`file.get`)||r.has(`file.put`))&&i.push(t(`Files`)),r.has(`screen`)&&i.push(t(`Screenshot`)),r.has(`open`)&&i.push(t(`Open links`)),[...r].some(e=>e.startsWith(`coding.`))&&i.push(t(`Coding agents`)),r.has(`notify`)&&i.push(t(`Notifications`)),i}function B({items:e}){return e.length===0?null:(0,k.jsx)(`div`,{className:`flex flex-wrap gap-1.5`,children:e.map(e=>(0,k.jsx)(`span`,{className:`rounded-full bg-surface-2 px-2.5 py-1 text-[12px] font-medium text-fg/80`,children:e},e))})}function V(e){return[e.os||``,e.version||``].filter(Boolean).join(` · `)}function H({hub:e,hands:t,onChange:n}){let{dispatch:i,toast:a}=s(),o=r(),[d,f]=(0,O.useState)(!1),[p,m]=(0,O.useState)(e.device.name),[h,_]=(0,O.useState)(!1),v=e.account.signed_in,y=e.state===`connected`,S=e.devices.find(e=>e.this),C=async e=>{_(!0);try{let t=await c.updateHub(e);i({type:`ws`,msg:{kind:`hub`,hub:t}}),n()}catch(e){a(e.message)}finally{_(!1)}},w=v?e.enabled?y?o(`Online`):e.state===`refused`?o(`Refused`):o(`Connecting…`):o(`Off`):o(`Signed out`),T=z(e.device.actions,o,t?.enabled&&t.available?[o(`Hands`)]:[]);return(0,k.jsxs)(P,{children:[(0,k.jsxs)(`div`,{className:`flex items-start gap-3.5`,children:[(0,k.jsx)(F,{kind:e.device.kind,online:y}),(0,k.jsxs)(`div`,{className:`min-w-0 flex-1`,children:[d?(0,k.jsxs)(`form`,{className:`flex items-center gap-2`,onSubmit:e=>{e.preventDefault(),p.trim()&&C({name:p.trim()}).then(()=>f(!1))},children:[(0,k.jsx)(`input`,{value:p,onChange:e=>m(e.target.value),maxLength:60,autoFocus:!0,"aria-label":o(`This device's name`),placeholder:o(`A name your other devices will see`),className:`h-9 min-w-0 flex-1 rounded-xl bg-surface-2 px-3 text-[15px] outline-none focus:ring-2 focus:ring-accent/40`}),(0,k.jsx)(`button`,{type:`submit`,disabled:h||!p.trim(),"aria-label":o(`Save`),className:`flex h-9 w-9 items-center justify-center rounded-full bg-accent text-accent-fg disabled:opacity-40`,children:(0,k.jsx)(l,{size:16})}),(0,k.jsx)(`button`,{type:`button`,onClick:()=>f(!1),"aria-label":o(`Cancel`),className:`flex h-9 w-9 items-center justify-center rounded-full bg-surface-2 text-muted`,children:(0,k.jsx)(u,{size:16})})]}):(0,k.jsxs)(`div`,{className:`flex items-center gap-1.5`,children:[(0,k.jsx)(`span`,{className:`truncate text-[16px] font-semibold leading-[22px]`,children:e.device.name}),(0,k.jsx)(`button`,{type:`button`,onClick:()=>{m(e.device.name),f(!0)},"aria-label":o(`Rename this device`),title:o(`Rename this device`),className:`flex h-7 w-7 shrink-0 items-center justify-center rounded-full text-muted hover:bg-surface-2 hover:text-fg`,children:(0,k.jsx)(g,{size:13})})]}),(0,k.jsxs)(`p`,{className:`mt-0.5 flex items-center gap-1.5 text-[13px] leading-[18px] text-muted`,children:[(0,k.jsx)(I,{online:y}),(0,k.jsx)(`span`,{className:`truncate`,children:[w,V(S??{})].filter(Boolean).join(` · `)})]}),T.length>0&&(0,k.jsx)(`div`,{className:`mt-3`,children:(0,k.jsx)(B,{items:T})})]})]}),(0,k.jsxs)(`div`,{className:`-mx-4 -mb-2 mt-4 border-t border-border/60`,children:[(0,k.jsx)(b,{label:o(`Join the hub`),checked:e.enabled&&v,disabled:!v||h,onChange:e=>void C({enabled:e})}),(0,k.jsx)(N,{children:o(v?`Reachable by your other devices while this runs.`:`Sign in first.`)}),(0,k.jsx)(x,{inset:16}),(0,k.jsx)(b,{label:o(`My other devices may operate it`),checked:e.remote_control,disabled:h,onChange:e=>void C({remote_control:e})}),(0,k.jsx)(N,{children:o(`They can run commands, read files and see its screen here; each step still goes through the Sentinel.`)})]}),(e.state===`refused`||e.state===`disconnected`)&&e.detail&&(0,k.jsx)(`div`,{className:`mt-3 rounded-xl bg-amber-500/12 px-3 py-2 text-[12.5px] text-amber-700 dark:text-amber-300`,children:e.detail})]})}function U({device:e,onAsk:t,onForget:n}){let i=r(),a=z(e.actions,i),o=e.online&&(e.actions??[]).includes(`task`);return(0,k.jsxs)(P,{className:`flex flex-col gap-3`,children:[(0,k.jsxs)(`div`,{className:`flex items-start gap-3.5`,children:[(0,k.jsx)(F,{kind:e.kind,online:e.online}),(0,k.jsxs)(`div`,{className:`min-w-0 flex-1`,children:[(0,k.jsx)(`p`,{className:`truncate text-[16px] font-semibold leading-[22px]`,children:e.name}),(0,k.jsxs)(`p`,{className:`mt-0.5 flex items-center gap-1.5 text-[13px] leading-[18px] text-muted`,children:[(0,k.jsx)(I,{online:e.online}),(0,k.jsx)(`span`,{className:`truncate`,children:[R(e,i),V(e)].filter(Boolean).join(` · `)})]})]}),(0,k.jsx)(W,{label:i(`More about {name}`,{name:e.name}),items:[{label:i(`Forget this device`),onClick:n,danger:!0}]})]}),(0,k.jsx)(B,{items:a}),o&&(0,k.jsx)(`p`,{className:`text-[12.5px] leading-[18px] text-muted`,children:i(`Type @{name} in the chat to hand it work.`,{name:e.name})}),e.online&&(0,k.jsxs)(`button`,{type:`button`,onClick:t,className:`flex h-9 w-fit items-center gap-1.5 rounded-full bg-accent/10 px-3.5 text-[13.5px] font-medium text-accent hover:bg-accent/15`,children:[(0,k.jsx)(h,{size:14}),` `,i(`Ask`)]})]})}function W({label:e,items:n}){let[r,i]=(0,O.useState)(!1),a=(0,O.useRef)(null);return(0,O.useEffect)(()=>{if(!r)return;let e=e=>{a.current?.contains(e.target)||i(!1)},t=e=>{e.key===`Escape`&&i(!1)};return window.addEventListener(`pointerdown`,e),window.addEventListener(`keydown`,t),()=>{window.removeEventListener(`pointerdown`,e),window.removeEventListener(`keydown`,t)}},[r]),(0,k.jsxs)(`div`,{ref:a,className:`relative -mr-1.5 -mt-1`,children:[(0,k.jsx)(`button`,{type:`button`,onClick:()=>i(e=>!e),"aria-label":e,"aria-haspopup":`menu`,"aria-expanded":r,className:`flex h-8 w-8 items-center justify-center rounded-full text-muted hover:bg-surface-2 hover:text-fg`,children:(0,k.jsx)(v,{size:18})}),r&&(0,k.jsx)(`ul`,{role:`menu`,className:`absolute right-0 top-9 z-30 min-w-[180px] overflow-hidden rounded-2xl border border-border bg-surface py-1 shadow-xl`,children:n.map(e=>(0,k.jsx)(`li`,{children:(0,k.jsx)(`button`,{type:`button`,role:`menuitem`,onClick:()=>{i(!1),e.onClick()},className:t(`w-full px-4 py-2.5 text-left text-[14px] hover:bg-surface-2`,e.danger&&`text-red-600 dark:text-red-400`),children:e.label})},e.label))})]})}function G({hub:e,signedIn:t}){let n=r(),i=t&&e?.state===`connected`;return(0,k.jsxs)(P,{className:`flex flex-col gap-3`,children:[(0,k.jsxs)(`div`,{className:`flex items-start gap-3.5`,children:[(0,k.jsx)(`span`,{className:`flex h-11 w-11 shrink-0 items-center justify-center rounded-xl bg-surface-2 text-muted`,"aria-hidden":!0,children:(0,k.jsx)(f,{size:22})}),(0,k.jsxs)(`div`,{className:`min-w-0 flex-1`,children:[(0,k.jsx)(`p`,{className:`text-[15px] font-semibold leading-[20px]`,children:n(i?`Add a device`:`No other device yet`)}),(0,k.jsx)(`p`,{className:`mt-1 text-[13px] leading-[18px] text-muted`,children:t?i?e?.account.hint?n(`Install nanoMuse on your phone, Mac or PC and sign in as {hint}; it appears here on its own.`,{hint:e.account.hint}):n(`Install nanoMuse on your phone, Mac or PC and sign in with the same account; it appears here on its own.`):J(e?.state??``,n):n(`Sign in above to see them.`)})]})]}),i&&(0,k.jsx)(`a`,{href:A,target:`_blank`,rel:`noopener noreferrer`,className:`flex h-9 w-fit items-center gap-1.5 rounded-full bg-accent/10 px-3.5 text-[13.5px] font-medium text-accent hover:bg-accent/15`,children:n(`Get the apps`)})]})}function K({hands:e,onChange:n}){let{dispatch:i,toast:a,state:o}=s(),l=r(),[u,d]=(0,O.useState)(!1),f=o.profile?.name??`nanoMuse`,h=async e=>{d(!0);try{let t=await c.setHands(e);i({type:`ws`,msg:{kind:`hands_state`,hands:t}}),n()}catch(e){a(e.message)}finally{d(!1)}},g=e.task_active?l(`Working`):e.enabled?e.available?l(`On`):l(`Unavailable`):l(`Off`);return(0,k.jsxs)(k.Fragment,{children:[(0,k.jsxs)(m,{className:`border border-border/70`,children:[(0,k.jsx)(b,{icon:(0,k.jsx)(_,{size:22}),label:l(`Hands on this computer`),value:g,checked:e.enabled,disabled:u,onChange:e=>void h({enabled:e})}),(0,k.jsx)(y,{className:`pb-3 pt-0`,children:e.task_active?e.task_text||l(`On the screen now`):e.available?l(`It looks at a screenshot and clicks by position; paying, sending and deleting ask you first.`):e.reason||l(`Nothing can drive this screen yet.`)}),(0,k.jsx)(x,{inset:16}),(0,k.jsxs)(`div`,{className:`flex items-center gap-2 px-4 py-3 text-[13px] text-muted`,children:[(0,k.jsxs)(`span`,{children:[l(`Driver`),`:`]}),[`auto`,`desktop`,`pyautogui`,`xdotool`].map(n=>(0,k.jsx)(`button`,{type:`button`,disabled:u,onClick:()=>void h({backend:n}),className:t(`rounded-full px-2.5 py-1`,(e.backend??`auto`)===n||n===`auto`&&!e.backend?`bg-fg text-bg`:`bg-surface-2 text-fg`),children:n},n))]}),(e.device?.platform===`darwin`||e.window?.available)&&(0,k.jsxs)(k.Fragment,{children:[(0,k.jsx)(x,{inset:16}),(0,k.jsxs)(`div`,{className:`flex flex-wrap items-center gap-2 px-4 py-3 text-[13px] text-muted`,children:[(0,k.jsxs)(`span`,{children:[l(`Where`),`:`]}),[`auto`,`window`,`screen`].map(n=>(0,k.jsx)(`button`,{type:`button`,disabled:u,onClick:()=>void h({mode:n}),className:t(`rounded-full px-2.5 py-1`,(e.mode??`auto`)===n?`bg-fg text-bg`:`bg-surface-2 text-fg`),children:l(n===`auto`?`Auto`:n===`window`?`One window`:`Whole screen`)},n))]}),(0,k.jsx)(y,{className:`pb-3 pt-0`,children:e.window?.active&&e.window.app?l(`Working in {app}'s window; the mouse stays yours.`,{app:e.window.app}):e.window?.reason&&(e.mode??`auto`)!==`screen`?l(`On the whole screen for now: {reason}`,{reason:e.window.reason}):l(`One window: the hands work inside the app they were given, send clicks and keys to it alone and leave your mouse alone. Whole screen: the system mouse, like other platforms. Auto picks one window as soon as an app is named.`)})]}),e.task_active&&(0,k.jsxs)(k.Fragment,{children:[(0,k.jsx)(x,{inset:16}),(0,k.jsx)(C,{icon:(0,k.jsx)(p,{size:18,fill:`currentColor`}),label:l(`Stop the hands`),onClick:()=>void c.stopHands().catch(e=>a(e.message)),chevron:!1})]})]}),e.enabled&&e.device?.platform===`darwin`&&(0,k.jsx)(y,{children:l(`On a Mac, allow nanoMuse under System Settings → Privacy & Security → Accessibility and Screen Recording when macOS asks; without them clicks do nothing and the screenshot is black. The first action in each app asks you once ("Let {name} use Safari?") and the answer is kept under Permissions.`,{name:f})})]})}function q(e,t=18){switch(e){case`phone`:return(0,k.jsx)(f,{size:t});case`computer`:return(0,k.jsx)(E,{size:t});case`web`:return(0,k.jsx)(S,{size:t});default:return(0,k.jsx)(D,{size:t})}}function J(e,t){switch(e){case`connected`:return t(`On the hub`);case`connecting`:case`disconnected`:return t(`Connecting to the hub…`);case`refused`:return t(`The hub refused this device. Sign in again.`);case`signed_out`:return t(`Not signed in.`);case`off`:case`stopped`:return t(`The hub is off on this device.`);default:return e}}export{j as DevicesScreen}; \ No newline at end of file diff --git a/nanomuse/server/static/assets/Form-DwKuBk1V.js b/nanomuse/server/static/assets/Form-B3Ejw5aI.js similarity index 97% rename from nanomuse/server/static/assets/Form-DwKuBk1V.js rename to nanomuse/server/static/assets/Form-B3Ejw5aI.js index 48981118e..9d3c41d05 100644 --- a/nanomuse/server/static/assets/Form-DwKuBk1V.js +++ b/nanomuse/server/static/assets/Form-B3Ejw5aI.js @@ -1 +1 @@ -import{E as e,J as t,b as n}from"./MuseHeader-Pw-NI98v.js";var r=t(`chevron-down`,[[`path`,{d:`m6 9 6 6 6-6`,key:`qrunsl`}]]),i=t(`chevron-up`,[[`path`,{d:`m18 15-6-6-6 6`,key:`153udz`}]]),a=t(`x`,[[`path`,{d:`M18 6 6 18`,key:`1bl5f8`}],[`path`,{d:`m6 6 12 12`,key:`d8bk6v`}]]),o=n();function s({icon:t,title:n,summary:a,status:s,open:c,onToggle:l,trailing:u,children:d}){let f=(0,o.jsxs)(o.Fragment,{children:[(0,o.jsx)(`span`,{className:`text-accent mt-0.5`,children:t}),(0,o.jsxs)(`span`,{className:`min-w-0 flex-1`,children:[(0,o.jsxs)(`span`,{className:`flex items-center gap-2`,children:[(0,o.jsx)(`span`,{className:`text-[15px] font-semibold`,children:n}),(0,o.jsx)(`span`,{className:e(`rounded-full px-2 py-0.5 text-[11px] font-medium`,s.tone===`ok`&&`bg-emerald-500/12 text-emerald-700 dark:text-emerald-300`,s.tone===`warn`&&`bg-amber-500/15 text-amber-700 dark:text-amber-300`,s.tone===`off`&&`bg-surface-2 text-muted`),children:s.text})]}),(0,o.jsx)(`span`,{className:`block text-[12.5px] text-muted truncate`,children:a})]}),u??(l?c?(0,o.jsx)(i,{size:18,className:`text-muted`}):(0,o.jsx)(r,{size:18,className:`text-muted`}):null)]});return(0,o.jsxs)(`section`,{className:`rounded-3xl bg-surface border border-border/70 shadow-sm`,children:[l?(0,o.jsx)(`button`,{type:`button`,onClick:l,className:`flex w-full items-start gap-3 px-4 py-3.5 text-left`,children:f}):(0,o.jsx)(`div`,{className:`flex w-full items-start gap-3 px-4 py-3.5`,children:f}),(c||!l&&d)&&d?(0,o.jsx)(`div`,{className:`px-4 pb-4 space-y-3`,children:d}):null]})}var c=`w-full rounded-2xl bg-surface-2 px-3.5 py-2.5 text-[14.5px] outline-none focus:ring-2 focus:ring-accent/40`,l=`flex items-center justify-center gap-1.5 rounded-2xl bg-accent text-accent-fg px-4 py-2.5 text-[14px] font-medium disabled:opacity-40`,u=`flex items-center justify-center gap-1.5 rounded-2xl border border-border px-4 py-2.5 text-[14px] font-medium text-muted disabled:opacity-40`;function d({label:t,hint:n,checked:r,onChange:i,disabled:a}){return(0,o.jsxs)(`label`,{className:`flex items-start gap-3 cursor-pointer`,children:[(0,o.jsxs)(`div`,{className:`flex-1`,children:[(0,o.jsx)(`div`,{className:`text-[14px]`,children:t}),n&&(0,o.jsx)(`div`,{className:`text-[12.5px] text-muted leading-snug`,children:n})]}),(0,o.jsx)(`button`,{type:`button`,role:`switch`,"aria-checked":r,disabled:a,onClick:()=>i(!r),className:e(`relative mt-0.5 h-7 w-12 shrink-0 rounded-full transition disabled:opacity-50`,r?`bg-accent`:`bg-surface-2 border border-border`),children:(0,o.jsx)(`span`,{className:e(`absolute top-0.5 h-6 w-6 rounded-full bg-white shadow transition`,r?`left-[22px]`:`left-0.5`)})})]})}export{u as a,r as c,l as i,d as n,a as o,c as r,i as s,s as t}; \ No newline at end of file +import{E as e,J as t,b as n}from"./MuseHeader-BDWXHKHT.js";var r=t(`chevron-down`,[[`path`,{d:`m6 9 6 6 6-6`,key:`qrunsl`}]]),i=t(`chevron-up`,[[`path`,{d:`m18 15-6-6-6 6`,key:`153udz`}]]),a=t(`x`,[[`path`,{d:`M18 6 6 18`,key:`1bl5f8`}],[`path`,{d:`m6 6 12 12`,key:`d8bk6v`}]]),o=n();function s({icon:t,title:n,summary:a,status:s,open:c,onToggle:l,trailing:u,children:d}){let f=(0,o.jsxs)(o.Fragment,{children:[(0,o.jsx)(`span`,{className:`text-accent mt-0.5`,children:t}),(0,o.jsxs)(`span`,{className:`min-w-0 flex-1`,children:[(0,o.jsxs)(`span`,{className:`flex items-center gap-2`,children:[(0,o.jsx)(`span`,{className:`text-[15px] font-semibold`,children:n}),(0,o.jsx)(`span`,{className:e(`rounded-full px-2 py-0.5 text-[11px] font-medium`,s.tone===`ok`&&`bg-emerald-500/12 text-emerald-700 dark:text-emerald-300`,s.tone===`warn`&&`bg-amber-500/15 text-amber-700 dark:text-amber-300`,s.tone===`off`&&`bg-surface-2 text-muted`),children:s.text})]}),(0,o.jsx)(`span`,{className:`block text-[12.5px] text-muted truncate`,children:a})]}),u??(l?c?(0,o.jsx)(i,{size:18,className:`text-muted`}):(0,o.jsx)(r,{size:18,className:`text-muted`}):null)]});return(0,o.jsxs)(`section`,{className:`rounded-3xl bg-surface border border-border/70 shadow-sm`,children:[l?(0,o.jsx)(`button`,{type:`button`,onClick:l,className:`flex w-full items-start gap-3 px-4 py-3.5 text-left`,children:f}):(0,o.jsx)(`div`,{className:`flex w-full items-start gap-3 px-4 py-3.5`,children:f}),(c||!l&&d)&&d?(0,o.jsx)(`div`,{className:`px-4 pb-4 space-y-3`,children:d}):null]})}var c=`w-full rounded-2xl bg-surface-2 px-3.5 py-2.5 text-[14.5px] outline-none focus:ring-2 focus:ring-accent/40`,l=`flex items-center justify-center gap-1.5 rounded-2xl bg-accent text-accent-fg px-4 py-2.5 text-[14px] font-medium disabled:opacity-40`,u=`flex items-center justify-center gap-1.5 rounded-2xl border border-border px-4 py-2.5 text-[14px] font-medium text-muted disabled:opacity-40`;function d({label:t,hint:n,checked:r,onChange:i,disabled:a}){return(0,o.jsxs)(`label`,{className:`flex items-start gap-3 cursor-pointer`,children:[(0,o.jsxs)(`div`,{className:`flex-1`,children:[(0,o.jsx)(`div`,{className:`text-[14px]`,children:t}),n&&(0,o.jsx)(`div`,{className:`text-[12.5px] text-muted leading-snug`,children:n})]}),(0,o.jsx)(`button`,{type:`button`,role:`switch`,"aria-checked":r,disabled:a,onClick:()=>i(!r),className:e(`relative mt-0.5 h-7 w-12 shrink-0 rounded-full transition disabled:opacity-50`,r?`bg-accent`:`bg-surface-2 border border-border`),children:(0,o.jsx)(`span`,{className:e(`absolute top-0.5 h-6 w-6 rounded-full bg-white shadow transition`,r?`left-[22px]`:`left-0.5`)})})]})}export{u as a,r as c,l as i,d as n,a as o,c as r,i as s,s as t}; \ No newline at end of file diff --git a/nanomuse/server/static/assets/GoalsScreen-Dp2fRaLA.js b/nanomuse/server/static/assets/GoalsScreen-ChIUN2rA.js similarity index 99% rename from nanomuse/server/static/assets/GoalsScreen-Dp2fRaLA.js rename to nanomuse/server/static/assets/GoalsScreen-ChIUN2rA.js index 2973d5d55..aab912a0f 100644 --- a/nanomuse/server/static/assets/GoalsScreen-Dp2fRaLA.js +++ b/nanomuse/server/static/assets/GoalsScreen-ChIUN2rA.js @@ -1,2 +1,2 @@ -import{A as e,E as t,J as n,K as r,N as i,Q as a,Y as o,b as s,f as c,r as l,x as u}from"./MuseHeader-Pw-NI98v.js";import{t as d}from"./StarNudge-DjXecvWj.js";import{H as f,Q as p,S as m,V as h,W as g,Z as _,_ as v,b as y,f as b,g as x,h as S,m as C,ot as w,p as T,v as E,w as D,wt as O,x as k,xt as A,y as j}from"./index-CIdGZ5PB.js";var M=n(`bell-ring`,[[`path`,{d:`M10.268 21a2 2 0 0 0 3.464 0`,key:`vwvbt9`}],[`path`,{d:`M22 8c0-2.3-.8-4.3-2-6`,key:`5bb3ad`}],[`path`,{d:`M3.262 15.326A1 1 0 0 0 4 17h16a1 1 0 0 0 .74-1.673C19.41 13.956 18 12.499 18 8A6 6 0 0 0 6 8c0 4.499-1.411 5.956-2.738 7.326`,key:`11g9vi`}],[`path`,{d:`M4 2C2.8 3.7 2 5.7 2 8`,key:`tap9e0`}]]),N=n(`circle-check`,[[`circle`,{cx:`12`,cy:`12`,r:`10`,key:`1mglay`}],[`path`,{d:`m9 12 2 2 4-4`,key:`dzmm74`}]]),P=n(`circle-dashed`,[[`path`,{d:`M10.1 2.182a10 10 0 0 1 3.8 0`,key:`5ilxe3`}],[`path`,{d:`M13.9 21.818a10 10 0 0 1-3.8 0`,key:`11zvb9`}],[`path`,{d:`M17.609 3.721a10 10 0 0 1 2.69 2.7`,key:`1iw5b2`}],[`path`,{d:`M2.182 13.9a10 10 0 0 1 0-3.8`,key:`c0bmvh`}],[`path`,{d:`M20.279 17.609a10 10 0 0 1-2.7 2.69`,key:`1ruxm7`}],[`path`,{d:`M21.818 10.1a10 10 0 0 1 0 3.8`,key:`qkgqxc`}],[`path`,{d:`M3.721 6.391a10 10 0 0 1 2.7-2.69`,key:`1mcia2`}],[`path`,{d:`M6.391 20.279a10 10 0 0 1-2.69-2.7`,key:`1fvljs`}]]),F=n(`circle-slash`,[[`circle`,{cx:`12`,cy:`12`,r:`10`,key:`1mglay`}],[`line`,{x1:`9`,x2:`15`,y1:`15`,y2:`9`,key:`1dfufj`}]]),I=n(`circle`,[[`circle`,{cx:`12`,cy:`12`,r:`10`,key:`1mglay`}]]),L=n(`ellipsis-vertical`,[[`circle`,{cx:`12`,cy:`12`,r:`1`,key:`41hilf`}],[`circle`,{cx:`12`,cy:`5`,r:`1`,key:`gxeob9`}],[`circle`,{cx:`12`,cy:`19`,r:`1`,key:`lyex9k`}]]),R=n(`octagon-alert`,[[`path`,{d:`M12 16h.01`,key:`1drbdi`}],[`path`,{d:`M12 8v4`,key:`1got3b`}],[`path`,{d:`M15.312 2a2 2 0 0 1 1.414.586l4.688 4.688A2 2 0 0 1 22 8.688v6.624a2 2 0 0 1-.586 1.414l-4.688 4.688a2 2 0 0 1-1.414.586H8.688a2 2 0 0 1-1.414-.586l-4.688-4.688A2 2 0 0 1 2 15.312V8.688a2 2 0 0 1 .586-1.414l4.688-4.688A2 2 0 0 1 8.688 2z`,key:`1fd625`}]]),z=n(`pause`,[[`rect`,{x:`14`,y:`3`,width:`5`,height:`18`,rx:`1`,key:`kaeet6`}],[`rect`,{x:`5`,y:`3`,width:`5`,height:`18`,rx:`1`,key:`1wsw3u`}]]),B=n(`square-check`,[[`rect`,{width:`18`,height:`18`,x:`3`,y:`3`,rx:`2`,key:`afitv7`}],[`path`,{d:`m9 12 2 2 4-4`,key:`dzmm74`}]]),V=a(o(),1),H=s(),U={pending:e=>(0,H.jsx)(I,{...e}),in_progress:e=>(0,H.jsx)(P,{...e,className:t(e.className,`text-accent`)}),done:e=>(0,H.jsx)(N,{...e,className:t(e.className,`text-emerald-500`)}),blocked:e=>(0,H.jsx)(R,{...e,className:t(e.className,`text-rose-500`)}),skipped:e=>(0,H.jsx)(F,{...e,className:t(e.className,`text-muted`)})},W={pending:`done`,in_progress:`done`,done:`pending`,blocked:`pending`,skipped:`pending`};function G(){let{state:e,refreshGoals:t,send:n,openThread:i,toast:a}=c(),[o,s]=(0,V.useState)(null),[f,p]=(0,V.useState)(!1),[m,h]=(0,V.useState)(null),[g,v]=(0,V.useState)(!1),y=(0,V.useRef)(null),x=e.profile?.name??`nanoMuse`,S=r();(0,V.useEffect)(()=>{t()},[t]);let T=e.goals.filter(e=>e.proposal&&e.status!==`cancelled`),E=[...e.goals.filter(e=>e.status===`active`),...e.goals.filter(e=>e.status===`paused`)],O=e.goals.filter(e=>e.status===`done`||e.status===`cancelled`),k=e.goals.find(e=>e.id===o)??null,A=async e=>{try{await u.advanceGoal(e.id),a(S(`{name} is working on “{title}” in the main chat`,{name:x,title:e.title})),i(`main`)}catch(e){a(e.message)}},[j,M]=(0,V.useState)(!1),N=async e=>{try{let n=e.status!==`done`;await u.patchGoal(e.id,{status:n?`done`:`active`}),n&&M(!0),t()}catch(e){a(e.message)}},P=e=>{h(null),n(`main`,S(`I'd like to create a {category} goal. Ask me a few short questions, one at a time (what exactly I want, why and by when, how often to check in), then create it with concrete steps using the goals tool.`,{category:S(e.label)})).catch(e=>a(e.message||S(`Could not send`))),i(`main`)};return(0,H.jsxs)(`div`,{className:`flex h-full flex-col`,children:[(0,H.jsx)(b,{title:S(`Goals`),children:(0,H.jsx)(l,{small:!0,onClick:()=>p(!0),label:S(`New goal`),children:(0,H.jsx)(_,{size:22})})}),(0,H.jsxs)(`div`,{className:`flex-1 overflow-y-auto pb-6`,children:[T.length>0&&(0,H.jsxs)(`section`,{className:`px-4 pb-2`,children:[(0,H.jsx)(`div`,{className:`px-1 mb-2 text-[12px] font-semibold uppercase tracking-wide text-muted`,children:S(`{name} suggests`,{name:x})}),(0,H.jsx)(`div`,{className:`space-y-2.5`,children:T.map(e=>(0,H.jsx)(Y,{goal:e,onChanged:t,onOpen:()=>s(e.id)},e.id))})]}),(0,H.jsx)(d,{moment:`goal_done`,due:j,className:`mx-4 mb-3`}),(0,H.jsx)(K,{label:S(`Tracking`),dot:!0,onAdd:()=>y.current?.scrollIntoView({behavior:`smooth`,block:`start`})}),E.length===0?(0,H.jsx)(`p`,{className:`px-5 pb-3 text-[13px] text-muted`,children:S(`Nothing tracked yet`)}):E.map(e=>(0,H.jsx)(J,{goal:e,onOpen:()=>s(e.id),onToggle:()=>void N(e)},e.id)),O.length>0&&(0,H.jsxs)(H.Fragment,{children:[(0,H.jsx)(`div`,{className:`h-1.5`}),(0,H.jsx)(K,{label:S(`Finished`)}),(g?O:O.slice(0,2)).map(e=>(0,H.jsx)(J,{goal:e,onOpen:()=>s(e.id),onToggle:()=>void N(e)},e.id)),!g&&O.length>2&&(0,H.jsx)(`button`,{type:`button`,onClick:()=>v(!0),className:`px-5 py-2 text-[13.5px] font-medium text-accent`,children:S(`Show {n} more`,{n:O.length-2})})]}),(0,H.jsxs)(`div`,{ref:y,className:`mt-2.5 border-t border-border/70 px-5 pt-3.5 pb-1.5`,children:[(0,H.jsx)(`h3`,{className:`text-[17px] font-semibold`,children:S(`Create a goal`)}),(0,H.jsx)(`p`,{className:`mt-1 text-[13px] leading-[18px] text-muted`,children:S(`Pick a category and tell me the goal you have in mind. I'll shape a plan with you and keep improving it as you go.`)})]}),C.map(e=>(0,H.jsxs)(`button`,{type:`button`,onClick:()=>h(e),className:`flex h-[50px] w-full items-center gap-3.5 pl-5 pr-2 text-left active:bg-surface-2/70`,children:[(0,H.jsx)(`span`,{className:`text-fg`,children:e.icon({size:22})}),(0,H.jsx)(`span`,{className:`flex-1 text-[15px] font-medium`,children:S(e.label)}),(0,H.jsx)(`span`,{className:`flex h-10 w-10 items-center justify-center text-muted`,children:(0,H.jsx)(_,{size:22})})]},e.id))]}),(0,H.jsx)(Q,{goal:k,onClose:()=>s(null),onAdvance:A,onChanged:t}),(0,H.jsx)($,{open:f,onClose:()=>p(!1),onCreated:()=>{p(!1),t()}}),(0,H.jsx)(D,{open:m!==null,onClose:()=>h(null),children:m&&(0,H.jsxs)(`div`,{className:`px-1 pb-2`,children:[(0,H.jsx)(`h3`,{className:`text-[20px] font-bold`,children:S(`Create a {category} goal`,{category:S(m.label)})}),(0,H.jsx)(`p`,{className:`mt-3.5 text-[15px] leading-[22px]`,children:S(`First, we'll shape the goal together in the chat. I'll ask a few questions so I understand exactly what you're after.`)}),(0,H.jsx)(`p`,{className:`mt-3.5 text-[15px] leading-[22px]`,children:S(`Once it's set, I'll track your progress here.`)}),(0,H.jsxs)(`button`,{type:`button`,onClick:()=>P(m),className:`mt-6 flex h-[50px] w-full items-center justify-center gap-2 rounded-full bg-accent text-[16px] font-semibold text-accent-fg`,children:[(0,H.jsx)(w,{size:18}),` `,S(`Start`)]})]})})]})}function K({label:e,dot:n=!1,onAdd:r}){return(0,H.jsxs)(`div`,{className:`flex items-center pl-5 pr-2 pt-1`,children:[n&&(0,H.jsx)(`span`,{className:`mr-2.5 h-2 w-2 rounded-full bg-emerald-500`}),(0,H.jsx)(`span`,{className:t(`flex-1 text-[15px] font-semibold`,n&&`text-emerald-600 dark:text-emerald-400`),children:e}),r?(0,H.jsx)(`button`,{type:`button`,onClick:r,"aria-label":e,className:`flex h-10 w-10 items-center justify-center text-muted`,children:(0,H.jsx)(_,{size:22})}):(0,H.jsx)(`span`,{className:`h-10`})]})}function q({id:e,size:n=`sm`}){let i=r(),a=x(e);return a?(0,H.jsxs)(`span`,{className:t(`inline-flex items-center gap-1 rounded-full font-medium`,a.tone,n===`sm`?`px-2 py-0.5 text-[11.5px]`:`px-2.5 py-1 text-[12.5px]`),children:[a.icon({size:n===`sm`?11:13}),` `,i(a.label)]}):null}function J({goal:n,onOpen:i,onToggle:a}){let o=r(),s=n.status===`done`,c=n.progress.total?Math.round(n.progress.done/n.progress.total*100):0,l=E(n.due,n.overdue),u=n.next_step?o(`Next: {step}`,{step:n.next_step}):n.description||``,d=n.status===`paused`?o(`Paused`):n.status===`cancelled`?o(`Cancelled`):s?o(`Done`):n.check_in?v(n.check_in):o(`Updated {when}`,{when:e(n.updated_at)});return(0,H.jsxs)(`div`,{className:`flex items-start pl-[18px] pr-1 pt-2 pb-2.5`,children:[(0,H.jsx)(`button`,{type:`button`,onClick:a,"aria-label":o(s?`Mark as not done`:`Mark as done`),className:`mt-0.5 flex h-7 w-7 shrink-0 items-center justify-center text-muted`,children:s?(0,H.jsx)(B,{size:22}):(0,H.jsx)(f,{size:22})}),(0,H.jsxs)(`button`,{type:`button`,onClick:i,className:`ml-2.5 min-w-0 flex-1 pt-[3px] text-left`,children:[(0,H.jsx)(`span`,{className:t(`line-clamp-2 block text-[15px] font-semibold leading-snug`,s&&`text-muted`),children:n.title}),u&&(0,H.jsx)(`span`,{className:`mt-0.5 line-clamp-2 block text-[13px] leading-[18px] text-muted`,children:u}),(0,H.jsxs)(`span`,{className:`mt-0.5 flex items-center gap-2 text-[12px] text-muted/80`,children:[(0,H.jsxs)(`span`,{className:`truncate`,children:[d,l&&n.status===`active`?` · ${l}`:``]}),c>0&&!s&&(0,H.jsxs)(`span`,{className:`shrink-0 font-medium text-emerald-600 dark:text-emerald-400`,children:[c,`%`]})]})]}),(0,H.jsx)(`button`,{type:`button`,onClick:i,"aria-label":o(`More`),className:`flex h-10 w-10 shrink-0 items-center justify-center text-muted`,children:(0,H.jsx)(L,{size:20})})]})}function Y({goal:e,onChanged:t,onOpen:n}){let{toast:i,state:a}=c(),[o,s]=(0,V.useState)(!1),l=a.profile?.name??`nanoMuse`,d=r(),f=e.proposal;if(!f)return null;let p=async n=>{s(!0);try{n?await u.acceptProposal(e.id):await u.dismissProposal(e.id),i(d(n?`Plan updated`:`Kept your plan`)),t()}catch(e){i(e.message)}finally{s(!1)}},m=e.steps.filter(e=>e.status===`done`||e.status===`skipped`).length;return(0,H.jsxs)(`div`,{className:`rounded-3xl border border-accent/30 bg-accent/5 px-4 py-3.5`,children:[(0,H.jsxs)(`button`,{type:`button`,onClick:n,className:`w-full text-left`,children:[(0,H.jsxs)(`div`,{className:`flex items-center gap-2 text-[12px] font-semibold uppercase tracking-wide text-accent`,children:[(0,H.jsx)(g,{size:13}),` `,d(`Adjust the plan for “{title}”?`,{title:e.title})]}),(0,H.jsx)(`p`,{className:`mt-1.5 text-[14px] leading-snug`,children:f.reason}),(0,H.jsxs)(`div`,{className:`mt-2 text-[12px] text-muted`,children:[m>0&&(0,H.jsxs)(`span`,{children:[m===1?d(`Keeps the 1 step already done.`):d(`Keeps the {n} steps already done.`,{n:m}),` `]}),d(`New remaining steps:`)]}),(0,H.jsx)(`ol`,{className:`mt-1 space-y-0.5 text-[13.5px] list-decimal pl-5`,children:f.steps.map((e,t)=>(0,H.jsx)(`li`,{children:e},t))})]}),(0,H.jsxs)(`div`,{className:`mt-3 flex gap-2`,children:[(0,H.jsx)(`button`,{type:`button`,disabled:o,onClick:()=>void p(!1),className:`flex-1 rounded-2xl border border-border py-2 text-[13.5px] font-medium disabled:opacity-50`,children:d(`Keep my plan`)}),(0,H.jsx)(`button`,{type:`button`,disabled:o,onClick:()=>void p(!0),className:`flex-1 rounded-2xl bg-accent text-accent-fg py-2 text-[13.5px] font-medium disabled:opacity-50`,children:d(`Use {name}'s plan`,{name:l})})]})]})}function X({value:e,onChange:n}){let i=r();return(0,H.jsx)(`div`,{className:`flex flex-wrap gap-1.5`,children:C.map(r=>(0,H.jsxs)(`button`,{type:`button`,onClick:()=>n(e===r.id?``:r.id),className:t(`inline-flex items-center gap-1 rounded-full px-2.5 py-1 text-[12.5px] font-medium transition border`,e===r.id?t(r.tone,`border-transparent ring-2 ring-accent/40`):`border-border text-muted`),children:[r.icon({size:12}),` `,i(r.label)]},r.id))})}function Z({value:e,onChange:n}){let i=r(),{cadence:a,anchor:o,time:s}=k(e),c=(e,t,r)=>n(j(e,t,r));return(0,H.jsxs)(`div`,{className:`space-y-2`,children:[(0,H.jsx)(`div`,{className:`flex flex-wrap gap-1.5`,children:T.map(e=>(0,H.jsx)(`button`,{type:`button`,onClick:()=>c(e.id,e.id===`weekly`?o||`mon`:e.id===`monthly`?o||`1`:``,s),className:t(`rounded-full px-2.5 py-1 text-[12.5px] font-medium border transition`,a===e.id?`bg-accent text-accent-fg border-transparent`:`border-border text-muted`),children:i(e.label)},e.id))}),a&&(0,H.jsxs)(`div`,{className:`flex items-center gap-2 text-[13.5px]`,children:[a===`weekly`&&(0,H.jsx)(`select`,{value:o||`mon`,onChange:e=>c(a,e.target.value,s),className:`rounded-xl bg-surface-2 px-2.5 py-1.5 outline-none`,children:S.map(e=>(0,H.jsx)(`option`,{value:e,children:m(e)},e))}),a===`monthly`&&(0,H.jsx)(`select`,{value:o||`1`,onChange:e=>c(a,e.target.value,s),className:`rounded-xl bg-surface-2 px-2.5 py-1.5 outline-none`,children:Array.from({length:28},(e,t)=>String(t+1)).map(e=>(0,H.jsx)(`option`,{value:e,children:y(Number(e))},e))}),(0,H.jsx)(`span`,{className:`text-muted`,children:i(`at`)}),(0,H.jsx)(`input`,{type:`time`,value:s,onChange:e=>c(a,o,e.target.value||`09:00`),className:`rounded-xl bg-surface-2 px-2.5 py-1.5 outline-none`})]})]})}function Q({goal:n,onClose:a,onAdvance:o,onChanged:s}){let{toast:l,send:d,openThread:f,state:m}=c(),[g,y]=(0,V.useState)(``),[b,x]=(0,V.useState)(!1),S=m.profile?.name??`nanoMuse`,C=r(),w=async e=>{if(n)try{await u.patchGoal(n.id,e),s()}catch(e){l(e.message)}},T=async()=>{if(n&&g.trim())try{await u.addStep(n.id,g.trim()),y(``),s()}catch(e){l(e.message)}},k=async()=>{if(n)try{await u.checkInGoal(n.id),l(C(`{name} will check in with you in the main chat`,{name:S})),f(`main`),a()}catch(e){l(e.message)}},j=async()=>{if(n&&window.confirm(C(`Delete “{title}”?`,{title:n.title})))try{await u.deleteGoal(n.id),s(),a()}catch(e){l(e.message)}},N=n?E(n.due,n.overdue):``;return(0,H.jsx)(D,{open:!!n,onClose:a,title:n?.title,footer:n&&(0,H.jsxs)(`div`,{className:`flex gap-2`,children:[n.status===`active`?(0,H.jsxs)(`button`,{type:`button`,onClick:()=>void w({status:`paused`}),className:`flex-1 rounded-2xl border border-border py-2.5 font-medium flex items-center justify-center gap-1.5`,children:[(0,H.jsx)(z,{size:16}),` `,C(`Pause`)]}):n.status===`paused`?(0,H.jsxs)(`button`,{type:`button`,onClick:()=>void w({status:`active`}),className:`flex-1 rounded-2xl border border-border py-2.5 font-medium flex items-center justify-center gap-1.5`,children:[(0,H.jsx)(p,{size:16}),` `,C(`Resume`)]}):null,n.status===`active`&&(0,H.jsxs)(`button`,{type:`button`,onClick:()=>o(n),className:`flex-1 rounded-2xl bg-accent text-accent-fg py-2.5 font-medium flex items-center justify-center gap-1.5`,children:[(0,H.jsx)(p,{size:16}),` `,C(`Work on it now`)]}),(0,H.jsx)(`button`,{type:`button`,onClick:()=>void j(),"aria-label":C(`Delete goal`),className:`rounded-2xl border border-border px-3 text-muted hover:text-rose-500`,children:(0,H.jsx)(h,{size:18})})]}),children:n&&(0,H.jsxs)(`div`,{className:`space-y-4`,children:[n.proposal&&(0,H.jsx)(Y,{goal:n,onChanged:s,onOpen:()=>void 0}),n.description&&(0,H.jsx)(`p`,{className:`text-[14px] text-muted leading-snug`,children:n.description}),(0,H.jsx)(`div`,{className:`rounded-2xl bg-surface-2/60 px-3.5 py-3`,children:b?(0,H.jsxs)(`div`,{className:`space-y-3`,children:[(0,H.jsxs)(`div`,{children:[(0,H.jsx)(`div`,{className:`text-[12px] font-semibold uppercase tracking-wide text-muted mb-1.5`,children:C(`Area of life`)}),(0,H.jsx)(X,{value:n.category,onChange:e=>void w({category:e})})]}),(0,H.jsxs)(`div`,{children:[(0,H.jsx)(`div`,{className:`text-[12px] font-semibold uppercase tracking-wide text-muted mb-1.5`,children:C(`Target date`)}),(0,H.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,H.jsx)(`input`,{type:`date`,value:n.due,onChange:e=>void w({due:e.target.value}),className:`rounded-xl bg-surface px-2.5 py-1.5 text-[13.5px] outline-none`}),n.due&&(0,H.jsx)(`button`,{type:`button`,onClick:()=>void w({due:``}),className:`text-[12.5px] text-muted`,children:C(`Clear`)})]})]}),(0,H.jsxs)(`div`,{children:[(0,H.jsx)(`div`,{className:`text-[12px] font-semibold uppercase tracking-wide text-muted mb-1.5`,children:C(`Reminders from {name}`,{name:S})}),(0,H.jsx)(Z,{value:n.check_in,onChange:e=>void w({check_in:e})})]}),(0,H.jsx)(`button`,{type:`button`,onClick:()=>x(!1),className:`text-[12.5px] text-accent font-medium`,children:C(`Done`)})]}):(0,H.jsxs)(`button`,{type:`button`,onClick:()=>x(!0),className:`w-full text-left`,children:[(0,H.jsxs)(`div`,{className:`flex flex-wrap items-center gap-1.5 text-[12.5px]`,children:[n.category?(0,H.jsx)(q,{id:n.category,size:`md`}):(0,H.jsx)(`span`,{className:`rounded-full border border-dashed border-border px-2.5 py-1 text-muted`,children:C(`No category`)}),(0,H.jsxs)(`span`,{className:t(`inline-flex items-center gap-1 rounded-full px-2.5 py-1`,n.overdue?`bg-rose-500/12 text-rose-600 dark:text-rose-300 font-medium`:`bg-surface text-muted`),children:[(0,H.jsx)(A,{size:13}),` `,N||C(`No target date`)]}),(0,H.jsxs)(`span`,{className:`inline-flex items-center gap-1 rounded-full bg-surface px-2.5 py-1 text-muted`,children:[(0,H.jsx)(O,{size:13}),` `,n.check_in?v(n.check_in):C(`No reminders`)]})]}),n.next_check_in&&n.status===`active`&&(0,H.jsxs)(`div`,{className:`mt-1.5 text-[12px] text-muted`,children:[C(`Next check-in {when}`,{when:e(n.next_check_in)}),` · `,i(n.next_check_in)]}),(0,H.jsx)(`div`,{className:`mt-1.5 text-[12px] text-accent font-medium`,children:C(`Edit`)})]})}),(0,H.jsxs)(`div`,{children:[(0,H.jsxs)(`div`,{className:`text-[12px] font-semibold uppercase tracking-wide text-muted mb-2`,children:[C(`Plan`),` · `,n.progress.done,`/`,n.progress.total]}),(0,H.jsx)(`ul`,{className:`space-y-1`,children:n.steps.map(e=>{let n=U[e.status];return(0,H.jsxs)(`li`,{className:`flex items-start gap-2.5 rounded-2xl px-2 py-1.5 hover:bg-surface-2/60`,children:[(0,H.jsx)(`button`,{type:`button`,"aria-label":C(`Mark step {n} {status}`,{n:e.idx,status:C(W[e.status])}),onClick:()=>void w({step_index:e.idx,step_status:W[e.status]}),className:`mt-0.5 text-muted`,children:(0,H.jsx)(n,{size:20})}),(0,H.jsxs)(`div`,{className:`flex-1 min-w-0`,children:[(0,H.jsxs)(`div`,{className:t(`text-[14.5px] leading-snug`,(e.status===`done`||e.status===`skipped`)&&`line-through text-muted`),children:[e.idx,`. `,e.title]}),e.note&&(0,H.jsx)(`div`,{className:`text-[12.5px] text-muted mt-0.5 whitespace-pre-wrap`,children:e.note})]})]},e.idx)})}),(0,H.jsxs)(`div`,{className:`mt-2 flex gap-2`,children:[(0,H.jsx)(`input`,{value:g,onChange:e=>y(e.target.value),onKeyDown:e=>e.key===`Enter`&&void T(),placeholder:C(`Add a step`),className:`flex-1 rounded-2xl bg-surface-2 px-3.5 py-2 text-[14px] outline-none focus:ring-2 focus:ring-accent/40`}),(0,H.jsx)(`button`,{type:`button`,onClick:()=>void T(),className:`rounded-2xl bg-surface-2 px-3 text-accent`,"aria-label":C(`Add step`),children:(0,H.jsx)(_,{size:18})})]})]}),n.notes&&(0,H.jsxs)(`div`,{children:[(0,H.jsx)(`div`,{className:`text-[12px] font-semibold uppercase tracking-wide text-muted mb-1.5`,children:C(`Notes from {name}`,{name:S})}),(0,H.jsx)(`pre`,{className:`whitespace-pre-wrap break-words text-[13px] leading-snug text-muted font-sans`,children:n.notes})]}),(0,H.jsxs)(`div`,{className:`flex flex-wrap gap-x-4 gap-y-1.5`,children:[(0,H.jsx)(`button`,{type:`button`,onClick:()=>{d(`main`,C(`About my goal “{title}” ({id}): what's the status, and what should we do next?`,{title:n.title,id:n.id})).catch(e=>l(e.message||C(`Could not send`))),f(`main`),a()},className:`text-[13.5px] text-accent font-medium`,children:C(`Discuss this goal in chat →`)}),n.status===`active`&&(0,H.jsxs)(`button`,{type:`button`,onClick:()=>void k(),className:`text-[13.5px] text-accent font-medium inline-flex items-center gap-1`,children:[(0,H.jsx)(M,{size:14}),` `,C(`Check in with me now`)]})]})]})})}function $({open:e,onClose:t,onCreated:n}){let{toast:i,send:a,openThread:o,state:s}=c(),[l,d]=(0,V.useState)(``),[f,p]=(0,V.useState)(``),[m,h]=(0,V.useState)(``),[_,v]=(0,V.useState)(``),[y,b]=(0,V.useState)(``),[x,S]=(0,V.useState)(``),[C,w]=(0,V.useState)(!1),T=s.profile?.name??`nanoMuse`,E=r(),O=()=>{d(``),p(``),h(``),v(``),b(``),S(``)},k=async()=>{if(l.trim()){w(!0);try{await u.createGoal({title:l.trim(),description:f.trim(),steps:m.split(` +import{A as e,E as t,J as n,K as r,N as i,Q as a,Y as o,b as s,f as c,r as l,x as u}from"./MuseHeader-BDWXHKHT.js";import{t as d}from"./StarNudge-B8P2bPEz.js";import{H as f,Q as p,S as m,V as h,W as g,Z as _,_ as v,b as y,f as b,g as x,h as S,m as C,ot as w,p as T,v as E,w as D,wt as O,x as k,xt as A,y as j}from"./index-DKrXW2Qj.js";var M=n(`bell-ring`,[[`path`,{d:`M10.268 21a2 2 0 0 0 3.464 0`,key:`vwvbt9`}],[`path`,{d:`M22 8c0-2.3-.8-4.3-2-6`,key:`5bb3ad`}],[`path`,{d:`M3.262 15.326A1 1 0 0 0 4 17h16a1 1 0 0 0 .74-1.673C19.41 13.956 18 12.499 18 8A6 6 0 0 0 6 8c0 4.499-1.411 5.956-2.738 7.326`,key:`11g9vi`}],[`path`,{d:`M4 2C2.8 3.7 2 5.7 2 8`,key:`tap9e0`}]]),N=n(`circle-check`,[[`circle`,{cx:`12`,cy:`12`,r:`10`,key:`1mglay`}],[`path`,{d:`m9 12 2 2 4-4`,key:`dzmm74`}]]),P=n(`circle-dashed`,[[`path`,{d:`M10.1 2.182a10 10 0 0 1 3.8 0`,key:`5ilxe3`}],[`path`,{d:`M13.9 21.818a10 10 0 0 1-3.8 0`,key:`11zvb9`}],[`path`,{d:`M17.609 3.721a10 10 0 0 1 2.69 2.7`,key:`1iw5b2`}],[`path`,{d:`M2.182 13.9a10 10 0 0 1 0-3.8`,key:`c0bmvh`}],[`path`,{d:`M20.279 17.609a10 10 0 0 1-2.7 2.69`,key:`1ruxm7`}],[`path`,{d:`M21.818 10.1a10 10 0 0 1 0 3.8`,key:`qkgqxc`}],[`path`,{d:`M3.721 6.391a10 10 0 0 1 2.7-2.69`,key:`1mcia2`}],[`path`,{d:`M6.391 20.279a10 10 0 0 1-2.69-2.7`,key:`1fvljs`}]]),F=n(`circle-slash`,[[`circle`,{cx:`12`,cy:`12`,r:`10`,key:`1mglay`}],[`line`,{x1:`9`,x2:`15`,y1:`15`,y2:`9`,key:`1dfufj`}]]),I=n(`circle`,[[`circle`,{cx:`12`,cy:`12`,r:`10`,key:`1mglay`}]]),L=n(`ellipsis-vertical`,[[`circle`,{cx:`12`,cy:`12`,r:`1`,key:`41hilf`}],[`circle`,{cx:`12`,cy:`5`,r:`1`,key:`gxeob9`}],[`circle`,{cx:`12`,cy:`19`,r:`1`,key:`lyex9k`}]]),R=n(`octagon-alert`,[[`path`,{d:`M12 16h.01`,key:`1drbdi`}],[`path`,{d:`M12 8v4`,key:`1got3b`}],[`path`,{d:`M15.312 2a2 2 0 0 1 1.414.586l4.688 4.688A2 2 0 0 1 22 8.688v6.624a2 2 0 0 1-.586 1.414l-4.688 4.688a2 2 0 0 1-1.414.586H8.688a2 2 0 0 1-1.414-.586l-4.688-4.688A2 2 0 0 1 2 15.312V8.688a2 2 0 0 1 .586-1.414l4.688-4.688A2 2 0 0 1 8.688 2z`,key:`1fd625`}]]),z=n(`pause`,[[`rect`,{x:`14`,y:`3`,width:`5`,height:`18`,rx:`1`,key:`kaeet6`}],[`rect`,{x:`5`,y:`3`,width:`5`,height:`18`,rx:`1`,key:`1wsw3u`}]]),B=n(`square-check`,[[`rect`,{width:`18`,height:`18`,x:`3`,y:`3`,rx:`2`,key:`afitv7`}],[`path`,{d:`m9 12 2 2 4-4`,key:`dzmm74`}]]),V=a(o(),1),H=s(),U={pending:e=>(0,H.jsx)(I,{...e}),in_progress:e=>(0,H.jsx)(P,{...e,className:t(e.className,`text-accent`)}),done:e=>(0,H.jsx)(N,{...e,className:t(e.className,`text-emerald-500`)}),blocked:e=>(0,H.jsx)(R,{...e,className:t(e.className,`text-rose-500`)}),skipped:e=>(0,H.jsx)(F,{...e,className:t(e.className,`text-muted`)})},W={pending:`done`,in_progress:`done`,done:`pending`,blocked:`pending`,skipped:`pending`};function G(){let{state:e,refreshGoals:t,send:n,openThread:i,toast:a}=c(),[o,s]=(0,V.useState)(null),[f,p]=(0,V.useState)(!1),[m,h]=(0,V.useState)(null),[g,v]=(0,V.useState)(!1),y=(0,V.useRef)(null),x=e.profile?.name??`nanoMuse`,S=r();(0,V.useEffect)(()=>{t()},[t]);let T=e.goals.filter(e=>e.proposal&&e.status!==`cancelled`),E=[...e.goals.filter(e=>e.status===`active`),...e.goals.filter(e=>e.status===`paused`)],O=e.goals.filter(e=>e.status===`done`||e.status===`cancelled`),k=e.goals.find(e=>e.id===o)??null,A=async e=>{try{await u.advanceGoal(e.id),a(S(`{name} is working on “{title}” in the main chat`,{name:x,title:e.title})),i(`main`)}catch(e){a(e.message)}},[j,M]=(0,V.useState)(!1),N=async e=>{try{let n=e.status!==`done`;await u.patchGoal(e.id,{status:n?`done`:`active`}),n&&M(!0),t()}catch(e){a(e.message)}},P=e=>{h(null),n(`main`,S(`I'd like to create a {category} goal. Ask me a few short questions, one at a time (what exactly I want, why and by when, how often to check in), then create it with concrete steps using the goals tool.`,{category:S(e.label)})).catch(e=>a(e.message||S(`Could not send`))),i(`main`)};return(0,H.jsxs)(`div`,{className:`flex h-full flex-col`,children:[(0,H.jsx)(b,{title:S(`Goals`),children:(0,H.jsx)(l,{small:!0,onClick:()=>p(!0),label:S(`New goal`),children:(0,H.jsx)(_,{size:22})})}),(0,H.jsxs)(`div`,{className:`flex-1 overflow-y-auto pb-6`,children:[T.length>0&&(0,H.jsxs)(`section`,{className:`px-4 pb-2`,children:[(0,H.jsx)(`div`,{className:`px-1 mb-2 text-[12px] font-semibold uppercase tracking-wide text-muted`,children:S(`{name} suggests`,{name:x})}),(0,H.jsx)(`div`,{className:`space-y-2.5`,children:T.map(e=>(0,H.jsx)(Y,{goal:e,onChanged:t,onOpen:()=>s(e.id)},e.id))})]}),(0,H.jsx)(d,{moment:`goal_done`,due:j,className:`mx-4 mb-3`}),(0,H.jsx)(K,{label:S(`Tracking`),dot:!0,onAdd:()=>y.current?.scrollIntoView({behavior:`smooth`,block:`start`})}),E.length===0?(0,H.jsx)(`p`,{className:`px-5 pb-3 text-[13px] text-muted`,children:S(`Nothing tracked yet`)}):E.map(e=>(0,H.jsx)(J,{goal:e,onOpen:()=>s(e.id),onToggle:()=>void N(e)},e.id)),O.length>0&&(0,H.jsxs)(H.Fragment,{children:[(0,H.jsx)(`div`,{className:`h-1.5`}),(0,H.jsx)(K,{label:S(`Finished`)}),(g?O:O.slice(0,2)).map(e=>(0,H.jsx)(J,{goal:e,onOpen:()=>s(e.id),onToggle:()=>void N(e)},e.id)),!g&&O.length>2&&(0,H.jsx)(`button`,{type:`button`,onClick:()=>v(!0),className:`px-5 py-2 text-[13.5px] font-medium text-accent`,children:S(`Show {n} more`,{n:O.length-2})})]}),(0,H.jsxs)(`div`,{ref:y,className:`mt-2.5 border-t border-border/70 px-5 pt-3.5 pb-1.5`,children:[(0,H.jsx)(`h3`,{className:`text-[17px] font-semibold`,children:S(`Create a goal`)}),(0,H.jsx)(`p`,{className:`mt-1 text-[13px] leading-[18px] text-muted`,children:S(`Pick a category and tell me the goal you have in mind. I'll shape a plan with you and keep improving it as you go.`)})]}),C.map(e=>(0,H.jsxs)(`button`,{type:`button`,onClick:()=>h(e),className:`flex h-[50px] w-full items-center gap-3.5 pl-5 pr-2 text-left active:bg-surface-2/70`,children:[(0,H.jsx)(`span`,{className:`text-fg`,children:e.icon({size:22})}),(0,H.jsx)(`span`,{className:`flex-1 text-[15px] font-medium`,children:S(e.label)}),(0,H.jsx)(`span`,{className:`flex h-10 w-10 items-center justify-center text-muted`,children:(0,H.jsx)(_,{size:22})})]},e.id))]}),(0,H.jsx)(Q,{goal:k,onClose:()=>s(null),onAdvance:A,onChanged:t}),(0,H.jsx)($,{open:f,onClose:()=>p(!1),onCreated:()=>{p(!1),t()}}),(0,H.jsx)(D,{open:m!==null,onClose:()=>h(null),children:m&&(0,H.jsxs)(`div`,{className:`px-1 pb-2`,children:[(0,H.jsx)(`h3`,{className:`text-[20px] font-bold`,children:S(`Create a {category} goal`,{category:S(m.label)})}),(0,H.jsx)(`p`,{className:`mt-3.5 text-[15px] leading-[22px]`,children:S(`First, we'll shape the goal together in the chat. I'll ask a few questions so I understand exactly what you're after.`)}),(0,H.jsx)(`p`,{className:`mt-3.5 text-[15px] leading-[22px]`,children:S(`Once it's set, I'll track your progress here.`)}),(0,H.jsxs)(`button`,{type:`button`,onClick:()=>P(m),className:`mt-6 flex h-[50px] w-full items-center justify-center gap-2 rounded-full bg-accent text-[16px] font-semibold text-accent-fg`,children:[(0,H.jsx)(w,{size:18}),` `,S(`Start`)]})]})})]})}function K({label:e,dot:n=!1,onAdd:r}){return(0,H.jsxs)(`div`,{className:`flex items-center pl-5 pr-2 pt-1`,children:[n&&(0,H.jsx)(`span`,{className:`mr-2.5 h-2 w-2 rounded-full bg-emerald-500`}),(0,H.jsx)(`span`,{className:t(`flex-1 text-[15px] font-semibold`,n&&`text-emerald-600 dark:text-emerald-400`),children:e}),r?(0,H.jsx)(`button`,{type:`button`,onClick:r,"aria-label":e,className:`flex h-10 w-10 items-center justify-center text-muted`,children:(0,H.jsx)(_,{size:22})}):(0,H.jsx)(`span`,{className:`h-10`})]})}function q({id:e,size:n=`sm`}){let i=r(),a=x(e);return a?(0,H.jsxs)(`span`,{className:t(`inline-flex items-center gap-1 rounded-full font-medium`,a.tone,n===`sm`?`px-2 py-0.5 text-[11.5px]`:`px-2.5 py-1 text-[12.5px]`),children:[a.icon({size:n===`sm`?11:13}),` `,i(a.label)]}):null}function J({goal:n,onOpen:i,onToggle:a}){let o=r(),s=n.status===`done`,c=n.progress.total?Math.round(n.progress.done/n.progress.total*100):0,l=E(n.due,n.overdue),u=n.next_step?o(`Next: {step}`,{step:n.next_step}):n.description||``,d=n.status===`paused`?o(`Paused`):n.status===`cancelled`?o(`Cancelled`):s?o(`Done`):n.check_in?v(n.check_in):o(`Updated {when}`,{when:e(n.updated_at)});return(0,H.jsxs)(`div`,{className:`flex items-start pl-[18px] pr-1 pt-2 pb-2.5`,children:[(0,H.jsx)(`button`,{type:`button`,onClick:a,"aria-label":o(s?`Mark as not done`:`Mark as done`),className:`mt-0.5 flex h-7 w-7 shrink-0 items-center justify-center text-muted`,children:s?(0,H.jsx)(B,{size:22}):(0,H.jsx)(f,{size:22})}),(0,H.jsxs)(`button`,{type:`button`,onClick:i,className:`ml-2.5 min-w-0 flex-1 pt-[3px] text-left`,children:[(0,H.jsx)(`span`,{className:t(`line-clamp-2 block text-[15px] font-semibold leading-snug`,s&&`text-muted`),children:n.title}),u&&(0,H.jsx)(`span`,{className:`mt-0.5 line-clamp-2 block text-[13px] leading-[18px] text-muted`,children:u}),(0,H.jsxs)(`span`,{className:`mt-0.5 flex items-center gap-2 text-[12px] text-muted/80`,children:[(0,H.jsxs)(`span`,{className:`truncate`,children:[d,l&&n.status===`active`?` · ${l}`:``]}),c>0&&!s&&(0,H.jsxs)(`span`,{className:`shrink-0 font-medium text-emerald-600 dark:text-emerald-400`,children:[c,`%`]})]})]}),(0,H.jsx)(`button`,{type:`button`,onClick:i,"aria-label":o(`More`),className:`flex h-10 w-10 shrink-0 items-center justify-center text-muted`,children:(0,H.jsx)(L,{size:20})})]})}function Y({goal:e,onChanged:t,onOpen:n}){let{toast:i,state:a}=c(),[o,s]=(0,V.useState)(!1),l=a.profile?.name??`nanoMuse`,d=r(),f=e.proposal;if(!f)return null;let p=async n=>{s(!0);try{n?await u.acceptProposal(e.id):await u.dismissProposal(e.id),i(d(n?`Plan updated`:`Kept your plan`)),t()}catch(e){i(e.message)}finally{s(!1)}},m=e.steps.filter(e=>e.status===`done`||e.status===`skipped`).length;return(0,H.jsxs)(`div`,{className:`rounded-3xl border border-accent/30 bg-accent/5 px-4 py-3.5`,children:[(0,H.jsxs)(`button`,{type:`button`,onClick:n,className:`w-full text-left`,children:[(0,H.jsxs)(`div`,{className:`flex items-center gap-2 text-[12px] font-semibold uppercase tracking-wide text-accent`,children:[(0,H.jsx)(g,{size:13}),` `,d(`Adjust the plan for “{title}”?`,{title:e.title})]}),(0,H.jsx)(`p`,{className:`mt-1.5 text-[14px] leading-snug`,children:f.reason}),(0,H.jsxs)(`div`,{className:`mt-2 text-[12px] text-muted`,children:[m>0&&(0,H.jsxs)(`span`,{children:[m===1?d(`Keeps the 1 step already done.`):d(`Keeps the {n} steps already done.`,{n:m}),` `]}),d(`New remaining steps:`)]}),(0,H.jsx)(`ol`,{className:`mt-1 space-y-0.5 text-[13.5px] list-decimal pl-5`,children:f.steps.map((e,t)=>(0,H.jsx)(`li`,{children:e},t))})]}),(0,H.jsxs)(`div`,{className:`mt-3 flex gap-2`,children:[(0,H.jsx)(`button`,{type:`button`,disabled:o,onClick:()=>void p(!1),className:`flex-1 rounded-2xl border border-border py-2 text-[13.5px] font-medium disabled:opacity-50`,children:d(`Keep my plan`)}),(0,H.jsx)(`button`,{type:`button`,disabled:o,onClick:()=>void p(!0),className:`flex-1 rounded-2xl bg-accent text-accent-fg py-2 text-[13.5px] font-medium disabled:opacity-50`,children:d(`Use {name}'s plan`,{name:l})})]})]})}function X({value:e,onChange:n}){let i=r();return(0,H.jsx)(`div`,{className:`flex flex-wrap gap-1.5`,children:C.map(r=>(0,H.jsxs)(`button`,{type:`button`,onClick:()=>n(e===r.id?``:r.id),className:t(`inline-flex items-center gap-1 rounded-full px-2.5 py-1 text-[12.5px] font-medium transition border`,e===r.id?t(r.tone,`border-transparent ring-2 ring-accent/40`):`border-border text-muted`),children:[r.icon({size:12}),` `,i(r.label)]},r.id))})}function Z({value:e,onChange:n}){let i=r(),{cadence:a,anchor:o,time:s}=k(e),c=(e,t,r)=>n(j(e,t,r));return(0,H.jsxs)(`div`,{className:`space-y-2`,children:[(0,H.jsx)(`div`,{className:`flex flex-wrap gap-1.5`,children:T.map(e=>(0,H.jsx)(`button`,{type:`button`,onClick:()=>c(e.id,e.id===`weekly`?o||`mon`:e.id===`monthly`?o||`1`:``,s),className:t(`rounded-full px-2.5 py-1 text-[12.5px] font-medium border transition`,a===e.id?`bg-accent text-accent-fg border-transparent`:`border-border text-muted`),children:i(e.label)},e.id))}),a&&(0,H.jsxs)(`div`,{className:`flex items-center gap-2 text-[13.5px]`,children:[a===`weekly`&&(0,H.jsx)(`select`,{value:o||`mon`,onChange:e=>c(a,e.target.value,s),className:`rounded-xl bg-surface-2 px-2.5 py-1.5 outline-none`,children:S.map(e=>(0,H.jsx)(`option`,{value:e,children:m(e)},e))}),a===`monthly`&&(0,H.jsx)(`select`,{value:o||`1`,onChange:e=>c(a,e.target.value,s),className:`rounded-xl bg-surface-2 px-2.5 py-1.5 outline-none`,children:Array.from({length:28},(e,t)=>String(t+1)).map(e=>(0,H.jsx)(`option`,{value:e,children:y(Number(e))},e))}),(0,H.jsx)(`span`,{className:`text-muted`,children:i(`at`)}),(0,H.jsx)(`input`,{type:`time`,value:s,onChange:e=>c(a,o,e.target.value||`09:00`),className:`rounded-xl bg-surface-2 px-2.5 py-1.5 outline-none`})]})]})}function Q({goal:n,onClose:a,onAdvance:o,onChanged:s}){let{toast:l,send:d,openThread:f,state:m}=c(),[g,y]=(0,V.useState)(``),[b,x]=(0,V.useState)(!1),S=m.profile?.name??`nanoMuse`,C=r(),w=async e=>{if(n)try{await u.patchGoal(n.id,e),s()}catch(e){l(e.message)}},T=async()=>{if(n&&g.trim())try{await u.addStep(n.id,g.trim()),y(``),s()}catch(e){l(e.message)}},k=async()=>{if(n)try{await u.checkInGoal(n.id),l(C(`{name} will check in with you in the main chat`,{name:S})),f(`main`),a()}catch(e){l(e.message)}},j=async()=>{if(n&&window.confirm(C(`Delete “{title}”?`,{title:n.title})))try{await u.deleteGoal(n.id),s(),a()}catch(e){l(e.message)}},N=n?E(n.due,n.overdue):``;return(0,H.jsx)(D,{open:!!n,onClose:a,title:n?.title,footer:n&&(0,H.jsxs)(`div`,{className:`flex gap-2`,children:[n.status===`active`?(0,H.jsxs)(`button`,{type:`button`,onClick:()=>void w({status:`paused`}),className:`flex-1 rounded-2xl border border-border py-2.5 font-medium flex items-center justify-center gap-1.5`,children:[(0,H.jsx)(z,{size:16}),` `,C(`Pause`)]}):n.status===`paused`?(0,H.jsxs)(`button`,{type:`button`,onClick:()=>void w({status:`active`}),className:`flex-1 rounded-2xl border border-border py-2.5 font-medium flex items-center justify-center gap-1.5`,children:[(0,H.jsx)(p,{size:16}),` `,C(`Resume`)]}):null,n.status===`active`&&(0,H.jsxs)(`button`,{type:`button`,onClick:()=>o(n),className:`flex-1 rounded-2xl bg-accent text-accent-fg py-2.5 font-medium flex items-center justify-center gap-1.5`,children:[(0,H.jsx)(p,{size:16}),` `,C(`Work on it now`)]}),(0,H.jsx)(`button`,{type:`button`,onClick:()=>void j(),"aria-label":C(`Delete goal`),className:`rounded-2xl border border-border px-3 text-muted hover:text-rose-500`,children:(0,H.jsx)(h,{size:18})})]}),children:n&&(0,H.jsxs)(`div`,{className:`space-y-4`,children:[n.proposal&&(0,H.jsx)(Y,{goal:n,onChanged:s,onOpen:()=>void 0}),n.description&&(0,H.jsx)(`p`,{className:`text-[14px] text-muted leading-snug`,children:n.description}),(0,H.jsx)(`div`,{className:`rounded-2xl bg-surface-2/60 px-3.5 py-3`,children:b?(0,H.jsxs)(`div`,{className:`space-y-3`,children:[(0,H.jsxs)(`div`,{children:[(0,H.jsx)(`div`,{className:`text-[12px] font-semibold uppercase tracking-wide text-muted mb-1.5`,children:C(`Area of life`)}),(0,H.jsx)(X,{value:n.category,onChange:e=>void w({category:e})})]}),(0,H.jsxs)(`div`,{children:[(0,H.jsx)(`div`,{className:`text-[12px] font-semibold uppercase tracking-wide text-muted mb-1.5`,children:C(`Target date`)}),(0,H.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,H.jsx)(`input`,{type:`date`,value:n.due,onChange:e=>void w({due:e.target.value}),className:`rounded-xl bg-surface px-2.5 py-1.5 text-[13.5px] outline-none`}),n.due&&(0,H.jsx)(`button`,{type:`button`,onClick:()=>void w({due:``}),className:`text-[12.5px] text-muted`,children:C(`Clear`)})]})]}),(0,H.jsxs)(`div`,{children:[(0,H.jsx)(`div`,{className:`text-[12px] font-semibold uppercase tracking-wide text-muted mb-1.5`,children:C(`Reminders from {name}`,{name:S})}),(0,H.jsx)(Z,{value:n.check_in,onChange:e=>void w({check_in:e})})]}),(0,H.jsx)(`button`,{type:`button`,onClick:()=>x(!1),className:`text-[12.5px] text-accent font-medium`,children:C(`Done`)})]}):(0,H.jsxs)(`button`,{type:`button`,onClick:()=>x(!0),className:`w-full text-left`,children:[(0,H.jsxs)(`div`,{className:`flex flex-wrap items-center gap-1.5 text-[12.5px]`,children:[n.category?(0,H.jsx)(q,{id:n.category,size:`md`}):(0,H.jsx)(`span`,{className:`rounded-full border border-dashed border-border px-2.5 py-1 text-muted`,children:C(`No category`)}),(0,H.jsxs)(`span`,{className:t(`inline-flex items-center gap-1 rounded-full px-2.5 py-1`,n.overdue?`bg-rose-500/12 text-rose-600 dark:text-rose-300 font-medium`:`bg-surface text-muted`),children:[(0,H.jsx)(A,{size:13}),` `,N||C(`No target date`)]}),(0,H.jsxs)(`span`,{className:`inline-flex items-center gap-1 rounded-full bg-surface px-2.5 py-1 text-muted`,children:[(0,H.jsx)(O,{size:13}),` `,n.check_in?v(n.check_in):C(`No reminders`)]})]}),n.next_check_in&&n.status===`active`&&(0,H.jsxs)(`div`,{className:`mt-1.5 text-[12px] text-muted`,children:[C(`Next check-in {when}`,{when:e(n.next_check_in)}),` · `,i(n.next_check_in)]}),(0,H.jsx)(`div`,{className:`mt-1.5 text-[12px] text-accent font-medium`,children:C(`Edit`)})]})}),(0,H.jsxs)(`div`,{children:[(0,H.jsxs)(`div`,{className:`text-[12px] font-semibold uppercase tracking-wide text-muted mb-2`,children:[C(`Plan`),` · `,n.progress.done,`/`,n.progress.total]}),(0,H.jsx)(`ul`,{className:`space-y-1`,children:n.steps.map(e=>{let n=U[e.status];return(0,H.jsxs)(`li`,{className:`flex items-start gap-2.5 rounded-2xl px-2 py-1.5 hover:bg-surface-2/60`,children:[(0,H.jsx)(`button`,{type:`button`,"aria-label":C(`Mark step {n} {status}`,{n:e.idx,status:C(W[e.status])}),onClick:()=>void w({step_index:e.idx,step_status:W[e.status]}),className:`mt-0.5 text-muted`,children:(0,H.jsx)(n,{size:20})}),(0,H.jsxs)(`div`,{className:`flex-1 min-w-0`,children:[(0,H.jsxs)(`div`,{className:t(`text-[14.5px] leading-snug`,(e.status===`done`||e.status===`skipped`)&&`line-through text-muted`),children:[e.idx,`. `,e.title]}),e.note&&(0,H.jsx)(`div`,{className:`text-[12.5px] text-muted mt-0.5 whitespace-pre-wrap`,children:e.note})]})]},e.idx)})}),(0,H.jsxs)(`div`,{className:`mt-2 flex gap-2`,children:[(0,H.jsx)(`input`,{value:g,onChange:e=>y(e.target.value),onKeyDown:e=>e.key===`Enter`&&void T(),placeholder:C(`Add a step`),className:`flex-1 rounded-2xl bg-surface-2 px-3.5 py-2 text-[14px] outline-none focus:ring-2 focus:ring-accent/40`}),(0,H.jsx)(`button`,{type:`button`,onClick:()=>void T(),className:`rounded-2xl bg-surface-2 px-3 text-accent`,"aria-label":C(`Add step`),children:(0,H.jsx)(_,{size:18})})]})]}),n.notes&&(0,H.jsxs)(`div`,{children:[(0,H.jsx)(`div`,{className:`text-[12px] font-semibold uppercase tracking-wide text-muted mb-1.5`,children:C(`Notes from {name}`,{name:S})}),(0,H.jsx)(`pre`,{className:`whitespace-pre-wrap break-words text-[13px] leading-snug text-muted font-sans`,children:n.notes})]}),(0,H.jsxs)(`div`,{className:`flex flex-wrap gap-x-4 gap-y-1.5`,children:[(0,H.jsx)(`button`,{type:`button`,onClick:()=>{d(`main`,C(`About my goal “{title}” ({id}): what's the status, and what should we do next?`,{title:n.title,id:n.id})).catch(e=>l(e.message||C(`Could not send`))),f(`main`),a()},className:`text-[13.5px] text-accent font-medium`,children:C(`Discuss this goal in chat →`)}),n.status===`active`&&(0,H.jsxs)(`button`,{type:`button`,onClick:()=>void k(),className:`text-[13.5px] text-accent font-medium inline-flex items-center gap-1`,children:[(0,H.jsx)(M,{size:14}),` `,C(`Check in with me now`)]})]})]})})}function $({open:e,onClose:t,onCreated:n}){let{toast:i,send:a,openThread:o,state:s}=c(),[l,d]=(0,V.useState)(``),[f,p]=(0,V.useState)(``),[m,h]=(0,V.useState)(``),[_,v]=(0,V.useState)(``),[y,b]=(0,V.useState)(``),[x,S]=(0,V.useState)(``),[C,w]=(0,V.useState)(!1),T=s.profile?.name??`nanoMuse`,E=r(),O=()=>{d(``),p(``),h(``),v(``),b(``),S(``)},k=async()=>{if(l.trim()){w(!0);try{await u.createGoal({title:l.trim(),description:f.trim(),steps:m.split(` `).map(e=>e.trim()).filter(Boolean),category:_,due:y,check_in:x}),O(),n()}catch(e){i(e.message)}finally{w(!1)}}};return(0,H.jsx)(D,{open:e,onClose:t,title:E(`New goal`),footer:(0,H.jsxs)(`div`,{className:`flex gap-2`,children:[(0,H.jsxs)(`button`,{type:`button`,onClick:()=>{if(!l.trim())return;let e=[_?`category: ${_}`:``,y?`target date: ${y}`:``,x?`check_in "${x}"`:``].filter(Boolean);a(`main`,E(`Create a goal for me: "{title}"{description}{extras}. Break it into concrete steps with the goals tool, then tell me the plan.`,{title:l.trim(),description:f.trim()?` (${f.trim()})`:``,extras:e.length?` (${e.join(`, `)})`:``})).catch(e=>i(e.message||E(`Could not send`))),O(),t(),o(`main`)},disabled:!l.trim(),className:`flex-1 rounded-2xl border border-border py-2.5 font-medium disabled:opacity-50 flex items-center justify-center gap-1.5`,children:[(0,H.jsx)(g,{size:16}),` `,E(`Let {name} plan it`,{name:T})]}),(0,H.jsx)(`button`,{type:`button`,onClick:()=>void k(),disabled:!l.trim()||C,className:`flex-1 rounded-2xl bg-accent text-accent-fg py-2.5 font-medium disabled:opacity-50`,children:E(`Create`)})]}),children:(0,H.jsxs)(`div`,{className:`space-y-3.5`,children:[(0,H.jsx)(`input`,{value:l,onChange:e=>d(e.target.value),placeholder:E(`What do you want to achieve?`),className:`w-full rounded-2xl bg-surface-2 px-3.5 py-2.5 text-[15px] outline-none focus:ring-2 focus:ring-accent/40`}),(0,H.jsxs)(`div`,{children:[(0,H.jsx)(`div`,{className:`text-[12px] font-semibold uppercase tracking-wide text-muted mb-1.5`,children:E(`Area of life`)}),(0,H.jsx)(X,{value:_,onChange:v})]}),(0,H.jsxs)(`div`,{className:`flex items-center gap-3`,children:[(0,H.jsx)(`div`,{className:`text-[12px] font-semibold uppercase tracking-wide text-muted flex-1`,children:E(`Target date`)}),(0,H.jsx)(`input`,{type:`date`,value:y,onChange:e=>b(e.target.value),className:`rounded-xl bg-surface-2 px-2.5 py-1.5 text-[13.5px] outline-none`})]}),(0,H.jsxs)(`div`,{children:[(0,H.jsx)(`div`,{className:`text-[12px] font-semibold uppercase tracking-wide text-muted mb-1.5`,children:E(`Reminders from {name}`,{name:T})}),(0,H.jsx)(Z,{value:x,onChange:S})]}),(0,H.jsx)(`textarea`,{value:f,onChange:e=>p(e.target.value),placeholder:E(`Why it matters, constraints (optional)`),rows:2,className:`w-full rounded-2xl bg-surface-2 px-3.5 py-2.5 text-[14px] outline-none focus:ring-2 focus:ring-accent/40 resize-none`}),(0,H.jsx)(`textarea`,{value:m,onChange:e=>h(e.target.value),placeholder:E(`Steps, one per line (optional, or let {name} plan them)`,{name:T}),rows:3,className:`w-full rounded-2xl bg-surface-2 px-3.5 py-2.5 text-[14px] outline-none focus:ring-2 focus:ring-accent/40 resize-none`})]})})}export{G as GoalsScreen}; \ No newline at end of file diff --git a/nanomuse/server/static/assets/IdeasScreen-CGfvq5H-.js b/nanomuse/server/static/assets/IdeasScreen-DKf-8dhs.js similarity index 99% rename from nanomuse/server/static/assets/IdeasScreen-CGfvq5H-.js rename to nanomuse/server/static/assets/IdeasScreen-DKf-8dhs.js index 8f582f3a2..006e9ba28 100644 --- a/nanomuse/server/static/assets/IdeasScreen-CGfvq5H-.js +++ b/nanomuse/server/static/assets/IdeasScreen-DKf-8dhs.js @@ -1 +1 @@ -import{A as e,J as t,K as n,Q as r,W as i,Y as a,b as o,f as s,q as c,x as l}from"./MuseHeader-Pw-NI98v.js";import{t as u}from"./refresh-cw-BKgIzslL.js";import{f as d,m as f,ot as p,w as m,yt as h}from"./index-CIdGZ5PB.js";var g=t(`flag`,[[`path`,{d:`M4 22V4a1 1 0 0 1 .4-.8A6 6 0 0 1 8 2c3 0 5 2 7.333 2q2 0 3.067-.8A1 1 0 0 1 20 4v10a1 1 0 0 1-.4.8A6 6 0 0 1 16 16c-3 0-5-2-8-2a6 6 0 0 0-4 1.528`,key:`1jaruq`}]]),_=r(a(),1),v={sections:[{id:`travel`,title:`Travel`,ideas:[{id:`train-watch`,emoji:`🚄`,title:`Tell me where you're going and when; I'll watch for seats and lower fares.`,body:`I set up the lookup tools in my sandbox, check trains, classes and availability as often as you like, and tell you the moment something opens up. Booking and paying stay in your hands.`,kind:`GOAL`,category:`other`,prompt:`I want to watch a train route: ask me for the origin, destination, date and acceptable departure window, then set up a goal that checks availability regularly.`},{id:`trip-plan`,emoji:`🗺️`,title:`Name a city and a number of days; I'll plan an itinerary you can follow as is.`,body:`Weather, opening hours and travel time between stops go into a day-by-day plan saved to your Library. Change one sentence and I'll rearrange the rest.`,kind:`CHAT`,prompt:`Help me plan a trip. Ask me where, how many days, with whom, a rough budget and the style I like, then give me a day-by-day itinerary as a file.`},{id:`commute-brief`,emoji:`🚦`,title:`Before you leave each morning, I'll tell you the traffic, the weather and the first thing on your plate.`,body:`A morning routine: I check the weather where you are, the traffic on your commute, glance at your calendar and boil the morning down to three sentences.`,kind:`ROUTINE`,time:`07:30`,prompt:`Morning brief: check today's weather and commute traffic, read my calendar for today, and tell me in at most five sentences the three things that matter most and what to bring.`},{id:`parcel-track`,emoji:`📦`,title:`Send me a tracking number; I'll tell you where the parcel is and when it lands.`,body:`I follow the shipment through the carrier's tracking, tell you about every new scan, and remind you to keep the phone nearby on delivery day.`,kind:`CHAT`,prompt:`Help me track a parcel. Ask me for the tracking number and carrier, check the current status once, then set a routine that checks every morning and reminds me the day before delivery.`}]},{id:`work`,title:`Work`,ideas:[{id:`meeting-prep`,emoji:`📝`,title:`Ten minutes before a meeting, I'll have the background and the questions ready.`,body:`I read the meeting's title and attendees from your calendar, look through what we've discussed and what you've put in the Library, and hand you one page: purpose, talking points, three questions worth asking.`,kind:`ROUTINE`,time:`08:50`,prompt:`Look at the meetings on my calendar today and prepare a one-page brief for each: the purpose, the points I should make, and three questions worth asking.`},{id:`weekly-review`,emoji:`📊`,title:`Every Friday afternoon, I'll review what you did this week and what next week needs.`,body:`From our conversations, your calendar and the notes I keep, I list what got done, what didn't, and three priorities for next week, as a draft you can send.`,kind:`ROUTINE`,time:`17:00`,prompt:`Write my weekly review: from this week's conversations, my calendar and what you remember, list what was completed, what is still open, and three priorities for next week. Save it as a Markdown file.`},{id:`inbox-triage`,emoji:`📬`,title:`Dump a pile of messages or emails on me; I'll sort them and draft the replies.`,body:`Paste text or screenshots. I sort them into 'reply today', 'this week' and 'just so you know', and draft each reply so you only need to edit and send.`,kind:`CHAT`,prompt:`I'm handing you a batch of messages to triage: sort them into 'reply today / this week / just so you know' and draft a reply for each one that needs it. Ask me to paste the content first.`},{id:`doc-digest`,emoji:`📄`,title:`Long documents, PDFs, web pages: I'll read them and give you the three-minute version.`,body:`Drop the file in a shared folder or send me the link. You get the conclusions, the key numbers and the decisions you need to make; ask follow-ups any time.`,kind:`CHAT`,prompt:`I have something long for you to read and summarise: ask me for the file or link, then give me conclusions, key numbers and decisions I need to make, at most five bullets each.`}]},{id:`life`,title:`Everyday`,ideas:[{id:`price-watch`,emoji:`🏷️`,title:`Tell me what you want to buy; the moment it hits your price, you'll know.`,body:`I check the product page on a schedule, keep the price history, and notify you at your target. Ordering and paying are yours; I don't touch them.`,kind:`GOAL`,category:`finance`,prompt:`I want to watch the price of a product: ask me for the link or name, my target price and how often to check, then create a goal that alerts me when it drops.`},{id:`photo-sort`,emoji:`🖼️`,title:`Mount your photos and I'll sort screenshots and pictures by what's in them.`,body:`Once your gallery is mounted as a shared folder I look at each image (receipts, chat screenshots, landscapes, documents), file it into the right folder and note anything important.`,kind:`CHAT`,prompt:`Help me sort my photos: ask me to mount the gallery in Shared Folders first, then sort by content (receipts, screenshots, scenery, documents, other) and list what you did.`},{id:`meal-log`,emoji:`🥗`,title:`Photograph what you eat; I'll estimate the calories and keep the log.`,body:`A photo or a sentence is enough: I estimate nutrition and calories, log it in the day's memory, and give you a summary each evening with one small suggestion for tomorrow.`,kind:`CHAT`,prompt:`From now on, log my meals: whenever I send a photo or a description, estimate calories and nutrition and write it into today's memory. Tell me first how best to send them.`},{id:`subscriptions`,emoji:`🔁`,title:`Send me your bills; I'll list every subscription that charges you each month, and you decide which to stop.`,body:`Give me bill screenshots or statements. I list every recurring charge, its next date and the yearly total; you decide what to cancel and I walk you through each cancellation.`,kind:`CHAT`,prompt:`Audit my subscriptions: ask me for bill screenshots or statements, then list every recurring charge, its next billing date and the yearly total, and flag the ones I may not need.`}]},{id:`learn`,title:`Learning`,ideas:[{id:`daily-words`,emoji:`🔤`,title:`Five new words every morning, a quick quiz every night.`,body:`You pick the language and level; I pick words by theme with examples and a memory hook, quiz you in the evening, and bring back the ones you missed.`,kind:`ROUTINE`,time:`08:00`,prompt:`Daily vocabulary: pick five new words for me (ask which language, level and topics first), each with a definition, one example sentence and a memory hook, plus a review quiz on yesterday's words.`},{id:`study-plan`,emoji:`🎯`,title:`Something you want to learn? I'll break it into weekly chunks and keep you honest.`,body:`Tell me the goal and the hours you can spare; I lay out four to eight weeks, check progress weekly, and adjust the pace so you actually finish.`,kind:`GOAL`,category:`interests`,prompt:`I want to learn something new and stick with it: ask me what, my current level, hours per week and the timeframe, then create a goal with a weekly progress check.`},{id:`explain`,emoji:`💡`,title:`Send me a concept you don't get; I'll explain it with things you already know.`,body:`I ask what you already understand and start from there, then check with two quick questions and leave you a flashcard if you want one.`,kind:`CHAT`,prompt:`There's a concept I don't understand: ask me what it is and what related things I already know, explain it with analogies, then check with two short questions.`},{id:`reading-notes`,emoji:`📚`,title:`Finished a book? I'll turn it into notes you'll actually reread.`,body:`Tell me the highlights, or send the passages you marked. I write structured notes into your Library and remember what stayed with you.`,kind:`CHAT`,prompt:`Help me write notes on a book: ask me the title, the three things that struck me most and the quotes I want to keep, then save structured Markdown notes.`}]},{id:`family`,title:`Family & friends`,ideas:[{id:`birthdays`,emoji:`🎂`,title:`Birthdays and anniversaries: I remind you a week ahead, gift ideas included.`,body:`Give me names and dates and I keep them. A week before each one I remind you, with a few gift directions based on what you've told me about them.`,kind:`CHAT`,prompt:`Remember the birthdays and anniversaries of the people who matter to me: ask for the list and dates, store them in long-term memory, and set a routine that reminds me a week before each.`},{id:`keep-in-touch`,emoji:`💬`,title:`Lost touch with old friends? Once a week I'll suggest who to reach out to, and how to start.`,body:`Give me a list of people you want to stay close to. I rotate through them and write a natural opening line based on what you last talked about.`,kind:`ROUTINE`,time:`19:00`,prompt:`Weekly keep-in-touch: from my list of people I want to stay close to, pick the one I've gone longest without contacting, remind me, and write a natural opening line based on what I noted about our last conversation.`},{id:`family-calendar`,emoji:`📅`,title:`Tell me the family's plans and I'll put them on the calendar and catch clashes.`,body:`Kids' lessons, a parent's appointment, a weekend get-together: one sentence and it's in the calendar; if two things collide, I say so first.`,kind:`CHAT`,prompt:`Help me run the family calendar: I'll tell you plans as they come up; write them into the calendar, confirm each before creating it, and warn me about conflicts.`},{id:`gift-ideas`,emoji:`🎁`,title:`Describe the person and I'll give you gift ideas that aren't the obvious ones.`,body:`Budget, relationship, what they're into lately: three questions, then five directions with one line each on why it fits.`,kind:`CHAT`,prompt:`Help me think of a gift: ask who it's for, my budget, their interests and what's going on in their life, then give me five directions with one line of reasoning each.`}]},{id:`more`,title:`More ideas`,ideas:[{id:`id-renewal`,emoji:`🪪`,title:`Tell me when your documents expire; I'll book the renewal and prep the paperwork list.`,body:`Passport, licence, visa: I note the dates, remind you three months ahead, list the documents and the office, and look up appointment slots where I can.`,kind:`CHAT`,prompt:`Help me track document expiry: ask which documents I have and when they expire, store them in memory, and set a reminder three months ahead of each with the renewal checklist.`},{id:`personality-quiz`,emoji:`❓`,title:`Two small questions a day; after a week I'll tell you what I've noticed about you.`,body:`Light questions, quick answers. I keep them and, once a week, write a short observation about your preferences and rhythm so I understand you better.`,kind:`ROUTINE`,time:`21:00`,prompt:`Two questions a day: ask me two small questions about preferences, habits or how things are going (never repeat one), store the answers in memory; every Sunday add a short observation about my week.`},{id:`event-plan`,emoji:`🎉`,title:`Name the occasion; I'll plan the run of show and draft the invitation.`,body:`Birthday, team outing, family dinner: give me the headcount, budget and date, and you get a timeline, a shopping list and an invitation you can send as is.`,kind:`CHAT`,prompt:`Help me plan an event: ask me the occasion, date, headcount and budget, then give me a timeline, a to-do list and an invitation text I can send.`},{id:`phone-cleanup`,emoji:`🧹`,title:`Let me look through the sandbox and shared folders; I'll clear the junk and organise the rest.`,body:`I list the big files and duplicates, show you the list first and only act when you say so; anything worth keeping goes into the Library.`,kind:`CHAT`,prompt:`Help me tidy the workspace and shared folders: list large files, duplicates and files untouched for a long time, and give me the list. Do not delete anything before I confirm.`}]}]},y={sections:[{id:`travel`,title:`出行`,ideas:[{id:`train-watch`,emoji:`🚄`,title:`告诉我你要去哪、哪天走,我盯着 12306 的余票和低价票。`,body:`我会在沙盒里装好查询工具,按你说的频率查车次、席别和余票,有票或价格合适时马上通知你;订票和付款那一步留给你自己点。`,kind:`GOAL`,category:`other`,prompt:`我想盯一趟火车票:请先问我出发地、目的地、日期和可接受的车次时段,然后为我建一个定期检查余票的目标。`},{id:`trip-plan`,emoji:`🗺️`,title:`说一个城市和几天,我给你排一份能直接照着走的行程。`,body:`我会查天气、开放时间和两点之间的路程,把每天的顺序排顺,写成一份文件放进资源库;你改一句,我就重排。`,kind:`CHAT`,prompt:`帮我规划一次出行。先问我去哪、几天、和谁、预算大概多少、喜欢什么风格,再给我一份按天排好的行程文件。`},{id:`commute-brief`,emoji:`🚦`,title:`每天出门前,我告诉你今天的路况、天气和第一件事。`,body:`一条早间例程:查你所在城市的天气、通勤路线的路况,翻一下日历,把上午的安排浓缩成三句话推给你。`,kind:`ROUTINE`,time:`07:30`,prompt:`早间简报:查询今天的天气和通勤路况,读取我今天的日历安排,用不超过五句话告诉我今天最重要的三件事和出门要带的东西。`},{id:`parcel-track`,emoji:`📦`,title:`把快递单号发我,到哪了、什么时候到,我随时告诉你。`,body:`我会用快递查询接口跟踪包裹,有新的物流节点就更新你;派送当天提醒你留意电话。`,kind:`CHAT`,prompt:`帮我跟踪一个快递。先问我单号和快递公司,然后查一次当前进度,并设一个每天早上检查一次、到派送前一天提醒我的例程。`}]},{id:`work`,title:`工作`,ideas:[{id:`meeting-prep`,emoji:`📝`,title:`开会前十分钟,我把这场会的背景和该问的问题整理好。`,body:`读日历里的会议主题和参会人,翻我们聊过的相关内容和你放进资源库的资料,给你一页纸:目的、要点、三个值得问的问题。`,kind:`ROUTINE`,time:`08:50`,prompt:`查看我今天日历里接下来的会议,为每一场准备一页会前提纲:这场会的目的、需要我发言的要点、三个值得提出的问题。`},{id:`weekly-review`,emoji:`📊`,title:`每周五下午,我帮你回顾这一周做了什么,下周该抓什么。`,body:`从我们的对话、你的日历和我记下的备忘里,整理出本周完成的事、没做完的事和下周的三个重点,写成一份周报草稿。`,kind:`ROUTINE`,time:`17:00`,prompt:`写一份本周回顾:根据我们这周的对话、我的日历和你记住的事项,列出完成了什么、什么没做完、下周三个重点,保存为一份 Markdown 文件。`},{id:`inbox-triage`,emoji:`📬`,title:`把一堆消息或邮件丢给我,我分好轻重缓急,写好回复草稿。`,body:`粘贴文字或截图给我,我按“今天必须回、这周处理、只需知道”分类,把每条要回的先拟好一版,你改一改就能发。`,kind:`CHAT`,prompt:`我要把一批消息交给你整理:请按“今天必须回 / 这周处理 / 只需知道”分类,并为需要回复的每一条写好回复草稿。请先让我粘贴内容。`},{id:`doc-digest`,emoji:`📄`,title:`长文档、PDF、网页,我读完给你三分钟版本。`,body:`把文件放进共享文件夹或把链接发我,我提炼结论、关键数字和你需要做的决定,问题可以接着追问。`,kind:`CHAT`,prompt:`我有一份长内容需要你读并总结:请先让我提供文件或链接,然后给我结论、关键数字、需要我做的决定三部分,每部分不超过五条。`}]},{id:`life`,title:`生活`,ideas:[{id:`price-watch`,emoji:`🏷️`,title:`想买的东西告诉我,降到你说的价格我立刻告诉你。`,body:`我会定期去商品页看价格,记录走势;到价就通知你。下单和付款由你来点,我不会碰。`,kind:`GOAL`,category:`finance`,prompt:`我想盯一件商品的价格:请先问我商品链接或名称、目标价格和检查频率,然后建一个到价提醒我的目标。`},{id:`photo-sort`,emoji:`🖼️`,title:`把相册挂给我,我按内容给截图和照片分类整理。`,body:`在「共享文件夹」里挂载相册后,我会看图识别内容(票据、聊天截图、风景、证件),归到对应文件夹,重要的信息顺手记下来。`,kind:`CHAT`,prompt:`帮我整理照片:请先让我在共享文件夹里挂载相册目录,然后按内容(票据、截图、风景、证件、其他)分类整理,并把整理结果列给我。`},{id:`meal-log`,emoji:`🥗`,title:`拍下你吃的,我帮你估热量、记下每一餐。`,body:`发一张照片或一句话,我估算营养和热量,记进当天的日记;晚上给你一天的小结和明天的一个小建议。`,kind:`CHAT`,prompt:`从现在起帮我记录饮食:每次我发照片或描述,估算热量与营养并记入当天记忆;请先告诉我怎么发给你最方便。`},{id:`subscriptions`,emoji:`🔁`,title:`帮你把每月自动扣费的订阅列出来,看看哪些该停。`,body:`把账单截图或消费记录给我,我列出所有周期性扣费、下一次扣款日和一年花多少;你决定停哪个,退订的步骤我一步步陪你走。`,kind:`CHAT`,prompt:`帮我盘点订阅扣费:请先让我提供账单截图或记录,然后列出所有周期性扣费、下一次扣款日、年费合计,并标出可能不再需要的。`}]},{id:`learn`,title:`学习`,ideas:[{id:`daily-words`,emoji:`🔤`,title:`每天早上五个新词,晚上考你一遍。`,body:`你定语言和难度,我按主题挑词、给例句和记忆点,晚上出五道小题,错的第二天再来。`,kind:`ROUTINE`,time:`08:00`,prompt:`每日词汇:为我挑五个新词(先问我学什么语言、什么水平和感兴趣的主题),每个给释义、一个例句和一个记忆点,并附上昨天的复习题。`},{id:`study-plan`,emoji:`🎯`,title:`有个想学会的东西?我陪你拆成每周能做完的小块。`,body:`告诉我目标和每周能投入的时间,我排一份四到八周的计划,每周检查进度、调整难度,帮你坚持到最后。`,kind:`GOAL`,category:`interests`,prompt:`我想学一样新东西并坚持下去:请先问我想学什么、现在的水平、每周能投入多少时间和希望多久见效,然后帮我建一个每周检查进度的目标。`},{id:`explain`,emoji:`💡`,title:`看不懂的概念发给我,我用你熟悉的东西讲明白。`,body:`先问你已经懂什么,再从那里出发讲;讲完出两道题确认你真懂了,需要的话给你一张记忆卡。`,kind:`CHAT`,prompt:`我有一个不太懂的概念想让你讲明白:请先问我这个概念是什么、我已经了解哪些相关知识,然后用类比讲解,最后出两道小题检验。`},{id:`reading-notes`,emoji:`📚`,title:`读完一本书,我帮你整理成能重读的笔记。`,body:`你说重点和感受,或者把划线的句子发我,我整理成结构化笔记,存进资源库,并记住你的收获。`,kind:`CHAT`,prompt:`帮我整理一本书的读书笔记:请先问我书名、最触动我的三点和我想记住的引文,然后整理成结构化的 Markdown 笔记并保存。`}]},{id:`family`,title:`家庭与关系`,ideas:[{id:`birthdays`,emoji:`🎂`,title:`重要的人的生日和纪念日,我提前一周提醒,顺手想好礼物。`,body:`把名字和日期告诉我,我记住;到日子前一周提醒你,并根据你说过的 TA 的喜好给几个礼物方向。`,kind:`CHAT`,prompt:`帮我记住重要的人的生日和纪念日:请先问我名单和日期,记入长期记忆,并为每个日期设一个提前一周提醒我的例程。`},{id:`keep-in-touch`,emoji:`💬`,title:`老朋友太久没联系?我每周提醒你该找谁聊聊,帮你开个头。`,body:`你给我一份想保持联系的名单,我按间隔轮着提醒,并根据上次聊的内容帮你写一句自然的开场。`,kind:`ROUTINE`,time:`19:00`,prompt:`每周联系提醒:从我告诉你的“想保持联系的人”名单里,挑一位最近最久没联系的,提醒我,并根据我记录过的上次聊天内容写一句自然的开场白。`},{id:`family-calendar`,emoji:`📅`,title:`把全家的安排告诉我,我帮你排进日历、发现冲突。`,body:`孩子的课、家人的门诊、周末的聚会,说一句我就写进日历,时间撞了我先提醒你。`,kind:`CHAT`,prompt:`帮我管理家庭日程:我会陆续告诉你家人的安排,请写进日历,创建前先复述确认,发现时间冲突时提醒我。`},{id:`gift-ideas`,emoji:`🎁`,title:`说说 TA 是什么样的人,我给你几个不落俗套的礼物点子。`,body:`预算、关系、TA 最近在忙什么,三个问题之后我给你五个方向,每个附一句为什么合适。`,kind:`CHAT`,prompt:`帮我想礼物:请先问我送给谁、预算、TA 的兴趣和最近的生活状态,然后给我五个礼物方向,每个附一句理由。`}]},{id:`more`,title:`更多点子`,ideas:[{id:`id-renewal`,emoji:`🪪`,title:`告诉我证件到期时间,我提前预约续签,把材料清单准备好。`,body:`护照、驾照、签证,我记下到期日,提前三个月提醒,列出所需材料和办理地点,能预约的帮你查好时段。`,kind:`CHAT`,prompt:`帮我管理证件到期:请先问我有哪些证件和到期日期,记入长期记忆,并为每一个设置提前三个月的提醒,附上续办所需材料清单。`},{id:`personality-quiz`,emoji:`❓`,title:`每天两个小问题,一周后我告诉你我发现了什么样的你。`,body:`问题很轻,回答很快;我把答案记下来,每周整理成一段关于你偏好和节奏的观察,方便我更懂你。`,kind:`ROUTINE`,time:`21:00`,prompt:`每日两问:问我两个关于偏好、习惯或近况的小问题(不重复以前问过的),把回答记入记忆;每周日额外给我一段关于我这周状态的观察。`},{id:`event-plan`,emoji:`🎉`,title:`说个场合,我帮你安排流程、拟好邀请。`,body:`生日、团建、家宴,人数、预算和日期告诉我,我给你时间线、采购清单和一段可以直接发出去的邀请文字。`,kind:`CHAT`,prompt:`帮我策划一次活动:请先问我场合、日期、人数和预算,然后给我时间线、待办清单和一段可直接发送的邀请文字。`},{id:`phone-cleanup`,emoji:`🧹`,title:`让我看看沙盒和共享文件夹里有什么,清掉没用的、整理有用的。`,body:`我列出占空间的大文件和重复文件,先给你看清单,你点头我再动;重要的整理进资源库。`,kind:`CHAT`,prompt:`帮我整理工作区和共享文件夹:先列出大文件、重复文件和很久没动的文件,给我一份清单;在我确认之前不要删除任何东西。`}]}]};function b(e){return e.toLowerCase().startsWith(`zh`)?y:v}function x(e){return{id:e.id,emoji:e.emoji,title:e.title,detail:e.body,prompt:e.prompt,kind:e.kind.toLowerCase(),time:e.time,category:e.category}}var S=o(),C=[{id:`planning`,label:`Planning`,emoji:`🗓️`},{id:`goals`,label:`Goals`,emoji:`🎯`},{id:`research`,label:`Research`,emoji:`🔍`},{id:`money`,label:`Money`,emoji:`💰`},{id:`health`,label:`Health`,emoji:`🌿`},{id:`home`,label:`Home`,emoji:`🏠`},{id:`learning`,label:`Learning`,emoji:`📚`},{id:`people`,label:`People`,emoji:`👥`},{id:`files`,label:`Files & tools`,emoji:`📄`},{id:`fun`,label:`Just for you`,emoji:`🎈`}];function w(){let{state:t,send:r,openThread:a,toast:o}=s(),[v,y]=(0,_.useState)(null),[C,w]=(0,_.useState)(!1),E=t.profile?.name??`nanoMuse`,D=n(),O=i(),k=async(e=!1)=>{w(!0);try{let t=await l.ideas(e);y(t),t.error&&o(D(`Could not refresh ideas: {error}`,{error:t.error}))}catch(e){o(e.message)}finally{w(!1)}};(0,_.useEffect)(()=>{k(!1)},[]);let A=v?.source===`model`&&v.ideas.length>0,j=A?T(v.ideas):b(O).sections.map(e=>({id:e.id,title:e.title,ideas:e.ideas.map(x)})),[M,N]=(0,_.useState)(null),P=e=>{N(null),r(`main`,e.prompt).catch(e=>o(e.message||D(`Could not send`))),a(`main`)},F=async e=>{N(null);let t=e.time&&/^([01]\d|2[0-3]):[0-5]\d$/.test(e.time)?e.time:`09:00`;try{await l.createReminder({text:e.prompt,kind:`task`,repeat:`daily ${t}`}),o(D(`Routine set: every day at {time}. It is listed under Goals.`,{time:t}))}catch(e){o(e.message)}},I=e=>{N(null);let t=f.find(t=>t.id===e.category)??f[f.length-1],n=D(`I'd like to create a {category} goal. Ask me a few short questions, one at a time (what exactly I want, why and by when, how often to check in), then create it with concrete steps using the goals tool.`,{category:D(t.label)});r(`main`,`${n} ${e.prompt}`).catch(e=>o(e.message||D(`Could not send`))),a(`main`)},L=e=>e.kind===`routine`||e.kind===`goal`?e.kind:`chat`;return(0,S.jsxs)(`div`,{className:`flex h-full flex-col`,children:[(0,S.jsx)(d,{title:D(`Ideas`),children:(0,S.jsx)(`button`,{type:`button`,onClick:()=>void k(!0),disabled:C,"aria-label":D(`Refresh ideas`),className:`flex h-10 w-10 items-center justify-center rounded-full bg-surface text-fg shadow-[0_1px_4px_rgba(0,0,0,0.14)] disabled:opacity-60 dark:border dark:border-border dark:shadow-none`,children:C?(0,S.jsx)(c,{size:20,className:`animate-spin`}):(0,S.jsx)(u,{size:19})})}),(0,S.jsxs)(`div`,{className:`flex-1 overflow-y-auto pb-6`,children:[j.map(({id:e,title:t,ideas:n},r)=>(0,S.jsxs)(`section`,{children:[(r>0||!A)&&(0,S.jsx)(`h2`,{className:`px-5 pt-[22px] pb-1 text-[20px] font-bold`,children:A?D(t):t}),(0,S.jsx)(`ul`,{children:n.map(e=>(0,S.jsxs)(`li`,{children:[(0,S.jsxs)(`button`,{type:`button`,onClick:()=>N({idea:e,emoji:e.emoji}),className:`flex w-full items-start gap-4 px-5 py-3.5 text-left active:bg-surface-2/70`,children:[(0,S.jsx)(`span`,{className:`flex w-10 shrink-0 justify-center text-[28px] leading-[34px]`,children:e.emoji}),(0,S.jsxs)(`span`,{className:`min-w-0 flex-1 space-y-1`,children:[(0,S.jsx)(`span`,{className:`block text-[16px] font-semibold leading-[22px]`,children:e.title}),e.detail&&(0,S.jsx)(`span`,{className:`line-clamp-4 block text-[13.5px] leading-[19px] text-muted`,children:e.detail})]})]}),(0,S.jsx)(`div`,{className:`ml-[76px] mr-5 border-b border-border/70`})]},e.title))})]},e)),v&&(0,S.jsx)(`div`,{className:`px-5 pt-4 text-[12.5px] text-muted`,children:v.source===`model`?D(`Generated {when}`,{when:e(v.generated_at)}):D(`Starter ideas. Refresh once {name} knows you better.`,{name:E})})]}),(0,S.jsx)(m,{open:M!==null,onClose:()=>N(null),children:M&&(0,S.jsxs)(`div`,{className:`px-1 pb-2`,children:[(0,S.jsxs)(`div`,{className:`flex items-center gap-3`,children:[(0,S.jsx)(`span`,{className:`text-[30px] leading-none`,children:M.emoji}),(0,S.jsx)(`h3`,{className:`flex-1 text-[18px] font-bold leading-6`,children:M.idea.title})]}),M.idea.detail&&(0,S.jsx)(`p`,{className:`mt-3 text-[15px] leading-[22px]`,children:M.idea.detail}),(0,S.jsxs)(`div`,{className:`mt-3.5 flex items-center gap-1.5 text-[13px] text-muted`,children:[L(M.idea)===`routine`&&(0,S.jsxs)(S.Fragment,{children:[(0,S.jsx)(h,{size:16}),` `,D(`Creates a routine`),M.idea.time?` · ${M.idea.time}`:``]}),L(M.idea)===`goal`&&(0,S.jsxs)(S.Fragment,{children:[(0,S.jsx)(g,{size:16}),` `,D(`Creates a goal`)]}),L(M.idea)===`chat`&&(0,S.jsxs)(S.Fragment,{children:[(0,S.jsx)(p,{size:16}),` `,D(`Starts a conversation`)]})]}),L(M.idea)===`routine`&&(0,S.jsxs)(`button`,{type:`button`,onClick:()=>void F(M.idea),className:`mt-[22px] flex h-[50px] w-full items-center justify-center gap-2 rounded-full bg-accent text-[16px] font-semibold text-accent-fg`,children:[(0,S.jsx)(h,{size:18}),` `,D(`Create routine`)]}),L(M.idea)===`goal`&&(0,S.jsxs)(`button`,{type:`button`,onClick:()=>I(M.idea),className:`mt-[22px] flex h-[50px] w-full items-center justify-center gap-2 rounded-full bg-accent text-[16px] font-semibold text-accent-fg`,children:[(0,S.jsx)(g,{size:18}),` `,D(`Start goal`)]}),L(M.idea)===`chat`&&(0,S.jsxs)(`button`,{type:`button`,onClick:()=>P(M.idea),className:`mt-[22px] flex h-[50px] w-full items-center justify-center gap-2 rounded-full bg-accent text-[16px] font-semibold text-accent-fg`,children:[(0,S.jsx)(p,{size:18}),` `,D(`Send to chat`)]})]})})]})}function T(e){let t=C[C.length-1],n=C.map(e=>({id:e.id,title:e.label,ideas:[]}));for(let r of e){let e=C.find(e=>e.id===(r.area||t.id))??t;(n.find(t=>t.id===e.id)??n[n.length-1]).ideas.push({...r,emoji:e.emoji})}return n.filter(e=>e.ideas.length>0)}export{w as IdeasScreen}; \ No newline at end of file +import{A as e,J as t,K as n,Q as r,W as i,Y as a,b as o,f as s,q as c,x as l}from"./MuseHeader-BDWXHKHT.js";import{t as u}from"./refresh-cw-qw351CFk.js";import{f as d,m as f,ot as p,w as m,yt as h}from"./index-DKrXW2Qj.js";var g=t(`flag`,[[`path`,{d:`M4 22V4a1 1 0 0 1 .4-.8A6 6 0 0 1 8 2c3 0 5 2 7.333 2q2 0 3.067-.8A1 1 0 0 1 20 4v10a1 1 0 0 1-.4.8A6 6 0 0 1 16 16c-3 0-5-2-8-2a6 6 0 0 0-4 1.528`,key:`1jaruq`}]]),_=r(a(),1),v={sections:[{id:`travel`,title:`Travel`,ideas:[{id:`train-watch`,emoji:`🚄`,title:`Tell me where you're going and when; I'll watch for seats and lower fares.`,body:`I set up the lookup tools in my sandbox, check trains, classes and availability as often as you like, and tell you the moment something opens up. Booking and paying stay in your hands.`,kind:`GOAL`,category:`other`,prompt:`I want to watch a train route: ask me for the origin, destination, date and acceptable departure window, then set up a goal that checks availability regularly.`},{id:`trip-plan`,emoji:`🗺️`,title:`Name a city and a number of days; I'll plan an itinerary you can follow as is.`,body:`Weather, opening hours and travel time between stops go into a day-by-day plan saved to your Library. Change one sentence and I'll rearrange the rest.`,kind:`CHAT`,prompt:`Help me plan a trip. Ask me where, how many days, with whom, a rough budget and the style I like, then give me a day-by-day itinerary as a file.`},{id:`commute-brief`,emoji:`🚦`,title:`Before you leave each morning, I'll tell you the traffic, the weather and the first thing on your plate.`,body:`A morning routine: I check the weather where you are, the traffic on your commute, glance at your calendar and boil the morning down to three sentences.`,kind:`ROUTINE`,time:`07:30`,prompt:`Morning brief: check today's weather and commute traffic, read my calendar for today, and tell me in at most five sentences the three things that matter most and what to bring.`},{id:`parcel-track`,emoji:`📦`,title:`Send me a tracking number; I'll tell you where the parcel is and when it lands.`,body:`I follow the shipment through the carrier's tracking, tell you about every new scan, and remind you to keep the phone nearby on delivery day.`,kind:`CHAT`,prompt:`Help me track a parcel. Ask me for the tracking number and carrier, check the current status once, then set a routine that checks every morning and reminds me the day before delivery.`}]},{id:`work`,title:`Work`,ideas:[{id:`meeting-prep`,emoji:`📝`,title:`Ten minutes before a meeting, I'll have the background and the questions ready.`,body:`I read the meeting's title and attendees from your calendar, look through what we've discussed and what you've put in the Library, and hand you one page: purpose, talking points, three questions worth asking.`,kind:`ROUTINE`,time:`08:50`,prompt:`Look at the meetings on my calendar today and prepare a one-page brief for each: the purpose, the points I should make, and three questions worth asking.`},{id:`weekly-review`,emoji:`📊`,title:`Every Friday afternoon, I'll review what you did this week and what next week needs.`,body:`From our conversations, your calendar and the notes I keep, I list what got done, what didn't, and three priorities for next week, as a draft you can send.`,kind:`ROUTINE`,time:`17:00`,prompt:`Write my weekly review: from this week's conversations, my calendar and what you remember, list what was completed, what is still open, and three priorities for next week. Save it as a Markdown file.`},{id:`inbox-triage`,emoji:`📬`,title:`Dump a pile of messages or emails on me; I'll sort them and draft the replies.`,body:`Paste text or screenshots. I sort them into 'reply today', 'this week' and 'just so you know', and draft each reply so you only need to edit and send.`,kind:`CHAT`,prompt:`I'm handing you a batch of messages to triage: sort them into 'reply today / this week / just so you know' and draft a reply for each one that needs it. Ask me to paste the content first.`},{id:`doc-digest`,emoji:`📄`,title:`Long documents, PDFs, web pages: I'll read them and give you the three-minute version.`,body:`Drop the file in a shared folder or send me the link. You get the conclusions, the key numbers and the decisions you need to make; ask follow-ups any time.`,kind:`CHAT`,prompt:`I have something long for you to read and summarise: ask me for the file or link, then give me conclusions, key numbers and decisions I need to make, at most five bullets each.`}]},{id:`life`,title:`Everyday`,ideas:[{id:`price-watch`,emoji:`🏷️`,title:`Tell me what you want to buy; the moment it hits your price, you'll know.`,body:`I check the product page on a schedule, keep the price history, and notify you at your target. Ordering and paying are yours; I don't touch them.`,kind:`GOAL`,category:`finance`,prompt:`I want to watch the price of a product: ask me for the link or name, my target price and how often to check, then create a goal that alerts me when it drops.`},{id:`photo-sort`,emoji:`🖼️`,title:`Mount your photos and I'll sort screenshots and pictures by what's in them.`,body:`Once your gallery is mounted as a shared folder I look at each image (receipts, chat screenshots, landscapes, documents), file it into the right folder and note anything important.`,kind:`CHAT`,prompt:`Help me sort my photos: ask me to mount the gallery in Shared Folders first, then sort by content (receipts, screenshots, scenery, documents, other) and list what you did.`},{id:`meal-log`,emoji:`🥗`,title:`Photograph what you eat; I'll estimate the calories and keep the log.`,body:`A photo or a sentence is enough: I estimate nutrition and calories, log it in the day's memory, and give you a summary each evening with one small suggestion for tomorrow.`,kind:`CHAT`,prompt:`From now on, log my meals: whenever I send a photo or a description, estimate calories and nutrition and write it into today's memory. Tell me first how best to send them.`},{id:`subscriptions`,emoji:`🔁`,title:`Send me your bills; I'll list every subscription that charges you each month, and you decide which to stop.`,body:`Give me bill screenshots or statements. I list every recurring charge, its next date and the yearly total; you decide what to cancel and I walk you through each cancellation.`,kind:`CHAT`,prompt:`Audit my subscriptions: ask me for bill screenshots or statements, then list every recurring charge, its next billing date and the yearly total, and flag the ones I may not need.`}]},{id:`learn`,title:`Learning`,ideas:[{id:`daily-words`,emoji:`🔤`,title:`Five new words every morning, a quick quiz every night.`,body:`You pick the language and level; I pick words by theme with examples and a memory hook, quiz you in the evening, and bring back the ones you missed.`,kind:`ROUTINE`,time:`08:00`,prompt:`Daily vocabulary: pick five new words for me (ask which language, level and topics first), each with a definition, one example sentence and a memory hook, plus a review quiz on yesterday's words.`},{id:`study-plan`,emoji:`🎯`,title:`Something you want to learn? I'll break it into weekly chunks and keep you honest.`,body:`Tell me the goal and the hours you can spare; I lay out four to eight weeks, check progress weekly, and adjust the pace so you actually finish.`,kind:`GOAL`,category:`interests`,prompt:`I want to learn something new and stick with it: ask me what, my current level, hours per week and the timeframe, then create a goal with a weekly progress check.`},{id:`explain`,emoji:`💡`,title:`Send me a concept you don't get; I'll explain it with things you already know.`,body:`I ask what you already understand and start from there, then check with two quick questions and leave you a flashcard if you want one.`,kind:`CHAT`,prompt:`There's a concept I don't understand: ask me what it is and what related things I already know, explain it with analogies, then check with two short questions.`},{id:`reading-notes`,emoji:`📚`,title:`Finished a book? I'll turn it into notes you'll actually reread.`,body:`Tell me the highlights, or send the passages you marked. I write structured notes into your Library and remember what stayed with you.`,kind:`CHAT`,prompt:`Help me write notes on a book: ask me the title, the three things that struck me most and the quotes I want to keep, then save structured Markdown notes.`}]},{id:`family`,title:`Family & friends`,ideas:[{id:`birthdays`,emoji:`🎂`,title:`Birthdays and anniversaries: I remind you a week ahead, gift ideas included.`,body:`Give me names and dates and I keep them. A week before each one I remind you, with a few gift directions based on what you've told me about them.`,kind:`CHAT`,prompt:`Remember the birthdays and anniversaries of the people who matter to me: ask for the list and dates, store them in long-term memory, and set a routine that reminds me a week before each.`},{id:`keep-in-touch`,emoji:`💬`,title:`Lost touch with old friends? Once a week I'll suggest who to reach out to, and how to start.`,body:`Give me a list of people you want to stay close to. I rotate through them and write a natural opening line based on what you last talked about.`,kind:`ROUTINE`,time:`19:00`,prompt:`Weekly keep-in-touch: from my list of people I want to stay close to, pick the one I've gone longest without contacting, remind me, and write a natural opening line based on what I noted about our last conversation.`},{id:`family-calendar`,emoji:`📅`,title:`Tell me the family's plans and I'll put them on the calendar and catch clashes.`,body:`Kids' lessons, a parent's appointment, a weekend get-together: one sentence and it's in the calendar; if two things collide, I say so first.`,kind:`CHAT`,prompt:`Help me run the family calendar: I'll tell you plans as they come up; write them into the calendar, confirm each before creating it, and warn me about conflicts.`},{id:`gift-ideas`,emoji:`🎁`,title:`Describe the person and I'll give you gift ideas that aren't the obvious ones.`,body:`Budget, relationship, what they're into lately: three questions, then five directions with one line each on why it fits.`,kind:`CHAT`,prompt:`Help me think of a gift: ask who it's for, my budget, their interests and what's going on in their life, then give me five directions with one line of reasoning each.`}]},{id:`more`,title:`More ideas`,ideas:[{id:`id-renewal`,emoji:`🪪`,title:`Tell me when your documents expire; I'll book the renewal and prep the paperwork list.`,body:`Passport, licence, visa: I note the dates, remind you three months ahead, list the documents and the office, and look up appointment slots where I can.`,kind:`CHAT`,prompt:`Help me track document expiry: ask which documents I have and when they expire, store them in memory, and set a reminder three months ahead of each with the renewal checklist.`},{id:`personality-quiz`,emoji:`❓`,title:`Two small questions a day; after a week I'll tell you what I've noticed about you.`,body:`Light questions, quick answers. I keep them and, once a week, write a short observation about your preferences and rhythm so I understand you better.`,kind:`ROUTINE`,time:`21:00`,prompt:`Two questions a day: ask me two small questions about preferences, habits or how things are going (never repeat one), store the answers in memory; every Sunday add a short observation about my week.`},{id:`event-plan`,emoji:`🎉`,title:`Name the occasion; I'll plan the run of show and draft the invitation.`,body:`Birthday, team outing, family dinner: give me the headcount, budget and date, and you get a timeline, a shopping list and an invitation you can send as is.`,kind:`CHAT`,prompt:`Help me plan an event: ask me the occasion, date, headcount and budget, then give me a timeline, a to-do list and an invitation text I can send.`},{id:`phone-cleanup`,emoji:`🧹`,title:`Let me look through the sandbox and shared folders; I'll clear the junk and organise the rest.`,body:`I list the big files and duplicates, show you the list first and only act when you say so; anything worth keeping goes into the Library.`,kind:`CHAT`,prompt:`Help me tidy the workspace and shared folders: list large files, duplicates and files untouched for a long time, and give me the list. Do not delete anything before I confirm.`}]}]},y={sections:[{id:`travel`,title:`出行`,ideas:[{id:`train-watch`,emoji:`🚄`,title:`告诉我你要去哪、哪天走,我盯着 12306 的余票和低价票。`,body:`我会在沙盒里装好查询工具,按你说的频率查车次、席别和余票,有票或价格合适时马上通知你;订票和付款那一步留给你自己点。`,kind:`GOAL`,category:`other`,prompt:`我想盯一趟火车票:请先问我出发地、目的地、日期和可接受的车次时段,然后为我建一个定期检查余票的目标。`},{id:`trip-plan`,emoji:`🗺️`,title:`说一个城市和几天,我给你排一份能直接照着走的行程。`,body:`我会查天气、开放时间和两点之间的路程,把每天的顺序排顺,写成一份文件放进资源库;你改一句,我就重排。`,kind:`CHAT`,prompt:`帮我规划一次出行。先问我去哪、几天、和谁、预算大概多少、喜欢什么风格,再给我一份按天排好的行程文件。`},{id:`commute-brief`,emoji:`🚦`,title:`每天出门前,我告诉你今天的路况、天气和第一件事。`,body:`一条早间例程:查你所在城市的天气、通勤路线的路况,翻一下日历,把上午的安排浓缩成三句话推给你。`,kind:`ROUTINE`,time:`07:30`,prompt:`早间简报:查询今天的天气和通勤路况,读取我今天的日历安排,用不超过五句话告诉我今天最重要的三件事和出门要带的东西。`},{id:`parcel-track`,emoji:`📦`,title:`把快递单号发我,到哪了、什么时候到,我随时告诉你。`,body:`我会用快递查询接口跟踪包裹,有新的物流节点就更新你;派送当天提醒你留意电话。`,kind:`CHAT`,prompt:`帮我跟踪一个快递。先问我单号和快递公司,然后查一次当前进度,并设一个每天早上检查一次、到派送前一天提醒我的例程。`}]},{id:`work`,title:`工作`,ideas:[{id:`meeting-prep`,emoji:`📝`,title:`开会前十分钟,我把这场会的背景和该问的问题整理好。`,body:`读日历里的会议主题和参会人,翻我们聊过的相关内容和你放进资源库的资料,给你一页纸:目的、要点、三个值得问的问题。`,kind:`ROUTINE`,time:`08:50`,prompt:`查看我今天日历里接下来的会议,为每一场准备一页会前提纲:这场会的目的、需要我发言的要点、三个值得提出的问题。`},{id:`weekly-review`,emoji:`📊`,title:`每周五下午,我帮你回顾这一周做了什么,下周该抓什么。`,body:`从我们的对话、你的日历和我记下的备忘里,整理出本周完成的事、没做完的事和下周的三个重点,写成一份周报草稿。`,kind:`ROUTINE`,time:`17:00`,prompt:`写一份本周回顾:根据我们这周的对话、我的日历和你记住的事项,列出完成了什么、什么没做完、下周三个重点,保存为一份 Markdown 文件。`},{id:`inbox-triage`,emoji:`📬`,title:`把一堆消息或邮件丢给我,我分好轻重缓急,写好回复草稿。`,body:`粘贴文字或截图给我,我按“今天必须回、这周处理、只需知道”分类,把每条要回的先拟好一版,你改一改就能发。`,kind:`CHAT`,prompt:`我要把一批消息交给你整理:请按“今天必须回 / 这周处理 / 只需知道”分类,并为需要回复的每一条写好回复草稿。请先让我粘贴内容。`},{id:`doc-digest`,emoji:`📄`,title:`长文档、PDF、网页,我读完给你三分钟版本。`,body:`把文件放进共享文件夹或把链接发我,我提炼结论、关键数字和你需要做的决定,问题可以接着追问。`,kind:`CHAT`,prompt:`我有一份长内容需要你读并总结:请先让我提供文件或链接,然后给我结论、关键数字、需要我做的决定三部分,每部分不超过五条。`}]},{id:`life`,title:`生活`,ideas:[{id:`price-watch`,emoji:`🏷️`,title:`想买的东西告诉我,降到你说的价格我立刻告诉你。`,body:`我会定期去商品页看价格,记录走势;到价就通知你。下单和付款由你来点,我不会碰。`,kind:`GOAL`,category:`finance`,prompt:`我想盯一件商品的价格:请先问我商品链接或名称、目标价格和检查频率,然后建一个到价提醒我的目标。`},{id:`photo-sort`,emoji:`🖼️`,title:`把相册挂给我,我按内容给截图和照片分类整理。`,body:`在「共享文件夹」里挂载相册后,我会看图识别内容(票据、聊天截图、风景、证件),归到对应文件夹,重要的信息顺手记下来。`,kind:`CHAT`,prompt:`帮我整理照片:请先让我在共享文件夹里挂载相册目录,然后按内容(票据、截图、风景、证件、其他)分类整理,并把整理结果列给我。`},{id:`meal-log`,emoji:`🥗`,title:`拍下你吃的,我帮你估热量、记下每一餐。`,body:`发一张照片或一句话,我估算营养和热量,记进当天的日记;晚上给你一天的小结和明天的一个小建议。`,kind:`CHAT`,prompt:`从现在起帮我记录饮食:每次我发照片或描述,估算热量与营养并记入当天记忆;请先告诉我怎么发给你最方便。`},{id:`subscriptions`,emoji:`🔁`,title:`帮你把每月自动扣费的订阅列出来,看看哪些该停。`,body:`把账单截图或消费记录给我,我列出所有周期性扣费、下一次扣款日和一年花多少;你决定停哪个,退订的步骤我一步步陪你走。`,kind:`CHAT`,prompt:`帮我盘点订阅扣费:请先让我提供账单截图或记录,然后列出所有周期性扣费、下一次扣款日、年费合计,并标出可能不再需要的。`}]},{id:`learn`,title:`学习`,ideas:[{id:`daily-words`,emoji:`🔤`,title:`每天早上五个新词,晚上考你一遍。`,body:`你定语言和难度,我按主题挑词、给例句和记忆点,晚上出五道小题,错的第二天再来。`,kind:`ROUTINE`,time:`08:00`,prompt:`每日词汇:为我挑五个新词(先问我学什么语言、什么水平和感兴趣的主题),每个给释义、一个例句和一个记忆点,并附上昨天的复习题。`},{id:`study-plan`,emoji:`🎯`,title:`有个想学会的东西?我陪你拆成每周能做完的小块。`,body:`告诉我目标和每周能投入的时间,我排一份四到八周的计划,每周检查进度、调整难度,帮你坚持到最后。`,kind:`GOAL`,category:`interests`,prompt:`我想学一样新东西并坚持下去:请先问我想学什么、现在的水平、每周能投入多少时间和希望多久见效,然后帮我建一个每周检查进度的目标。`},{id:`explain`,emoji:`💡`,title:`看不懂的概念发给我,我用你熟悉的东西讲明白。`,body:`先问你已经懂什么,再从那里出发讲;讲完出两道题确认你真懂了,需要的话给你一张记忆卡。`,kind:`CHAT`,prompt:`我有一个不太懂的概念想让你讲明白:请先问我这个概念是什么、我已经了解哪些相关知识,然后用类比讲解,最后出两道小题检验。`},{id:`reading-notes`,emoji:`📚`,title:`读完一本书,我帮你整理成能重读的笔记。`,body:`你说重点和感受,或者把划线的句子发我,我整理成结构化笔记,存进资源库,并记住你的收获。`,kind:`CHAT`,prompt:`帮我整理一本书的读书笔记:请先问我书名、最触动我的三点和我想记住的引文,然后整理成结构化的 Markdown 笔记并保存。`}]},{id:`family`,title:`家庭与关系`,ideas:[{id:`birthdays`,emoji:`🎂`,title:`重要的人的生日和纪念日,我提前一周提醒,顺手想好礼物。`,body:`把名字和日期告诉我,我记住;到日子前一周提醒你,并根据你说过的 TA 的喜好给几个礼物方向。`,kind:`CHAT`,prompt:`帮我记住重要的人的生日和纪念日:请先问我名单和日期,记入长期记忆,并为每个日期设一个提前一周提醒我的例程。`},{id:`keep-in-touch`,emoji:`💬`,title:`老朋友太久没联系?我每周提醒你该找谁聊聊,帮你开个头。`,body:`你给我一份想保持联系的名单,我按间隔轮着提醒,并根据上次聊的内容帮你写一句自然的开场。`,kind:`ROUTINE`,time:`19:00`,prompt:`每周联系提醒:从我告诉你的“想保持联系的人”名单里,挑一位最近最久没联系的,提醒我,并根据我记录过的上次聊天内容写一句自然的开场白。`},{id:`family-calendar`,emoji:`📅`,title:`把全家的安排告诉我,我帮你排进日历、发现冲突。`,body:`孩子的课、家人的门诊、周末的聚会,说一句我就写进日历,时间撞了我先提醒你。`,kind:`CHAT`,prompt:`帮我管理家庭日程:我会陆续告诉你家人的安排,请写进日历,创建前先复述确认,发现时间冲突时提醒我。`},{id:`gift-ideas`,emoji:`🎁`,title:`说说 TA 是什么样的人,我给你几个不落俗套的礼物点子。`,body:`预算、关系、TA 最近在忙什么,三个问题之后我给你五个方向,每个附一句为什么合适。`,kind:`CHAT`,prompt:`帮我想礼物:请先问我送给谁、预算、TA 的兴趣和最近的生活状态,然后给我五个礼物方向,每个附一句理由。`}]},{id:`more`,title:`更多点子`,ideas:[{id:`id-renewal`,emoji:`🪪`,title:`告诉我证件到期时间,我提前预约续签,把材料清单准备好。`,body:`护照、驾照、签证,我记下到期日,提前三个月提醒,列出所需材料和办理地点,能预约的帮你查好时段。`,kind:`CHAT`,prompt:`帮我管理证件到期:请先问我有哪些证件和到期日期,记入长期记忆,并为每一个设置提前三个月的提醒,附上续办所需材料清单。`},{id:`personality-quiz`,emoji:`❓`,title:`每天两个小问题,一周后我告诉你我发现了什么样的你。`,body:`问题很轻,回答很快;我把答案记下来,每周整理成一段关于你偏好和节奏的观察,方便我更懂你。`,kind:`ROUTINE`,time:`21:00`,prompt:`每日两问:问我两个关于偏好、习惯或近况的小问题(不重复以前问过的),把回答记入记忆;每周日额外给我一段关于我这周状态的观察。`},{id:`event-plan`,emoji:`🎉`,title:`说个场合,我帮你安排流程、拟好邀请。`,body:`生日、团建、家宴,人数、预算和日期告诉我,我给你时间线、采购清单和一段可以直接发出去的邀请文字。`,kind:`CHAT`,prompt:`帮我策划一次活动:请先问我场合、日期、人数和预算,然后给我时间线、待办清单和一段可直接发送的邀请文字。`},{id:`phone-cleanup`,emoji:`🧹`,title:`让我看看沙盒和共享文件夹里有什么,清掉没用的、整理有用的。`,body:`我列出占空间的大文件和重复文件,先给你看清单,你点头我再动;重要的整理进资源库。`,kind:`CHAT`,prompt:`帮我整理工作区和共享文件夹:先列出大文件、重复文件和很久没动的文件,给我一份清单;在我确认之前不要删除任何东西。`}]}]};function b(e){return e.toLowerCase().startsWith(`zh`)?y:v}function x(e){return{id:e.id,emoji:e.emoji,title:e.title,detail:e.body,prompt:e.prompt,kind:e.kind.toLowerCase(),time:e.time,category:e.category}}var S=o(),C=[{id:`planning`,label:`Planning`,emoji:`🗓️`},{id:`goals`,label:`Goals`,emoji:`🎯`},{id:`research`,label:`Research`,emoji:`🔍`},{id:`money`,label:`Money`,emoji:`💰`},{id:`health`,label:`Health`,emoji:`🌿`},{id:`home`,label:`Home`,emoji:`🏠`},{id:`learning`,label:`Learning`,emoji:`📚`},{id:`people`,label:`People`,emoji:`👥`},{id:`files`,label:`Files & tools`,emoji:`📄`},{id:`fun`,label:`Just for you`,emoji:`🎈`}];function w(){let{state:t,send:r,openThread:a,toast:o}=s(),[v,y]=(0,_.useState)(null),[C,w]=(0,_.useState)(!1),E=t.profile?.name??`nanoMuse`,D=n(),O=i(),k=async(e=!1)=>{w(!0);try{let t=await l.ideas(e);y(t),t.error&&o(D(`Could not refresh ideas: {error}`,{error:t.error}))}catch(e){o(e.message)}finally{w(!1)}};(0,_.useEffect)(()=>{k(!1)},[]);let A=v?.source===`model`&&v.ideas.length>0,j=A?T(v.ideas):b(O).sections.map(e=>({id:e.id,title:e.title,ideas:e.ideas.map(x)})),[M,N]=(0,_.useState)(null),P=e=>{N(null),r(`main`,e.prompt).catch(e=>o(e.message||D(`Could not send`))),a(`main`)},F=async e=>{N(null);let t=e.time&&/^([01]\d|2[0-3]):[0-5]\d$/.test(e.time)?e.time:`09:00`;try{await l.createReminder({text:e.prompt,kind:`task`,repeat:`daily ${t}`}),o(D(`Routine set: every day at {time}. It is listed under Goals.`,{time:t}))}catch(e){o(e.message)}},I=e=>{N(null);let t=f.find(t=>t.id===e.category)??f[f.length-1],n=D(`I'd like to create a {category} goal. Ask me a few short questions, one at a time (what exactly I want, why and by when, how often to check in), then create it with concrete steps using the goals tool.`,{category:D(t.label)});r(`main`,`${n} ${e.prompt}`).catch(e=>o(e.message||D(`Could not send`))),a(`main`)},L=e=>e.kind===`routine`||e.kind===`goal`?e.kind:`chat`;return(0,S.jsxs)(`div`,{className:`flex h-full flex-col`,children:[(0,S.jsx)(d,{title:D(`Ideas`),children:(0,S.jsx)(`button`,{type:`button`,onClick:()=>void k(!0),disabled:C,"aria-label":D(`Refresh ideas`),className:`flex h-10 w-10 items-center justify-center rounded-full bg-surface text-fg shadow-[0_1px_4px_rgba(0,0,0,0.14)] disabled:opacity-60 dark:border dark:border-border dark:shadow-none`,children:C?(0,S.jsx)(c,{size:20,className:`animate-spin`}):(0,S.jsx)(u,{size:19})})}),(0,S.jsxs)(`div`,{className:`flex-1 overflow-y-auto pb-6`,children:[j.map(({id:e,title:t,ideas:n},r)=>(0,S.jsxs)(`section`,{children:[(r>0||!A)&&(0,S.jsx)(`h2`,{className:`px-5 pt-[22px] pb-1 text-[20px] font-bold`,children:A?D(t):t}),(0,S.jsx)(`ul`,{children:n.map(e=>(0,S.jsxs)(`li`,{children:[(0,S.jsxs)(`button`,{type:`button`,onClick:()=>N({idea:e,emoji:e.emoji}),className:`flex w-full items-start gap-4 px-5 py-3.5 text-left active:bg-surface-2/70`,children:[(0,S.jsx)(`span`,{className:`flex w-10 shrink-0 justify-center text-[28px] leading-[34px]`,children:e.emoji}),(0,S.jsxs)(`span`,{className:`min-w-0 flex-1 space-y-1`,children:[(0,S.jsx)(`span`,{className:`block text-[16px] font-semibold leading-[22px]`,children:e.title}),e.detail&&(0,S.jsx)(`span`,{className:`line-clamp-4 block text-[13.5px] leading-[19px] text-muted`,children:e.detail})]})]}),(0,S.jsx)(`div`,{className:`ml-[76px] mr-5 border-b border-border/70`})]},e.title))})]},e)),v&&(0,S.jsx)(`div`,{className:`px-5 pt-4 text-[12.5px] text-muted`,children:v.source===`model`?D(`Generated {when}`,{when:e(v.generated_at)}):D(`Starter ideas. Refresh once {name} knows you better.`,{name:E})})]}),(0,S.jsx)(m,{open:M!==null,onClose:()=>N(null),children:M&&(0,S.jsxs)(`div`,{className:`px-1 pb-2`,children:[(0,S.jsxs)(`div`,{className:`flex items-center gap-3`,children:[(0,S.jsx)(`span`,{className:`text-[30px] leading-none`,children:M.emoji}),(0,S.jsx)(`h3`,{className:`flex-1 text-[18px] font-bold leading-6`,children:M.idea.title})]}),M.idea.detail&&(0,S.jsx)(`p`,{className:`mt-3 text-[15px] leading-[22px]`,children:M.idea.detail}),(0,S.jsxs)(`div`,{className:`mt-3.5 flex items-center gap-1.5 text-[13px] text-muted`,children:[L(M.idea)===`routine`&&(0,S.jsxs)(S.Fragment,{children:[(0,S.jsx)(h,{size:16}),` `,D(`Creates a routine`),M.idea.time?` · ${M.idea.time}`:``]}),L(M.idea)===`goal`&&(0,S.jsxs)(S.Fragment,{children:[(0,S.jsx)(g,{size:16}),` `,D(`Creates a goal`)]}),L(M.idea)===`chat`&&(0,S.jsxs)(S.Fragment,{children:[(0,S.jsx)(p,{size:16}),` `,D(`Starts a conversation`)]})]}),L(M.idea)===`routine`&&(0,S.jsxs)(`button`,{type:`button`,onClick:()=>void F(M.idea),className:`mt-[22px] flex h-[50px] w-full items-center justify-center gap-2 rounded-full bg-accent text-[16px] font-semibold text-accent-fg`,children:[(0,S.jsx)(h,{size:18}),` `,D(`Create routine`)]}),L(M.idea)===`goal`&&(0,S.jsxs)(`button`,{type:`button`,onClick:()=>I(M.idea),className:`mt-[22px] flex h-[50px] w-full items-center justify-center gap-2 rounded-full bg-accent text-[16px] font-semibold text-accent-fg`,children:[(0,S.jsx)(g,{size:18}),` `,D(`Start goal`)]}),L(M.idea)===`chat`&&(0,S.jsxs)(`button`,{type:`button`,onClick:()=>P(M.idea),className:`mt-[22px] flex h-[50px] w-full items-center justify-center gap-2 rounded-full bg-accent text-[16px] font-semibold text-accent-fg`,children:[(0,S.jsx)(p,{size:18}),` `,D(`Send to chat`)]})]})})]})}function T(e){let t=C[C.length-1],n=C.map(e=>({id:e.id,title:e.label,ideas:[]}));for(let r of e){let e=C.find(e=>e.id===(r.area||t.id))??t;(n.find(t=>t.id===e.id)??n[n.length-1]).ideas.push({...r,emoji:e.emoji})}return n.filter(e=>e.ideas.length>0)}export{w as IdeasScreen}; \ No newline at end of file diff --git a/nanomuse/server/static/assets/IdentityForm-BTGczGT_.js b/nanomuse/server/static/assets/IdentityForm-BweNfU4E.js similarity index 97% rename from nanomuse/server/static/assets/IdentityForm-BTGczGT_.js rename to nanomuse/server/static/assets/IdentityForm-BweNfU4E.js index 38f94da52..5fe6fefa1 100644 --- a/nanomuse/server/static/assets/IdentityForm-BTGczGT_.js +++ b/nanomuse/server/static/assets/IdentityForm-BweNfU4E.js @@ -1 +1 @@ -import{E as e,J as t,K as n,Q as r,Y as i,b as a,i as o}from"./MuseHeader-Pw-NI98v.js";import{r as s}from"./AvatarPicker-gR2knlot.js";var c=t(`shuffle`,[[`path`,{d:`m18 14 4 4-4 4`,key:`10pe0f`}],[`path`,{d:`m18 2 4 4-4 4`,key:`pucp1d`}],[`path`,{d:`M2 18h1.973a4 4 0 0 0 3.3-1.7l5.454-8.6a4 4 0 0 1 3.3-1.7H22`,key:`1ailkh`}],[`path`,{d:`M2 6h1.972a4 4 0 0 1 3.6 2.2`,key:`km57vx`}],[`path`,{d:`M22 18h-6.041a4 4 0 0 1-3.3-1.8l-.359-.45`,key:`os18l9`}]]),l=r(i(),1),u=a(),d=[`Muse`,`Veda`,`Nova`,`Pip`,`Sage`,`Juno`,`Kit`,`Wren`,`Iris`,`Milo`,`Echo`,`Remy`,`Otto`,`Luna`,`Ari`,`Bea`,`Nico`,`Zed`,`小墨`,`阿柒`,`小满`,`知了`,`豆豆`,`小竹`],f=[`formal`,`casual`,`playful`,`concise`],p=[`short`,`detailed`,`bullets`],m={formal:`Formal`,casual:`Casual`,playful:`Playful`,concise:`Concise`},h={short:`Short replies`,detailed:`Detailed`,bullets:`Bullet points`};function g(e,t){let n=d.filter(t=>t!==e),r=[],i=t||1,a=[...n];for(;r.length<6&&a.length;)i=(i*9301+49297)%233280,r.push(a.splice(i%a.length,1)[0]);return r}function _({active:t,onClick:n,children:r}){return(0,u.jsx)(`button`,{type:`button`,onClick:n,className:e(`rounded-full px-3 py-1.5 text-[13px] border transition-colors`,t?`border-accent bg-accent/10 text-accent font-medium`:`border-border text-muted`),children:r})}function v({value:t,onChange:r,suggestions:i=!0,askUserName:a=!0,inputCls:d,onStudio:v}){let y=n(),b=(0,l.useId)(),[x,S]=(0,l.useState)(7),C=(0,l.useMemo)(()=>g(t.name,x),[t.name,x]),w=e=>r({...t,...e}),T={...t,proactivity:`default`,proactive:!0,goal_interval_minutes:60,quiet_hours:``};return(0,u.jsxs)(`div`,{className:`space-y-5`,children:[(0,u.jsxs)(`div`,{className:`flex items-start gap-4`,children:[(0,u.jsx)(o,{profile:T,size:72}),(0,u.jsxs)(`div`,{className:`flex-1 min-w-0 space-y-2`,children:[(0,u.jsx)(`div`,{children:(0,u.jsx)(`input`,{value:t.name,onChange:e=>w({name:e.target.value.slice(0,20)}),maxLength:20,className:e(d,`text-[17px] font-medium`),placeholder:`nanoMuse`,"aria-label":y(`Name`),autoCapitalize:`words`})}),(0,u.jsx)(`input`,{value:t.tagline,onChange:e=>w({tagline:e.target.value.slice(0,60)}),maxLength:60,className:e(d,`text-[14px]`),placeholder:y(`A line under the name, e.g. Your day, sorted.`),"aria-label":y(`Tagline`)})]})]}),i&&(0,u.jsxs)(`div`,{className:`flex flex-wrap items-center gap-1.5`,children:[C.map(e=>(0,u.jsx)(_,{active:t.name===e,onClick:()=>w({name:e}),children:e},e)),(0,u.jsx)(`button`,{type:`button`,onClick:()=>S(e=>e+1),"aria-label":y(`More names`),className:`rounded-full border border-border p-1.5 text-muted`,children:(0,u.jsx)(c,{size:14})})]}),(0,u.jsx)(s,{value:{avatar:t.avatar,emoji:t.emoji,color:t.color},onChange:e=>w(e),onStudio:v}),(0,u.jsxs)(`div`,{children:[(0,u.jsx)(`label`,{className:`text-[12px] text-muted`,children:y(`Tone`)}),(0,u.jsx)(`div`,{className:`mt-1.5 flex flex-wrap gap-1.5`,children:f.map(e=>(0,u.jsx)(_,{active:t.tone===e,onClick:()=>w({tone:t.tone===e?``:e}),children:y(m[e])},e))})]}),(0,u.jsxs)(`div`,{children:[(0,u.jsx)(`label`,{className:`text-[12px] text-muted`,children:y(`How much it says`)}),(0,u.jsx)(`div`,{className:`mt-1.5 flex flex-wrap gap-1.5`,children:p.map(e=>(0,u.jsx)(_,{active:t.communication===e,onClick:()=>w({communication:t.communication===e?``:e}),children:y(h[e])},e))})]}),(0,u.jsxs)(`div`,{children:[(0,u.jsx)(`label`,{htmlFor:`${b}-style`,className:`text-[12px] text-muted`,children:y(`Anything else about how it should be`)}),(0,u.jsx)(`textarea`,{id:`${b}-style`,value:t.style,onChange:e=>w({style:e.target.value}),rows:2,placeholder:y(`e.g. A little witty. Uses metric units. Never uses emoji.`),className:e(d,`mt-1 resize-none text-[14px]`)})]}),a&&(0,u.jsxs)(`div`,{children:[(0,u.jsx)(`label`,{htmlFor:`${b}-user`,className:`text-[12px] text-muted`,children:y(`What it calls you`)}),(0,u.jsx)(`input`,{id:`${b}-user`,value:t.user_name,onChange:e=>w({user_name:e.target.value}),maxLength:60,placeholder:y(`Your name`),className:e(d,`mt-1 text-[14px]`)})]})]})}function y(e,t,n){return{name:e?.name??`nanoMuse`,tagline:e?.tagline??``,avatar:e?.avatar??t,emoji:e?.emoji??`✨`,color:e?.color??n,tone:e?.tone??``,communication:e?.communication??``,style:e?.style??``,user_name:e?.user_name??``}}function b(e){return{...e,name:e.name.trim()||`nanoMuse`,tagline:e.tagline.trim(),style:e.style.trim(),user_name:e.user_name.trim()}}export{b as n,y as r,v as t}; \ No newline at end of file +import{E as e,J as t,K as n,Q as r,Y as i,b as a,i as o}from"./MuseHeader-BDWXHKHT.js";import{r as s}from"./AvatarPicker-CwYa9V6R.js";var c=t(`shuffle`,[[`path`,{d:`m18 14 4 4-4 4`,key:`10pe0f`}],[`path`,{d:`m18 2 4 4-4 4`,key:`pucp1d`}],[`path`,{d:`M2 18h1.973a4 4 0 0 0 3.3-1.7l5.454-8.6a4 4 0 0 1 3.3-1.7H22`,key:`1ailkh`}],[`path`,{d:`M2 6h1.972a4 4 0 0 1 3.6 2.2`,key:`km57vx`}],[`path`,{d:`M22 18h-6.041a4 4 0 0 1-3.3-1.8l-.359-.45`,key:`os18l9`}]]),l=r(i(),1),u=a(),d=[`Muse`,`Veda`,`Nova`,`Pip`,`Sage`,`Juno`,`Kit`,`Wren`,`Iris`,`Milo`,`Echo`,`Remy`,`Otto`,`Luna`,`Ari`,`Bea`,`Nico`,`Zed`,`小墨`,`阿柒`,`小满`,`知了`,`豆豆`,`小竹`],f=[`formal`,`casual`,`playful`,`concise`],p=[`short`,`detailed`,`bullets`],m={formal:`Formal`,casual:`Casual`,playful:`Playful`,concise:`Concise`},h={short:`Short replies`,detailed:`Detailed`,bullets:`Bullet points`};function g(e,t){let n=d.filter(t=>t!==e),r=[],i=t||1,a=[...n];for(;r.length<6&&a.length;)i=(i*9301+49297)%233280,r.push(a.splice(i%a.length,1)[0]);return r}function _({active:t,onClick:n,children:r}){return(0,u.jsx)(`button`,{type:`button`,onClick:n,className:e(`rounded-full px-3 py-1.5 text-[13px] border transition-colors`,t?`border-accent bg-accent/10 text-accent font-medium`:`border-border text-muted`),children:r})}function v({value:t,onChange:r,suggestions:i=!0,askUserName:a=!0,inputCls:d,onStudio:v}){let y=n(),b=(0,l.useId)(),[x,S]=(0,l.useState)(7),C=(0,l.useMemo)(()=>g(t.name,x),[t.name,x]),w=e=>r({...t,...e}),T={...t,proactivity:`default`,proactive:!0,goal_interval_minutes:60,quiet_hours:``};return(0,u.jsxs)(`div`,{className:`space-y-5`,children:[(0,u.jsxs)(`div`,{className:`flex items-start gap-4`,children:[(0,u.jsx)(o,{profile:T,size:72}),(0,u.jsxs)(`div`,{className:`flex-1 min-w-0 space-y-2`,children:[(0,u.jsx)(`div`,{children:(0,u.jsx)(`input`,{value:t.name,onChange:e=>w({name:e.target.value.slice(0,20)}),maxLength:20,className:e(d,`text-[17px] font-medium`),placeholder:`nanoMuse`,"aria-label":y(`Name`),autoCapitalize:`words`})}),(0,u.jsx)(`input`,{value:t.tagline,onChange:e=>w({tagline:e.target.value.slice(0,60)}),maxLength:60,className:e(d,`text-[14px]`),placeholder:y(`A line under the name, e.g. Your day, sorted.`),"aria-label":y(`Tagline`)})]})]}),i&&(0,u.jsxs)(`div`,{className:`flex flex-wrap items-center gap-1.5`,children:[C.map(e=>(0,u.jsx)(_,{active:t.name===e,onClick:()=>w({name:e}),children:e},e)),(0,u.jsx)(`button`,{type:`button`,onClick:()=>S(e=>e+1),"aria-label":y(`More names`),className:`rounded-full border border-border p-1.5 text-muted`,children:(0,u.jsx)(c,{size:14})})]}),(0,u.jsx)(s,{value:{avatar:t.avatar,emoji:t.emoji,color:t.color},onChange:e=>w(e),onStudio:v}),(0,u.jsxs)(`div`,{children:[(0,u.jsx)(`label`,{className:`text-[12px] text-muted`,children:y(`Tone`)}),(0,u.jsx)(`div`,{className:`mt-1.5 flex flex-wrap gap-1.5`,children:f.map(e=>(0,u.jsx)(_,{active:t.tone===e,onClick:()=>w({tone:t.tone===e?``:e}),children:y(m[e])},e))})]}),(0,u.jsxs)(`div`,{children:[(0,u.jsx)(`label`,{className:`text-[12px] text-muted`,children:y(`How much it says`)}),(0,u.jsx)(`div`,{className:`mt-1.5 flex flex-wrap gap-1.5`,children:p.map(e=>(0,u.jsx)(_,{active:t.communication===e,onClick:()=>w({communication:t.communication===e?``:e}),children:y(h[e])},e))})]}),(0,u.jsxs)(`div`,{children:[(0,u.jsx)(`label`,{htmlFor:`${b}-style`,className:`text-[12px] text-muted`,children:y(`Anything else about how it should be`)}),(0,u.jsx)(`textarea`,{id:`${b}-style`,value:t.style,onChange:e=>w({style:e.target.value}),rows:2,placeholder:y(`e.g. A little witty. Uses metric units. Never uses emoji.`),className:e(d,`mt-1 resize-none text-[14px]`)})]}),a&&(0,u.jsxs)(`div`,{children:[(0,u.jsx)(`label`,{htmlFor:`${b}-user`,className:`text-[12px] text-muted`,children:y(`What it calls you`)}),(0,u.jsx)(`input`,{id:`${b}-user`,value:t.user_name,onChange:e=>w({user_name:e.target.value}),maxLength:60,placeholder:y(`Your name`),className:e(d,`mt-1 text-[14px]`)})]})]})}function y(e,t,n){return{name:e?.name??`nanoMuse`,tagline:e?.tagline??``,avatar:e?.avatar??t,emoji:e?.emoji??`✨`,color:e?.color??n,tone:e?.tone??``,communication:e?.communication??``,style:e?.style??``,user_name:e?.user_name??``}}function b(e){return{...e,name:e.name.trim()||`nanoMuse`,tagline:e.tagline.trim(),style:e.style.trim(),user_name:e.user_name.trim()}}export{b as n,y as r,v as t}; \ No newline at end of file diff --git a/nanomuse/server/static/assets/LibraryScreen-B8JlrC_n.js b/nanomuse/server/static/assets/LibraryScreen-CLqu6Lu-.js similarity index 97% rename from nanomuse/server/static/assets/LibraryScreen-B8JlrC_n.js rename to nanomuse/server/static/assets/LibraryScreen-CLqu6Lu-.js index a5701e101..fb0e94ce8 100644 --- a/nanomuse/server/static/assets/LibraryScreen-B8JlrC_n.js +++ b/nanomuse/server/static/assets/LibraryScreen-CLqu6Lu-.js @@ -1 +1 @@ -import{D as e,E as t,J as n,K as r,Q as i,S as a,Y as o,b as s,f as c,q as l,x as u}from"./MuseHeader-Pw-NI98v.js";import{C as d,I as f,X as p,_t as m,f as h,mt as g,pt as _,xt as v}from"./index-CIdGZ5PB.js";var y=n(`file-image`,[[`path`,{d:`M6 22a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h8a2.4 2.4 0 0 1 1.704.706l3.588 3.588A2.4 2.4 0 0 1 20 8v12a2 2 0 0 1-2 2z`,key:`1oefj6`}],[`path`,{d:`M14 2v5a1 1 0 0 0 1 1h5`,key:`wfsgrz`}],[`circle`,{cx:`10`,cy:`12`,r:`2`,key:`737tya`}],[`path`,{d:`m20 17-1.296-1.296a2.41 2.41 0 0 0-3.408 0L9 22`,key:`wt3hpn`}]]),b=n(`file-spreadsheet`,[[`path`,{d:`M6 22a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h8a2.4 2.4 0 0 1 1.704.706l3.588 3.588A2.4 2.4 0 0 1 20 8v12a2 2 0 0 1-2 2z`,key:`1oefj6`}],[`path`,{d:`M14 2v5a1 1 0 0 0 1 1h5`,key:`wfsgrz`}],[`path`,{d:`M8 13h2`,key:`yr2amv`}],[`path`,{d:`M14 13h2`,key:`un5t4a`}],[`path`,{d:`M8 17h2`,key:`2yhykz`}],[`path`,{d:`M14 17h2`,key:`10kma7`}]]),x=n(`library-big`,[[`rect`,{width:`8`,height:`18`,x:`3`,y:`3`,rx:`1`,key:`oynpb5`}],[`path`,{d:`M7 3v18`,key:`bbkbws`}],[`path`,{d:`M20.4 18.9c.2.5-.1 1.1-.6 1.3l-1.9.7c-.5.2-1.1-.1-1.3-.6L11.1 5.1c-.2-.5.1-1.1.6-1.3l1.9-.7c.5-.2 1.1.1 1.3.6Z`,key:`1qboyk`}]]),S=i(o(),1),C=s(),w=new Set([`png`,`jpg`,`jpeg`,`gif`,`webp`,`svg`,`heic`,`mp3`,`wav`,`m4a`,`ogg`,`flac`,`mp4`,`mov`,`webm`,`mkv`]);function T(e){return w.has(e.toLowerCase().split(`.`).pop()??``)}function E(){let{state:e,openFile:t}=c(),[n,i]=(0,S.useState)(null),[a,o]=(0,S.useState)(null),[s,f]=(0,S.useState)(0),[m,g]=(0,S.useState)(0),[_,v]=(0,S.useState)(``),y=r(),b=Object.values(e.events).reduce((e,t)=>e+t.length,0);(0,S.useEffect)(()=>{let e=!0;return u.files(500).then(t=>{e&&(i(t),o(null))}).catch(t=>e&&o(t.message)),()=>{e=!1}},[b,e.feedVersion,s]);let w=(0,S.useMemo)(()=>{let e=_.trim().toLowerCase();return(n??[]).filter(t=>T(t.name)===(m===1)&&(!e||t.path.toLowerCase().includes(e)))},[n,m,_]);return(0,C.jsxs)(`div`,{className:`flex h-full flex-col`,children:[(0,C.jsx)(h,{title:y(`Library`)}),(0,C.jsxs)(`div`,{className:`shrink-0 px-4 pt-1 pb-2.5`,children:[(0,C.jsx)(D,{labels:[y(`Artifacts`),y(`Media`)],selected:m,onSelect:e=>g(e)}),(n?.length??0)>8&&(0,C.jsxs)(`label`,{className:`mt-2.5 flex items-center gap-2 rounded-full bg-surface-2 px-3.5 py-2`,children:[(0,C.jsx)(p,{size:16,className:`text-muted`}),(0,C.jsx)(`input`,{value:_,onChange:e=>v(e.target.value),placeholder:y(`Search files`),className:`flex-1 bg-transparent text-[14.5px] outline-none`})]})]}),(0,C.jsxs)(`div`,{className:`flex-1 overflow-y-auto pb-6`,children:[n===null&&a&&(0,C.jsx)(d,{message:a,onRetry:()=>f(e=>e+1)}),n===null&&!a&&(0,C.jsx)(`div`,{className:`flex justify-center py-10 text-muted`,children:(0,C.jsx)(l,{className:`animate-spin`,size:20})}),n!==null&&w.length===0&&(0,C.jsxs)(`div`,{className:`flex flex-col items-center px-8 pt-9 text-center`,children:[(0,C.jsx)(x,{size:34,className:`text-muted`}),(0,C.jsx)(`div`,{className:`mt-3.5 text-[16px] font-medium text-muted`,children:y(_?`No files match.`:m===0?`Nothing created yet`:`No media yet`)}),!_&&(0,C.jsx)(`p`,{className:`mt-1 text-[12px] text-muted`,children:y(m===0?`Documents, tables and pages I write for you will show up here.`:`Photos, screenshots and recordings I produce will show up here.`)})]}),(0,C.jsx)(`ul`,{children:w.map(e=>(0,C.jsx)(`li`,{children:(0,C.jsx)(O,{file:e,onOpen:()=>t(e.path)})},e.path))})]})]})}function D({labels:e,selected:n,onSelect:r}){return(0,C.jsx)(`div`,{role:`tablist`,className:`flex h-12 w-full rounded-full border border-border bg-surface p-1`,children:e.map((e,i)=>(0,C.jsx)(`button`,{type:`button`,role:`tab`,"aria-selected":i===n,onClick:()=>r(i),className:t(`flex-1 rounded-full text-[14px] font-semibold transition`,i===n?`bg-surface-2`:`bg-transparent`),children:e},e))})}function O({file:t,onOpen:n}){let r=e(t.name),i=r===`html`?(0,C.jsx)(_,{size:22}):r===`image`?(0,C.jsx)(y,{size:22}):r===`data`?(0,C.jsx)(b,{size:22}):r===`code`?(0,C.jsx)(m,{size:22}):r===`event`?(0,C.jsx)(v,{size:22}):(0,C.jsx)(g,{size:22}),o=t.path.includes(`/`)?t.path.slice(0,t.path.lastIndexOf(`/`)):``;return(0,C.jsxs)(`button`,{type:`button`,onClick:n,className:`flex w-full items-center gap-3.5 px-4 py-2 text-left active:bg-surface-2/70`,children:[(0,C.jsx)(`span`,{className:`flex h-[46px] w-[46px] shrink-0 items-center justify-center overflow-hidden rounded-[10px] bg-surface-2 text-muted`,children:r===`image`?(0,C.jsx)(`img`,{src:a(t.path),alt:``,loading:`lazy`,className:`h-full w-full object-cover`}):i}),(0,C.jsxs)(`span`,{className:`min-w-0 flex-1 space-y-0.5`,children:[(0,C.jsx)(`span`,{className:`block truncate text-[15px] font-medium`,children:t.name}),(0,C.jsx)(`span`,{className:`block truncate text-[12px] text-muted`,children:[f(t.modified),k(t.size),o].filter(Boolean).join(` · `)})]})]})}function k(e){return e<1024?`${e} B`:e<1048576?`${(e/1024).toFixed(+(e<10240))} KB`:`${(e/1024/1024).toFixed(1)} MB`}export{E as LibraryScreen}; \ No newline at end of file +import{D as e,E as t,J as n,K as r,Q as i,S as a,Y as o,b as s,f as c,q as l,x as u}from"./MuseHeader-BDWXHKHT.js";import{C as d,I as f,X as p,_t as m,f as h,mt as g,pt as _,xt as v}from"./index-DKrXW2Qj.js";var y=n(`file-image`,[[`path`,{d:`M6 22a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h8a2.4 2.4 0 0 1 1.704.706l3.588 3.588A2.4 2.4 0 0 1 20 8v12a2 2 0 0 1-2 2z`,key:`1oefj6`}],[`path`,{d:`M14 2v5a1 1 0 0 0 1 1h5`,key:`wfsgrz`}],[`circle`,{cx:`10`,cy:`12`,r:`2`,key:`737tya`}],[`path`,{d:`m20 17-1.296-1.296a2.41 2.41 0 0 0-3.408 0L9 22`,key:`wt3hpn`}]]),b=n(`file-spreadsheet`,[[`path`,{d:`M6 22a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h8a2.4 2.4 0 0 1 1.704.706l3.588 3.588A2.4 2.4 0 0 1 20 8v12a2 2 0 0 1-2 2z`,key:`1oefj6`}],[`path`,{d:`M14 2v5a1 1 0 0 0 1 1h5`,key:`wfsgrz`}],[`path`,{d:`M8 13h2`,key:`yr2amv`}],[`path`,{d:`M14 13h2`,key:`un5t4a`}],[`path`,{d:`M8 17h2`,key:`2yhykz`}],[`path`,{d:`M14 17h2`,key:`10kma7`}]]),x=n(`library-big`,[[`rect`,{width:`8`,height:`18`,x:`3`,y:`3`,rx:`1`,key:`oynpb5`}],[`path`,{d:`M7 3v18`,key:`bbkbws`}],[`path`,{d:`M20.4 18.9c.2.5-.1 1.1-.6 1.3l-1.9.7c-.5.2-1.1-.1-1.3-.6L11.1 5.1c-.2-.5.1-1.1.6-1.3l1.9-.7c.5-.2 1.1.1 1.3.6Z`,key:`1qboyk`}]]),S=i(o(),1),C=s(),w=new Set([`png`,`jpg`,`jpeg`,`gif`,`webp`,`svg`,`heic`,`mp3`,`wav`,`m4a`,`ogg`,`flac`,`mp4`,`mov`,`webm`,`mkv`]);function T(e){return w.has(e.toLowerCase().split(`.`).pop()??``)}function E(){let{state:e,openFile:t}=c(),[n,i]=(0,S.useState)(null),[a,o]=(0,S.useState)(null),[s,f]=(0,S.useState)(0),[m,g]=(0,S.useState)(0),[_,v]=(0,S.useState)(``),y=r(),b=Object.values(e.events).reduce((e,t)=>e+t.length,0);(0,S.useEffect)(()=>{let e=!0;return u.files(500).then(t=>{e&&(i(t),o(null))}).catch(t=>e&&o(t.message)),()=>{e=!1}},[b,e.feedVersion,s]);let w=(0,S.useMemo)(()=>{let e=_.trim().toLowerCase();return(n??[]).filter(t=>T(t.name)===(m===1)&&(!e||t.path.toLowerCase().includes(e)))},[n,m,_]);return(0,C.jsxs)(`div`,{className:`flex h-full flex-col`,children:[(0,C.jsx)(h,{title:y(`Library`)}),(0,C.jsxs)(`div`,{className:`shrink-0 px-4 pt-1 pb-2.5`,children:[(0,C.jsx)(D,{labels:[y(`Artifacts`),y(`Media`)],selected:m,onSelect:e=>g(e)}),(n?.length??0)>8&&(0,C.jsxs)(`label`,{className:`mt-2.5 flex items-center gap-2 rounded-full bg-surface-2 px-3.5 py-2`,children:[(0,C.jsx)(p,{size:16,className:`text-muted`}),(0,C.jsx)(`input`,{value:_,onChange:e=>v(e.target.value),placeholder:y(`Search files`),className:`flex-1 bg-transparent text-[14.5px] outline-none`})]})]}),(0,C.jsxs)(`div`,{className:`flex-1 overflow-y-auto pb-6`,children:[n===null&&a&&(0,C.jsx)(d,{message:a,onRetry:()=>f(e=>e+1)}),n===null&&!a&&(0,C.jsx)(`div`,{className:`flex justify-center py-10 text-muted`,children:(0,C.jsx)(l,{className:`animate-spin`,size:20})}),n!==null&&w.length===0&&(0,C.jsxs)(`div`,{className:`flex flex-col items-center px-8 pt-9 text-center`,children:[(0,C.jsx)(x,{size:34,className:`text-muted`}),(0,C.jsx)(`div`,{className:`mt-3.5 text-[16px] font-medium text-muted`,children:y(_?`No files match.`:m===0?`Nothing created yet`:`No media yet`)}),!_&&(0,C.jsx)(`p`,{className:`mt-1 text-[12px] text-muted`,children:y(m===0?`Documents, tables and pages I write for you will show up here.`:`Photos, screenshots and recordings I produce will show up here.`)})]}),(0,C.jsx)(`ul`,{children:w.map(e=>(0,C.jsx)(`li`,{children:(0,C.jsx)(O,{file:e,onOpen:()=>t(e.path)})},e.path))})]})]})}function D({labels:e,selected:n,onSelect:r}){return(0,C.jsx)(`div`,{role:`tablist`,className:`flex h-12 w-full rounded-full border border-border bg-surface p-1`,children:e.map((e,i)=>(0,C.jsx)(`button`,{type:`button`,role:`tab`,"aria-selected":i===n,onClick:()=>r(i),className:t(`flex-1 rounded-full text-[14px] font-semibold transition`,i===n?`bg-surface-2`:`bg-transparent`),children:e},e))})}function O({file:t,onOpen:n}){let r=e(t.name),i=r===`html`?(0,C.jsx)(_,{size:22}):r===`image`?(0,C.jsx)(y,{size:22}):r===`data`?(0,C.jsx)(b,{size:22}):r===`code`?(0,C.jsx)(m,{size:22}):r===`event`?(0,C.jsx)(v,{size:22}):(0,C.jsx)(g,{size:22}),o=t.path.includes(`/`)?t.path.slice(0,t.path.lastIndexOf(`/`)):``;return(0,C.jsxs)(`button`,{type:`button`,onClick:n,className:`flex w-full items-center gap-3.5 px-4 py-2 text-left active:bg-surface-2/70`,children:[(0,C.jsx)(`span`,{className:`flex h-[46px] w-[46px] shrink-0 items-center justify-center overflow-hidden rounded-[10px] bg-surface-2 text-muted`,children:r===`image`?(0,C.jsx)(`img`,{src:a(t.path),alt:``,loading:`lazy`,className:`h-full w-full object-cover`}):i}),(0,C.jsxs)(`span`,{className:`min-w-0 flex-1 space-y-0.5`,children:[(0,C.jsx)(`span`,{className:`block truncate text-[15px] font-medium`,children:t.name}),(0,C.jsx)(`span`,{className:`block truncate text-[12px] text-muted`,children:[f(t.modified),k(t.size),o].filter(Boolean).join(` · `)})]})]})}function k(e){return e<1024?`${e} B`:e<1048576?`${(e/1024).toFixed(+(e<10240))} KB`:`${(e/1024/1024).toFixed(1)} MB`}export{E as LibraryScreen}; \ No newline at end of file diff --git a/nanomuse/server/static/assets/MemoryScreen-M8j03G3u.js b/nanomuse/server/static/assets/MemoryScreen-B7ALbqAO.js similarity index 97% rename from nanomuse/server/static/assets/MemoryScreen-M8j03G3u.js rename to nanomuse/server/static/assets/MemoryScreen-B7ALbqAO.js index c49d41a42..baeb70f42 100644 --- a/nanomuse/server/static/assets/MemoryScreen-M8j03G3u.js +++ b/nanomuse/server/static/assets/MemoryScreen-B7ALbqAO.js @@ -1 +1 @@ -import{A as e,J as t,K as n,Q as r,Y as i,b as a,f as o,q as s,x as c}from"./MuseHeader-Pw-NI98v.js";import{C as l,St as u,V as d,W as f,Z as p}from"./index-CIdGZ5PB.js";import{t as m}from"./BackBar-Dl56jHZM.js";var h=t(`undo-2`,[[`path`,{d:`M9 14 4 9l5-5`,key:`102s5s`}],[`path`,{d:`M4 9h10.5a5.5 5.5 0 0 1 5.5 5.5a5.5 5.5 0 0 1-5.5 5.5H11`,key:`f3b9sd`}]]),g=r(i(),1),_=a(),v=[`profile`,`preference`,`people`,`routine`,`constraint`,`general`];function y(){let{state:t,toast:r,openThread:i,setTab:a}=o(),[y,b]=(0,g.useState)(null),[x,S]=(0,g.useState)(null),[C,w]=(0,g.useState)([]),[T,E]=(0,g.useState)(``),[D,O]=(0,g.useState)(`profile`),[k,A]=(0,g.useState)(!1),[j,M]=(0,g.useState)(!1),N=t.profile?.name??`nanoMuse`,P=n(),F=()=>Promise.all([c.memory().then(b),c.memoryChanges().then(w)]).then(()=>S(null)).catch(e=>y===null?S(e.message):r(e.message));(0,g.useEffect)(()=>{F()},[t.memoryVersion]);let I=(0,g.useMemo)(()=>{let e=new Map;for(let t of y??[])e.set(t.category,[...e.get(t.category)??[],t]);return[...e.entries()].sort((e,t)=>t[1].length-e[1].length)},[y]),L=async()=>{if(T.trim()){A(!0);try{await c.addMemory(T.trim(),D),E(``),await F()}catch(e){r(e.message)}finally{A(!1)}}},R=async e=>{if(window.confirm(P(`Forget “{text}”?`,{text:e.content.slice(0,60)})))try{await c.forgetMemory(e.id),b(t=>t?.filter(t=>t.id!==e.id)??t)}catch(e){r(e.message)}},z=async()=>{M(!0);try{let e=await c.tidyMemory();r(e.changed===0?P(`Nothing to tidy: {n} memories, all distinct.`,{n:e.considered}):P(`Tidied: {merged} merged, {dropped} dropped. Undo below if needed.`,{merged:e.merged.length,dropped:e.dropped.length})),await F()}catch(e){r(e.message)}finally{M(!1)}},B=async e=>{try{await c.restoreMemoryChange(e.id),await F()}catch(e){r(e.message)}};return(0,_.jsxs)(`div`,{className:`flex h-full flex-col`,children:[(0,_.jsx)(m,{title:P(`Memory`),description:P(`What {name} remembers about you. Read it, add to it, or make {name} forget; nothing here is hidden from you.`,{name:N}),actions:(y?.length??0)>=2&&(0,_.jsxs)(`button`,{type:`button`,disabled:j,onClick:()=>void z(),title:P(`Merge lines that say the same thing and drop what was never a fact about you. Every change can be undone.`),className:`flex h-10 items-center gap-1.5 rounded-full bg-surface px-3.5 text-[13.5px] font-medium shadow-[0_1px_4px_rgba(0,0,0,0.14)] disabled:opacity-50 dark:border dark:border-border dark:shadow-none`,children:[(0,_.jsx)(f,{size:15,className:j?`animate-pulse text-accent`:`text-accent`}),P(j?`Tidying…`:`Tidy up`)]})}),(0,_.jsxs)(`div`,{className:`flex-1 overflow-y-auto px-4 pb-6 space-y-5`,children:[(0,_.jsxs)(`div`,{className:`rounded-3xl bg-surface border border-border/70 shadow-sm p-3.5 space-y-2.5`,children:[(0,_.jsx)(`textarea`,{value:T,onChange:e=>E(e.target.value),rows:2,placeholder:P(`Tell {name} something to remember, e.g. “I'm vegetarian” or “My sister's birthday is 14 May”`,{name:N}),className:`w-full resize-none rounded-2xl bg-surface-2 px-3.5 py-2.5 text-[14.5px] outline-none focus:ring-2 focus:ring-accent/40`}),(0,_.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,_.jsx)(`select`,{value:D,onChange:e=>O(e.target.value),className:`rounded-2xl bg-surface-2 px-3 py-2 text-[13.5px] outline-none`,children:v.map(e=>(0,_.jsx)(`option`,{value:e,children:P(e)},e))}),(0,_.jsx)(`div`,{className:`flex-1`}),(0,_.jsxs)(`button`,{type:`button`,disabled:!T.trim()||k,onClick:()=>void L(),className:`rounded-2xl bg-accent text-accent-fg px-3.5 py-2 text-[14px] font-medium flex items-center gap-1.5 disabled:opacity-50`,children:[(0,_.jsx)(p,{size:16}),` `,P(`Remember`)]})]})]}),y===null&&x&&(0,_.jsx)(l,{message:x,onRetry:()=>void F()}),y===null&&!x&&(0,_.jsx)(`div`,{className:`flex justify-center py-10 text-muted`,children:(0,_.jsx)(s,{className:`animate-spin`,size:20})}),y!==null&&y.length===0&&(0,_.jsxs)(`div`,{className:`rounded-3xl border border-dashed border-border p-6 text-center`,children:[(0,_.jsx)(u,{className:`mx-auto text-accent`}),(0,_.jsx)(`div`,{className:`mt-2 font-semibold`,children:P(`Nothing remembered yet`)}),(0,_.jsx)(`p`,{className:`mt-1 text-[13.5px] text-muted`,children:P(`{name} saves durable facts you share in chat (preferences, people, routines) and never secrets.`,{name:N})}),(0,_.jsx)(`button`,{type:`button`,onClick:()=>{i(`main`),a(`chat`)},className:`mt-3 rounded-full bg-accent px-4 py-2 text-[13.5px] font-semibold text-accent-fg`,children:P(`Tell {name} something to remember`,{name:N})})]}),I.map(([t,n])=>(0,_.jsxs)(`section`,{children:[(0,_.jsxs)(`div`,{className:`px-1 mb-2 text-[12px] font-semibold uppercase tracking-wide text-muted`,children:[P(t),` · `,n.length]}),(0,_.jsx)(`ul`,{className:`rounded-3xl bg-surface border border-border/70 shadow-sm divide-y divide-border/70 overflow-hidden`,children:n.map(t=>(0,_.jsxs)(`li`,{className:`flex items-start gap-3 px-4 py-3`,children:[(0,_.jsxs)(`div`,{className:`flex-1 min-w-0`,children:[(0,_.jsx)(`div`,{className:`text-[14.5px] leading-snug break-words`,children:t.content}),(0,_.jsxs)(`div`,{className:`mt-0.5 text-[11.5px] text-muted`,children:[t.source===`user`?P(`added by you`):P(`saved by {name}`,{name:N}),` · `,e(t.created_at),t.updated_at?` · ${P(`updated {when}`,{when:e(t.updated_at)})}`:``]})]}),(0,_.jsx)(`button`,{type:`button`,"aria-label":P(`Forget`),onClick:()=>void R(t),className:`p-1.5 text-muted hover:text-rose-500`,children:(0,_.jsx)(d,{size:17})})]},t.id))})]},t)),C.length>0&&(0,_.jsxs)(`section`,{children:[(0,_.jsx)(`div`,{className:`px-1 mb-2 text-[12px] font-semibold uppercase tracking-wide text-muted`,children:P(`Recent changes`)}),(0,_.jsx)(`ul`,{className:`rounded-3xl bg-surface border border-border/70 shadow-sm divide-y divide-border/70 overflow-hidden`,children:C.map(t=>(0,_.jsx)(`li`,{className:`px-4 py-3 ${t.restored?`opacity-60`:``}`,children:(0,_.jsxs)(`div`,{className:`flex items-start gap-3`,children:[(0,_.jsxs)(`div`,{className:`flex-1 min-w-0 text-[13.5px] leading-snug`,children:[(0,_.jsxs)(`div`,{className:`text-muted`,children:[t.action===`merge`?P(`Merged`):t.action===`drop`?P(`Dropped`):P(`Updated`),t.reason?` · ${t.reason}`:``,` · `,e(t.at),t.restored?` · ${P(`restored`)}`:``]}),t.before.map(e=>(0,_.jsx)(`div`,{className:`break-words line-through text-muted`,children:e.content},e.id)),t.after&&(0,_.jsxs)(`div`,{className:`break-words`,children:[`→ `,t.after.content]})]}),!t.restored&&(0,_.jsxs)(`button`,{type:`button`,onClick:()=>void B(t),className:`shrink-0 rounded-xl bg-surface-2 px-2.5 py-1.5 text-[12.5px] font-medium flex items-center gap-1`,children:[(0,_.jsx)(h,{size:14}),` `,P(`Undo`)]})]})},t.id))})]})]})]})}export{y as MemoryScreen}; \ No newline at end of file +import{A as e,J as t,K as n,Q as r,Y as i,b as a,f as o,q as s,x as c}from"./MuseHeader-BDWXHKHT.js";import{C as l,St as u,V as d,W as f,Z as p}from"./index-DKrXW2Qj.js";import{t as m}from"./BackBar-DqcCClHf.js";var h=t(`undo-2`,[[`path`,{d:`M9 14 4 9l5-5`,key:`102s5s`}],[`path`,{d:`M4 9h10.5a5.5 5.5 0 0 1 5.5 5.5a5.5 5.5 0 0 1-5.5 5.5H11`,key:`f3b9sd`}]]),g=r(i(),1),_=a(),v=[`profile`,`preference`,`people`,`routine`,`constraint`,`general`];function y(){let{state:t,toast:r,openThread:i,setTab:a}=o(),[y,b]=(0,g.useState)(null),[x,S]=(0,g.useState)(null),[C,w]=(0,g.useState)([]),[T,E]=(0,g.useState)(``),[D,O]=(0,g.useState)(`profile`),[k,A]=(0,g.useState)(!1),[j,M]=(0,g.useState)(!1),N=t.profile?.name??`nanoMuse`,P=n(),F=()=>Promise.all([c.memory().then(b),c.memoryChanges().then(w)]).then(()=>S(null)).catch(e=>y===null?S(e.message):r(e.message));(0,g.useEffect)(()=>{F()},[t.memoryVersion]);let I=(0,g.useMemo)(()=>{let e=new Map;for(let t of y??[])e.set(t.category,[...e.get(t.category)??[],t]);return[...e.entries()].sort((e,t)=>t[1].length-e[1].length)},[y]),L=async()=>{if(T.trim()){A(!0);try{await c.addMemory(T.trim(),D),E(``),await F()}catch(e){r(e.message)}finally{A(!1)}}},R=async e=>{if(window.confirm(P(`Forget “{text}”?`,{text:e.content.slice(0,60)})))try{await c.forgetMemory(e.id),b(t=>t?.filter(t=>t.id!==e.id)??t)}catch(e){r(e.message)}},z=async()=>{M(!0);try{let e=await c.tidyMemory();r(e.changed===0?P(`Nothing to tidy: {n} memories, all distinct.`,{n:e.considered}):P(`Tidied: {merged} merged, {dropped} dropped. Undo below if needed.`,{merged:e.merged.length,dropped:e.dropped.length})),await F()}catch(e){r(e.message)}finally{M(!1)}},B=async e=>{try{await c.restoreMemoryChange(e.id),await F()}catch(e){r(e.message)}};return(0,_.jsxs)(`div`,{className:`flex h-full flex-col`,children:[(0,_.jsx)(m,{title:P(`Memory`),description:P(`What {name} remembers about you. Read it, add to it, or make {name} forget; nothing here is hidden from you.`,{name:N}),actions:(y?.length??0)>=2&&(0,_.jsxs)(`button`,{type:`button`,disabled:j,onClick:()=>void z(),title:P(`Merge lines that say the same thing and drop what was never a fact about you. Every change can be undone.`),className:`flex h-10 items-center gap-1.5 rounded-full bg-surface px-3.5 text-[13.5px] font-medium shadow-[0_1px_4px_rgba(0,0,0,0.14)] disabled:opacity-50 dark:border dark:border-border dark:shadow-none`,children:[(0,_.jsx)(f,{size:15,className:j?`animate-pulse text-accent`:`text-accent`}),P(j?`Tidying…`:`Tidy up`)]})}),(0,_.jsxs)(`div`,{className:`flex-1 overflow-y-auto px-4 pb-6 space-y-5`,children:[(0,_.jsxs)(`div`,{className:`rounded-3xl bg-surface border border-border/70 shadow-sm p-3.5 space-y-2.5`,children:[(0,_.jsx)(`textarea`,{value:T,onChange:e=>E(e.target.value),rows:2,placeholder:P(`Tell {name} something to remember, e.g. “I'm vegetarian” or “My sister's birthday is 14 May”`,{name:N}),className:`w-full resize-none rounded-2xl bg-surface-2 px-3.5 py-2.5 text-[14.5px] outline-none focus:ring-2 focus:ring-accent/40`}),(0,_.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,_.jsx)(`select`,{value:D,onChange:e=>O(e.target.value),className:`rounded-2xl bg-surface-2 px-3 py-2 text-[13.5px] outline-none`,children:v.map(e=>(0,_.jsx)(`option`,{value:e,children:P(e)},e))}),(0,_.jsx)(`div`,{className:`flex-1`}),(0,_.jsxs)(`button`,{type:`button`,disabled:!T.trim()||k,onClick:()=>void L(),className:`rounded-2xl bg-accent text-accent-fg px-3.5 py-2 text-[14px] font-medium flex items-center gap-1.5 disabled:opacity-50`,children:[(0,_.jsx)(p,{size:16}),` `,P(`Remember`)]})]})]}),y===null&&x&&(0,_.jsx)(l,{message:x,onRetry:()=>void F()}),y===null&&!x&&(0,_.jsx)(`div`,{className:`flex justify-center py-10 text-muted`,children:(0,_.jsx)(s,{className:`animate-spin`,size:20})}),y!==null&&y.length===0&&(0,_.jsxs)(`div`,{className:`rounded-3xl border border-dashed border-border p-6 text-center`,children:[(0,_.jsx)(u,{className:`mx-auto text-accent`}),(0,_.jsx)(`div`,{className:`mt-2 font-semibold`,children:P(`Nothing remembered yet`)}),(0,_.jsx)(`p`,{className:`mt-1 text-[13.5px] text-muted`,children:P(`{name} saves durable facts you share in chat (preferences, people, routines) and never secrets.`,{name:N})}),(0,_.jsx)(`button`,{type:`button`,onClick:()=>{i(`main`),a(`chat`)},className:`mt-3 rounded-full bg-accent px-4 py-2 text-[13.5px] font-semibold text-accent-fg`,children:P(`Tell {name} something to remember`,{name:N})})]}),I.map(([t,n])=>(0,_.jsxs)(`section`,{children:[(0,_.jsxs)(`div`,{className:`px-1 mb-2 text-[12px] font-semibold uppercase tracking-wide text-muted`,children:[P(t),` · `,n.length]}),(0,_.jsx)(`ul`,{className:`rounded-3xl bg-surface border border-border/70 shadow-sm divide-y divide-border/70 overflow-hidden`,children:n.map(t=>(0,_.jsxs)(`li`,{className:`flex items-start gap-3 px-4 py-3`,children:[(0,_.jsxs)(`div`,{className:`flex-1 min-w-0`,children:[(0,_.jsx)(`div`,{className:`text-[14.5px] leading-snug break-words`,children:t.content}),(0,_.jsxs)(`div`,{className:`mt-0.5 text-[11.5px] text-muted`,children:[t.source===`user`?P(`added by you`):P(`saved by {name}`,{name:N}),` · `,e(t.created_at),t.updated_at?` · ${P(`updated {when}`,{when:e(t.updated_at)})}`:``]})]}),(0,_.jsx)(`button`,{type:`button`,"aria-label":P(`Forget`),onClick:()=>void R(t),className:`p-1.5 text-muted hover:text-rose-500`,children:(0,_.jsx)(d,{size:17})})]},t.id))})]},t)),C.length>0&&(0,_.jsxs)(`section`,{children:[(0,_.jsx)(`div`,{className:`px-1 mb-2 text-[12px] font-semibold uppercase tracking-wide text-muted`,children:P(`Recent changes`)}),(0,_.jsx)(`ul`,{className:`rounded-3xl bg-surface border border-border/70 shadow-sm divide-y divide-border/70 overflow-hidden`,children:C.map(t=>(0,_.jsx)(`li`,{className:`px-4 py-3 ${t.restored?`opacity-60`:``}`,children:(0,_.jsxs)(`div`,{className:`flex items-start gap-3`,children:[(0,_.jsxs)(`div`,{className:`flex-1 min-w-0 text-[13.5px] leading-snug`,children:[(0,_.jsxs)(`div`,{className:`text-muted`,children:[t.action===`merge`?P(`Merged`):t.action===`drop`?P(`Dropped`):P(`Updated`),t.reason?` · ${t.reason}`:``,` · `,e(t.at),t.restored?` · ${P(`restored`)}`:``]}),t.before.map(e=>(0,_.jsx)(`div`,{className:`break-words line-through text-muted`,children:e.content},e.id)),t.after&&(0,_.jsxs)(`div`,{className:`break-words`,children:[`→ `,t.after.content]})]}),!t.restored&&(0,_.jsxs)(`button`,{type:`button`,onClick:()=>void B(t),className:`shrink-0 rounded-xl bg-surface-2 px-2.5 py-1.5 text-[12.5px] font-medium flex items-center gap-1`,children:[(0,_.jsx)(h,{size:14}),` `,P(`Undo`)]})]})},t.id))})]})]})]})}export{y as MemoryScreen}; \ No newline at end of file diff --git a/nanomuse/server/static/assets/MuseHeader-Pw-NI98v.js b/nanomuse/server/static/assets/MuseHeader-BDWXHKHT.js similarity index 76% rename from nanomuse/server/static/assets/MuseHeader-Pw-NI98v.js rename to nanomuse/server/static/assets/MuseHeader-BDWXHKHT.js index 0387567f1..d18bcf3c6 100644 --- a/nanomuse/server/static/assets/MuseHeader-Pw-NI98v.js +++ b/nanomuse/server/static/assets/MuseHeader-BDWXHKHT.js @@ -1 +1 @@ -var e=Object.create,t=Object.defineProperty,n=Object.getOwnPropertyDescriptor,r=Object.getOwnPropertyNames,i=Object.getPrototypeOf,a=Object.prototype.hasOwnProperty,o=(e,t)=>()=>(t||(e((t={exports:{}}).exports,t),e=null),t.exports),s=(e,n)=>{let r={};for(var i in e)t(r,i,{get:e[i],enumerable:!0});return n||t(r,Symbol.toStringTag,{value:`Module`}),r},c=(e,i,o,s)=>{if(i&&typeof i==`object`||typeof i==`function`)for(var c=r(i),l=0,u=c.length,d;li[e]).bind(null,d),enumerable:!(s=n(i,d))||s.enumerable});return e},l=(n,r,o)=>(o=n==null?{}:e(i(n)),c(r||!n||!n.__esModule||!a.call(n,`default`)?t(o,`default`,{value:n,enumerable:!0}):o,n)),u=o((e=>{var t=Symbol.for(`react.element`),n=Symbol.for(`react.portal`),r=Symbol.for(`react.fragment`),i=Symbol.for(`react.strict_mode`),a=Symbol.for(`react.profiler`),o=Symbol.for(`react.provider`),s=Symbol.for(`react.context`),c=Symbol.for(`react.forward_ref`),l=Symbol.for(`react.suspense`),u=Symbol.for(`react.memo`),d=Symbol.for(`react.lazy`),f=Symbol.iterator;function p(e){return typeof e!=`object`||!e?null:(e=f&&e[f]||e[`@@iterator`],typeof e==`function`?e:null)}var m={isMounted:function(){return!1},enqueueForceUpdate:function(){},enqueueReplaceState:function(){},enqueueSetState:function(){}},h=Object.assign,g={};function _(e,t,n){this.props=e,this.context=t,this.refs=g,this.updater=n||m}_.prototype.isReactComponent={},_.prototype.setState=function(e,t){if(typeof e!=`object`&&typeof e!=`function`&&e!=null)throw Error(`setState(...): takes an object of state variables to update or a function which returns an object of state variables.`);this.updater.enqueueSetState(this,e,t,`setState`)},_.prototype.forceUpdate=function(e){this.updater.enqueueForceUpdate(this,e,`forceUpdate`)};function v(){}v.prototype=_.prototype;function y(e,t,n){this.props=e,this.context=t,this.refs=g,this.updater=n||m}var b=y.prototype=new v;b.constructor=y,h(b,_.prototype),b.isPureReactComponent=!0;var x=Array.isArray,S=Object.prototype.hasOwnProperty,C={current:null},w={key:!0,ref:!0,__self:!0,__source:!0};function ee(e,n,r){var i,a={},o=null,s=null;if(n!=null)for(i in n.ref!==void 0&&(s=n.ref),n.key!==void 0&&(o=``+n.key),n)S.call(n,i)&&!w.hasOwnProperty(i)&&(a[i]=n[i]);var c=arguments.length-2;if(c===1)a.children=r;else if(1{t.exports=u()})),f=l(d()),p=(...e)=>e.filter((e,t,n)=>!!e&&e.trim()!==``&&n.indexOf(e)===t).join(` `).trim(),m=e=>e.replace(/([a-z0-9])([A-Z])/g,`$1-$2`).toLowerCase(),h=e=>e.replace(/^([A-Z])|[\s-_]+(\w)/g,(e,t,n)=>n?n.toUpperCase():t.toLowerCase()),g=e=>{let t=h(e);return t.charAt(0).toUpperCase()+t.slice(1)},_={xmlns:`http://www.w3.org/2000/svg`,width:24,height:24,viewBox:`0 0 24 24`,fill:`none`,stroke:`currentColor`,strokeWidth:2,strokeLinecap:`round`,strokeLinejoin:`round`},v=e=>{for(let t in e)if(t.startsWith(`aria-`)||t===`role`||t===`title`)return!0;return!1},y=(0,f.forwardRef)(({color:e=`currentColor`,size:t=24,strokeWidth:n=2,absoluteStrokeWidth:r,className:i=``,children:a,iconNode:o,...s},c)=>(0,f.createElement)(`svg`,{ref:c,..._,width:t,height:t,stroke:e,strokeWidth:r?Number(n)*24/Number(t):n,className:p(`lucide`,i),...!a&&!v(s)&&{"aria-hidden":`true`},...s},[...o.map(([e,t])=>(0,f.createElement)(e,t)),...Array.isArray(a)?a:[a]])),b=(e,t)=>{let n=(0,f.forwardRef)(({className:n,...r},i)=>(0,f.createElement)(y,{ref:i,iconNode:t,className:p(`lucide-${m(g(e))}`,`lucide-${e}`,n),...r}));return n.displayName=g(e),n},x=b(`loader-circle`,[[`path`,{d:`M21 12a9 9 0 1 1-6.219-8.56`,key:`13zald`}]]),S=21600,C=32;function w(e=Date.now()){return(Math.floor(e/1e3/S)+2)*S}function ee(e,t,n){let r=new TextEncoder;return E(te(r.encode(e),r.encode(`${n}\n${t}`))).slice(0,C)}function T(e,t,n=Date.now()){let r=w(n),i=new URLSearchParams;return i.set(`exp`,String(r)),i.set(`sig`,ee(e,t,r)),i}function E(e){let t=``;for(let n of e)t+=n.toString(16).padStart(2,`0`);return t}function te(e,t){let n=new Uint8Array(64);n.set(e.length>64?k(e):e);let r=new Uint8Array(64+t.length),i=new Uint8Array(96);for(let e=0;e<64;e++)r[e]=n[e]^54,i[e]=n[e]^92;return r.set(t,64),i.set(k(r),64),k(i)}var D=new Uint32Array([1116352408,1899447441,3049323471,3921009573,961987163,1508970993,2453635748,2870763221,3624381080,310598401,607225278,1426881987,1925078388,2162078206,2614888103,3248222580,3835390401,4022224774,264347078,604807628,770255983,1249150122,1555081692,1996064986,2554220882,2821834349,2952996808,3210313671,3336571891,3584528711,113926993,338241895,666307205,773529912,1294757372,1396182291,1695183700,1986661051,2177026350,2456956037,2730485921,2820302411,3259730800,3345764771,3516065817,3600352804,4094571909,275423344,430227734,506948616,659060556,883997877,958139571,1322822218,1537002063,1747873779,1955562222,2024104815,2227730452,2361852424,2428436474,2756734187,3204031479,3329325298]),O=(e,t)=>e>>>t|e<<32-t;function k(e){let t=new Uint32Array([1779033703,3144134277,1013904242,2773480762,1359893119,2600822924,528734635,1541459225]),n=new Uint8Array(e.length+9+63>>6<<6);n.set(e),n[e.length]=128;let r=new DataView(n.buffer),i=e.length*8;r.setUint32(n.length-8,Math.floor(i/4294967296)),r.setUint32(n.length-4,i>>>0);let a=new Uint32Array(64);for(let e=0;e>>3,i=O(n,17)^O(n,19)^n>>>10;a[e]=a[e-16]+r+a[e-7]+i>>>0}let n=t[0],i=t[1],o=t[2],s=t[3],c=t[4],l=t[5],u=t[6],d=t[7];for(let e=0;e<64;e++){let t=O(c,6)^O(c,11)^O(c,25),r=c&l^~c&u,f=d+t+r+D[e]+a[e]>>>0,p=(O(n,2)^O(n,13)^O(n,22))+(n&i^n&o^i&o)>>>0;d=u,u=l,l=c,c=s+f>>>0,s=o,o=i,i=n,n=f+p>>>0}t[0]+=n,t[1]+=i,t[2]+=o,t[3]+=s,t[4]+=c,t[5]+=l,t[6]+=u,t[7]+=d}let o=new Uint8Array(32),s=new DataView(o.buffer);for(let e=0;e<8;e++)s.setUint32(e*4,t[e]);return o}var A={Chat:`聊天`,Feed:`动态`,Ideas:`点子`,Goals:`目标`,Library:`资源库`,"Main chat":`主要聊天`,"Side chat":`旁聊`,"Reconnecting to your nanoMuse…":`正在重新连接你的 nanoMuse…`,"This demo has ended.":`这次体验已经结束。`,"This nanoMuse has stopped. Reload the page once it is running again.":`这个 nanoMuse 已停止。等它重新运行后,刷新页面即可。`,"Reconnecting…":`重新连接中…`,"Connect to your nanoMuse":`连接到你的 nanoMuse`,"This app talks to the nanoMuse server you run yourself. Scan the QR code printed by":`这个应用连接的是你自己运行的 nanoMuse 服务器。扫描下面命令打印的二维码`,", or paste the access token below.":`,或在下方粘贴访问令牌。`,"Access token":`访问令牌`,Connect:`连接`,Connected:`已连接`,"Hi, I'm {name}.":`你好,我是 {name}。`,"I don't just answer; I get things done: research, plans, files, code, email, long-running goals. Everything I do shows up here, and anything hard to undo waits for your approval.":`我不只是回答问题,而是把事情做完:调研、计划、文件、代码、邮件、长期目标。我做的每件事都会显示在这里,任何难以撤销的操作都会先等你批准。`,"What can you do for me?":`你能为我做什么?`,"Plan my week: ask me what's on my plate":`帮我规划这一周:先问问我手头有什么`,"Research and compare two options for me":`帮我调研并比较两个选项`,"Set up a long-term goal and track it":`建立一个长期目标并持续跟进`,"Answer {name}…":`回复 {name}…`,"Reply below to continue.":`在下方回复以继续。`,"{name} is working; anything you send now is picked up right away.":`{name} 正在工作,你现在发的消息会马上接着处理。`,"Working…":`处理中…`,"On it":`正在处理`,"Show the agent's steps":`显示执行步骤`,"Every tool it uses becomes a chip in the chat. Off, the chat keeps to the conversation and the line under the name says what it is on. This device only.":`每用一个工具就在对话里多一个小标签。关闭时对话只保留对话本身,名字下方的一行字说明它正在做什么。仅本设备。`,"On it: {request}":`正在处理:{request}`,"A star on GitHub helps":`GitHub 上的一颗 Star 帮得上忙`,"Welcome. nanoMuse is free, open source and non-profit, a personal agent for anyone who runs it. If that is worth something to you, a star on GitHub is how the next person finds it.":`欢迎。nanoMuse 免费、开源、非营利,做的是一个属于每个人的个人智能体。如果你认同,GitHub 上的一颗 Star 能让下一个人也找到这里。`,"Three tasks done. If nanoMuse is useful, a star on GitHub helps the next person find it.":`三个任务完成了。如果 nanoMuse 用得上,到 GitHub 点一颗 Star,下一个人也能找到它。`,"{n} tasks done. If nanoMuse is useful, a star on GitHub helps the next person find it.":`已经完成 {n} 个任务了。如果 nanoMuse 用得上,到 GitHub 点一颗 Star,下一个人也能找到它。`,"A week with nanoMuse. If it has earned a place in your day, a star on GitHub helps the next person find it.":`和 nanoMuse 一起一周了。如果它在你的日常里站住了脚,到 GitHub 点一颗 Star,下一个人也能找到它。`,"A month with nanoMuse. If it has become part of your routine, a star on GitHub tells others it is worth a try.":`和 nanoMuse 一起一个月了。如果它成了你习惯的一部分,一颗 Star 会让更多人愿意试一试。`,"{n} days with nanoMuse. If it has earned a place in your day, a star on GitHub helps the next person find it.":`和 nanoMuse 一起 {n} 天了。如果它在你的日常里站住了脚,到 GitHub 点一颗 Star,下一个人也能找到它。`,"Goal reached. If nanoMuse helped you get there, a star on GitHub tells the people building it that it did.":`目标达成了。如果 nanoMuse 帮你走到了这里,到 GitHub 点一颗 Star,做它的人就知道了。`,"Ten tasks together. If nanoMuse has become part of your day, a star on GitHub tells others it is worth a try.":`已经一起完成十个任务了。如果 nanoMuse 成了你日常的一部分,一颗 Star 会让更多人愿意试一试。`,"A new face, drawn for you. If you like where nanoMuse is going, a star on GitHub helps more people find it.":`一张为你画的新面孔。如果你喜欢 nanoMuse 现在的样子,到 GitHub 点一颗 Star,更多人就能遇见它。`,"The free allowance is used up. Thank you for coming this far. If nanoMuse has earned it, a star on GitHub keeps the project in view for the next person.":`免费额度用完了,谢谢你一路用到这里。如果 nanoMuse 值得,到 GitHub 点一颗 Star,下一个人也能找到它。`,"Load earlier messages":`加载更早的消息`,"New side chat":`新建旁聊`,"New side chat, e.g. “Trip to Kyoto”":`新建旁聊,例如“京都之旅”`,Chats:`对话`,New:`新建`,Create:`创建`,Clear:`清空`,"Clear this conversation? Memory and goals are kept.":`清空这段对话?记忆和目标会保留。`,"Delete this side chat and its history?":`删除这个旁聊及其历史记录?`,"Could not send":`发送失败`,"Could not send decision":`无法提交决定`,Send:`发送`,"Show thinking":`显示思考过程`,"Hide thinking":`隐藏思考过程`,"You:":`你:`,"{name} asks":`{name} 提问`,"{name} suggests":`{name} 建议`,"{name} is on it":`{name} 正在处理`,"Browser: {title}":`浏览器:{title}`,safe:`安全`,moderate:`中等`,sensitive:`敏感`,high:`高`,"Exactly what will run":`将要执行的具体内容`,"Why it asks: {reasons}":`询问原因:{reasons}`,"{tool} is on your always-ask list":`{tool} 在你的「总是询问」列表里`,"{tool} is on your always-allow list":`{tool} 在你的「总是允许」列表里`,"{tool} is switched off in your settings":`{tool} 已在你的设置里关闭`,"an action rated {risk}, in {mode} mode":`这个操作的风险等级是「{risk}」,哨兵处于{mode}模式`,"auto mode: not asked":`自动模式:未询问`,"covered by your {scope} permission for {key}":`已在你对 {key} 的「{scope}」授权范围内`,"private data was read earlier in this conversation, and {tool} could send it to {target}, which is not on your allowed list":`这段对话早些时候读取过私密数据,而 {tool} 可能把它发给 {target},这个地址不在你的允许列表里`,ask:`询问`,auto:`自动`,strict:`严格`,once:`一次`,conversation:`本次对话`,session:`本次运行`,"24h":`24 小时`,low:`低`,"Stopped.":`已停止。`,"Use nanoMuse Cloud this time":`这次改用 nanoMuse Cloud`,"Answered by nanoMuse Cloud this time ({model})":`这次由 nanoMuse Cloud 回答({model})`,Deny:`拒绝`,"Allow once":`允许一次`,Allow:`允许`,"{name} wants to":`{name} 想要`,"at {host}":`站点:{host}`,"to {recipient}":`收件人:{recipient}`,"Allow {subject} for longer…":`更长时间允许 {subject}…`,"For this conversation":`本次对话`,"the device {name}":`设备「{name}」`,"Until restart":`直到重启`,"For 24 hours":`24 小时内`,"Always for {subject}":`始终允许 {subject}`,"Fewer options":`收起`,"Show all":`展开全部`,"This kind of action is approved one at a time.":`这类操作需要逐次批准。`,Approved:`已批准`,Denied:`已拒绝`,"Expired without an answer":`已过期,未作答`,"approved by you":`已由你批准`,"covered by your {scope} permission":`已由你的{scope}授权覆盖`,"for this conversation":`本次对话`,"until restart":`直到重启`,"for 24 hours":`24 小时内`,always:`始终`,"email to {who}":`发送给 {who} 的邮件`,"{what} commands":`{what} 命令`,browser:`浏览器`,email:`邮件`,secret:`密钥`,"Waiting for you":`等你确认`,Answer:`回答`,LIVE:`实时`,BROWSER:`浏览器`,"Frame no longer available":`画面已不可用`,Page:`页面`,Document:`文档`,Image:`图片`,Data:`数据`,Code:`代码`,Open:`打开`,Download:`下载`,"Type into the focused field…":`输入到当前聚焦的输入框…`,Type:`输入`,"Press Enter":`按回车`,"Open a URL…":`打开一个网址…`,Go:`前往`,"Tap the page to click. If the browser was closed, open a URL first.":`点击画面即可点击网页。如果浏览器已关闭,请先打开一个网址。`,Refresh:`刷新`,"Take over":`接管`,"This frame is no longer available.":`这一帧画面已不可用。`,"Look again":`重新查看`,"1 frame":`1 帧`,"{n} frames":`{n} 帧`,"Scroll up":`向上滚动`,"Scroll down":`向下滚动`,"You have the page. Press Done when you are finished.":`页面现在由你操作。完成后按「完成」。`,"{name} waits meanwhile, then looks at the page as you left it and carries on. Passwords you type here go to the website, never to the model.":`{name} 会先等着,然后从你离开时的页面接着做。你在这里输入的密码只发给网站,不会给模型。`,"{name} is waiting for you":`{name} 在等你`,"{name} is working":`{name} 正在工作`,"Your turn":`该你了`,"Your turn: {reason}":`该你了:{reason}`,"You took over {thing}":`你接管了{thing}`,"the browser":`浏览器`,"the phone":`手机`,"The browser":`浏览器`,"The phone":`手机`,"Do this part yourself, then press Done. {name} looks again and carries on from there.":`这一步请你自己来,做完按「完成」。{name} 会重新看一眼屏幕,从那里接着做。`,"{name} waits. Press Done when you are finished and it looks again.":`{name} 在等。你弄完后按「完成」,它会重新看一眼。`,"{name} waited ten minutes and went on without you.":`{name} 等了十分钟,没等到你,先继续了。`,"Ended when the runtime restarted.":`运行时重启,这次接管结束。`,"You did it; {name} carried on.":`你做完了,{name} 接着做了。`,"Handed back; {name} carried on.":`已交还,{name} 接着做了。`,Close:`关闭`,"Open in a new tab":`在新标签页打开`,"No preview for this file type.":`此类型文件无法预览。`,"Download it":`下载文件`,"Empty file.":`空文件。`,"Could not load the file: {error}":`无法加载文件:{error}`,"Writing…":`正在写…`,"While you were away":`你离开期间`,"Could not write posts: {error}":`无法生成动态:{error}`,"Nothing yet. Once {name} works on a goal in the background or needs your approval, it shows up here.":`暂时还没有内容。当 {name} 在后台推进目标或需要你批准时,会显示在这里。`,"Next up":`接下来`,"Background work is off. {name} only acts when you ask.":`后台工作已关闭。{name} 只在你要求时行动。`,"Turn it on":`开启`,"No goal has a next step to work on.":`没有目标有可执行的下一步。`,"Add one":`添加一个`,"Working now":`正在进行`,"Quiet hours after {time}":`免打扰时段,{time} 之后`,"Around {time}":`大约 {time}`,Soon:`即将`,overdue:`已逾期`,"{n} more in line":`还有 {n} 个排队中`,"Check-in on":`跟进`,"{n} more":`还有 {n} 个`,Reminder:`提醒`,Routine:`例程`,"Working on your goal: {title}":`推进目标:{title}`,"Check-in: {title}":`跟进:{title}`,"Reminder: {title}":`提醒:{title}`,"Routine: {title}":`例程:{title}`,"New mail: {title}":`新邮件:{title}`,"Coming up: {title}":`即将开始:{title}`,"Webhook: {title}":`Webhook:{title}`,"Tidied memory":`整理了记忆`,"{label}: nothing new":`{label}:没有新进展`,"Open chat":`打开对话`,Today:`今天`,Yesterday:`昨天`,Menu:`菜单`,Stop:`停止`,"Nothing to stop":`没有正在进行的任务`,Message:`发消息`,"An emoji instead":`改用表情符号`,"Refresh ideas":`刷新灵感`,Planning:`规划`,Research:`调研`,Money:`财务`,People:`人际`,"Files & tools":`文件与工具`,"Just for you":`专属于你`,Tracking:`追踪`,"Show {n} more":`还有 {n} 个`,Cancelled:`已取消`,"Starter ideas. Refresh once {name} knows you better.":`入门灵感。等 {name} 更了解你之后再刷新。`,"Generated {when}":`生成于 {when}`,"Could not refresh ideas: {error}":`无法刷新灵感:{error}`,"Do it for me":`帮我做`,Health:`健康`,Finance:`财务`,Career:`事业`,Learning:`学习`,Relationships:`关系`,Family:`家庭`,Home:`家居`,Travel:`旅行`,Creative:`创作`,Other:`其他`,"New goal":`新目标`,Paused:`已暂停`,Finished:`已完成`,active:`进行中`,paused:`已暂停`,done:`已完成`,cancelled:`已取消`,pending:`待处理`,blocked:`受阻`,"{done}/{total} done":`已完成 {done}/{total}`,"Next: {step}":`下一步:{step}`,"Next check-in {when}":`下次跟进 {when}`,"Due today":`今天到期`,"Due tomorrow":`明天到期`,"Due in {n} days":`{n} 天后到期`,"Was due {date}":`原定 {date} 到期`,"By {date}":`截止 {date}`,"No target date":`没有目标日期`,"No category":`未分类`,"Every day":`每天`,"Once a week":`每周一次`,"Once a month":`每月一次`,Weekdays:`工作日`,Weekly:`每周`,Monthly:`每月`,"Daily at {time}":`每天 {time}`,"Weekdays at {time}":`工作日 {time}`,"Weekly at {time}":`每周 {time}`,"{day}s at {time}":`每{day} {time}`,"Monthly on the {day} at {time}":`每月 {day} 日 {time}`,"Work on it now":`现在就推进`,"Work on {title} now":`现在推进「{title}」`,"{name} is working on “{title}” in the main chat":`{name} 正在主要聊天中推进“{title}”`,"{name} is working on it in the main chat":`{name} 正在主要聊天中处理`,"Check in with me now":`现在跟我确认进度`,"{name} will check in with you in the main chat":`{name} 会在主要聊天中跟你确认进度`,"Discuss this goal in chat →":`在对话中讨论这个目标 →`,"About my goal “{title}” ({id}): what's the status, and what should we do next?":`我们来聊聊我的目标“{title}”({id})。现在进展如何,下一步该做什么?`,Pause:`暂停`,Resume:`继续`,Done:`完成`,Delete:`删除`,"Delete goal":`删除目标`,"Delete “{title}”?":`删除“{title}”?`,Edit:`编辑`,Save:`保存`,"Saving…":`保存中…`,Saved:`已保存`,Cancel:`取消`,"Add step":`添加步骤`,"Add a step":`添加一个步骤`,"What should be done…":`要做什么…`,"Mark step {n} {status}":`把第 {n} 步标记为{status}`,"Adjust the plan for “{title}”?":`调整“{title}”的计划?`,"Keeps the 1 step already done.":`保留已完成的 1 个步骤。`,"Keeps the {n} steps already done.":`保留已完成的 {n} 个步骤。`,"New remaining steps:":`新的剩余步骤:`,"Keep my plan":`保留我的计划`,"Use {name}'s plan":`采用 {name} 的计划`,"Kept your plan":`已保留你的计划`,"Plan updated":`计划已更新`,"What do you want to achieve?":`你想实现什么?`,"Why it matters, constraints (optional)":`为什么重要、有哪些限制(可选)`,"Area of life":`生活领域`,"Target date":`目标日期`,"Steps, one per line (optional, or let {name} plan them)":`步骤,每行一个(可选,也可以让 {name} 来规划)`,"Let {name} plan it":`让 {name} 来规划`,'Create a goal for me: "{title}"{description}{extras}. Break it into concrete steps with the goals tool, then tell me the plan.':`帮我创建一个目标:“{title}”{description}{extras}。用 goals 工具把它拆成具体步骤,然后告诉我计划。`,"Day {d}":`第 {d} 天`,"Search files":`搜索文件`,"No files match.":`没有匹配的文件。`,Latest:`最新`,"Updated {when}":`更新于 {when}`,Memory:`记忆`,"What {name} remembers about you. Read it, add to it, or make {name} forget; nothing here is hidden from you.":`{name} 对你的了解都在这里。你可以翻看、补充,或让 {name} 忘掉,没有什么是瞒着你的。`,"Tell {name} something to remember, e.g. “I'm vegetarian” or “My sister's birthday is 14 May”":`告诉 {name} 要记住的事,例如“我是素食者”或“我妹妹的生日是 5 月 14 日”`,Remember:`记住`,Forget:`忘掉`,"Forget “{text}”?":`忘掉“{text}”?`,"Nothing remembered yet":`还没有记住任何内容`,"{name} saves durable facts you share in chat (preferences, people, routines) and never secrets.":`{name} 会保存你在对话中分享的长期事实(偏好、人物、习惯),绝不保存密钥或密码。`,"added by you":`由你添加`,"saved by {name}":`由 {name} 保存`,"updated {when}":`更新于{when}`,"Tidy up":`整理`,"Tidying…":`整理中…`,"Merge lines that say the same thing and drop what was never a fact about you. Every change can be undone.":`把意思相同的条目合并,删掉那些并不是你本人情况的内容。每处改动都能撤销。`,"Nothing to tidy: {n} memories, all distinct.":`无需整理:{n} 条记忆,互不重复。`,"Tidied: {merged} merged, {dropped} dropped. Undo below if needed.":`已整理:合并 {merged} 条,去掉 {dropped} 条。如有需要可在下方撤销。`,"Recent changes":`最近的改动`,Merged:`已合并`,Dropped:`已去掉`,Updated:`已更新`,restored:`已恢复`,Undo:`撤销`,profile:`个人资料`,preference:`偏好`,people:`人物`,routine:`习惯`,constraint:`限制`,general:`一般`,idle:`空闲`,working:`工作中`,waiting:`等待中`,Activity:`活动`,Approvals:`审批`,Connections:`连接`,Settings:`设置`,"Nothing is waiting for you.":`没有需要你处理的事项。`,"{n} events":`{n} 个事件`,failed:`失败`,updated:`已更新`,"background check":`后台检查`,"Every tool call goes through the Sentinel and is written to the audit log, including the ones it refused.":`每一次工具调用都经过 Sentinel 审查并写入审计日志,包括被拒绝的那些。`,"Sentinel mode:":`Sentinel 模式:`,balanced:`平衡`,cautious:`谨慎`,"hands-off":`放手`,"Safe and moderate actions run freely; anything sensitive (email, shell, purchases) waits for you.":`安全和中等风险的操作自由执行;任何敏感操作(邮件、终端命令、购买)都会等你批准。`,"Moderate and sensitive actions both wait for your approval.":`中等和敏感风险的操作都会等待你的批准。`,"Everything is approved automatically except explicit deny rules. Use with care.":`除明确的拒绝规则外,一切自动批准。请谨慎使用。`,"Always asks before: {tools}.":`以下操作总会先问你:{tools}。`,"Private data was read this session: network calls to new destinations need approval.":`本次会话已读取过私密数据:访问新的网络目标需要批准。`,"Commands run in a sandbox":`命令在沙箱中运行`,"Commands run without a sandbox":`命令未在沙箱中运行`,"Each shell or Python call gets its own namespace: only the workspace is writable, your home directory is not there, and there is no network unless the command needs it.":`每次 shell 或 Python 调用都有独立的命名空间:只有工作区可写,你的主目录不在其中,命令不需要网络就没有网络。`,"Each shell or Python call runs in the workspace with a scrubbed environment; the container is the boundary.":`每次 shell 或 Python 调用都在工作区中以清洗过的环境运行;容器就是边界。`,"Each shell or Python call runs in the workspace with a scrubbed environment. On Linux, installing bubblewrap gives each one its own namespace.":`每次 shell 或 Python 调用都在工作区中以清洗过的环境运行。在 Linux 上安装 bubblewrap 后,每次调用会有独立的命名空间。`,"After reading private data, new network destinations need approval.":`读取私密数据之后,访问新的网络目标需要批准。`,"Permissions you granted":`你授予的权限`,"No standing approvals. When you answer “always allow” to a risky step, it is listed here and can be revoked; approvals you give once are not kept.":`还没有长期批准。对有风险的操作选择“始终允许”后,会列在这里,随时可以撤回;“允许一次”的批准不会保留。`,"Nothing yet today. What you ask for and what {name} does about it shows up here.":`今天还没有动态。你提的要求和 {name} 做的事会显示在这里。`,"Share avatar":`分享形象`,"Creates a routine":`会创建一条例程`,"Creates a goal":`会创建一个目标`,"Create routine":`创建例程`,"Start goal":`开始这个目标`,"Routine set: every day at {time}. It is listed under Goals.":`例程已设好:每天 {time}。在「目标」页可以看到。`,"A morning brief":`早间简报`,"Before you leave each morning: the weather, the first thing on your plate and anything new worth knowing.":`每天出门前:天气、今天的第一件事,以及值得知道的新消息。`,"Morning brief: check today's weather, read my calendar and reminders for today, and tell me in five lines what matters.":`早间简报:查今天的天气,读我今天的日程和提醒,用五行告诉我要紧的事。`,"drawn from the picture you attached":`按你附的图片来画`,"Share my avatar":`分享我的虚拟形象`,"Pick a card. It goes out through the system share sheet, or saves as a picture where there is none.":`选一张卡片,用系统分享发出去;没有系统分享的浏览器会保存为图片。`,"Hi, I'm {name}, a personal AI agent. Meet nanoMuse: open source, runs on your phone.":`你好,我是你的个人 AI 智能体 {name}。认识一下 nanoMuse:开源,在手机上本地运行。`,"Your personal AI agent, open source · {repo}":`你的个人 AI 智能体,开源 · {repo}`,Later:`以后再说`,Share:`分享`,"Save picture":`保存图片`,"Saved the card as a picture.":`卡片已保存为图片。`,"The card could not be drawn.":`卡片没能画出来。`,"the hands in {app}":`在 {app} 里动手`,"granted {time}":`授予于 {time}`,"until {time}":`直到 {time}`,"Revoke {what}":`撤销 {what}`,"Revoked: {subject}":`已撤销:{subject}`,"Reset all granted permissions":`重置所有已授予的权限`,"Permissions reset":`权限已重置`,"Always ask (from config)":`始终询问(来自配置)`,Off:`关闭`,Low:`低`,Default:`默认`,High:`高`,"Off. {name} only works when you ask.":`已关闭。{name} 只在你要求时工作。`,"every {n} min {name} picks one active goal and works on its next step.":`每 {n} 分钟 {name} 挑选一个进行中的目标并推进它的下一步。`,"Quiet hours until {time}.":`免打扰时段直到 {time}。`,"Next around {time}.":`下一次大约在 {time}。`,"No background work in this window; anything due waits until it ends.":`此时段不进行后台工作;到期的事项会等到时段结束。`,"Level, interval and quiet hours in Settings":`在设置中调整级别、间隔和免打扰时段`,"In line":`排队中`,"No active goal has a next step. Add one in Goals and {name} will pick it up.":`没有进行中的目标有下一步。在目标中添加一个,{name} 会接手。`,"{n} queued":`{n} 个排队中`,"Check-ins":`跟进`,"Goal nudges you asked for; they arrive whatever the proactivity level, but wait out quiet hours.":`你要求的目标提醒;无论主动性级别如何都会送达,但会避开免打扰时段。`,"Reminders & routines":`提醒与例程`,"When something happens":`当某事发生时`,"mail matching “{match}”":`匹配“{match}”的邮件`,"any new mail":`任何新邮件`,"events matching “{match}”":`匹配“{match}”的日程`,"any event":`任何日程`,"{n} min before {what}":`{what}开始前 {n} 分钟`,"webhook “{match}”":`Webhook“{match}”`,webhook:`Webhook`,"Nothing yet. Tell {name} “when the landlord writes back, summarise it and draft a reply” or “half an hour before any review, brief me”.":`还没有。告诉 {name}“房东回信时,帮我总结并起草回复”或“任何评审开始前半小时,给我一份简报”。`,"fired {n}×":`触发 {n} 次`,"not fired yet":`尚未触发`,"Copy URL":`复制地址`,"Run now: {text}":`现在运行:{text}`,"Webhook URL copied":`已复制 Webhook 地址`,"The inbox could not be read: {error}":`无法读取收件箱:{error}`,"Inbox checked {when}; {name} looks every {n} min.":`收件箱{when}检查过;{name}每 {n} 分钟查看一次。`,"{name} will look at the inbox shortly, then every {n} min.":`{name}稍后会查看收件箱,之后每 {n} 分钟一次。`,"Each time it happens {name} does the work in the chat it was set from and reports in the Feed. A mail or a request is treated as data, never as instructions.":`每次触发时,{name} 会在设定它的那个对话里把事做完,再到动态里汇报。邮件和请求的内容只当资料看,绝不当作指令执行。`,"Webhook ready":`Webhook 已就绪`,"POST anything to this URL and the work starts. The key is in the URL; share it only with the program that will call it.":`向这个地址 POST 任意内容即可开始工作。密钥就在地址里,只交给要调用它的程序。`,Copy:`复制`,"New mail":`新邮件`,"Before an event":`日程开始前`,Webhook:`Webhook`,"Connect a mailbox under Connections first.":`请先在“连接”里接入邮箱。`,"Add a calendar under Connections first.":`请先在“连接”里添加日历。`,"Words in the sender or subject (empty: any mail)":`发件人或主题中的词(留空:任何邮件)`,"Words in the title or place (empty: any event)":`标题或地点中的词(留空:任何日程)`,"A name for this hook":`给这个 Webhook 起个名字`,"Minutes before":`提前分钟数`,"min before":`分钟前`,"What should be done each time…":`每次要做什么……`,"When {condition}":`当{condition}`,"Set trigger":`设置触发器`,"A time you named is kept whatever the level or the quiet hours. Reminders just say it; routines do the work and report.":`你指定的时间无论级别或免打扰时段都会遵守。提醒只是说一声;例程会执行工作并汇报。`,"No reminders":`没有提醒`,"Nothing scheduled. Tell {name} “remind me at six to call mum” or “every weekday morning, summarise my unread email”.":`没有安排。告诉 {name}“六点提醒我给妈妈打电话”或“每个工作日早上汇总我的未读邮件”。`,"{n} finished recently":`最近完成 {n} 个`,"Do “{text}” now":`现在执行“{text}”`,"Remind me now: {text}":`现在提醒我:{text}`,"Cancel: {text}":`取消:{text}`,"{name} will say it now":`{name} 现在就会说`,"+ Add":`+ 添加`,"Remind me":`提醒我`,Repeat:`重复`,"What to remind you of…":`提醒你什么…`,"Set reminder":`设置提醒`,"Set routine":`设置例程`,at:`于`,"1 approval waiting for you":`需要你批准`,"{n} approvals waiting for you":`{n} 项需要你批准`,"{n} approval":`{n} 项审批`,You:`你`,"Its name and look, how careful it is, how often it speaks up.":`名字和形象,有多谨慎,多主动。`,Name:`名字`,Avatar:`头像`,"What it calls you":`它怎么称呼你`,"Safety · Sentinel":`安全 · Sentinel`,"A separate gatekeeper reviews every action. Pick how often it should check in with you.":`一个独立的守门人审查每一次操作。选择它多久向你确认一次。`,Balanced:`平衡`,"Browse, read and write files freely; stop for anything hard to undo: email, purchases, shell commands.":`自由浏览、读写文件;遇到难以撤销的操作时停下:邮件、购买、终端命令。`,Cautious:`谨慎`,"Also ask before moderate actions like fetching web pages or writing files.":`对抓取网页或写入文件等中等风险操作也先询问。`,"Hands-off":`放手`,"Approve everything automatically except explicit deny rules. For trusted, unattended runs only.":`除明确的拒绝规则外一切自动批准。仅用于可信的无人值守运行。`,"Decides when the Sentinel asks you before a call.":`决定 Sentinel 在调用前何时向你询问。`,Proactivity:`主动性`,"Only works when you ask.":`只在你要求时工作。`,"Checks in half as often; speaks up only when a step is done or it needs you.":`检查频率减半;只在完成一步或需要你时才发声。`,"Works on goals on schedule; reports real progress, stays quiet otherwise.":`按计划推进目标;汇报实质进展,其余时间保持安静。`,"Checks in twice as often and always reports, even 'still on track'.":`检查频率加倍并总是汇报,即使只是“仍在正轨上”。`,"Background work":`后台工作`,"Check-in interval":`检查间隔`,"{n} min":`{n} 分钟`,"{n} h":`{n} 小时`,"{n} d":`{n} 天`,"Halved at this level":`此级别下减半`,"Doubled at this level":`此级别下加倍`,"Quiet hours":`免打扰时段`,From:`从`,to:`到`,Notifications:`通知`,"Approvals, questions, finished background work and check-ins; nothing while the app is on screen.":`审批、提问、后台完成的事和到点的跟进;应用在前台时不打扰。`,"Let {name} notify this device":`让 {name} 通知这台设备`,"Let {name} notify this phone":`让 {name} 通知这台手机`,"The app stays connected to your server in the background. Approvals, questions and finished background work arrive as notifications and open the right chat.":`应用在后台保持与服务器的连接。审批、提问和后台完成的工作会以通知送达,并打开对应的对话。`,"nanoMuse for Android {version}":`nanoMuse Android 版 {version}`,"Disconnect from this server":`断开此服务器`,"This device only":`仅这台设备`,"1 device subscribed":`1 台设备已订阅`,"{n} devices subscribed":`{n} 台设备已订阅`,"Send a test":`发送测试`,"Sent. It should arrive in a moment":`已发送,应该马上就到`,"Notifications need https:// (or localhost). Over plain http on your LAN the app works, this part stays off; see docs/deployment.md.":`通知需要 https://(或 localhost)。在局域网的普通 http 上应用可以使用,但这部分功能保持关闭,参见 docs/deployment.md。`,"This browser cannot receive push notifications.":`这个浏览器无法接收推送通知。`,"This browser has no push service (embedded browsers often don't). Use Chrome, Edge, Firefox or Safari 16.4+ on the phone.":`这个浏览器没有推送服务(内嵌浏览器通常没有)。请在手机上使用 Chrome、Edge、Firefox 或 Safari 16.4+。`,"Notifications are blocked for this site in the browser settings":`浏览器设置中已屏蔽此站点的通知`,"Blocked for this site. Allow notifications in the browser's site settings, then try again.":`通知在这个站点被关掉了。到浏览器的站点设置里允许通知,再试一次。`,"The server was installed without pywebpush.":`服务器安装时未包含 pywebpush。`,"On a phone, add the app to the home screen first; the icon then shows a badge and notifications open the right chat.":`手机上请先把应用添加到主屏幕;图标会显示角标,通知会打开对应的对话。`,Model:`模型`,"Provider / model":`服务商 / 模型`,"Reveal the model's reasoning under each reply when the provider exposes it.":`当服务商提供时,在每条回复下方显示模型的推理过程。`,"Reply language":`回复语言`,"What {name} writes in":`{name} 用什么语言回复`,Auto:`自动`,"Match mine":`跟随我的语言`,"App language":`应用语言`,Appearance:`外观`,Light:`浅色`,Dark:`深色`,"Follow the system":`跟随系统`,About:`关于`,"{version} is out":`{version} 已发布`,"nanoMuse {version}":`nanoMuse {version}`,"Tell {name} something to remember":`在对话里告诉 {name} 一件值得记住的事`,"Write one":`写一个`,"Latest {version}; you have it":`最新版 {version},你已经在用了`,Update:`更新`,"Check now":`现在检查`,"Checking…":`正在检查…`,"Could not check":`没能检查到最新版本`,"Checked {when}":`上次检查:{when}`,"The phone app checks for updates on its own.":`手机 App 会自己检查更新。`,"Update checks are off here.":`这里关闭了更新检查。`,"To update: pip install -U nanomuse, pull the new image, or use the desktop app's Update.":`更新方式:pip install -U nanomuse、拉取新镜像,或在桌面 App 里点“更新”。`,"Data:":`数据:`,"Workspace:":`工作区:`,"Forget this device's access token":`忘掉这台设备的访问令牌`,"does the work":`负责干活`,Calendar:`日历`,calendar:`日历`,Tomorrow:`明天`,"all day":`全天`,"{n} scheduled":`{n} 个安排`,"Nothing on the calendar today.":`今天日历上没有安排。`,"Ask about your week":`问问这周的安排`,"{name} could not be read":`{name} 读取失败`,"Your agenda, free time, and events it can draft":`你的日程、空闲时间,以及它起草的日程`,"{n} not reading":`{n} 个读取失败`,"1 event":`1 个事件`,"{n} calendars":`{n} 个日历`,"read {when}":`{when}读取`,"Calendar connected":`日历已连接`,"Reads your calendar from its private .ics link; the link stays in the vault. It never changes your calendar; an event it proposes comes as a file you add with a tap.":`通过私密 .ics 链接读取你的日历,链接存在保险库里。它不会改动你的日历;它建议的日程会做成文件给你,点一下就能加进去。`,"not read yet":`尚未读取`,"Where is the link?":`链接在哪里?`,"Settings → your calendar → Integrate calendar → Secret address in iCal format":`设置 → 你的日历 → 整合日历 → iCal 格式的私密地址`,"Settings → Calendar → Shared calendars → Publish a calendar → ICS link":`设置 → 日历 → 共享日历 → 发布日历 → ICS 链接`,"Share Calendar → Public Calendar → copy the webcal:// link":`共享日历 → 公共日历 → 复制 webcal:// 链接`,"Settings → Calendars → Export → Calendar URL":`设置 → 日历 → 导出 → 日历 URL`,"A path on the machine where nanoMuse runs, for example ~/calendar.ics":`nanoMuse 所在机器上的文件路径,例如 ~/calendar.ics`,".ics file":`.ics 文件`,Work:`工作`,"Private .ics link or file path":`私密 .ics 链接或文件路径`,"Stored encrypted in the vault as CALENDAR_{name}.":`加密保存在保险库中,名为 CALENDAR_{name}。`,"nanoMuse fetches whatever address you put here, from this machine; only paste links you trust.":`nanoMuse 会从这台机器上去取你填的任何地址,只粘贴你信任的链接。`,"Add a calendar":`添加日历`,"Added, but it could not be read: {error}":`已添加,但读取失败:{error}`,Contacts:`通讯录`,"1 person":`1 人`,"{n} people":`{n} 人`,"Address book connected":`通讯录已连接`,"Who is who, so it never guesses an address":`知道谁是谁,从不猜地址`,"told to it in chat":`在聊天中告诉它的`,"{n} address books":`{n} 个通讯录`,"Import a .vcf export from Google Contacts, iCloud, Outlook or your phone, or paste a link to one. People you mention in chat go into its own book. It looks people up before writing to them and warns when an address is unknown.":`导入 Google 通讯录、iCloud、Outlook 或手机导出的 .vcf 文件,或粘贴一个链接。你在聊天中提到的人会记进它自己的名册。写信前它会先查人,地址不认识时会提醒。`,"My contacts":`我的联系人`,"added in chat":`聊天中添加`,iPhone:`iPhone`,"A .vcf file from your phone or computer":`手机或电脑上的 .vcf 文件`,"Google Contacts: Export → vCard. iPhone: Contacts → select all → Share → Save to Files. Outlook: People → Manage → Export.":`Google 通讯录:导出 → vCard。iPhone:通讯录 → 全选 → 共享 → 存储到“文件”。Outlook:人员 → 管理 → 导出。`,"Choose a .vcf file":`选择 .vcf 文件`,"Or a link / path to one":`或一个链接 / 路径`,"A link is stored encrypted in the vault as CONTACTS_{name}.":`链接会加密保存在保险库中,名为 CONTACTS_{name}。`,"Add an address book":`添加通讯录`,"Find someone, as the agent would":`像 Agent 那样查一个人`,"No one matches.":`没有匹配的人。`,"Working hours":`工作时间`,"Free time is looked for inside these hours.":`空闲时间只在这个时段内查找。`,"Read again":`重新读取`,Event:`日程`,"No event in this file.":`这个文件里没有日程。`,"Untitled event":`未命名日程`,"Add to calendar":`加入日历`,"Opens in your calendar app, which asks before it saves anything.":`会在你的日历应用中打开,保存前会先询问你。`,"What {name} can reach; keys stay in the vault on this machine.":`{name} 能用到的东西;密钥留在这台机器的保险库里。`,"No key yet":`还没有密钥`,"Key missing from vault":`保险库中缺少密钥`,"Key in vault":`密钥已在保险库`,"Key from config":`密钥来自配置`,"No key needed":`无需密钥`,Provider:`服务商`,"Base URL":`Base URL`,"API key":`API 密钥`,"A key is in the vault. Leave blank to keep it.":`保险库中已有密钥。留空则保持不变。`,"Stored encrypted in the vault as LLM_API_KEY.":`以 LLM_API_KEY 加密存储在保险库中。`,"model name":`模型名称`,"Tool calling":`工具调用`,"Auto uses the API's function calling and falls back to describing tools in the prompt when the endpoint rejects them. Prompt: for endpoints that silently ignore tools.":`自动:使用 API 的函数调用,当端点拒绝时回退为在提示词中描述工具。提示词:用于会静默忽略工具的端点。`,Test:`测试`,"Model saved":`模型已保存`,'Replied "{reply}" in {ms} ms':`在 {ms} 毫秒内回复了“{reply}”`,"Email connected":`邮件已连接`,"Saved, but the test failed":`已保存,但测试失败`,"Email disconnected":`邮件已断开`,Incomplete:`未完成`,"Not connected":`未连接`,Email:`邮件`,"reads and sends":`读取和发送`,"Read your inbox, draft and send mail":`读取收件箱、起草和发送邮件`,"Reading is a moderate action; sending always asks you first. Use an app password where your provider offers one.":`读取是中等风险操作;发送总会先询问你。如果服务商提供应用专用密码,请使用它。`,Address:`邮箱地址`,Password:`密码`,"app password":`应用专用密码`,"A password is in the vault. Leave blank to keep it.":`保险库中已有密码。留空则保持不变。`,"Stored encrypted in the vault as EMAIL_PASSWORD.":`以 EMAIL_PASSWORD 加密存储在保险库中。`,"IMAP server":`IMAP 服务器`,Port:`端口`,"SMTP server":`SMTP 服务器`,"STARTTLS for SMTP (off for port 465)":`SMTP 使用 STARTTLS(465 端口请关闭)`,"Save & test":`保存并测试`,Disconnect:`断开`,"Signed in · {n} messages in the inbox":`已登录 · 收件箱有 {n} 封邮件`,Browser:`浏览器`,"Open pages, click, fill forms, screenshot":`打开页面、点击、填表、截图`,"Playwright is not installed on the server":`服务器上未安装 Playwright`,On:`开`,Unavailable:`不可用`,"Install it where the server runs:":`在服务器运行的机器上安装:`,"Server connected":`服务器已连接`,"MCP servers":`MCP 服务器`,"{n} of {total} connected · {tools} tools":`{total} 个中已连接 {n} 个 · {tools} 个工具`,"Add tools from any Model Context Protocol server":`从任意 Model Context Protocol 服务器添加工具`,"{n} on":`{n} 个已开启`,None:`无`,"{n} tools":`{n} 个工具`,"from config.toml":`来自 config.toml`,Remove:`移除`,Command:`命令`,"Run locally over stdio, for example: npx -y @modelcontextprotocol/server-filesystem ./workspace":`通过 stdio 在本地运行,例如:npx -y @modelcontextprotocol/server-filesystem ./workspace`,"or URL":`或 URL`,"A remote server over Streamable HTTP.":`通过 Streamable HTTP 连接的远程服务器。`,"Risk of its tools":`其工具的风险级别`,"Add a server":`添加服务器`,"Connected on {device}; sign in here to use it on this device":`已在 {device} 上连接,在这台设备上登录后即可使用`,"Sign in here":`在这里登录`,"Stored in the vault":`已存入保险库`,Vault:`保险库`,"{n} secrets · encrypted on your machine":`{n} 个密钥 · 在你的机器上加密`,"Encrypted secrets the model never sees":`模型永远看不到的加密密钥`,"Refer to a secret as":`在工具调用或配置中用`,"in a tool call or config: the value is filled in after the Sentinel approves and is redacted from everything the model reads.":`引用密钥:真实值会在 Sentinel 批准后填入,并从模型读到的所有内容中脱敏。`,"Delete {name}":`删除 {name}`,Value:`值`,Store:`存储`,"Skip setup":`跳过设置`,"Meet your nanoMuse":`认识你的 nanoMuse`,"Your name":`你的名字`,"The model behind it":`背后的模型`,"A model is already set up on the server. Keep it, or switch here.":`服务器上已经配置了模型。可以保留,也可以在这里切换。`,"Connect your mail, calendar and contacts":`连接你的邮箱、日历和通讯录`,"Optional. With a mailbox connected it can read what came in and draft replies; it will always ask before sending. With a calendar it knows your day and finds free time. With your contacts it knows who is who. The browser and MCP servers are under Connections later.":`可选。连上邮箱,它能读新邮件、起草回复,发之前一定先问你。连上日历,它知道你这一天的安排,也能找出空档。连上通讯录,它知道谁是谁。浏览器和 MCP 服务器之后在「连接」里设置。`,Back:`返回`,"Get started":`开始`,Skip:`跳过`,"Save a model to continue":`保存模型后继续`,"Skip for now":`暂时跳过`,"just now":`刚刚`,"any moment":`随时`,"in {span}":`{span}后`,"{span} ago":`{span}前`,"Checked on {label}: nothing new":`已检查 {label}:没有新进展`,"Notes from {name}":`来自 {name} 的笔记`,"Reminders from {name}":`来自 {name} 的提醒`,Once:`一次`,Plan:`计划`,Skills:`技能`,Yours:`你的`,"Built in":`内置`,Fetch:`获取`,"Use in chat":`在聊天中使用`,"Make your own copy":`复制一份改成你的`,"Edit skill":`编辑技能`,"New skill":`新建技能`,"From a link":`从链接导入`,"Files that come with it":`随附文件`,"Folders that could not be read":`无法读取的文件夹`,"Nothing of your own yet":`还没有你自己的技能`,"How {name} does a job, written down once. Start one in chat with /name, or just ask; it picks the skill that fits.":`把 {name} 做某件事的方法写下来,一次就够。在聊天里输入 /名称 直接开始,或者直接提要求,它会自己挑合适的技能。`,"After a job went well, tell {name} “save this as a skill”; it writes the steps down and asks you first. Or write one here, or paste a link to a SKILL.md.":`一件事做得顺利之后,对 {name} 说“把这个存成技能”,它会把步骤写下来,并先征求你的同意。也可以在这里手写一个,或粘贴一个 SKILL.md 的链接。`,"Switch one off to keep it out of {name}'s list. A skill of yours with the same name replaces it.":`关掉某一项,它就不会出现在 {name} 的清单里。你的同名技能会替代内置的那一个。`,"Yours live in {dir}, one folder each with a SKILL.md, the Agent Skills format, so recipes written for other agents work here too.":`你的技能保存在 {dir},每个一个文件夹,里面是一份 SKILL.md。这是 Agent Skills 通用格式,为其他智能体写的技能在这里同样可用。`,"Delete the skill “{name}”? Its folder goes with it.":`删除技能“{name}”?它的文件夹会一并删除。`,"Saving makes a copy of yours with the same name; it replaces the built-in one.":`保存后会生成一份你的同名技能,替代内置的那一个。`,"A SKILL.md: a name and a one-line description up top, then the steps in Markdown.":`一份 SKILL.md:开头是名称和一行说明,下面用 Markdown 写步骤。`,"A raw SKILL.md link, or a GitHub folder or file page.":`SKILL.md 的原始文件链接,或 GitHub 上的文件夹/文件页面。`,"Pick a name first; a template appears here.":`先起个名字,这里会出现一份模板。`,"Attach a file":`添加附件`,Attachments:`附件`,"Say what to do with it…":`说说要拿它做什么……`,"Upload failed":`上传失败`,"Web search":`网页搜索`,"Not set up":`未设置`,"{provider} at {host}":`{provider}({host})`,"{provider} needs {what}; searches use DuckDuckGo until then":`{provider}还需要{what},在此之前搜索走 DuckDuckGo`,"a key":`一个密钥`,"an instance URL":`实例地址`,"DuckDuckGo needs nothing, but it is scraped and rate-limits now and then. For searches that always work, use a provider with an API. Whichever you pick, a failed search falls back to DuckDuckGo with a note.":`DuckDuckGo 无需任何配置,但它是抓取来的结果,偶尔会被限流。想让搜索始终可用,选一个带 API 的服务。无论选哪个,搜索失败时都会退回 DuckDuckGo 并附上说明。`,"Stored encrypted in the vault as SEARCH_API_KEY.":`加密存入保险库,名为 SEARCH_API_KEY。`,"Get a key from {label}":`到 {label} 获取密钥`,"Instance URL":`实例地址`,"A SearXNG you run, with the JSON format enabled in its settings.":`你自己运行的 SearXNG,需在其设置中启用 JSON 格式。`,"{provider} · {n} results · {ms} ms":`{provider} · {n} 条结果 · {ms} 毫秒`,"Recall by meaning":`按含义召回`,"Keyword recall only":`仅按关键词召回`,"By keyword":`按关键词`,"Not reachable":`连不上`,"Not tried yet":`尚未尝试`,Mode:`模式`,Endpoint:`接口`,"Embedding model":`向量模型`,"Same as the model":`与模型相同`,"Another endpoint":`另一个接口`,"{model} at {host}":`{model}({host})`,"{model} · {n} of {total} memories indexed":`{model} · 已索引 {n}/{total} 条记忆`,"{model} · {dims} dims · {n} memories indexed · {ms} ms":`{model} · {dims} 维 · 已索引 {n} 条记忆 · {ms} 毫秒`,"Memories are embedded once and a message finds the ones that mean the same thing, in any language: “写邮件给房东” finds “the landlord is Bob Li”. Keyword recall stays; the two are fused.":`每条记忆只做一次向量化,一句话就能找到含义相同的记忆,不分语言:“写邮件给房东”能找到“the landlord is Bob Li”。关键词召回仍然保留,两者合并排序。`,"Auto uses the model's endpoint when it has embeddings and falls back to keywords when it does not. On insists and warns. Off: keywords only.":`自动:模型接口支持向量化就用,不支持就退回关键词。开:坚持使用,失败时给出警告。关:只用关键词。`,"Any OpenAI-compatible /embeddings: Ollama with an embedding model pulled, OpenAI, a gateway.":`任何 OpenAI 兼容的 /embeddings 接口:拉取了向量模型的 Ollama、OpenAI、网关。`,"The model's endpoint and key. DeepSeek has no embeddings; pick another endpoint.":`使用模型自己的接口和密钥。DeepSeek 没有向量化接口,请选另一个接口。`,"Stored encrypted in the vault as EMBEDDINGS_API_KEY. Ollama needs none.":`加密存在保险库里,名为 EMBEDDINGS_API_KEY。Ollama 不需要密钥。`,"Blank uses the endpoint's default: {model}. On Ollama: ollama pull qwen3-embedding:0.6b (reads Chinese and English).":`留空则用该接口的默认模型:{model}。Ollama 上:ollama pull qwen3-embedding:0.6b(中英文都能读)。`,Phone:`手机`,"{name} is connected":`{name} 已连接`,"A phone":`一台手机`,"No phone connected. Open the app on the phone":`没有连接的手机。在手机上打开 App`,"Tap, type and swipe in the apps on your phone":`在你手机上的 App 里点击、输入、滑动`,Waiting:`等待中`,"Operate the phone":`操作手机`,"When on, the agent can read the screen and act in the apps on the connected phone: 12306, WeChat, Alipay… It asks before paying, sending or deleting.":`打开后,智能体可以读取已连接手机的屏幕,并在上面的 App 里操作:12306、微信、支付宝……付款、发送、删除之前会先问你。`,"{name} ({platform}), {n} apps":`{name}({platform}),{n} 个 App`,Ready:`就绪`,"Not yet":`还没开`,"Not on this Android":`这个安卓版本不支持`,"Operating the screen needs Android 11 or newer; this phone can still be used for everything else.":`操作屏幕需要 Android 11 或更新;其他功能这台手机都能用。`,"Turn on the nanoMuse accessibility service; that is how it sees the screen and taps for you, only while a task runs, with a Stop button on screen.":`打开 nanoMuse 的无障碍服务,它靠这个看屏幕、替你点击,只在任务进行时工作,屏幕上始终有停止按钮。`,"Open Accessibility settings":`打开无障碍设置`,"App settings":`应用设置`,"Greyed out with “Restricted setting”? Android 13+ does that for apps installed from a download: in App settings tap ⋮ → Allow restricted settings, then come back.":`灰色且提示「受限设置」?Android 13+ 对下载安装的应用会这样:在应用设置里点 ⋮ → 允许受限设置,再回来。`,"Android may switch the service off after an update or a battery clean-up; if the phone stops answering, come back here.":`系统更新或电池清理后安卓可能会把服务关掉;手机不再响应时回到这里看看。`,"On the phone's screen: {gui} of {total} steps ({pct}%). The screen is the last resort; a skill, a fetch or the browser comes first.":`在手机屏幕上操作:{total} 步里有 {gui} 步({pct}%)。屏幕是最后一招,技能、抓取、浏览器优先。`,"last seen in {app}":`上次看到在 {app}`,"The operator's model looks at screens step by step: a small, fast model that takes pictures. The Hands model row under Chat model picks one on the same endpoint and key; the fields here are for a different endpoint. Empty = {model}.":`操作屏幕的模型一步步看截图:选一个小而快、能看图的模型。「对话模型」卡片里的「动手模型」一行在同一个接口和 key 上选;这里的字段用于另一个接口。留空 = {model}。`,"same as the chat model":`与对话模型相同`,"the chat model":`对话模型`,"Chat model":`对话模型`,"Hands model":`动手模型`,"Currently {value}":`当前为 {value}`,"The model that looks at screens when the hands run: the phone, this computer, a page the browser cannot read. Your account's hands model is {model}; the chat model above is a different pick.":`动手时看屏幕的模型:手机、这台电脑、浏览器读不了的页面。你账号的动手模型是 {model};上面的对话模型是另一项选择。`,"The model that looks at screens when the hands run: a small, fast one that takes pictures, on the same endpoint and key. Default: this provider's own hands model.":`动手时看屏幕的模型:小而快、能看图,用同一个接口和 key。默认:这个服务商自己的动手模型。`,"The model that looks at screens when the hands run. This provider has no model that sees, so the hands use your account's, {model}, unless you pick one here.":`动手时看屏幕的模型。这个服务商没有能看图的模型,所以不在这里选的话,双手用你账号里的 {model}。`,"{model} does not take pictures, so the hands would be blind with it. Pick a model that sees for them.":`{model} 不能看图,动手时会是盲的。给它选一个能看图的模型。`,"A key is in the vault; leave empty to keep it.":`保险库里已有密钥;留空则保留。`,"Set in config.toml.":`在 config.toml 里设置。`,"Leave empty to use the main model's key.":`留空则使用主模型的密钥。`,"Save and test":`保存并测试`,"The operator's model answers.":`操作手机的模型有回应。`,"A personal agent of your own. Three things to know:":`一个属于你自己的个人智能体。三件事:`,"It does things for you.":`它替你把事情做完。`,"Searches, browses, writes, books, reads mail, and hands you the result, not a list of links.":`搜索、浏览、写作、预订、读邮件,交给你的是结果,不是一堆链接。`,"It keeps working when you close the app.":`你关掉应用,它还在干活。`,"Goals move forward between your visits; it reports in the Feed and notifies you when something is worth it.":`目标在你不在的时候继续推进;它在动态里汇报,值得打扰你时才通知你。`,"It asks you first where it matters.":`要紧的事,它先问你。`,"A separate Sentinel reviews every action. Sending, paying, deleting: it stops and asks; your keys stay in a vault the model cannot read.":`独立的 Sentinel 审查每一个动作。发送、付款、删除:它会停下来问你;你的密钥放在模型读不到的保险库里。`,"Set it up":`设置一下`,"Add a model":`添加模型`,"Pick a provider and paste a key. Yours, stored in the vault.":`选一个服务商,粘贴密钥。密钥是你的,存在保险库里。`,"Connect mail, calendar, contacts":`连接邮箱、日历、通讯录`,"Connected. Tap to add more.":`已连接。点击添加更多。`,"Optional. It can read what came in, know your day, and who is who.":`可选。它就能读到来信、知道你的日程、认得谁是谁。`,Start:`开始`,"Needs a model first.":`先要有一个模型。`,"Add a model to start":`添加模型后开始`,optional:`可选`,"A line under the name, e.g. Your day, sorted.":`名字下面的一句话,例如:你的一天,安排好了。`,Tagline:`标语`,"More names":`换一批名字`,Tone:`语气`,Formal:`正式`,Casual:`随和`,Playful:`活泼`,Concise:`简洁`,"How much it says":`话说多少`,"Short replies":`回答简短`,Detailed:`详细`,"Bullet points":`要点列表`,"Anything else about how it should be":`还有什么想让它成为的样子`,"e.g. A little witty. Uses metric units. Never uses emoji.":`例如:有点风趣。用公制单位。从不用 emoji。`,"OpenAI-compatible · Chat Completions":`OpenAI 兼容 · Chat Completions`,"Responses API":`Responses API`,"Local or your own endpoint":`本地或你自己的端点`,"/v1 is added when the URL has no path.":`URL 没有路径时会自动补上 /v1。`,"The endpoint that serves /chat/completions, for example http://127.0.0.1:8000/v1.":`提供 /chat/completions 的端点,例如 http://127.0.0.1:8000/v1。`,"{n} models from the endpoint":`端点返回了 {n} 个模型`,"Asking the endpoint…":`正在询问端点…`,"Could not list the endpoint's models; these are the usual ones.":`无法列出端点的模型;这些是常见的几个。`,"Get a key from {vendor}":`去 {vendor} 获取密钥`,"No key":`无需密钥`,"No key will be sent.":`不会发送密钥。`,"Show key":`显示密钥`,"Hide key":`隐藏密钥`,"Actions {name} wants to take but cannot without you. Each one shows what will run and why; a permission you grant is bound to that exact tool and target.":`这些是 {name} 想做、但没有你点头就不能做的事。每一项都写明要运行什么、为什么;你给的许可只对那个具体的工具和对象有效。`,"Forget every permission you granted? {name} will ask again next time.":`忘掉你授予的所有权限?下次 {name} 会重新询问。`,"This phone":`这台手机`,"Keep it running":`保持运行`,"Android stops apps that seem idle. {name} runs as a foreground service and holds the phone awake only while a task runs; these switches let it keep that promise on this phone.":`安卓会停掉看起来闲着的应用。{name} 以前台服务运行,只在任务进行时让手机保持唤醒;下面这几个开关,是让它在这台手机上真能做到这一点。`,Battery:`电池`,Unrestricted:`无限制`,Optimised:`已优化`,"Optimised means Android may freeze the agent after a while with the screen off; routines and check-ins then wait until the phone wakes.":`「已优化」意味着熄屏一段时间后安卓可能冻结 Agent;例行任务和提醒要等手机醒来才跑。`,"Display over other apps":`显示在其他应用上层`,Allowed:`已允许`,"Not allowed":`未允许`,"Lets the agent bring an app to the front from the background and show its status capsule while it works in other apps.":`让 Agent 能从后台把应用调到前台,并在其他应用里工作时显示状态胶囊。`,"Alarms & reminders":`闹钟和提醒`,Exact:`精确`,Approximate:`大致`,"With exact alarms a reminder fires at the minute you named even when the phone is asleep; without them Android may deliver it up to a quarter of an hour late.":`有精确闹钟,提醒会在你说的那一分钟响起,哪怕手机在睡眠;没有的话安卓可能晚最多一刻钟送达。`,"Start after a reboot":`重启后自动启动`,"Bring the runtime back when the phone restarts, so routines and check-ins do not stop.":`手机重启后把运行时带回来,例行任务和提醒不中断。`,"Reconnect to your computer when the phone restarts, so approvals keep arriving.":`手机重启后重新连上你的电脑,审批照常送达。`,"On this phone's Android":`这台手机的安卓系统`,"Open the auto-start settings":`打开自启动设置`,"Xiaomi / Redmi / POCO: Settings → Apps → Manage apps → {name} → Autostart on; Battery saver → No restrictions; Other permissions → Display pop-up windows while running in the background on.":`小米 / Redmi / POCO:设置 → 应用设置 → 应用管理 → {name} → 自启动打开;省电策略 → 无限制;其他权限 → 后台弹出界面 允许。`,"Huawei: Settings → Battery → App launch → {name} → Manage manually, all three on (auto-launch, secondary launch, run in background); Settings → Apps → {name} → Battery → Launch: manage manually.":`华为:设置 → 电池 → 应用启动管理 → {name} → 手动管理,三项全开(自动启动、关联启动、后台活动);设置 → 应用 → {name} → 电池 → 启动管理:手动管理。`,"Honor: Settings → Battery → App launch → {name} → Manage manually, all three on; Battery → More battery settings → Stay connected while asleep on.":`荣耀:设置 → 电池 → 应用启动管理 → {name} → 手动管理,三项全开;电池 → 更多电池设置 → 休眠时始终保持网络连接 打开。`,"OPPO / realme / OnePlus: Settings → Battery → More settings → Optimise battery use → {name} → Don't optimise; Settings → Apps → {name} → Battery usage → Allow background activity, Allow auto launch.":`OPPO / realme / 一加:设置 → 电池 → 更多设置 → 应用耗电优化 → {name} → 不优化;设置 → 应用 → {name} → 耗电管理 → 允许后台活动、允许自动启动。`,"vivo / iQOO: i Manager → App manager → Autostart → {name} on; Settings → Battery → Background power consumption management → {name} → Allow high background power consumption.":`vivo / iQOO:i 管家 → 应用管理 → 自启动 → {name} 打开;设置 → 电池 → 后台耗电管理 → {name} → 允许后台高耗电。`,"Samsung: Settings → Battery → Background usage limits → {name} not in Sleeping or Deep sleeping apps (add it to Never sleeping apps); turn off Adaptive battery if it keeps stopping.":`三星:设置 → 电池 → 后台使用限制 → {name} 不在「休眠应用」或「深度休眠应用」里(加入「永不休眠的应用」);如果还是被停,关闭自适应电池。`,"Meizu: Settings → Apps → {name} → Background management → Keep running in the background; Battery → App power management → Allow.":`魅族:设置 → 应用管理 → {name} → 后台管理 → 允许后台运行;电池 → 应用耗电管理 → 允许。`,"Crashes are written to a file on this phone and nowhere else. Export bundles them with the runtime's log for someone you choose.":`崩溃只写到这台手机上的文件里,不上报任何地方。导出会把它们和运行时日志打成一个包,发给你选的人。`,"Export logs":`导出日志`,"clipboard, notifications, calendar, contacts, location, alarms, photos":`剪贴板、通知、日历、通讯录、位置、闹钟、照片`,Devices:`设备`,"Only this one":`只有这一台`,Idle:`空闲`,"A chat addressed to a device runs there; you see every step here and answer its approvals.":`对着某台设备的对话在那台设备上执行;每一步都在这里看得到,审批也在这里答。`,"nanoMuse Cloud":`nanoMuse Cloud`,"Free. One account for all your devices, and a model to start with.":`免费。一个账号连起你所有设备,还附带一个可以先用起来的模型。`,"Signed in":`已登录`,"Not signed in":`未登录`,"Not signed in.":`未登录。`,"Signed out":`已退出`,"{hint} · hub":`{hint} · 中继`,"{hint} · model and hub":`{hint} · 模型和中继`,"Signed in as {hint}. Your devices meet here; the Cloud model comes with a free allowance.":`已登录:{hint}。你的设备在这里互相看见;Cloud 模型自带一份免费额度。`,"Use the Cloud model":`使用 Cloud 模型`,"The Cloud model is in use.":`已切换到 Cloud 模型。`,"Sign out":`退出登录`,"Sign out of nanoMuse Cloud on this device? The hub and the Cloud model stop working here until you sign in again.":`在这台设备上退出 nanoMuse Cloud?重新登录之前,这里的中继和 Cloud 模型都会停用。`,"Mainland China phone number or e-mail":`中国大陆手机号或邮箱`,"138 0000 0000 or you@example.com":`138 0000 0000 或 you@example.com`,"One free account. It is what lets your phone and computers work as one and brings a model to start with.":`一个免费账号。有了它,手机和电脑就是同一个 nanoMuse,还自带一个可以先用起来的模型。`,"It uses your phone and computers for you":`替你操作手机和电脑`,"The relay keeps an account id, a masked identifier, usage counts and your agent's name and look; what else, and what is yours to switch off, is in the":`中继保存账号 id、打码后的手机号或邮箱、用量计数和你的智能体的名字与形象;其余保存什么、哪些由你决定,见`,"privacy policy":`隐私政策`,"Free, open source, non-profit":`免费、开源、非营利`,"nanoMuse is a non-profit open-source community project, free forever.":`nanoMuse 是非营利的开源社区项目,永久免费。`,"Chat apps":`聊天入口`,"nanoMuse is a non-profit open-source community project, free forever. Sign in with a phone number or an e-mail and the model comes with a free allowance, paid by the developer; when it is gone, use your own key (Alibaba Cloud Bailian in mainland China, OpenRouter elsewhere). Nothing is sold; what the relay keeps is in the privacy policy, and Settings → Data controls is yours. Delete the account whenever you like.":`nanoMuse 是非营利的开源社区项目,永久免费。用手机号或邮箱登录,模型自带一份免费额度,费用由开发者承担;用完可以换自己的 key(中国大陆用阿里云百炼,海外用 OpenRouter)。数据不会出售;服务器保存什么写在隐私政策里,「设置 → 数据控制」由你决定。账号随时可以删除。`,"The people building it use it every day. Report a bug, ask for a feature, send a pull request: that is what moves the project. A star on GitHub helps others find it.":`做它的人每天都在用。欢迎反馈问题、提需求、贡献代码,项目就是这样往前走的。在 GitHub 点个 Star,能让更多人找到它。`,"Star on GitHub":`去 GitHub 点个 Star`,"Report a bug or ask for a feature":`反馈问题 / 提需求`,"Data controls":`数据控制`,"Help improve nanoMuse's AI models":`帮助改进 nanoMuse 的 AI 模型`,"While this is on, the text of your chats with the nanoMuse Cloud models (what you wrote, what it answered and the tools it chose to call) is kept on the relay to train the community's own open model. Not your memory or SOUL (the system prompt), not what tools returned, not pictures, and never next to who you are. Your own API key never passes through the relay.":`开启后,你与 nanoMuse Cloud 模型对话的文字(你写的、它回答的,以及它选择调用的工具)会保存在中继上,用来训练社区自己的开源模型。不保存你的记忆和 SOUL(系统提示)、工具返回的内容和图片,也不和你的身份放在一起。用自己的 API key 时,对话不经过中继。`,"New accounts start with it on.":`新账号默认开启。`,"New accounts start with it off.":`新账号默认关闭。`,"Sign in to nanoMuse Cloud to use it.":`登录 nanoMuse Cloud 后可用。`,"{n} turns kept so far.":`目前已保存 {n} 轮对话。`,"{n} turns kept so far":`已保存 {n} 轮对话`,"{n} turns":`{n} 轮`,"On. Turn it off here at any time.":`已开启。随时可以在这里关闭。`,"Off. Nothing more is kept.":`已关闭。之后的对话不再保存。`,"Delete the kept conversations":`删除已保存的对话`,"Removes every turn kept from this account, whether the switch is on or off now. Turning the switch off keeps what was kept until you delete it here.":`删除这个账号已保存的全部对话,不管开关现在是开是关。只关掉开关不会删除已保存的内容,要在这里删。`,"The kept conversations are removed from the server. This cannot be undone.":`已保存的对话会从服务器上删除,不可恢复。`,"{n} turns deleted":`已删除 {n} 轮`,"Set a password":`设一个密码`,"Your account is in. With a password, your phone and your other computers sign in at once, without waiting for a code. Optional; you can set one later under Account.":`账号已登录。设了密码,手机和其他电脑就能直接登录,不用再等验证码。可选,以后也可以在「账号」里设置。`,"At least 8 characters":`至少 8 个字符`,"Set the password":`设置密码`,"Not now":`以后再说`,"I already starred":`已经点过了`,"Free allowance":`免费额度`,"left of ¥{grant}":`剩余 / 共 ¥{grant}`,"¥{spent} used{usd}; the allowance does not reset.":`已用 ¥{spent}{usd};额度不按天重置。`,"No limit on this account.":`这个账号不限额度。`,"¥{allowance} to start, +¥{invite} for each friend you invite, and +¥{invite} for them; after that, your own key keeps the model going.":`起始 ¥{allowance},每邀请一位朋友你 +¥{invite}、对方也 +¥{invite};用完后换自己的 key 继续。`,"The free allowance is used up.":`免费额度已用完。`,"The image provider is busy right now; try again in a minute.":`生图服务现在有点忙,请过一分钟再试。`,"Nearly used up: ¥{left} of ¥{grant} left.":`额度快用完了:还剩 ¥{left}(共 ¥{grant})。`,"Invite a friend (+¥{invite} for each of you) or bring your own key; your sign-in keeps working either way.":`邀请一位新用户(你和对方各 +¥{invite}),或者换成自己的 key;无论哪种,登录都不受影响。`,"See the ways":`看看怎么办`,Dismiss:`关闭`,"Three ways on; your sign-in and your devices keep working whichever you pick.":`三个办法继续用;无论选哪个,登录和多设备功能都不受影响。`,"Use your own model key":`换成自己的 key`,"Alibaba Cloud Bailian is a good start: a new account comes with a free quota, set-up takes about two minutes, and one key covers chat, the hands, pictures and clips.":`推荐阿里云百炼:新用户有免费额度,开通约 2 分钟,一个 key 就能对话、动手、画图、生成视频。`,"Alibaba Cloud Bailian only signs up accounts from mainland China. Outside, OpenRouter is the easy way: one account, one key, pay as you go, for chat, the hands and pictures; clips need Bailian.":`海外用户用不了百炼,推荐 OpenRouter:一个账号一把 key,按量付费,对话、动手、画图都行;生成视频需要百炼。`,"Other providers and what each key covers":`其他服务商,以及各自的 key 能做什么`,"Get a key":`去申请 key`,"covers {list}":`支持{list}`,", ":`、`," or ":`或`,"Sign in with a plan you already pay for":`用你已经在付费的套餐登录`,"{plans}: the plan's models answer here, no key to make. ChatGPT works on every device, the others on the phones. A ChatGPT sign-in covers chat and the hands; pictures and clips still want a key.":`{plans}:套餐里的模型直接在这里回答,不用申请 key。ChatGPT 在每台设备上都可以,其他的在手机上。ChatGPT 登录只覆盖对话和动手;画图和生成视频仍需要一把 key。`,"Sign in with ChatGPT":`用 ChatGPT 登录`,"Or sign in with a ChatGPT plan":`或者用 ChatGPT 套餐登录`,"Covers chat and the hands. Pictures and clips are not part of it; those need a provider with image or video models.":`覆盖对话和动手。画图和生成视频不在其中,那两项需要一个有图像或视频模型的服务商。`,"OpenAI's terms cover using a ChatGPT plan inside OpenAI's own Codex; other apps have had this access cut off before (OpenCode, January 2026). If it stops working, an API key does.":`OpenAI 的条款只允许在它自家的 Codex 里使用 ChatGPT 套餐;其他应用曾被切断过这条路(OpenCode,2026 年 1 月)。哪天它不能用了,API key 仍然可以。`,"This nanoMuse has no sign-in route yet. In a terminal on this computer, run":`这个 nanoMuse 还没有登录接口。在这台电脑的终端里运行`,"and reload this page.":`然后刷新本页。`,"Signed in with {label}.":`已用 {label} 登录。`,"Use it for the chat":`让它来回答对话`,"Sign out of ChatGPT":`退出 ChatGPT`,"A page from OpenAI opened in a new tab. Sign in there; this card follows on its own.":`已在新标签页打开 OpenAI 的页面。在那里登录,这张卡片会自己跟上。`,"Open the page again":`再次打开页面`,"The sign-in did not finish in ten minutes. Try again.":`登录十分钟内没有完成。再试一次。`,"A page from OpenAI opened in a new tab. Sign in there; when the browser ends on an address that will not load, paste that address below.":`已在新标签页打开 OpenAI 的页面。在那里登录;浏览器最后停在一个打不开的地址时,把那个地址粘贴到下面。`,"The address the browser ended on":`浏览器最后停在的地址`,"Use this address":`用这个地址`,"This nanoMuse runs where the browser cannot reach port 1455, so it cannot pick the sign-in up by itself.":`这个 nanoMuse 运行的机器上,浏览器连不到 1455 端口,所以它没法自己接住登录结果。`,"That address belongs to another sign-in attempt. Open the page again and paste the address it ends on.":`这个地址属于另一次登录尝试。再次打开页面,粘贴它最后停在的地址。`,"ChatGPT answers the chat now.":`现在由 ChatGPT 回答对话。`,"Pictures need a provider with image models: {providers}.":`画图需要一个有图像模型的服务商:{providers}。`,"Clips need a provider with video models: {providers}.":`生成视频需要一个有视频模型的服务商:{providers}。`,"The hands need a model that sees pictures: {providers}.":`动手需要一个能看图的模型:{providers}。`,"Chat needs a model: {providers}.":`对话需要一个模型:{providers}。`,How:`怎么做`,"Automatic · {model}":`自动 · {model}`,"E-mail (or a mainland China phone number)":`邮箱(或中国大陆手机号)`,"Text-message codes reach mainland-China numbers only. Use an e-mail address instead.":`短信验证码只能发到中国大陆手机号。其他地区请用邮箱登录。`,"Step-by-step guide":`图文教程`,"Invite a friend: +¥{bonus} for you and +¥{bonus} for them, for each new person who signs up with your link.":`邀请朋友:每有一位新用户通过你的链接注册,你 +¥{bonus},对方也 +¥{bonus}。`,"Your invite link is under Account":`邀请链接在「账号」页`,"Try nanoMuse with me, a fully open-source personal agent, free to use. Sign up with my link: {link}":`来和我一起用 nanoMuse,完全开源的个人智能体,免费使用。用我的链接注册:{link}`,"Invite code (optional)":`邀请码(选填)`,"A friend's code counts for a new account: you both get ¥{invite} more allowance.":`朋友的邀请码只对新账号有效:你和对方的额度各 +¥{invite}。`,"Have an invite code?":`有邀请码?`,"Invite a friend":`邀请朋友`,"Each new person who signs up with your code adds ¥{bonus} to your allowance, and ¥{bonus} to theirs. It never expires.":`每有一位新用户用你的邀请码注册,你的额度 +¥{bonus},对方也 +¥{bonus},不过期。`,"Your code":`邀请码`,Copied:`已复制`,"Share the link":`分享链接`,"Copy the link":`复制链接`,"Try nanoMuse with me, a fully open-source personal agent, free to use. Sign up with my code {code}: {link}":`来和我一起用 nanoMuse,完全开源的个人智能体,免费使用。用我的邀请码 {code} 注册:{link}`,"{n} friends joined":`已邀请 {n} 位`,"¥{amount} added by invitations":`邀请带来 ¥{amount}`,"The code you received":`收到的验证码`,"Send again":`重新发送`,"Send me a code":`发送验证码`,"Sign in":`登录`,"Sign in and use its model":`登录并使用它的模型`,"Signed in to nanoMuse Cloud.":`已登录 nanoMuse Cloud。`,"Or bring your own key":`或者用你自己的密钥`,"This device":`这台设备`,"A name your other devices will see":`其他设备看到的名字`,"On the hub":`已连上中继`,"Reachable by your other devices while this runs.":`运行期间,你的其他设备可以找到它。`,"Sign in first.":`先登录。`,"My other devices may operate it":`允许我的其他设备操作它`,"They can run commands, read files and see its screen here; each step still goes through the Sentinel.":`其他设备可以在这里运行命令、读文件、看屏幕;每一步仍经 Sentinel 审核。`,Refused:`被拒绝`,"Connecting…":`连接中…`,"Connecting to the hub…":`正在连接中继…`,"The hub refused this device. Sign in again.":`中继拒绝了这台设备。请重新登录。`,"The hub is off on this device.":`这台设备没有开启中继。`,"Sign in above to see them.":`先在上面登录,就能看到。`,"{n} online":`{n} 台在线`,online:`在线`,Ask:`去问它`,"Ask one of your devices":`让某台设备去做`,"Every device signed in to your account is a Muse of its own, on the same conversations. Type @ and a device's name in the chat to hand it work; a computer lends its hands.":`登录你账号的每台设备都是一个自己的 Muse,看到的是同一批对话。在聊天里输入 @ 加设备名,就能把活交给它;电脑还能出借它的双手。`,"1 device":`1 台设备`,"{n} devices":`{n} 台设备`,"Other devices":`其他设备`,Online:`在线`,"Last seen {when}":`最后在线 {when}`,Tasks:`任务`,Commands:`命令`,Screenshot:`截屏`,"Open links":`打开链接`,Hands:`双手`,"More about {name}":`{name} 的更多操作`,"Forget this device":`移除这台设备`,"Type @{name} in the chat to hand it work.":`在聊天里输入 @{name},就能把活交给它。`,"Add a device":`添加一台设备`,"No other device yet":`还没有其他设备`,"Install nanoMuse on your phone, Mac or PC and sign in as {hint}; it appears here on its own.":`在手机、Mac 或 PC 上安装 nanoMuse,用 {hint} 登录,它就会自己出现在这里。`,"Install nanoMuse on your phone, Mac or PC and sign in with the same account; it appears here on its own.":`在手机、Mac 或 PC 上安装 nanoMuse,用同一个账号登录,它就会自己出现在这里。`,"Get the apps":`下载应用`,"Forget {name}? It can join again by signing in.":`忘掉 {name}?它重新登录后还可以加入。`,"on {device}":`在 {device} 上`,"from {device}":`来自 {device}`,"asked from {device}":`从 {device} 发来`,"{name} on {device} wants to":`{device} 上的 {name} 想要`,"Hands on this computer":`操作这台电脑`,"On the screen now":`正在操作屏幕`,"Nothing can drive this screen yet.":`目前没有能驱动这块屏幕的组件。`,'On a Mac, allow nanoMuse under System Settings → Privacy & Security → Accessibility and Screen Recording when macOS asks; without them clicks do nothing and the screenshot is black. The first action in each app asks you once ("Let {name} use Safari?") and the answer is kept under Permissions.':`Mac 上,macOS 弹窗询问时请在「系统设置 → 隐私与安全性」的「辅助功能」和「屏幕录制」里允许 nanoMuse;不允许的话点击没有反应,截图也是黑的。每个应用的第一步会先问你一次(「让 {name} 使用 Safari 吗?」),答复记在「权限」里。`,Where:`范围`,"One window":`单个窗口`,"Whole screen":`整个屏幕`,"Working in {app}'s window; the mouse stays yours.":`正在 {app} 的窗口里操作;鼠标仍归你用。`,"On the whole screen for now: {reason}":`暂时在整个屏幕上操作:{reason}`,"One window: the hands work inside the app they were given, send clicks and keys to it alone and leave your mouse alone. Whole screen: the system mouse, like other platforms. Auto picks one window as soon as an app is named.":`单个窗口:只在指定的应用里操作,点击和按键只发给它,不动你的鼠标。整个屏幕:用系统鼠标,和其他平台一样。自动:一旦指定了应用就用单个窗口。`,"It looks at a screenshot and clicks by position; paying, sending and deleting ask you first.":`它看截图、按位置点击;支付、发送、删除前都会先问你。`,Driver:`驱动`,Working:`工作中`,"Stop the hands":`停止操作`,"{name} is using this computer":`{name} 正在操作这台电脑`,"Hands done":`操作完成`,"Hands stopped":`操作已停止`,"{n} steps":`{n} 步`,Clicked:`点击`,"Clicked {label}":`点击了 {label}`,"Double-clicked":`双击`,"Double-clicked {label}":`双击了 {label}`,"Right-clicked":`右键点击`,"Right-clicked {label}":`右键点击了 {label}`,"Pointed at {label}":`指向了 {label}`,"Moved the mouse":`移动了鼠标`,"Typed {n} characters":`输入了 {n} 个字符`,"Pressed {keys}":`按下了 {keys}`,Scrolled:`滚动`,Dragged:`拖动`,"Opened {label}":`打开了 {label}`,"Opened an application":`打开了一个应用`,Waited:`等待`,"The dragon":`小龙`,"The face drawn for you":`为你画的形象`,"Draw four":`画四张`,send_email:`发邮件`,shell:`运行命令`,"E-mail, calendar, browser, MCP servers":`邮件、日历、浏览器、MCP 服务器`,"Rename this device":`给这台设备改名`,"Use my own API key or a plan I pay for":`用我自己的 API key,或我在付费的套餐`,"{first} first, then {others}":`首选 {first},其次 {others}`,"DeepSeek, Kimi, OpenAI, ChatGPT…":`DeepSeek、Kimi、OpenAI、ChatGPT…`,"OpenAI, ChatGPT, Gemini, DeepSeek…":`OpenAI、ChatGPT、Gemini、DeepSeek…`,"Which model answers?":`让哪个模型来回答?`,"Your account already brings one. You can add your own API key as well and switch at any time.":`你的账号已经自带了一个。也可以加上自己的 API key,随时切换。`,"DeepSeek for the chat and Qwen for the hands, with a free allowance per account paid by the developer. Nothing to configure.":`对话用 DeepSeek,动手用 Qwen;每个账号都有一份由开发者承担的免费额度,不用配置。`,"I have my own API key":`我有自己的 API key`,"Alibaba Cloud Bailian first (one key covers chat, the hands, pictures and clips), then DeepSeek, Kimi, Zhipu, OpenAI, OpenRouter and any OpenAI-compatible endpoint. The key stays on this device.":`首选阿里云百炼(一个 key 就能对话、动手、画图、生成视频),其次是 DeepSeek、Kimi、智谱、OpenAI、OpenRouter,以及任何兼容 OpenAI 接口的服务。key 只留在这台设备上。`,"OpenRouter first (one account, one key, pay as you go), then OpenAI, Anthropic, Gemini, DeepSeek and any OpenAI-compatible endpoint. The key stays on this device.":`首选 OpenRouter(一个账号一把 key,按量付费),其次是 OpenAI、Anthropic、Gemini、DeepSeek,以及任何兼容 OpenAI 接口的服务。key 只留在这台设备上。`,"A ChatGPT plan signs in from Connections and answers the chat and the hands. Pictures and clips still want a key.":`ChatGPT 套餐可在「连接」里登录,回答对话并驱动双手。画图和生成视频仍需要一把 key。`,"3D toy (Muse)":`3D 玩偶(Muse)`,Flat:`扁平`,"3D clay":`3D 黏土`,Watercolour:`水彩`,Pixel:`像素`,Line:`线条`,Sticker:`贴纸`,Draw:`画`,"Making pictures":`生成图片`,"Making clips":`生成视频`,"Portraits of your Muse.":`形象的肖像。`,"Short clips of your Muse.":`形象的短视频。`,"The chat model's provider":`对话模型的服务商`,"Your key":`你的 key`,"Add a provider":`添加服务商`,"Other OpenAI-compatible endpoint":`其他 OpenAI 兼容接口`,"The endpoint that serves /images/generations, for example https://host/v1.":`提供 /images/generations 的接口,例如 https://host/v1。`,"Stored encrypted in the vault as {name}.":`以 {name} 加密存储在保险库中。`,"Uses the chat model's key.":`用对话模型的 key。`,"Your phone can now operate this computer: run commands, fetch files, hand over whole tasks. Each risky step still asks here first.":`你的手机现在可以操作这台电脑了:跑命令、取文件、把整件事交给它。有风险的每一步仍会先在这里问你。`,"Picture model":`图片模型`,"Clip model":`短片模型`,"Other model…":`其他模型…`,"More models on your account":`账号可用的更多模型`,"Search models":`搜索模型`,"No model matches":`没有匹配的模型`,"reads pictures":`能看图`,"Type a model id…":`手动输入模型 id…`,"Pick from the list":`从列表里选`,"{n} models your account may use: the menu first, then everything else the provider lists under the Cloud key. Pick one; the ones beyond the menu are priced as the dearest menu model of their kind.":`账号可用的模型共 {n} 个:先是菜单,然后是服务商在 Cloud 这把 key 下列出的其他模型。直接选就行;菜单之外的按同类里最贵的菜单模型计费。`,"Your account may name any model the provider has, not only these: type its id (a chat model here, a picture or clip model below) and it goes through as typed.":`你的账号可以使用服务商的任意模型,不限于这几个:直接输入模型 id(对话模型填在这里,图片或短片模型填在下面),会原样转发。`,Automatic:`自动`,"{n} pictures":`{n} 张图`,"{n} pictures and {c} clips":`{n} 张图加 {c} 段短片`,"{what}, made with your own key at your provider's prices.":`{what},用你自己的 key 按服务商价格计费。`,"The cost could not be checked: {error}":`费用暂时查不到:{error}`,"Checking the cost…":`正在查费用…`,"About ¥{cny} for {what}; your account has no limit.":`{what}约 ¥{cny};你的账号没有额度限制。`,"About ¥{cny} for {what}, more than the ¥{left} left in your allowance.":`{what}约 ¥{cny},超过了额度里剩下的 ¥{left}。`,"About ¥{cny} for {what}; ¥{left} left in your allowance.":`{what}约 ¥{cny};额度还剩 ¥{left}。`,"A new look for {name}":`给{name}换个形象`,"Drawing four to choose from…":`正在画四个供你挑选…`,"Pick one: tap it, or say which":`选一个:点它,或者说第几个`,"Drawing the poses…":`正在画各种姿态…`,"The new look is on; making the clips…":`新形象已经换上,正在做短片…`,"The new look is on":`新形象已经换上`,"Not this time":`这次先不换`,"That did not work":`没成功`,"Candidate {n}":`第 {n} 个`,Redraw:`重画一组`,"Idle, working, waiting, happy, sorry: the face follows what {name} is doing.":`待机、工作、等待、开心、抱歉:形象会跟着 {name} 正在做的事变化。`,"Four more pictures from the one you picked; this takes a minute or two.":`根据你选的这张再画四张;需要一两分钟。`,"Some poses could not be drawn and show the idle picture instead.":`有几个姿态没画出来,先用待机图代替。`,"The face is already on; four short clips are being made from the poses, a few minutes.":`形象已经换上了;正在根据这几张姿态图做四段短片,需要几分钟。`,"Some clips could not be made; those moods stay still.":`有几段短片没做出来,这些状态就用静态图。`,"The new look is on; the clips are being made.":`新形象已经换上;短片正在做。`,"The new look is on.":`新形象已经换上。`,"Not this time.":`这次先不换。`,"New look: {description}. Say what to change any time, or pick another under Settings.":`新形象:{description}。想改随时说,也可以在「设置」里换别的。`,"Join the hub":`加入中继`,"This chat goes to {device}.":`这个对话发给 {device}。`,"Whatever you ask here, the {name} on {device} does where it is: its shell, its files, its screen. Every step shows up here, and anything that needs an approval asks you here.":`在这里说的每件事,都由 {device} 上的 {name} 在它那边完成:它的命令行、它的文件、它的屏幕。每一步都显示在这里,需要批准的事也在这里问你。`,"What is on your screen right now?":`你屏幕上现在是什么?`,"Which folder are you in, and what is in it?":`你在哪个目录,里面有什么?`,"Check for updates and tell me what needs a restart":`检查一下更新,告诉我哪些需要重启`,Account:`账号`,"Account deleted.":`账号已删除。`,"Account id":`账号 ID`,"Sign in to nanoMuse Cloud":`登录 nanoMuse Cloud`,"Sign in to {name}":`登录 {name}`,"nanoMuse Cloud · one account for all your devices":`nanoMuse Cloud · 一个账号,所有设备`,"Every device of yours, one nanoMuse":`你的每台设备,同一个 nanoMuse`,"A model with a free allowance, or your own key":`自带免费额度的模型,或用你自己的 key`,"Keys in your vault; nothing you say is kept on the relay":`key 留在你的保险库里;你说的内容不会留在中继上`,"Free. One account for all your devices, with a model and ¥{allowance} of use to start; a code the first time, a password afterwards if you like.":`免费。一个账号连起你所有设备,自带模型和 ¥{allowance} 的起始额度;第一次用验证码登录,之后可以设密码。`,"With a code":`验证码登录`,"With a password":`密码登录`,"No password yet? Use a code first; set one under Account.":`还没有密码?先用验证码登录,再到「账号」里设置。`,"E-mail":`邮箱`,"Mobile number":`手机号`,"since {date}":`{date} 起`,Unlimited:`不限量`,"All time":`累计`,Usage:`用量`,"Every kind of use is counted, not just the chat model.":`每一类用量都会统计,不只是对话模型。`,Pictures:`图片`,Clips:`视频`,Calls:`通话`,"Nothing yet":`还没有`,"{n} answers · {tokens} tokens":`{n} 次回答 · {tokens} tokens`,"{n} requests · {tokens} tokens":`{n} 次请求 · {tokens} tokens`,"{n} requests":`{n} 次请求`,"By model, all time":`按模型(累计)`,"A password is set":`已设置密码`,"No password yet":`还没有密码`,"Sign in with it on a new device, or with a code as before.":`新设备可以用密码登录,也可以像以前一样用验证码。`,"Optional. With one, a new device can sign in without waiting for a code.":`可选。设置后,新设备不用等验证码就能登录。`,Change:`修改`,Set:`设置`,"Current password":`当前密码`,"New password (8 characters or more)":`新密码(至少 8 位)`,"Once more":`再输一次`,"The two do not match.":`两次输入不一致。`,"Change password":`修改密码`,"Set password":`设置密码`,"Password set.":`密码已设置。`,"Password changed.":`密码已修改。`,"Password removed.":`密码已移除。`,"Signed in on":`已登录的设备`,"Unnamed device":`未命名设备`,"This one":`本机`,code:`验证码`,password:`密码`,"used {when}":`{when}用过`,"Sign out {device}? It will need to sign in again.":`让 {device} 退出登录?它需要重新登录。`,"Recent activity":`最近动态`,"Show all {n}":`全部 {n} 条`,"Show less":`收起`,"Account created":`账号已创建`,"Signed in with a code":`用验证码登录`,"Signed in with the password":`用密码登录`,"A sign-in attempt failed":`一次登录失败`,"Signed out everywhere":`已在所有设备退出`,"Password removed":`密码已移除`,"Password changed":`密码已修改`,"Password set":`密码已设置`,"A request was refused: the allowance is used up":`一次请求被拒绝:免费额度已用完`,"Call ended":`通话结束`,"The model provider returned an error":`模型服务返回了错误`,"Allowance added":`额度已增加`,"Allowance adjusted":`额度已调整`,"Signed up with a friend's code":`用朋友的邀请码注册`,"A friend signed up with your code":`一位朋友用你的邀请码注册`,"An invite code was not recognised":`邀请码无法识别`,"Data controls: on for new accounts":`数据控制:新账号默认开启`,"Data controls: help improve turned on":`数据控制:已开启「帮助改进」`,"Data controls: help improve turned off":`数据控制:已关闭「帮助改进」`,"Data controls: kept conversations deleted":`数据控制:已删除保存的对话`,"Agent's name and look saved":`已保存智能体的名字与形象`,"Agent's name and look cleared":`已清除智能体的名字与形象`,"Sign out everywhere":`在所有设备退出`,"Sign out on every device, including this one?":`在所有设备退出登录,包括这一台?`,"Delete the account? The relay forgets your identifier, your devices and your usage. This cannot be undone.":`删除账号?中继会忘掉你的标识、设备和用量记录,且无法恢复。`,"Really delete it?":`真的要删除吗?`,"Signed out.":`已退出登录。`,"Delete the account":`删除账号`,"The Cloud model is in use; after signing out, pick another under Connections.":`当前使用的是 Cloud 模型;退出后请到「连接」里换一个。`,"{n} min ago":`{n} 分钟前`,"{n} h ago":`{n} 小时前`,"{n} d ago":`{n} 天前`,"Use the nanoMuse Cloud model":`使用 nanoMuse Cloud 模型`,"Signed in as {hint}. A free allowance, nothing to paste. Recommended to start.":`已登录 {hint}。自带免费额度,无需粘贴任何 key,推荐先用它。`,"Your account brings a model with a free allowance, nothing to set up. Or paste a key of your own; it is stored encrypted in the vault on the server, never shown to the model, and nothing you say passes through the relay.":`你的账号自带一个有免费额度的模型,不用再设置什么。也可以粘贴自己的 key:它加密存在服务端的保险库里,不会给模型看到,你说的内容也不经过中继。`,"Voice input":`语音输入`,"Stop voice input":`停止语音输入`,"The microphone is not allowed. Allow it in the browser and try again.":`没有拿到麦克风权限。在浏览器里允许后再试一次。`,"Voice input stopped ({code}).":`语音输入中断了({code})。`,"said on a call":`通话中说的`,"Coding agents":`编程助手`,"Cursor, Codex and Claude Code: see what they are doing, and tell them things from anywhere.":`Cursor、Codex 和 Claude Code:随时看它们在做什么,在任何地方给它们发消息。`,Coding:`编程`,"This computer":`这台电脑`,"This one · {name}":`本机 · {name}`,installed:`已安装`,"chats only":`仅记录`,"not found":`未找到`,"{agent} chats":`{agent} 的对话`,"Recent chats":`最近的对话`,"New chat":`新对话`,"No coding agent found on this computer. Install Cursor, Codex or Claude Code and their chats appear here.":`这台电脑上没有找到编程助手。安装 Cursor、Codex 或 Claude Code 后,它们的对话会出现在这里。`,"No chats yet.":`还没有对话。`,"Untitled chat":`未命名对话`,"{n} messages":`{n} 条消息`,"Sent through nanoMuse":`经 nanoMuse 发送的`,stopped:`已停止`,"Sent to {agent}.":`已发给 {agent}。`,"{agent} is working…":`{agent} 正在处理…`,"Tell {agent}…":`对 {agent} 说…`,"Nothing readable in this chat yet.":`这个对话里还没有可读的内容。`,"via nanoMuse":`经 nanoMuse`,"Continued as a new chat: the agent could not reopen the old one.":`原来的对话打不开了,已经另起一个新对话接着聊。`,"Made in the IDE: your message starts a new chat in the same workspace, with the last exchange quoted.":`这是 IDE 里的对话:你的消息会在同一工作区开一个新对话,并带上上一轮的内容。`,"Continue in a new chat…":`在新对话里接着说…`,"starting…":`启动中…`,"Send to {agent}":`发给 {agent}`,"Project folder":`项目目录`,"What to do":`要做什么`,"Add tests for the parser and run them":`给解析器补上测试并跑一遍`,"The agent runs on that computer with its own permissions; nanoMuse only carries the message and brings the answer back.":`助手在那台电脑上以它自己的权限运行;nanoMuse 只负责传话和带回结果。`,"The file is larger than {n} MB.":`文件超过了 {n} MB。`,"empty file":`文件是空的`,"thread is busy":`这个对话正忙`,"the main chat cannot be deleted":`主对话不能删除`,"no pending approval with that id":`这张卡片已经不在等待中`,"the device did not take the answer":`那台设备没有接受这个回答`,"already finished":`已经结束了`,"already cancelled":`已经取消了`,"memory is disabled":`记忆已关闭`,"memory is off":`记忆已关闭`,"recall by meaning is off":`按含义回忆已关闭`,"nothing proposed":`没有待处理的提议`,"that frame is gone":`这一帧已经不在了`,"no such file":`没有这个文件`,"no such post":`没有这条动态`,"no such skill of yours (built-in skills are switched off, not removed)":`没有这个你自己的技能(内置技能只能关闭,不能删除)`,"the file is larger than 16 MB":`文件超过了 16 MB`,"body too large (64 KB max)":`内容太大(最多 64 KB)`,"fill in the servers, the address and the password first":`先填好服务器、地址和密码`,"add a calendar link first":`先添加一个日历链接`,"signed out":`未登录`,"Sign in to nanoMuse Cloud first.":`请先登录 nanoMuse Cloud。`,"Enter the password.":`请输入密码。`,"The relay returned no key.":`中继没有返回 key。`,Details:`详情`,"Hide details":`收起详情`,"Today's share of the free allowance is used up; it comes back tomorrow. Your own model key under Connections keeps you going now.":`今天的免费额度用完了,明天恢复。在「连接」里填上你自己的模型 key,现在就能继续。`,"The free allowance is used up. Invite a friend (the relay adds to both your allowances) or add your own model key under Connections; your sign-in and your devices keep working either way.":`免费额度已用完。邀请一位新用户(你和对方的额度都会增加),或者在「连接」里填上自己的模型 key;无论选哪个,登录和多设备功能都不受影响。`,"The account's free allowance is used up. Add your own model key under Connections to keep going.":`这个账号的免费额度已经用完。在「连接」里填上你自己的模型 key 就能继续。`,"Too many requests at once; wait a moment and try again.":`请求太密集了,稍等一下再试。`,"The model provider is busy; try again in a moment.":`模型服务商正忙,稍后再试。`,"The model provider's content check declined this request; try different words.":`模型服务商的内容审核没有放行这次请求,换个说法再试。`,"The relay's model provider refused its key; the operator has been told. Your own key under Connections works meanwhile.":`中继的模型服务商拒绝了它的 key,运营者已收到通知。这期间可以在「连接」里用你自己的 key。`,"The model provider does not know this model right now; pick another under Connections.":`模型服务商暂时不认识这个模型,在「连接」里换一个。`,"nanoMuse Cloud has no model key configured; the operator has been told.":`nanoMuse Cloud 还没有配置模型 key,运营者已收到通知。`,"This nanoMuse Cloud account is disabled.":`这个 nanoMuse Cloud 账号已被停用。`,"The nanoMuse Cloud sign-in is no longer valid; sign in again under Account.":`nanoMuse Cloud 的登录已失效,请在「账号」里重新登录。`,"That model is not offered by nanoMuse Cloud; pick another under Connections.":`nanoMuse Cloud 不提供这个模型,在「连接」里换一个。`,"That message is too large for the model's window. Shorten it, leave out some attachments, or start a new chat.":`这条消息超出了模型的上下文窗口。精简一下、去掉部分附件,或者开一个新对话。`,"This relay takes new accounts by invitation only; sign in with an invite code under Account.":`这个中继只接受邀请注册;在「账号」里用邀请码登录。`,"Too many turns are running on this account at once; wait for one to finish and try again.":`这个账号同时进行的对话太多了,等一轮结束后再试。`,"New sign-ups are paused on this relay for now; existing accounts keep working. Try again later.":`这个中继暂时停止了新注册,已有账号照常使用。稍后再试。`,"nanoMuse Cloud is paused by its operator for now; your sign-in and your data are kept. Try again later.":`nanoMuse Cloud 被运营者暂时停用了,你的登录和数据都保留着。稍后再试。`,"Conversation sync is paused on this relay for now; what is stored is kept and your devices keep working on their own.":`这个中继暂时停止了对话同步,已存的内容保留着,各设备各自继续使用。`,"The device hub is paused on this relay for now; each device keeps working on its own.":`这个中继暂时停止了设备互联,各设备各自继续使用。`,"The free allowance is paused on this relay for now, not used up. Your own model key under Connections keeps you going; your sign-in, your devices and what is left stay as they are.":`这个中继暂时停发了免费额度,不是用完了。在「连接」里填上你自己的模型 key 就能继续;你的登录、设备和剩余额度都保持原样。`,"This demo Muse has used its share of the model for this visit. Start over for a new one, or install nanoMuse and use your own key.":`这个演示 Muse 这一次的模型额度用完了。点「重新开始」再来一个,或者安装 nanoMuse,用你自己的 key。`,"The showcase has used today's share of the model; it comes back tomorrow. Install nanoMuse and use your own key to keep going.":`在线体验今天的模型额度用完了,明天会恢复。安装 nanoMuse,用你自己的 key 可以继续。`,"The model provider is having trouble; try again in a moment.":`模型服务商出了点问题,稍后再试。`,"The model provider refused the API key. Check it under Connections.":`模型服务商拒绝了这个 API key,去「连接」里检查一下。`,"The endpoint does not know this model. Pick another under Connections.":`这个接口不认识这个模型,在「连接」里换一个。`,"The model provider is rate-limiting this key; wait a moment and try again.":`模型服务商正在限制这个 key 的请求频率,稍等一下再试。`,"The model took too long to answer. Try again.":`模型回答超时了,再试一次。`,"Could not reach the model provider. Check the connection and try again.":`连不上模型服务商,检查一下网络再试。`,"This conversation is too long for the model. Start a new one, or pick a model with a larger context.":`这段对话对模型来说太长了。开一个新对话,或者换一个上下文更大的模型。`,"Enter a phone number or an e-mail address.":`请输入手机号或邮箱。`,"Enter a mainland phone number or an e-mail address":`请输入中国大陆手机号或邮箱`,"Enter a mainland phone number or an e-mail address.":`请输入中国大陆手机号或邮箱。`,"Codes reach mainland China numbers only for now; elsewhere, sign in with an e-mail address.":`短信验证码目前只支持中国大陆手机号,海外用户请用邮箱登录。`,"That code is not right.":`验证码不对。`,"That code has expired; ask for a new one.":`验证码已过期,重新获取一个。`,"Too many codes were sent; wait a few minutes.":`验证码发得太频繁了,几分钟后再试。`,"This relay is private; that address is not on its list.":`这个中继是私有的,这个邮箱不在它的名单上。`,"The code could not be sent; try again in a moment.":`验证码没能发出,稍后再试。`,"Sign in again.":`请重新登录。`,"This account has used its tokens.":`这个账号的额度已经用完。`,"This account is disabled.":`这个账号已被停用。`,"That model is not offered here.":`这里不提供这个模型。`,"Too many requests; slow down a little.":`请求太频繁了,稍微慢一点。`,"The free allowance is used up. Invite a friend (the relay adds to both your allowances) or add your own model key; your sign-in and your devices keep working either way.":`免费额度已用完。邀请一位新用户(你和对方的额度都会增加),或者换成自己的 key;无论选哪个,登录和多设备功能都不受影响。`,"Today's token quota is used up; it comes back tomorrow.":`今天的 token 配额用完了,明天恢复。`,"The model provider did not answer.":`模型服务商没有响应。`,"nanoMuse Cloud has no model key configured.":`nanoMuse Cloud 还没有配置模型 key。`,"nanoMuse Cloud cannot be reached.":`连不上 nanoMuse Cloud。`,"That address and password do not match.":`邮箱与密码不匹配。`,"This account has no password yet; sign in with a code and set one under Account.":`这个账号还没有设置密码:先用验证码登录,再在「账号」里设置。`,"Too many wrong passwords; wait a while or sign in with a code.":`密码错误次数太多,等一会儿再试,或者改用验证码登录。`,"Use at least 8 characters.":`至少 8 个字符。`,"Choose a stronger password.":`换一个更强的密码。`,"That is not the current password.":`当前密码不正确。`,"Enter the current password.":`请输入当前密码。`,"That sign-in is already gone.":`那个登录已经不存在了。`,"Cannot reach your nanoMuse right now.":`现在连不上你的 nanoMuse。`,"Your nanoMuse hit a problem; try again in a moment.":`你的 nanoMuse 出了点问题,稍后再试。`,"Your nanoMuse could not do that.":`你的 nanoMuse 没能完成这个操作。`,"Could not reach your nanoMuse.":`连不上你的 nanoMuse。`,"Connecting to your nanoMuse…":`正在连接你的 nanoMuse…`,"Try again":`再试一次`,"Could not load.":`没能加载出来。`,"Use /{name}":`使用 /{name}`,Retry:`重试`,"Could not load the conversation. Pull to retry.":`对话没能加载出来,下拉重试。`,"Could not load the connections.":`连接信息没能加载出来。`,"Your account":`你的账号`,"your account's model, with a free allowance":`账号自带的模型,带免费额度`,"on this machine, no key":`跑在本机,不用 key`,"vLLM, LM Studio, a gateway, anything with /v1":`vLLM、LM Studio、网关,任何带 /v1 的服务`,"Your account's model":`账号自带的模型`,"Your account's model, or a key of your own.":`用账号自带的模型,或者你自己的 key。`,"Your account's model, with its free allowance. Keep it, or switch to a key of your own here.":`账号自带的模型,带免费额度。可以保留,也可以在这里换成你自己的 key。`,"Avatar studio":`形象工坊`,"Avatar studio…":`形象工坊…`,"Draw a look with your image model; it moves with what it is doing.":`用你的图像模型画一个形象;它会随着工作状态动起来。`,More:`更多`,"Name & style":`名字与风格`,"Image model":`图像模型`,"Redraw the poses":`重画状态`,"Back to the built-in look":`换回内置形象`,"Back to the built-in look.":`已换回内置形象。`,"Something went wrong":`出了点问题`,"Drawing the poses… {done}/{total}":`正在画各个状态… {done}/{total}`,"The new look is on; making the clips… {done}/{total}":`新形象已经用上;正在生成动态片段… {done}/{total}`,"All five poses are in.":`五个状态都画好了。`,"{done} of {total} poses are in; the rest show the main picture.":`画好了 {total} 个状态里的 {done} 个,其余先用主图。`,"Describe a new look":`描述一个新形象`,"One sentence is enough: what it is, what it wears, its air. Pick a style and your image model draws four to choose from.":`一句话就够:它是什么、穿什么、什么气质。选一种风格,你的图像模型会画四张让你挑。`,"a round, custard-yellow baby dragon with small orange horns and folded little wings":`一只圆滚滚的奶黄色小龙,橙色小角,折着小翅膀`,"Drawing…":`正在画…`,"Draw four more":`再画四张`,"Drawn by {provider} · {model}":`由 {provider} · {model} 绘制`,"Pick one":`挑一张`,"Draw four more any time; the old ones stay until you do.":`随时可以再画四张;没重画之前旧的会留着。`,"Use this one":`就用这个`,"Next, its poses are drawn from it in the background: working, waiting for you, done, something wrong.":`接下来会在后台以它为底画出各个状态:干活、等你、搞定、出错。`,"Keep the current look":`先不换了`,"Nothing came back.":`什么也没生成出来。`,"The pictures stay in this computer's workspace under avatar/. Each new look asks your provider for eight pictures (four to choose from and four poses) and four short clips where there is a video model.":`图片存在这台电脑的工作区 avatar/ 下。每换一次形象会向你的服务商要八张图(四张供你挑选,四个状态),有视频模型时还会生成四段短动画。`,"Or just say it in the chat: “change your avatar to a corgi”.":`也可以直接在对话里说:“把虚拟形象改成一只柯基”。`,"Change your avatar to ":`把虚拟形象改成`,"Alibaba Cloud Bailian":`阿里云百炼`,Zhipu:`智谱`,"Volcano Ark":`火山方舟`,"this computer":`这台电脑`,"Change model":`更换`,Search:`搜索`,"Search chats":`搜索对话`,"Side chats":`旁聊`,"Start a side chat":`发起旁聊`,"Side chats are an optional way to keep conversations organised by topic.":`旁聊是按主题整理对话的可选方式。`,Keep:`保留`,"No chats match.":`没有匹配的对话。`,"A side chat keeps one topic apart from the rest.":`一个旁聊,把一个话题和其他的分开。`,"Report a bug":`报告问题`,"Developer tools":`开发者工具`,Developer:`开发者`,"The Coding screen (Cursor, Codex and the other coding agents on this computer) in the sidebar, and the runtime's address below. This device only.":`在侧栏显示「编程」(这台电脑上的 Cursor、Codex 等编程智能体),并在下面显示运行时的地址。仅此设备。`,"Runtime:":`运行时:`,"the token is in the server_token file in the data folder":`令牌在数据目录的 server_token 文件里`,"The command line and the API":`命令行与 API`,"nanoMuse on DeepSeek Harness":`nanoMuse 的 DeepSeek Harness 版`,"Desktop app":`桌面应用`,"Start with the computer":`开机自动启动`,"Opens in the tray at sign-in; the agent's goals and check-ins run from then on.":`登录系统后在托盘里启动;从那时起,它的目标和定时检查就开始跑了。`,"In the tray":`托盘图标`,"The icon by the clock shows what the hands are doing and has Stop; closing the window keeps the agent running.":`时钟旁的图标显示它正在操作什么,并带「停止」;关掉窗口后它仍在后台运行。`,Shortcuts:`快捷键`,"Quick chat":`快速对话`,"Show the window":`打开窗口`,"Feed settings":`动态设置`,"About the feed":`动态版块说明`,"Your feed is driven by the instruction below. Any edit you make here applies to every post from now on.":`动态由下面这句话来定。在这里改动它,今后的每一条帖子都会照着来。`,"Build me a feed about what I care about. Keep it short and direct, easy to skim, no clickbait.":`给我做一个关于我关心的事的动态。短一点、直接一点,扫一眼就能看完,别搞标题党。`,"Got it":`知道了`,"Write it now":`现在写一版`,"Nothing in the feed yet":`动态里还没有内容`,"As we get to know each other, new posts will show up here. Every day at {time} I read what I remember about you (your memory files, the last week of diary, your goals) and write a few short posts.":`随着我们相互了解,新的帖子会显示在这里。每天 {time},我会读一遍记得的关于你的东西(记忆文件、最近一周的日记、你的目标),然后写几条简短的帖子。`,"Steer it with one sentence":`一句话就能调整`,"Tap the sliders at the top right to tell me what you want more of, switch the daily routine off, or have me write the first day now.":`点右上角的滑杆,告诉我你想多看什么、关掉每天的例程,或者让我现在就写第一天。`,"Short posts your agent writes for you from what it remembers: your memory files, the last week of diary, your goals. The sentence below steers every post from now on; edit it any time.":`这里是你的智能体为你写的短帖子,取材于它记得的东西:记忆文件、最近一周的日记、你的目标。下面这句话决定今后每一条帖子的方向,随时可以改。`,"Write it every day":`每天自动写`,"Time of day":`时间`,"Add a model first; the feed is written by your agent.":`先添加一个模型,动态由你的智能体来写。`,Discuss:`讨论`,"About this post":`这条帖子的信息`,"Delete this post":`删除这条`,Written:`写于`,Note:`随记`,Files:`文件`,Fun:`休闲`,"About this post from my feed:":`聊聊我动态里的这一条:`,"Post type":`类型`,morning:`上午`,afternoon:`下午`,evening:`晚上`,"{weekday} {part}":`{weekday}{part}`,"Starts a conversation":`会开始一段对话`,"Send to chat":`发到聊天`,"Nothing tracked yet":`尚未追踪任何内容`,"Create a goal":`创建目标`,"Pick a category and tell me the goal you have in mind. I'll shape a plan with you and keep improving it as you go.":`选一个类别,告诉我你心里的目标。我会和你一起定出计划,并在推进过程中不断调整。`,"Create a {category} goal":`创建{category}目标`,"First, we'll shape the goal together in the chat. I'll ask a few questions so I understand exactly what you're after.":`首先,我们将在聊天中一起完善目标。我会问几个问题,准确了解你的目标。`,"Once it's set, I'll track your progress here.":`目标设置后,我会在这里追踪你的进度。`,"I'd like to create a {category} goal. Ask me a few short questions, one at a time (what exactly I want, why and by when, how often to check in), then create it with concrete steps using the goals tool.":`我想创建一个{category}目标。请一次问我一个简短的问题(我具体想达成什么、为什么以及什么时候、多久检查一次),然后用 goals 工具把它建成带具体步骤的目标。`,"Mark as done":`标记为已完成`,"Mark as not done":`标记为未完成`,"Plan my week":`规划我的一周`,"Tell me what's on your plate and I'll turn it into a realistic plan with the important things first.":`告诉我你手头有什么,我把它排成一份切实可行的计划,重要的事放前面。`,"Help me plan my week. Ask me what I need to get done, then propose a schedule.":`帮我规划这一周。先问我有哪些事要做,然后给出一份日程安排。`,"Research & compare options":`调研并比较选项`,"Laptops, flights, insurance, a new phone plan: I'll gather the facts and compare them for you.":`笔记本、机票、保险、新的手机套餐,我帮你收集事实并逐项比较。`,"I need to make a purchase decision. Ask me what I'm choosing between, then research and compare the options.":`我想买个东西,拿不定主意。先问我在哪几个里面挑,然后帮我查一查、比一比。`,"Set up a long-term goal":`建立一个长期目标`,"Share a goal (learn a language, run a 10k, save for a trip) and I'll break it into steps and keep track.":`说一个目标(学一门语言、跑完 10 公里、攒一次旅行的钱),我把它拆成步骤并持续跟进。`,"I want to set up a long-term goal. Ask me about it, then create a plan with concrete steps and track it.":`我想建立一个长期目标。先问问我,然后制定一份带具体步骤的计划并跟进。`,"Tell me about yourself":`介绍一下你自己`,"The more I know about your preferences, routines and constraints, the more useful I get. I'll remember what matters.":`我越了解你的偏好、作息和限制,就越能帮上忙。重要的事我会记住。`,"Ask me a few questions about myself so you can help me better, and remember the answers.":`问我几个关于我的问题,好更了解我,然后把答案记住。`,"Build a quick tracker":`做一个简单的追踪表`,"Spending, habits, workouts, reading: I can write a small script or document to track it for you.":`开支、习惯、锻炼、阅读,我可以写一个小脚本或文档帮你记录。`,"Build me a simple tracker. Ask me what I want to track and how, then create it in the workspace.":`帮我做一个简单的追踪表。先问我想记录什么、怎么记,然后在工作区里建好。`,Artifacts:`构件`,Media:`影音内容`,"Nothing created yet":`还没有创建任何内容`,"Documents, tables and pages I write for you will show up here.":`我为你写的文档、表格和页面会显示在这里。`,"No media yet":`还没有影音内容`,"Photos, screenshots and recordings I produce will show up here.":`我生成的图片、截图和录音会显示在这里。`,"No model yet":`还没有模型`,"Add a provider and pick its models":`添加一个服务商并选择模型`,"Image & video models":`图像与视频模型`,"Name & personality":`名字与人格`,"About nanoMuse":`关于 nanoMuse`,"Privacy policy":`隐私政策`,Feedback:`反馈问题`,none:`无`,"Change avatar":`更换虚拟形象`,"Edit name":`编辑名称`,Daily:`每日`,"Soul & memory":`SOUL 与记忆`,"Handle with care":`请谨慎访问`,"This device's name":`这台设备的名字`,"Sync conversations between my devices":`在我的设备之间同步对话`,"The text of your chats is kept on nanoMuse Cloud so every device shows the same conversations. Files and images stay on the device they were made on.":`对话文字会保存在 nanoMuse Cloud,让每台设备看到同样的对话。文件和图片只留在产生它们的设备上。`,"Paused: sign in again to continue.":`已暂停:重新登录后继续。`,"{c} chats, {m} messages kept so far.":`目前保存了 {c} 个对话、{m} 条消息。`,"Delete synced conversations":`删除已同步的对话`,"{n} chats":`{n} 个对话`,"Removes what nanoMuse Cloud stores for this account; the chats on each device stay, and the switch stays on. Deleting a chat on one device deletes it on all of them.":`删除 nanoMuse Cloud 为这个账号保存的内容;每台设备上的对话保留,开关也保持打开。在一台设备上删除某个对话,会在所有设备上一起删除。`,"Off deletes the synced conversations from nanoMuse Cloud. The chats on each device stay.":`关闭后会从 nanoMuse Cloud 删除已同步的对话。每台设备上的对话保留。`,"On. Your devices show the same conversations from now on.":`已打开。从现在起,你的设备会看到同样的对话。`,"Off. Nothing is kept on nanoMuse Cloud any more.":`已关闭。nanoMuse Cloud 不再保存任何对话。`,"The synced conversations are removed from nanoMuse Cloud. The chats on each device stay. This cannot be undone.":`已同步的对话将从 nanoMuse Cloud 删除。每台设备上的对话保留。此操作无法撤销。`,"Synced conversations deleted.":`已删除已同步的对话。`,"Also sync side chats":`同时同步旁聊`,"Off: side chats stay on this device. On: this device's side chats go to the account and the other devices' side chats come here.":`关:旁聊只留在本机。开:本机的旁聊上传到账号,其他设备的旁聊也会同步过来。`,"On. This device's side chats go to the account; the other devices' are on their way.":`已打开。本机的旁聊会上传到账号,其他设备的旁聊正在同步过来。`,"Off. Side chats stay on this device from now on.":`已关闭。从现在起,旁聊只留在本机。`,"{device} is working…":`{device} 正在处理…`,"From {device}":`来自 {device}`,"to {device}":`发给 {device}`,"This goes to {device}.":`这条会发给 {device}。`,"Runs this there and reports back":`在那台设备上执行并汇报结果`,Offline:`离线`,"There is no form to fill in: once it has a model, it introduces itself in the chat and asks what to call you.":`不用填表:有了模型之后,它会在聊天里介绍自己,并问你希望怎么称呼你。`,"A model, then the chat. A minute.":`先接一个模型,再去聊天。一分钟。`,"Open the chat. It introduces itself and asks your name.":`打开聊天。它会介绍自己,并问你的名字。`,"Pick a name for me, or type one":`给我挑一个名字,或者自己输入一个`,"Something else":`自己起一个`,"Proxy (optional)":`代理(可选)`,"Only this provider's requests go through it. nanoMuse Cloud never does.":`只有这个服务商的请求走代理;nanoMuse Cloud 的请求从不经过它。`,"Talk to your Muse from the chat apps you already use. Nothing needs a public address: each app keeps a long connection open.":`在你已经在用的聊天软件里和 Muse 对话。不需要公网地址:每个应用各自保持一条长连接。`,"Waiting for a yes":`等待通过`,"{name} wrote to the bot. Approve to let them talk to your Muse.":`{name} 给机器人发了消息。通过后对方就能和 Muse 对话。`,Approve:`通过`,"Code {code}":`配对码 {code}`,"Needs settings":`还缺设置`,"Not installed":`未安装`,Error:`出错`,Missing:`缺少`,"Switched on":`已开启`,"Install on the computer running nanoMuse, then switch it on again:":`在运行 nanoMuse 的电脑上安装,再重新开启:`,"Saved.":`已保存。`,Saving:`保存中`,"Set; leave blank to keep":`已设置,留空则保持不变`,"Clear the saved value":`清除已保存的值`,"In groups, reply":`在群里回复`,"only when @-mentioned":`只在被 @ 时`,"to every message":`每条消息`,"Always allowed (ids, one per line)":`免配对的 ID(每行一个)`,"People listed here never need a pairing code. A lone * lets anyone in; do that only on a bot nobody else can reach.":`列在这里的人不需要配对码。单独一个 * 表示放行所有人,只在别人找不到的机器人上这样做。`,"Paired chats":`已配对的聊天`,"Nobody yet. Write to the bot from the app; a pairing code comes back, approve it here.":`还没有人。在聊天软件里给机器人发条消息,会收到配对码,在这里通过即可。`,"Deliver here":`推送到这里`,"Chats with “deliver here” on also get what the Muse does on its own: check-ins, reminders, the results of background work, and the questions it needs answered.":`开了「推送到这里」的聊天还会收到 Muse 主动做的事:问候、提醒、后台任务的结果,以及需要你回答的问题。`,"Remove {name}? They will need a new pairing code.":`移除 {name}?对方需要重新配对。`,"Send a test message":`发送测试消息`,Sending:`发送中`,"Create the bot by QR code":`扫码创建机器人`,"Open in Feishu":`在飞书里打开`,"Scan with Feishu, confirm the new bot, and the App ID and Secret are saved for you.":`用飞书扫码,确认创建机器人,App ID 和 Secret 会自动保存。`,"Lark (international) instead of 飞书":`用 Lark(国际版)而不是飞书`,"Waiting for the scan…":`等待扫码…`,"The bot was created and is connecting.":`机器人已创建,正在连接。`,"The login did not finish ({error}).":`登录没有完成({error})。`,"Set up":`设置步骤`,"Open the console":`打开控制台`,"Then write to the bot from the app. The first message gets a pairing code; approve it here or run":`然后在聊天软件里给机器人发消息。第一条消息会收到配对码,在这里通过,或运行`,"Each chat is one conversation of your Muse; its replies stream back as they are written.":`每个聊天对应 Muse 的一个会话;回复会边写边发回来。`,"In the Feishu developer console create a custom app and add the Bot capability.":`在飞书开放平台创建企业自建应用,添加「机器人」能力。`,"Permissions: im:message, im:message.p2p_msg:readonly, im:message.group_at_msg:readonly, im:resource.":`权限:im:message、im:message.p2p_msg:readonly、im:message.group_at_msg:readonly、im:resource。`,"Events & callbacks: subscription mode Long connection; add im.message.receive_v1; callback mode Long connection; add card.action.trigger.":`事件与回调:订阅方式选「长连接」,添加 im.message.receive_v1;回调方式选「长连接」,添加 card.action.trigger。`,"Copy App ID and App Secret from Credentials & Basic Info, then publish a version.":`在「凭证与基础信息」复制 App ID 和 App Secret,然后发布版本。`,"In the DingTalk developer console create an internal app and add the Robot capability.":`在钉钉开放平台创建企业内部应用,添加「机器人」能力。`,"Set the message receive mode to Stream.":`消息接收模式选「Stream 模式」。`,"Copy Client ID (AppKey) and Client Secret (AppSecret) from Credentials & Basic Info.":`在「凭证与基础信息」复制 Client ID(AppKey)和 Client Secret(AppSecret)。`,"Add the robot send-message permission and publish the version.":`添加机器人发消息权限,发布版本。`,"In the WeCom admin console open Intelligent robot and create a robot in API mode with a long connection.":`在企业微信管理后台打开「智能机器人」,创建 API 模式、长连接的机器人。`,"Copy the Bot ID and Secret.":`复制 Bot ID 和 Secret。`,"Add the robot to the chats where it should listen.":`把机器人加到需要它在的聊天里。`,"In Telegram talk to @BotFather, send /newbot and copy the token.":`在 Telegram 里找 @BotFather,发送 /newbot,复制 token。`,"Direct messages work at once. For a group, add the bot to it; with Group Privacy on it only hears @-mentions and replies.":`私聊立即可用。群聊需要先把机器人拉进群;开着 Group Privacy 时它只听 @ 和回复。`,"If api.telegram.org is out of reach from this computer, set a proxy below.":`如果这台电脑连不上 api.telegram.org,在下面填一个代理。`,"Use nanoMuse Cloud models":`使用 nanoMuse Cloud 模型`,"nanoMuse Cloud is one of the sources for the chat, the hands, pictures and clips; what runs on it comes off your allowance.":`nanoMuse Cloud 是聊天、双手、图片和短片的来源之一;在它上面运行的内容会消耗你的额度。`,"Off: nothing runs on nanoMuse Cloud unless you choose it yourself. You stay signed in for sync and your devices.":`关闭后,除非你自己选择,否则不会有任何内容在 nanoMuse Cloud 上运行。账号保持登录,用于同步和你的设备。`,"Add a provider of your own first; with nanoMuse Cloud off, nothing else could answer.":`先添加一个自己的服务商;关掉 nanoMuse Cloud 后没有别的模型能回答。`,"Use your own API key instead":`改用自己的 API key`,"You can sign in later under Connections, for sync and your devices.":`之后可以在「连接」里登录,用于同步和你的设备。`},ne=[{value:`auto`,label:`Auto`},{value:`en`,label:`English`},{value:`zh-CN`,label:`简体中文`}],j=`nanomuse_locale`,M={en:{},"zh-CN":A};function re(){try{let e=localStorage.getItem(j);if(e===`en`||e===`zh-CN`||e===`auto`)return e}catch{}return`auto`}var N=re(),P=new Set;function ie(){return(typeof navigator>`u`?[]:[navigator.language,...navigator.languages??[]]).some(e=>/^zh\b/i.test(e??``))?`zh-CN`:`en`}function ae(){return N}function F(){return N===`auto`?ie():N}function oe(e){N=e;try{localStorage.setItem(j,e)}catch{}se(),P.forEach(e=>e())}function se(){typeof document<`u`&&(document.documentElement.lang=F())}function ce(e){return P.add(e),()=>P.delete(e)}function le(){return(0,f.useSyncExternalStore)(ce,F,F)}function ue(){return(0,f.useSyncExternalStore)(ce,ae,ae)}function de(e,t){return t?e.replace(/\{(\w+)\}/g,(e,n)=>n in t?String(t[n]):e):e}function I(e,t){let n=M[F()];return de(n[e]??e,t)}function fe(e){let t=t=>({title:e.slice(t.length)});return e.startsWith(`Working on your goal: `)?I(`Working on your goal: {title}`,t(`Working on your goal: `)):e.startsWith(`Check-in: `)?I(`Check-in: {title}`,t(`Check-in: `)):e.startsWith(`Reminder: `)?I(`Reminder: {title}`,t(`Reminder: `)):e.startsWith(`Routine: `)?I(`Routine: {title}`,t(`Routine: `)):e.startsWith(`New mail: `)?I(`New mail: {title}`,t(`New mail: `)):e.startsWith(`Coming up: `)?I(`Coming up: {title}`,t(`Coming up: `)):e.startsWith(`Webhook: `)?I(`Webhook: {title}`,t(`Webhook: `)):e===`Tidied memory`?I(`Tidied memory`):e}function pe(e){let t=/^'([^']+)' is in always_ask_tools$/.exec(e);return t?I(`{tool} is on your always-ask list`,{tool:t[1]}):(t=/^'([^']+)' is in always_allow_tools$/.exec(e),t?I(`{tool} is on your always-allow list`,{tool:t[1]}):(t=/^'([^']+)' is in sentinel\.deny_tools$/.exec(e),t?I(`{tool} is switched off in your settings`,{tool:t[1]}):(t=/^risk level is '(\w+)' \(mode=(\w+)\)$/.exec(e),t?I(`an action rated {risk}, in {mode} mode`,{risk:I(t[1]),mode:I(t[2])}):e===`auto mode: approval skipped`?I(`auto mode: not asked`):(t=/^covered by your '([^']+)' permission for (.+)$/.exec(e),t?I(`covered by your {scope} permission for {key}`,{scope:I(t[1]),key:t[2]}):(t=/^private data was read earlier in this conversation and '([^']+)' can send data to (.+), which is not on sentinel\.egress_allowlist$/.exec(e),t?I(`private data was read earlier in this conversation, and {tool} could send it to {target}, which is not on your allowed list`,{tool:t[1],target:t[2]}):I(e))))))}function me(e){let t=/^the file is larger than (\d+) MB$/.exec(e);return t?I(`The file is larger than {n} MB.`,{n:t[1]}):I(e)}function he(){return le(),I}function L(){return F()===`zh-CN`?`zh-CN`:`en-US`}function ge(e){if(!e)return``;let t=new Date(e);if(Number.isNaN(t.getTime()))return``;let n=new Date,r=t.toDateString()===n.toDateString(),i=t.toLocaleTimeString(L(),{hour:`2-digit`,minute:`2-digit`});return r?i:`${t.toLocaleDateString(L(),{month:`short`,day:`numeric`})} ${i}`}function _e(e){if(!e)return``;let t=new Date(e);if(Number.isNaN(t.getTime()))return``;let n=t.toLocaleTimeString(L(),{hour:`numeric`,minute:`2-digit`}),r=new Date,i=new Date(r);return i.setDate(r.getDate()-1),t.toDateString()===r.toDateString()?`${I(`Today`)} ${n}`:t.toDateString()===i.toDateString()?`${I(`Yesterday`)} ${n}`:`${ve(e)} ${n}`}function ve(e,t={}){if(!e)return``;let n=new Date(e);if(Number.isNaN(n.getTime()))return``;let r=n.getFullYear()===new Date().getFullYear();return n.toLocaleDateString(L(),{month:`short`,day:`numeric`,...r?{}:{year:`numeric`},...t})}function ye(e){if(!e)return``;let t=Date.now()-new Date(e).getTime();if(Number.isNaN(t))return``;let n=Math.round(Math.abs(t)/1e3);if(n<45)return I(t>=0?`just now`:`any moment`);let r=Math.round(n/60),i=Math.round(r/60),a=Math.round(i/24),o=r<60?I(`{n} min`,{n:r}):i<24?I(`{n} h`,{n:i}):I(`{n} d`,{n:a});return I(t>=0?`{span} ago`:`in {span}`,{span:o})}function be(e){let t=Math.max(0,Math.floor(Date.now()/1e3-e));return t<60?I(`just now`):t<3600?I(`{n} min ago`,{n:Math.floor(t/60)}):t<86400?I(`{n} h ago`,{n:Math.floor(t/3600)}):t<604800?I(`{n} d ago`,{n:Math.floor(t/86400)}):new Date(e*1e3).toLocaleDateString(L())}function R(e){try{return localStorage.getItem(e)}catch{return null}}function z(e,t){try{t===null?localStorage.removeItem(e):localStorage.setItem(e,t)}catch{}}function B(...e){return e.filter(Boolean).join(` `)}function xe(e){try{return decodeURIComponent(e)}catch{return e}}function Se(e){let t=e.toLowerCase().split(`.`).pop()??``;return t===`ics`?`event`:[`md`,`txt`,`log`,`rtf`].includes(t)?`text`:[`py`,`js`,`ts`,`tsx`,`jsx`,`sh`,`toml`,`yaml`,`yml`,`sql`,`rs`,`go`,`java`,`c`,`cpp`].includes(t)?`code`:[`html`,`htm`].includes(t)?`html`:[`png`,`jpg`,`jpeg`,`gif`,`webp`,`svg`].includes(t)?`image`:t===`pdf`?`pdf`:[`csv`,`json`,`xlsx`,`xls`,`parquet`].includes(t)?`data`:`other`}var V=`nanomuse_token`,H=class extends Error{constructor(){super(`unauthorized`)}};function Ce(e){let t=e.hash.replace(/^#/,``).split(`&`).filter(Boolean),n=t.findIndex(e=>e.startsWith(`token=`));if(n>=0){let r=decodeURIComponent(t[n].slice(6));return t.splice(n,1),e.hash=t.length?`#${t.join(`&`)}`:``,r||null}let r=e.searchParams.get(`token`);return r?(e.searchParams.delete(`token`),r):null}function U(){let e=new URL(window.location.href),t=Ce(e);return t&&(z(V,t),window.history.replaceState(null,``,e.pathname+e.search+e.hash)),R(V)??``}function we(e){z(V,e||null)}function W(e,t=!1){let n=U(),r=n?T(n,`/api/files/${e}`):new URLSearchParams;t&&r.set(`download`,`1`);let i=r.toString();return`/api/files/${e.split(`/`).map(encodeURIComponent).join(`/`)}${i?`?${i}`:``}`}function Te(e,t){let n=U(),r=n?`?${T(n,`/api/browser/${e}/frames/${t}.jpg`)}`:``;return`/api/browser/${encodeURIComponent(e)}/frames/${encodeURIComponent(t)}.jpg${r}`}async function G(e,t={}){let n={...t.headers},r=U();r&&(n.Authorization=`Bearer ${r}`),t.body&&!n[`Content-Type`]&&(n[`Content-Type`]=`application/json`);let i;try{i=await fetch(e,{...t,headers:n})}catch{throw Error(`Cannot reach your nanoMuse right now.`)}if(i.status===401)throw new H;if(!i.ok){let e;try{e=await i.json()}catch{}throw Error(Ee(i.status,e))}return await i.json()}function Ee(e,t){let n=t&&typeof t==`object`?t.detail:void 0;return typeof n==`string`&&n.trim()?n:e>=500?`Your nanoMuse hit a problem; try again in a moment.`:`Your nanoMuse could not do that.`}var K=e=>({method:`POST`,body:JSON.stringify(e)}),q={state:()=>G(`/api/state`),cloud:()=>G(`/api/cloud`),cloudCode:e=>G(`/api/cloud/code`,K({identifier:e})),cloudVerify:(e,t,n=``)=>G(`/api/cloud/verify`,K(n?{identifier:e,code:t,invite:n}:{identifier:e,code:t})),cloudSignOut:()=>G(`/api/cloud/sign-out`,K({})),cloudModels:e=>G(`/api/cloud/models`,K({on:e})),cloudLogin:(e,t)=>G(`/api/cloud/login`,K({identifier:e,password:t})),cloudPassword:(e,t)=>G(`/api/cloud/password`,K({password:e,current:t??null})),cloudSessions:()=>G(`/api/cloud/sessions`),cloudRevokeSession:e=>G(`/api/cloud/sessions/${encodeURIComponent(e)}`,{method:`DELETE`}),cloudSignOutAll:(e=!1)=>G(`/api/cloud/sign-out-all`,K({all:e})),cloudEvents:(e=50)=>G(`/api/cloud/events?limit=${e}`),cloudDelete:()=>G(`/api/cloud/delete`,K({})),cloudMe:()=>G(`/api/cloud/me`),cloudConfig:()=>G(`/api/cloud/config`),cloudContribute:e=>G(`/api/cloud/contribute`,K({on:e})),cloudDeleteSamples:()=>G(`/api/cloud/samples`,{method:`DELETE`}),cloudUseAsModel:(e=``)=>G(`/api/cloud/use-as-model`,K({model:e})),syncState:()=>G(`/api/sync/state`),syncSetState:e=>G(`/api/sync/state`,{method:`PUT`,body:JSON.stringify({enabled:e})}),syncSetSideChats:e=>G(`/api/sync/state`,{method:`PUT`,body:JSON.stringify({side_chats:e})}),syncDelete:()=>G(`/api/sync/delete`,K({})),syncPull:()=>G(`/api/sync/pull`,K({})),avatarView:()=>G(`/api/avatar`),avatarBegin:(e,t=`main`,n=`muse`)=>G(`/api/avatar/begin`,K({description:e,thread:t,style:n})),avatarStart:e=>G(`/api/avatar/start`,K({session:e})),avatarChoose:(e,t)=>G(`/api/avatar/choose`,K({session:e,index:t})),avatarCancel:e=>G(`/api/avatar/cancel`,K({session:e})),avatarMoods:()=>G(`/api/avatar/moods`,K({})),coding:(e=``)=>G(`/api/coding${e?`?device=${encodeURIComponent(e)}`:``}`),codingSessions:(e={})=>{let t=new URLSearchParams;e.agent&&t.set(`agent`,e.agent),e.limit&&t.set(`limit`,String(e.limit)),e.workspace&&t.set(`workspace`,e.workspace),e.device&&t.set(`device`,e.device);let n=t.toString();return G(`/api/coding/sessions${n?`?${n}`:``}`)},codingSession:(e,t,n=``)=>G(`/api/coding/sessions/${encodeURIComponent(e)}/${encodeURIComponent(t)}${n?`?device=${encodeURIComponent(n)}`:``}`),codingSend:e=>G(`/api/coding/send`,K(e)),codingStop:(e,t=``)=>G(`/api/coding/stop`,K({run:e,device:t})),hub:()=>G(`/api/hub`),updateHub:e=>G(`/api/hub`,{method:`PUT`,body:JSON.stringify(e)}),joinHub:()=>G(`/api/hub/join`,K({})),leaveHub:()=>G(`/api/hub/leave`,K({})),refreshHub:()=>G(`/api/hub/refresh`,K({})),forgetDevice:e=>G(`/api/hub/devices/${encodeURIComponent(e)}`,{method:`DELETE`}),askDevice:(e,t=``)=>G(`/api/hub/ask`,K({device:e,text:t})),hands:()=>G(`/api/hands`),setHands:e=>G(`/api/connections/hands`,{method:`PUT`,body:JSON.stringify(e)}),stopHands:()=>G(`/api/hands/stop`,K({})),holds:()=>G(`/api/holds`),openHold:(e,t,n=``)=>G(`/api/holds`,K({thread:e,tool:t,reason:n})),doneHold:e=>G(`/api/holds/${encodeURIComponent(e)}/done`,K({})),health:()=>G(`/api/health`),threads:()=>G(`/api/threads`),createThread:e=>G(`/api/threads`,K({title:e})),renameThread:(e,t)=>G(`/api/threads/${e}`,{method:`PATCH`,body:JSON.stringify({title:t})}),deleteThread:e=>G(`/api/threads/${e}`,{method:`DELETE`}),clearThread:e=>G(`/api/threads/${e}/clear`,{method:`POST`}),stopThread:e=>G(`/api/threads/${e}/stop`,{method:`POST`}),events:(e,t=200,n)=>G(`/api/threads/${e}/events?limit=${t}${n?`&before=${encodeURIComponent(n)}`:``}`),send:(e,t,n=[],r=``,i=``)=>G(`/api/threads/${e}/send`,K(i?{text:t,files:n,language:r,via:i}:{text:t,files:n,language:r})),upload:e=>G(`/api/files/upload?name=${encodeURIComponent(e.name||`photo.jpg`)}`,{method:`POST`,headers:{"Content-Type":e.type||`application/octet-stream`},body:e}),decide:(e,t,n=`once`,r=``)=>G(`/api/approvals/${e}`,K({approved:t,scope:n,reason:r})),resetApprovals:()=>G(`/api/approvals`,{method:`DELETE`}),revokeGrant:e=>G(`/api/approvals/grants/${encodeURIComponent(e)}`,{method:`DELETE`}),goals:()=>G(`/api/goals`),createGoal:e=>G(`/api/goals`,K(e)),patchGoal:(e,t)=>G(`/api/goals/${e}`,{method:`PATCH`,body:JSON.stringify(t)}),addStep:(e,t)=>G(`/api/goals/${e}/steps`,K({title:t})),advanceGoal:e=>G(`/api/goals/${e}/advance`,{method:`POST`}),checkInGoal:e=>G(`/api/goals/${e}/check-in`,{method:`POST`}),acceptProposal:e=>G(`/api/goals/${e}/proposal/accept`,{method:`POST`}),dismissProposal:e=>G(`/api/goals/${e}/proposal`,{method:`DELETE`}),deleteGoal:e=>G(`/api/goals/${e}`,{method:`DELETE`}),memory:()=>G(`/api/memory`),addMemory:(e,t)=>G(`/api/memory`,K({content:e,category:t})),forgetMemory:e=>G(`/api/memory/${e}`,{method:`DELETE`}),tidyMemory:()=>G(`/api/memory/tidy`,{method:`POST`}),memoryChanges:(e=30)=>G(`/api/memory/changes?limit=${e}`),restoreMemoryChange:e=>G(`/api/memory/changes/${e}/restore`,{method:`POST`}),ideas:(e=!1)=>G(`/api/ideas${e?`?refresh=1`:``}`),activity:(e=150)=>G(`/api/activity?n=${e}`),feed:(e=60)=>G(`/api/feed?limit=${e}`),feedPosts:()=>G(`/api/feed/posts`),setFeedInstructions:e=>G(`/api/feed/instructions`,{method:`PUT`,body:JSON.stringify(e)}),refreshFeedPosts:()=>G(`/api/feed/posts/refresh`,{method:`POST`}),deleteFeedPost:e=>G(`/api/feed/posts/${e}`,{method:`DELETE`}),upcoming:()=>G(`/api/upcoming`),reminders:(e=!1)=>G(`/api/reminders${e?`?all=1`:``}`),createReminder:e=>G(`/api/reminders`,{method:`POST`,body:JSON.stringify(e)}),fireReminder:e=>G(`/api/reminders/${e}/fire`,{method:`POST`}),cancelReminder:e=>G(`/api/reminders/${e}`,{method:`DELETE`}),triggers:()=>G(`/api/triggers`),createTrigger:e=>G(`/api/triggers`,{method:`POST`,body:JSON.stringify(e)}),fireTrigger:e=>G(`/api/triggers/${e}/fire`,{method:`POST`}),cancelTrigger:e=>G(`/api/triggers/${e}`,{method:`DELETE`}),files:(e=300)=>G(`/api/files?limit=${e}`),fileText:async e=>{let t={},n=U();n&&(t.Authorization=`Bearer ${n}`);let r=await fetch(`/api/files/${e.split(`/`).map(encodeURIComponent).join(`/`)}`,{headers:t});if(r.status===401)throw new H;if(!r.ok)throw Error(Ee(r.status,await r.json().catch(()=>void 0)));return r.text()},settings:()=>G(`/api/settings`),update:(e=!1)=>G(`/api/update${e?`?refresh=1`:``}`),nudges:()=>G(`/api/nudges`),updateSettings:e=>G(`/api/settings`,{method:`PUT`,body:JSON.stringify(e)}),connections:()=>G(`/api/connections`),providers:e=>G(`/api/providers${e?`?region=${encodeURIComponent(e)}`:``}`),chatgptLogin:()=>G(`/api/chatgpt/login`,K({})),chatgptStatus:()=>G(`/api/chatgpt/status`),chatgptCallback:e=>G(`/api/chatgpt/callback`,K({url:e})),chatgptLogout:()=>G(`/api/chatgpt/logout`,K({})),setLLM:e=>G(`/api/connections/llm`,{method:`PUT`,body:JSON.stringify(e)}),testLLM:()=>G(`/api/connections/llm/test`,{method:`POST`}),llmModels:e=>G(`/api/llm/models`,K(e)),setEmbeddings:e=>G(`/api/connections/embeddings`,{method:`PUT`,body:JSON.stringify(e)}),testEmbeddings:()=>G(`/api/connections/embeddings/test`,{method:`POST`}),setSearch:e=>G(`/api/connections/search`,{method:`PUT`,body:JSON.stringify(e)}),testSearch:()=>G(`/api/connections/search/test`,{method:`POST`}),setEmail:e=>G(`/api/connections/email`,{method:`PUT`,body:JSON.stringify(e)}),disconnectEmail:()=>G(`/api/connections/email`,{method:`DELETE`}),testEmail:()=>G(`/api/connections/email/test`,{method:`POST`}),calendar:()=>G(`/api/calendar`),setCalendar:e=>G(`/api/connections/calendar`,{method:`PUT`,body:JSON.stringify(e)}),addCalendarFeed:(e,t)=>G(`/api/connections/calendar/feeds`,K({name:e,url:t})),removeCalendarFeed:e=>G(`/api/connections/calendar/feeds/${encodeURIComponent(e)}`,{method:`DELETE`}),testCalendar:()=>G(`/api/connections/calendar/test`,{method:`POST`}),contacts:(e=``,t=8)=>G(`/api/contacts?q=${encodeURIComponent(e)}&limit=${t}`),setContacts:e=>G(`/api/connections/contacts`,{method:`PUT`,body:JSON.stringify(e)}),addContactsSource:(e,t)=>G(`/api/connections/contacts/sources`,K({name:e,url:t})),importContacts:(e,t)=>G(`/api/connections/contacts/import?name=${encodeURIComponent(e)}`,{method:`POST`,headers:{"Content-Type":`text/vcard; charset=utf-8`},body:t}),removeContactsSource:e=>G(`/api/connections/contacts/sources/${encodeURIComponent(e)}`,{method:`DELETE`}),testContacts:()=>G(`/api/connections/contacts/test`,{method:`POST`}),skills:()=>G(`/api/skills`),skill:e=>G(`/api/skills/${encodeURIComponent(e)}`),saveSkill:(e,t)=>G(`/api/skills/${encodeURIComponent(e)}`,{method:`PUT`,body:JSON.stringify({content:t})}),deleteSkill:e=>G(`/api/skills/${encodeURIComponent(e)}`,{method:`DELETE`}),setSkillEnabled:(e,t)=>G(`/api/skills/${encodeURIComponent(e)}/enabled`,K({enabled:t})),importSkill:e=>G(`/api/skills/import`,K({url:e})),setGui:e=>G(`/api/connections/gui`,{method:`PUT`,body:JSON.stringify(e)}),testGui:()=>G(`/api/connections/gui/test`,{method:`POST`}),media:e=>G(`/api/connections/${e}`),setMedia:(e,t)=>G(`/api/connections/${e}`,{method:`PUT`,body:JSON.stringify(t)}),setBrowser:e=>G(`/api/connections/browser`,{method:`PUT`,body:JSON.stringify({enabled:e})}),addMCP:e=>G(`/api/connections/mcp`,K(e)),removeMCP:e=>G(`/api/connections/mcp/${encodeURIComponent(e)}`,{method:`DELETE`}),vaultSet:(e,t)=>G(`/api/vault/${encodeURIComponent(e)}`,{method:`PUT`,body:JSON.stringify({value:t})}),vaultDelete:e=>G(`/api/vault/${encodeURIComponent(e)}`,{method:`DELETE`}),onboarded:(e=!0)=>G(`/api/onboarded`,K({done:e})),firstrun:e=>G(`/api/firstrun?lang=${encodeURIComponent(e)}`),firstrunStart:e=>G(`/api/firstrun/start`,K({lang:e})),firstrunPick:e=>G(`/api/firstrun/pick`,K({name:e})),firstrunDismiss:()=>G(`/api/firstrun/dismiss`,K({})),browserControl:(e,t)=>G(`/api/browser/${encodeURIComponent(e)}/control`,K(t)),push:()=>G(`/api/push`),pushSubscribe:e=>G(`/api/push/subscribe`,K({subscription:e})),pushUnsubscribe:e=>G(`/api/push/unsubscribe`,K({endpoint:e})),pushTest:()=>G(`/api/push/test`,{method:`POST`})};function De(e){return e===4401?`auth`:e===4404?`gone`:`retry`}function Oe(e){let t=null,n=!1,r=0,i,a=()=>{let o=window.location.protocol===`https:`?`wss`:`ws`;t=new WebSocket(`${o}://${window.location.host}/ws`),t.onopen=()=>{let n=U();n&&t?.send(JSON.stringify({kind:`auth`,token:n})),r=0,e.onOpen?.()},t.onmessage=t=>{try{e.onMessage(JSON.parse(t.data))}catch{}},t.onclose=t=>{e.onClose?.();let o=De(t.code);if(o===`auth`){e.onAuthError?.();return}if(o===`gone`){n=!0,e.onGone?.();return}if(n)return;let s=Math.min(15e3,500*2**r++);i=window.setTimeout(a,s)},t.onerror=()=>t?.close()};return a(),{send:e=>t&&t.readyState===WebSocket.OPEN?(t.send(JSON.stringify(e)),!0):!1,close:()=>{n=!0,i&&window.clearTimeout(i),t?.close()}}}var ke=o((e=>{var t=d(),n=Symbol.for(`react.element`),r=Symbol.for(`react.fragment`),i=Object.prototype.hasOwnProperty,a=t.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.ReactCurrentOwner,o={key:!0,ref:!0,__self:!0,__source:!0};function s(e,t,r){var s,c={},l=null,u=null;for(s in r!==void 0&&(l=``+r),t.key!==void 0&&(l=``+t.key),t.ref!==void 0&&(u=t.ref),t)i.call(t,s)&&!o.hasOwnProperty(s)&&(c[s]=t[s]);if(e&&e.defaultProps)for(s in t=e.defaultProps,t)c[s]===void 0&&(c[s]=t[s]);return{$$typeof:n,type:e,key:l,ref:u,props:c,_owner:a.current}}e.Fragment=r,e.jsx=s,e.jsxs=s})),Ae=o(((e,t)=>{t.exports=ke()})),je=6e5;function Me(e,t=Date.now()){let n={};for(let r of e??[])t-r.at*1e3<6e5&&(n[r.thread]=r);return n}function Ne(){return`serviceWorker`in navigator&&`PushManager`in window&&`Notification`in window}async function Pe(){if(!(`serviceWorker`in navigator)||!window.isSecureContext)return null;try{return await navigator.serviceWorker.register(`/sw.js`)}catch{return null}}async function Fe(){if(!Ne())return`unsupported`;if(!window.isSecureContext)return`insecure`;if(Notification.permission===`denied`)return`denied`;let e=await navigator.serviceWorker.getRegistration();return e&&await e.pushManager.getSubscription()?`on`:`off`}function Ie(e){let t=`=`.repeat((4-e.length%4)%4),n=atob((e+t).replace(/-/g,`+`).replace(/_/g,`/`)),r=new Uint8Array(new ArrayBuffer(n.length));for(let e=0;e0?t.setAppBadge?.(e):t.clearAppBadge?.()}catch{}}var Be=`nanomuse_theme`,Ve={light:`#fcfcfc`,dark:`#181819`};function He(){try{let e=localStorage.getItem(Be);if(e===`light`||e===`dark`||e===`system`)return e}catch{}return`light`}var J=He(),Y=new Set,Ue=typeof matchMedia==`function`?matchMedia(`(prefers-color-scheme: dark)`):null;function We(){return Ue?.matches?`dark`:`light`}function Ge(){return J}function X(){return J===`system`?We():J}function Ke(e){J=e;try{localStorage.setItem(Be,e)}catch{}Z(),Y.forEach(e=>e())}function Z(){if(typeof document>`u`)return;let e=X();document.documentElement.dataset.theme=e;let t=document.querySelector(`meta[name="theme-color"]`);t&&t.setAttribute(`content`,Ve[e])}Ue?.addEventListener?.(`change`,()=>{J===`system`&&(Z(),Y.forEach(e=>e()))});function qe(e){return Y.add(e),()=>Y.delete(e)}function Je(){return(0,f.useSyncExternalStore)(qe,Ge,Ge)}function Ye(){return(0,f.useSyncExternalStore)(qe,X,X)}var Q=Ae();function Xe(){if(window.parent===window)return null;let e=window.location.ancestorOrigins;if(e&&e.length>0&&e[0]!==`null`)return e[0];if(document.referrer)try{return new URL(document.referrer).origin}catch{return null}return null}function Ze(e){let t=Xe();t&&window.parent.postMessage(e,t)}var Qe=[`chat`,`feed`,`ideas`,`goals`,`library`,`memory`,`devices`,`connections`,`channels`,`skills`,`you`,`account`,`coding`,`avatar`],$e=`nanomuse_feed_seen`,et=`nanomuse_sign_in_skipped`,tt=`nanomuse.ui.lite`;function nt(){try{let e=new URL(window.location.href);return e.searchParams.get(`ui`)===`lite`?(sessionStorage.setItem(tt,`1`),!0):e.searchParams.get(`ui`)===`full`?(sessionStorage.removeItem(tt),!1):sessionStorage.getItem(tt)===`1`}catch{return!1}}var rt={connected:!1,loaded:!1,authError:!1,gone:!1,error:null,version:``,profile:null,status:{state:`idle`,detail:``,thread:`main`},threads:[],activeThread:`main`,events:{},hasMore:{},streams:{},goals:[],settings:null,goalsVersion:0,memoryVersion:0,remindersVersion:0,calendarVersion:0,pendingApprovals:[],feedVersion:0,feedSeenAt:R($e)??``,viewer:null,draft:null,draftFiles:null,connectionsVersion:0,skillsVersion:0,onboardingDismissed:!1,signInSkipped:R(et)===`1`,tab:`chat`,toast:null,drawer:!1,finishedAt:0,mishapAt:0,hub:null,codingLive:{},lite:nt(),hands:null,holds:[],handsLive:null,studio:null,working:{},firstrun:null};function it(e,t){if(t.type!==`approval`)return e;let n=e.filter(e=>e.id!==t.id);return t.status===`pending`?[...n,t]:n}function at(e){return e.type===`approval`||e.type===`question`||e.source===`background`||e.source===`goal`}function ot(e){let t=e.ts;return typeof t==`number`?{...e,ts:new Date(t*1e3).toISOString()}:e}function st(e,t){let n=e??[],r=n.findIndex(e=>e.id===t.id);if(r>=0){let e=n.slice();return e[r]=t,e}if(t.synced&&t.ts&&n.length>0&&(n[n.length-1]?.ts??``)>t.ts){let e=n.length;for(;e>0&&(n[e-1]?.ts??``)>t.ts;)--e;return[...n.slice(0,e),t,...n.slice(e)]}return[...n,t]}function ct(e,t){let n=e.filter(e=>e.id!==t.id);return t.status===`on`?[...n,t]:n}function lt(e,t){let n=e.findIndex(e=>e.id===t.id);if(n>=0){let r=e.slice();return r[n]=t,r}return[...e,t]}function ut(e,t){switch(t.type){case`hello`:{let n=t.state;for(let e of Object.keys($))delete $[e];return{...e,loaded:!0,authError:!1,version:n.version,profile:n.profile,status:n.status,streams:{},threads:n.threads,goals:n.goals,settings:n.settings,pendingApprovals:n.pending_approvals,feedVersion:e.feedVersion+1,activeThread:n.threads.some(t=>t.id===e.activeThread)?e.activeThread:`main`,hub:n.hub??e.hub,hands:n.hands??e.hands,holds:(n.holds??[]).map(ot),working:Me(n.working),firstrun:n.firstrun??e.firstrun}}case`connection`:return{...e,connected:t.connected};case`authError`:return{...e,authError:!0,connected:!1};case`gone`:return{...e,gone:!0,connected:!1};case`error`:return{...e,error:t.error};case`events`:{let n=e.events[t.thread]??[],r=t.events.map(ot),i=t.prepend?[...r,...n.filter(e=>!r.some(t=>t.id===e.id))]:r;return{...e,events:{...e.events,[t.thread]:i},hasMore:{...e.hasMore,[t.thread]:t.hasMore}}}case`eventsFailed`:return{...e,events:{...e.events,[t.thread]:e.events[t.thread]??[]},toast:I(`Could not load the conversation. Pull to retry.`)};case`activeThread`:return{...e,activeThread:t.thread,tab:`chat`};case`goals`:return{...e,goals:t.goals};case`settings`:return{...e,settings:t.settings,profile:t.settings.profile};case`tab`:return{...e,tab:t.tab};case`drawer`:return{...e,drawer:t.open};case`feedSeen`:return z($e,t.at),{...e,feedSeenAt:t.at};case`viewer`:return{...e,viewer:t.path};case`draft`:return{...e,draft:t.text};case`draftFiles`:return{...e,draftFiles:t.files};case`onboardingDismissed`:return{...e,onboardingDismissed:!0};case`signInSkipped`:return{...e,signInSkipped:!0};case`toast`:return{...e,toast:t.toast};case`ws`:return dt(e,t.msg);default:return e}}function dt(e,t){switch(t.kind){case`hello`:return ut(e,{type:`hello`,state:t.state});case`event`:case`update`:{let n=ot(t.event),r={...e.streams},i=r[n.thread];n.type===`assistant`&&i&&i.id===n.id&&(r[n.thread]=void 0);let a=e.threads.map(e=>e.id===n.thread&&t.kind===`event`?{...e,updated_at:n.ts}:e),o=e.events[n.thread]!==void 0,s=n.type===`tool`&&(n.status===`error`||n.status===`blocked`)||n.type===`notice`&&n.level===`error`,c=e.working,l=c[n.thread];return l&&n.type===`assistant`&&n.synced&&n.via_device===l.device&&(c={...c,[n.thread]:void 0}),{...e,streams:r,threads:a,working:c,events:o?{...e.events,[n.thread]:st(e.events[n.thread],n)}:e.events,holds:n.type===`hold`?ct(e.holds,n):e.holds,pendingApprovals:it(e.pendingApprovals,n),feedVersion:at(n)?e.feedVersion+1:e.feedVersion,mishapAt:s?Date.now():e.mishapAt}}case`stream_start`:return{...e,streams:{...e.streams,[t.thread]:{id:t.id,text:``,ended:!1}}};case`delta`:{let n=e.streams[t.thread],r=n&&n.id===t.id?{...n,text:n.text+t.text}:{id:t.id,text:t.text,ended:!1};return{...e,streams:{...e.streams,[t.thread]:r}}}case`stream_end`:{let n=e.streams[t.thread];return!n||n.id!==t.id?e:t.discard||!n.text.trim()?{...e,streams:{...e.streams,[t.thread]:void 0}}:{...e,streams:{...e.streams,[t.thread]:{...n,ended:!0}}}}case`status`:{let n=t.status,r={...e.streams};r[n.thread]?.ended&&n.state!==`working`&&(r[n.thread]=void 0);let i=ft(e.status,n),a=e.status.state===`working`&&i.state===`idle`;return{...e,status:i,streams:r,finishedAt:a?Date.now():e.finishedAt}}case`thread`:return{...e,threads:lt(e.threads,t.thread)};case`thread_deleted`:{let n={...e.events};return delete n[t.thread],{...e,events:n,holds:e.holds.filter(e=>e.thread!==t.thread),threads:e.threads.filter(e=>e.id!==t.thread),pendingApprovals:e.pendingApprovals.filter(e=>e.thread!==t.thread),activeThread:e.activeThread===t.thread?`main`:e.activeThread}}case`thread_cleared`:return{...e,events:{...e.events,[t.thread]:[]},holds:e.holds.filter(e=>e.thread!==t.thread),pendingApprovals:e.pendingApprovals.filter(e=>e.thread!==t.thread)};case`event_removed`:{let n=e.events[t.thread];return n?{...e,events:{...e.events,[t.thread]:n.filter(e=>e.id!==t.id)}}:e}case`firstrun`:return{...e,firstrun:t.firstrun};case`working`:{let{kind:n,working:r,...i}=t,a=e.working[i.thread];return r?{...e,working:{...e.working,[i.thread]:i}}:!a||a.device!==i.device?e:{...e,working:{...e.working,[i.thread]:void 0}}}case`goals`:return{...e,goalsVersion:e.goalsVersion+1};case`memory`:return{...e,memoryVersion:e.memoryVersion+1};case`reminders`:case`triggers`:return{...e,remindersVersion:e.remindersVersion+1};case`calendar`:return{...e,calendarVersion:e.calendarVersion+1};case`feed_posts`:return{...e,feedVersion:e.feedVersion+1};case`profile`:return{...e,profile:t.profile,settings:e.settings?{...e.settings,profile:t.profile}:e.settings};case`settings`:return{...e,settings:t.settings,profile:t.settings.profile};case`connections`:return{...e,connectionsVersion:e.connectionsVersion+1};case`hub`:return{...e,hub:t.hub};case`coding`:{let n=t.run?.id??t.event.run;if(!n)return e;let r=e.codingLive[n],i=t.run??r?.run;if(!i)return e;let a=t.event.kind===`run`?r?.events??[]:[...r?.events??[],t.event].slice(-400),o=r?.current??``;t.event.kind===`text`&&(o=t.event.partial?o+(t.event.text??``):``),(t.event.kind===`done`||t.event.kind===`error`)&&(o=``);let s={...e.codingLive,[n]:{run:{...i,device:t.device??i.device},events:a,current:o}},c=Object.keys(s);if(c.length>20)for(let e of c.sort((e,t)=>s[e].run.started_at-s[t].run.started_at).slice(0,c.length-20))delete s[e];return{...e,codingLive:s}}case`hands_state`:return{...e,hands:t.hands};case`studio`:return{...e,studio:t.current};case`hands`:{let{kind:n,...r}=t,i=r.event===`end`||r.event===`stop`;return{...e,handsLive:i?null:r}}case`skills`:return{...e,skillsVersion:e.skillsVersion+1};case`error`:return{...e,toast:I(t.error)};case`pong`:return{...e,status:t.status};default:return e}}var $={};function ft(e,t){$[t.thread]=t;let n=Object.values($).filter(e=>e.state!==`idle`);return n.length?(n.sort((e,t)=>Number(e.thread!==`main`)-Number(t.thread!==`main`)),n[0]??e):{state:`idle`,detail:``,thread:`main`}}var pt=(0,f.createContext)(null);function mt({children:e}){let[t,n]=(0,f.useReducer)(ut,rt),r=(0,f.useRef)(null);(0,f.useEffect)(()=>{U();let e=[],t=0,i=()=>{t=0;let r=e.splice(0);for(let e of r)n({type:`ws`,msg:e})},a=Oe({onMessage:n=>{e.push(n),t||=window.setTimeout(i,0)},onOpen:()=>n({type:`connection`,connected:!0}),onClose:()=>n({type:`connection`,connected:!1}),onAuthError:()=>n({type:`authError`}),onGone:()=>n({type:`gone`})});return r.current=a,q.state().then(e=>n({type:`hello`,state:e})).catch(e=>{e instanceof H?n({type:`authError`}):n({type:`error`,error:String(e.message??e)})}),()=>{t&&window.clearTimeout(t),a.close()}},[]);let i=(0,f.useRef)({}),a=(0,f.useCallback)(async(e,t)=>{let r=t?void 0:i.current[e]=(i.current[e]??0)+1;try{let a=await q.events(e,150,t);if(r!==void 0&&i.current[e]!==r)return;n({type:`events`,thread:e,events:a.events,hasMore:a.has_more,prepend:!!t})}catch(t){t instanceof H?n({type:`authError`}):n({type:`eventsFailed`,thread:e})}},[]),o=(0,f.useCallback)(async()=>{try{n({type:`ws`,msg:{kind:`hub`,hub:await q.hub()}})}catch{}},[]);(0,f.useEffect)(()=>{t.loaded&&a(t.activeThread)},[t.loaded,t.activeThread,a]);let s=(0,f.useRef)(!1);(0,f.useEffect)(()=>{t.connected&&s.current&&t.loaded&&a(t.activeThread),s.current=t.connected},[t.connected,t.loaded,t.activeThread,a]);let c=(0,f.useCallback)(async()=>{try{n({type:`goals`,goals:await q.goals()})}catch{}},[]);(0,f.useEffect)(()=>{t.loaded&&c()},[t.goalsVersion,t.loaded,c]);let l=(0,f.useCallback)(async()=>{try{n({type:`settings`,settings:await q.settings()})}catch{}},[]);(0,f.useEffect)(()=>{if(!t.toast)return;let e=window.setTimeout(()=>n({type:`toast`,toast:null}),3500);return()=>window.clearTimeout(e)},[t.toast]),(0,f.useEffect)(()=>{Pe();let e=e=>{let t=new URL(e,window.location.origin),r=t.searchParams.get(`thread`),i=t.searchParams.get(`tab`);r&&n({type:`activeThread`,thread:r}),i&&Qe.includes(i)&&!r?n({type:`tab`,tab:i}):n({type:`tab`,tab:`chat`});let a=t.searchParams.get(`draft`);a&&n({type:`draft`,text:a});let o=t.searchParams.get(`attach`);if(o)try{let e=JSON.parse(o);Array.isArray(e)&&e.length&&n({type:`draftFiles`,files:e.filter(e=>e&&typeof e.path==`string`)})}catch{}},t=new URL(window.location.href);if([`thread`,`tab`,`draft`,`attach`,`ui`].some(e=>t.searchParams.has(e))){e(t.href);for(let e of[`thread`,`tab`,`draft`,`attach`,`ui`])t.searchParams.delete(e);window.history.replaceState({},``,t.toString())}let r=t=>{t.data&&t.data.type===`open`&&e(String(t.data.url||`/`))};navigator.serviceWorker?.addEventListener(`message`,r);let i=e=>{if(window.parent===window||e.source!==window.parent)return;let t=e.data;t&&t.type===`nanomuse:draft`&&typeof t.text==`string`&&(n({type:`tab`,tab:`chat`}),n({type:`draft`,text:t.text.slice(0,4e3)}))};return window.addEventListener(`message`,i),()=>{navigator.serviceWorker?.removeEventListener(`message`,r),window.removeEventListener(`message`,i)}},[]);let u=Ye();(0,f.useEffect)(()=>{t.loaded&&Ze({type:`nanomuse:ready`,name:t.profile?.name??``,theme:u})},[t.loaded,t.profile?.name]),(0,f.useEffect)(()=>{t.loaded&&Ze({type:`nanomuse:theme`,theme:u})},[t.loaded,u]),(0,f.useEffect)(()=>{t.loaded&&ze(t.pendingApprovals.length)},[t.loaded,t.pendingApprovals.length]);let d=(0,f.useMemo)(()=>({state:t,dispatch:n,send:async(e,t,i=[])=>{if(!t.trim()&&i.length===0)return;let a=F();try{(i.length>0||!r.current?.send({kind:`send`,thread:e,text:t,language:a}))&&await q.send(e,t,i,a)}catch(e){throw e instanceof H&&n({type:`authError`}),e}},sendViaCloud:async(e,t,r=[])=>{if(t.trim()||r.length!==0)try{await q.send(e,t,r,F(),`cloud`)}catch(e){throw e instanceof H&&n({type:`authError`}),e}},decide:async(e,t,i=`once`)=>{try{r.current?.send({kind:`approval`,id:e,approved:t,scope:i})||await q.decide(e,t,i)}catch(e){throw e instanceof H&&n({type:`authError`}),e}},loadEvents:a,refreshGoals:c,refreshSettings:l,refreshHub:o,setTab:e=>n({type:`tab`,tab:e}),setDrawer:e=>n({type:`drawer`,open:e}),openThread:e=>n({type:`activeThread`,thread:e}),markFeedSeen:e=>n({type:`feedSeen`,at:e}),openFile:e=>n({type:`viewer`,path:e}),draftFiles:e=>n({type:`draftFiles`,files:e}),draft:e=>{n({type:`draft`,text:e}),e!==null&&n({type:`tab`,tab:`chat`})},dismissOnboarding:()=>n({type:`onboardingDismissed`}),skipSignIn:()=>{z(et,`1`),n({type:`signInSkipped`})},toast:e=>n({type:`toast`,toast:I(e)})}),[t,a,c,l,o]);return(0,Q.jsx)(pt.Provider,{value:d,children:e})}function ht(){let e=(0,f.useContext)(pt);if(!e)throw Error(`useStore outside provider`);return e}var gt=`dragon`,_t=new Set([`panda`,`sunny`,`moss`,`sky`,`fox`,`bolt`,`plum`]);function vt(e){return!e||e===`dragon`||_t.has(e)}function yt(e,t){return W(`avatar/${e}/${t===`working`||t===`waiting`||t===`happy`||t===`error`?t:`idle`}.webp`)}function bt(e){return`/avatars/dragon-${e===`working`||e===`waiting`||e===`happy`||e===`error`?e:`idle`}.webp`}function xt(e){return e===`working`||e===`waiting`||e===`happy`?e:`idle`}function St(e){return e===`error`?null:`/avatars/dragon-${xt(e)}.mp4`}function Ct(e,t){return t===`error`?null:W(`avatar/${e}/${xt(t)}.mp4`)}var wt=3e3,Tt=4e3;function Et(e){let{state:t}=ht(),n=Dt(e?[t.mishapAt+Tt,t.finishedAt+wt]:[]);return e?t.loaded&&!t.connected?`sleepy`:e.state===`waiting`?`waiting`:e.state===`working`?`working`:t.mishapAt&&n-t.mishapAt<4e3?`error`:t.finishedAt&&n-t.finishedAt<3e3?`happy`:`idle`:`idle`}function Dt(e){let[t,n]=(0,f.useState)(()=>Date.now()),r=e.join(`,`);(0,f.useEffect)(()=>n(Date.now()),[r]);let i=Math.min(...e.filter(e=>e>t),1/0);return(0,f.useEffect)(()=>{if(!Number.isFinite(i))return;let e=window.setTimeout(()=>n(Date.now()),Math.max(0,i-Date.now())+20);return()=>window.clearTimeout(e)},[i]),t}var Ot=44,kt=new Set,At=typeof window<`u`&&typeof window.matchMedia==`function`&&window.matchMedia(`(prefers-reduced-motion: reduce)`).matches;function jt({profile:e,status:t,size:n=40,onClick:r,still:i=!1,className:a}){let[o,s]=(0,f.useState)(!1),[,c]=(0,f.useState)(0);(0,f.useEffect)(()=>{if(!o)return;let e=window.setTimeout(()=>s(!1),900);return()=>window.clearTimeout(e)},[o]);let l=Et(t),u=t?.state??`idle`,d=e?.color??`#0064d4`,p=!e||vt(e.avatar),m=!p&&e?.avatar?e.avatar:null,h=o?`happy`:i?`idle`:l,g=i||At||n{kt.add(_),c(e=>e+1)},className:`h-full w-full object-cover`},_):p||m?(0,Q.jsx)(`img`,{src:y,alt:``,draggable:!1,className:`h-full w-full object-cover`}):(0,Q.jsx)(`span`,{className:`flex h-full w-full items-center justify-center leading-none drop-shadow-sm`,style:{fontSize:n*.5},children:e?.emoji??`✨`})}),t&&u!==`idle`&&(0,Q.jsx)(`span`,{className:B(`absolute -bottom-0.5 -right-0.5 rounded-full border-2 border-bg`,u===`working`?`bg-amber-400`:`bg-rose-500`),style:{width:Math.max(10,n*.28),height:Math.max(10,n*.28)}})]});return r?(0,Q.jsx)(`button`,{type:`button`,onClick:()=>{s(!0),r()},"aria-label":b,className:B(x,`transition active:scale-95`),style:{width:n,height:n},children:S}):(0,Q.jsx)(`span`,{role:`img`,"aria-label":b,onClick:()=>s(!0),className:x,style:{width:n,height:n},children:S})}function Mt({profile:e,status:t,name:n,statusLine:r,statusTone:i=`muted`,spinning:a=!1,badge:o,onAvatar:s,onName:c,leading:l,trailing:u,under:d,size:f=72,className:p}){return(0,Q.jsxs)(`header`,{className:B(`safe-top relative shrink-0 bg-bg pt-1.5 pb-1`,p),children:[(0,Q.jsxs)(`div`,{className:`flex flex-col items-center px-16`,children:[(0,Q.jsxs)(`button`,{type:`button`,onClick:s,"aria-label":n,className:`relative rounded-full`,children:[(0,Q.jsx)(jt,{profile:e,status:t,size:f}),o!==void 0&&o>0&&(0,Q.jsx)(`span`,{className:`pointer-events-none absolute -right-0.5 top-0 flex h-[18px] min-w-[18px] items-center justify-center rounded-full border-2 border-bg bg-rose-500 px-1 text-[10.5px] font-bold text-white`,children:o})]}),(0,Q.jsxs)(`div`,{className:`relative z-10 -mt-2.5 flex min-h-[44px] flex-col items-center`,children:[(0,Q.jsx)(Nt,{name:n,statusLine:r,statusTone:i,spinning:a,onClick:c??s}),d&&(0,Q.jsx)(`div`,{className:`mt-1.5 flex max-w-full items-center`,children:d})]})]}),l&&(0,Q.jsx)(`div`,{className:`absolute left-4 top-1.5 safe-top`,children:l}),u&&(0,Q.jsx)(`div`,{className:`absolute right-4 top-1.5 safe-top flex items-center gap-2`,children:u})]})}function Nt({name:e,statusLine:t,statusTone:n=`muted`,spinning:r=!1,onClick:i}){let a=(0,Q.jsxs)(Q.Fragment,{children:[(0,Q.jsx)(`span`,{className:`max-w-[240px] truncate text-[14px] leading-[18px] text-fg`,children:e}),t&&(0,Q.jsxs)(`span`,{className:B(`mt-0.5 flex max-w-[240px] items-center gap-1 text-[11.5px] leading-[14px]`,n===`accent`?`text-accent`:`text-muted`),children:[r&&(0,Q.jsx)(`span`,{className:`h-2.5 w-2.5 shrink-0 animate-spin rounded-full border-[1.5px] border-current border-t-transparent`}),(0,Q.jsx)(`span`,{className:`truncate`,children:t})]})]}),o=`flex flex-col items-center rounded-[14px] bg-surface px-3 py-1 shadow-[0_1px_4px_rgba(0,0,0,0.16)] dark:border dark:border-border dark:shadow-none`;return i?(0,Q.jsx)(`button`,{type:`button`,onClick:i,className:o,children:a}):(0,Q.jsx)(`div`,{className:o,children:a})}function Pt({onClick:e,label:t,children:n,dot:r=!1,small:i=!1,className:a,disabled:o=!1,expanded:s}){return(0,Q.jsxs)(`button`,{type:`button`,onClick:e,"aria-label":t,"aria-expanded":s,disabled:o,className:B(`relative flex items-center justify-center rounded-full bg-surface text-fg shadow-[0_1px_4px_rgba(0,0,0,0.14)] hover:bg-surface-2 disabled:opacity-50 dark:border dark:border-border dark:shadow-none`,i?`h-10 w-10`:`h-11 w-11`,a),children:[n,r&&(0,Q.jsx)(`span`,{className:`absolute right-[3px] top-[3px] h-[9px] w-[9px] rounded-full border-[1.5px] border-surface bg-accent`})]})}function Ft({children:e,className:t}){return(0,Q.jsx)(`h1`,{className:B(`px-5 pt-1.5 pb-1.5 text-[26px] font-bold leading-8 tracking-tight`,t),children:e})}export{ye as A,fe as B,Te as C,Se as D,B as E,ne as F,ue as G,oe as H,se as I,b as J,he as K,F as L,_e as M,ge as N,R as O,z as P,l as Q,L as R,W as S,we as T,I as U,pe as V,le as W,o as X,d as Y,s as Z,Le as _,gt as a,Ae as b,vt as c,mt as d,ht as f,Re as g,Je as h,jt as i,xe as j,be as k,Ct as l,Ke as m,Ft as n,St as o,Z as p,x as q,Pt as r,bt as s,Mt as t,yt as u,Fe as v,G as w,q as x,je as y,me as z}; \ No newline at end of file +var e=Object.create,t=Object.defineProperty,n=Object.getOwnPropertyDescriptor,r=Object.getOwnPropertyNames,i=Object.getPrototypeOf,a=Object.prototype.hasOwnProperty,o=(e,t)=>()=>(t||(e((t={exports:{}}).exports,t),e=null),t.exports),s=(e,n)=>{let r={};for(var i in e)t(r,i,{get:e[i],enumerable:!0});return n||t(r,Symbol.toStringTag,{value:`Module`}),r},c=(e,i,o,s)=>{if(i&&typeof i==`object`||typeof i==`function`)for(var c=r(i),l=0,u=c.length,d;li[e]).bind(null,d),enumerable:!(s=n(i,d))||s.enumerable});return e},l=(n,r,o)=>(o=n==null?{}:e(i(n)),c(r||!n||!n.__esModule||!a.call(n,`default`)?t(o,`default`,{value:n,enumerable:!0}):o,n)),u=o((e=>{var t=Symbol.for(`react.element`),n=Symbol.for(`react.portal`),r=Symbol.for(`react.fragment`),i=Symbol.for(`react.strict_mode`),a=Symbol.for(`react.profiler`),o=Symbol.for(`react.provider`),s=Symbol.for(`react.context`),c=Symbol.for(`react.forward_ref`),l=Symbol.for(`react.suspense`),u=Symbol.for(`react.memo`),d=Symbol.for(`react.lazy`),f=Symbol.iterator;function p(e){return typeof e!=`object`||!e?null:(e=f&&e[f]||e[`@@iterator`],typeof e==`function`?e:null)}var m={isMounted:function(){return!1},enqueueForceUpdate:function(){},enqueueReplaceState:function(){},enqueueSetState:function(){}},h=Object.assign,g={};function _(e,t,n){this.props=e,this.context=t,this.refs=g,this.updater=n||m}_.prototype.isReactComponent={},_.prototype.setState=function(e,t){if(typeof e!=`object`&&typeof e!=`function`&&e!=null)throw Error(`setState(...): takes an object of state variables to update or a function which returns an object of state variables.`);this.updater.enqueueSetState(this,e,t,`setState`)},_.prototype.forceUpdate=function(e){this.updater.enqueueForceUpdate(this,e,`forceUpdate`)};function v(){}v.prototype=_.prototype;function y(e,t,n){this.props=e,this.context=t,this.refs=g,this.updater=n||m}var b=y.prototype=new v;b.constructor=y,h(b,_.prototype),b.isPureReactComponent=!0;var x=Array.isArray,S=Object.prototype.hasOwnProperty,C={current:null},w={key:!0,ref:!0,__self:!0,__source:!0};function ee(e,n,r){var i,a={},o=null,s=null;if(n!=null)for(i in n.ref!==void 0&&(s=n.ref),n.key!==void 0&&(o=``+n.key),n)S.call(n,i)&&!w.hasOwnProperty(i)&&(a[i]=n[i]);var c=arguments.length-2;if(c===1)a.children=r;else if(1{t.exports=u()})),f=l(d()),p=(...e)=>e.filter((e,t,n)=>!!e&&e.trim()!==``&&n.indexOf(e)===t).join(` `).trim(),m=e=>e.replace(/([a-z0-9])([A-Z])/g,`$1-$2`).toLowerCase(),h=e=>e.replace(/^([A-Z])|[\s-_]+(\w)/g,(e,t,n)=>n?n.toUpperCase():t.toLowerCase()),g=e=>{let t=h(e);return t.charAt(0).toUpperCase()+t.slice(1)},_={xmlns:`http://www.w3.org/2000/svg`,width:24,height:24,viewBox:`0 0 24 24`,fill:`none`,stroke:`currentColor`,strokeWidth:2,strokeLinecap:`round`,strokeLinejoin:`round`},v=e=>{for(let t in e)if(t.startsWith(`aria-`)||t===`role`||t===`title`)return!0;return!1},y=(0,f.forwardRef)(({color:e=`currentColor`,size:t=24,strokeWidth:n=2,absoluteStrokeWidth:r,className:i=``,children:a,iconNode:o,...s},c)=>(0,f.createElement)(`svg`,{ref:c,..._,width:t,height:t,stroke:e,strokeWidth:r?Number(n)*24/Number(t):n,className:p(`lucide`,i),...!a&&!v(s)&&{"aria-hidden":`true`},...s},[...o.map(([e,t])=>(0,f.createElement)(e,t)),...Array.isArray(a)?a:[a]])),b=(e,t)=>{let n=(0,f.forwardRef)(({className:n,...r},i)=>(0,f.createElement)(y,{ref:i,iconNode:t,className:p(`lucide-${m(g(e))}`,`lucide-${e}`,n),...r}));return n.displayName=g(e),n},x=b(`loader-circle`,[[`path`,{d:`M21 12a9 9 0 1 1-6.219-8.56`,key:`13zald`}]]),S=21600,C=32;function w(e=Date.now()){return(Math.floor(e/1e3/S)+2)*S}function ee(e,t,n){let r=new TextEncoder;return E(te(r.encode(e),r.encode(`${n}\n${t}`))).slice(0,C)}function T(e,t,n=Date.now()){let r=w(n),i=new URLSearchParams;return i.set(`exp`,String(r)),i.set(`sig`,ee(e,t,r)),i}function E(e){let t=``;for(let n of e)t+=n.toString(16).padStart(2,`0`);return t}function te(e,t){let n=new Uint8Array(64);n.set(e.length>64?k(e):e);let r=new Uint8Array(64+t.length),i=new Uint8Array(96);for(let e=0;e<64;e++)r[e]=n[e]^54,i[e]=n[e]^92;return r.set(t,64),i.set(k(r),64),k(i)}var D=new Uint32Array([1116352408,1899447441,3049323471,3921009573,961987163,1508970993,2453635748,2870763221,3624381080,310598401,607225278,1426881987,1925078388,2162078206,2614888103,3248222580,3835390401,4022224774,264347078,604807628,770255983,1249150122,1555081692,1996064986,2554220882,2821834349,2952996808,3210313671,3336571891,3584528711,113926993,338241895,666307205,773529912,1294757372,1396182291,1695183700,1986661051,2177026350,2456956037,2730485921,2820302411,3259730800,3345764771,3516065817,3600352804,4094571909,275423344,430227734,506948616,659060556,883997877,958139571,1322822218,1537002063,1747873779,1955562222,2024104815,2227730452,2361852424,2428436474,2756734187,3204031479,3329325298]),O=(e,t)=>e>>>t|e<<32-t;function k(e){let t=new Uint32Array([1779033703,3144134277,1013904242,2773480762,1359893119,2600822924,528734635,1541459225]),n=new Uint8Array(e.length+9+63>>6<<6);n.set(e),n[e.length]=128;let r=new DataView(n.buffer),i=e.length*8;r.setUint32(n.length-8,Math.floor(i/4294967296)),r.setUint32(n.length-4,i>>>0);let a=new Uint32Array(64);for(let e=0;e>>3,i=O(n,17)^O(n,19)^n>>>10;a[e]=a[e-16]+r+a[e-7]+i>>>0}let n=t[0],i=t[1],o=t[2],s=t[3],c=t[4],l=t[5],u=t[6],d=t[7];for(let e=0;e<64;e++){let t=O(c,6)^O(c,11)^O(c,25),r=c&l^~c&u,f=d+t+r+D[e]+a[e]>>>0,p=(O(n,2)^O(n,13)^O(n,22))+(n&i^n&o^i&o)>>>0;d=u,u=l,l=c,c=s+f>>>0,s=o,o=i,i=n,n=f+p>>>0}t[0]+=n,t[1]+=i,t[2]+=o,t[3]+=s,t[4]+=c,t[5]+=l,t[6]+=u,t[7]+=d}let o=new Uint8Array(32),s=new DataView(o.buffer);for(let e=0;e<8;e++)s.setUint32(e*4,t[e]);return o}var A={Chat:`聊天`,Feed:`动态`,Ideas:`点子`,Goals:`目标`,Library:`资源库`,"Main chat":`主要聊天`,"Side chat":`旁聊`,"Reconnecting to your nanoMuse…":`正在重新连接你的 nanoMuse…`,"This demo has ended.":`这次体验已经结束。`,"This nanoMuse has stopped. Reload the page once it is running again.":`这个 nanoMuse 已停止。等它重新运行后,刷新页面即可。`,"Reconnecting…":`重新连接中…`,"Connect to your nanoMuse":`连接到你的 nanoMuse`,"This app talks to the nanoMuse server you run yourself. Scan the QR code printed by":`这个应用连接的是你自己运行的 nanoMuse 服务器。扫描下面命令打印的二维码`,", or paste the access token below.":`,或在下方粘贴访问令牌。`,"Access token":`访问令牌`,Connect:`连接`,Connected:`已连接`,"Hi, I'm {name}.":`你好,我是 {name}。`,"I don't just answer; I get things done: research, plans, files, code, email, long-running goals. Everything I do shows up here, and anything hard to undo waits for your approval.":`我不只是回答问题,而是把事情做完:调研、计划、文件、代码、邮件、长期目标。我做的每件事都会显示在这里,任何难以撤销的操作都会先等你批准。`,"What can you do for me?":`你能为我做什么?`,"Plan my week: ask me what's on my plate":`帮我规划这一周:先问问我手头有什么`,"Research and compare two options for me":`帮我调研并比较两个选项`,"Set up a long-term goal and track it":`建立一个长期目标并持续跟进`,"Answer {name}…":`回复 {name}…`,"Reply below to continue.":`在下方回复以继续。`,"{name} is working; anything you send now is picked up right away.":`{name} 正在工作,你现在发的消息会马上接着处理。`,"Working…":`处理中…`,"On it":`正在处理`,"Show the agent's steps":`显示执行步骤`,"Every tool it uses becomes a chip in the chat. Off, the chat keeps to the conversation and the line under the name says what it is on. This device only.":`每用一个工具就在对话里多一个小标签。关闭时对话只保留对话本身,名字下方的一行字说明它正在做什么。仅本设备。`,"On it: {request}":`正在处理:{request}`,"A star on GitHub helps":`GitHub 上的一颗 Star 帮得上忙`,"Welcome. nanoMuse is free, open source and non-profit, a personal agent for anyone who runs it. If that is worth something to you, a star on GitHub is how the next person finds it.":`欢迎。nanoMuse 免费、开源、非营利,做的是一个属于每个人的个人智能体。如果你认同,GitHub 上的一颗 Star 能让下一个人也找到这里。`,"Three tasks done. If nanoMuse is useful, a star on GitHub helps the next person find it.":`三个任务完成了。如果 nanoMuse 用得上,到 GitHub 点一颗 Star,下一个人也能找到它。`,"{n} tasks done. If nanoMuse is useful, a star on GitHub helps the next person find it.":`已经完成 {n} 个任务了。如果 nanoMuse 用得上,到 GitHub 点一颗 Star,下一个人也能找到它。`,"A week with nanoMuse. If it has earned a place in your day, a star on GitHub helps the next person find it.":`和 nanoMuse 一起一周了。如果它在你的日常里站住了脚,到 GitHub 点一颗 Star,下一个人也能找到它。`,"A month with nanoMuse. If it has become part of your routine, a star on GitHub tells others it is worth a try.":`和 nanoMuse 一起一个月了。如果它成了你习惯的一部分,一颗 Star 会让更多人愿意试一试。`,"{n} days with nanoMuse. If it has earned a place in your day, a star on GitHub helps the next person find it.":`和 nanoMuse 一起 {n} 天了。如果它在你的日常里站住了脚,到 GitHub 点一颗 Star,下一个人也能找到它。`,"Goal reached. If nanoMuse helped you get there, a star on GitHub tells the people building it that it did.":`目标达成了。如果 nanoMuse 帮你走到了这里,到 GitHub 点一颗 Star,做它的人就知道了。`,"Ten tasks together. If nanoMuse has become part of your day, a star on GitHub tells others it is worth a try.":`已经一起完成十个任务了。如果 nanoMuse 成了你日常的一部分,一颗 Star 会让更多人愿意试一试。`,"A new face, drawn for you. If you like where nanoMuse is going, a star on GitHub helps more people find it.":`一张为你画的新面孔。如果你喜欢 nanoMuse 现在的样子,到 GitHub 点一颗 Star,更多人就能遇见它。`,"The free allowance is used up. Thank you for coming this far. If nanoMuse has earned it, a star on GitHub keeps the project in view for the next person.":`免费额度用完了,谢谢你一路用到这里。如果 nanoMuse 值得,到 GitHub 点一颗 Star,下一个人也能找到它。`,"Load earlier messages":`加载更早的消息`,"New side chat":`新建旁聊`,"New side chat, e.g. “Trip to Kyoto”":`新建旁聊,例如“京都之旅”`,Chats:`对话`,New:`新建`,Create:`创建`,Clear:`清空`,"Clear this conversation? Memory and goals are kept.":`清空这段对话?记忆和目标会保留。`,"Delete this side chat and its history?":`删除这个旁聊及其历史记录?`,"Could not send":`发送失败`,"Could not send decision":`无法提交决定`,Send:`发送`,"Show thinking":`显示思考过程`,"Hide thinking":`隐藏思考过程`,"You:":`你:`,"{name} asks":`{name} 提问`,"{name} suggests":`{name} 建议`,"{name} is on it":`{name} 正在处理`,"Browser: {title}":`浏览器:{title}`,safe:`安全`,moderate:`中等`,sensitive:`敏感`,high:`高`,"Exactly what will run":`将要执行的具体内容`,"Why it asks: {reasons}":`询问原因:{reasons}`,"{tool} is on your always-ask list":`{tool} 在你的「总是询问」列表里`,"{tool} is on your always-allow list":`{tool} 在你的「总是允许」列表里`,"{tool} is switched off in your settings":`{tool} 已在你的设置里关闭`,"an action rated {risk}, in {mode} mode":`这个操作的风险等级是「{risk}」,哨兵处于{mode}模式`,"auto mode: not asked":`自动模式:未询问`,"covered by your {scope} permission for {key}":`已在你对 {key} 的「{scope}」授权范围内`,"private data was read earlier in this conversation, and {tool} could send it to {target}, which is not on your allowed list":`这段对话早些时候读取过私密数据,而 {tool} 可能把它发给 {target},这个地址不在你的允许列表里`,ask:`询问`,auto:`自动`,strict:`严格`,once:`一次`,conversation:`本次对话`,session:`本次运行`,"24h":`24 小时`,low:`低`,"Stopped.":`已停止。`,"Use nanoMuse Cloud this time":`这次改用 nanoMuse Cloud`,"Answered by nanoMuse Cloud this time ({model})":`这次由 nanoMuse Cloud 回答({model})`,Deny:`拒绝`,"Allow once":`允许一次`,Allow:`允许`,"{name} wants to":`{name} 想要`,"at {host}":`站点:{host}`,"to {recipient}":`收件人:{recipient}`,"Allow {subject} for longer…":`更长时间允许 {subject}…`,"For this conversation":`本次对话`,"the device {name}":`设备「{name}」`,"Until restart":`直到重启`,"For 24 hours":`24 小时内`,"Always for {subject}":`始终允许 {subject}`,"Fewer options":`收起`,"Show all":`展开全部`,"This kind of action is approved one at a time.":`这类操作需要逐次批准。`,Approved:`已批准`,Denied:`已拒绝`,"Expired without an answer":`已过期,未作答`,"approved by you":`已由你批准`,"covered by your {scope} permission":`已由你的{scope}授权覆盖`,"for this conversation":`本次对话`,"until restart":`直到重启`,"for 24 hours":`24 小时内`,always:`始终`,"email to {who}":`发送给 {who} 的邮件`,"{what} commands":`{what} 命令`,browser:`浏览器`,email:`邮件`,secret:`密钥`,"Waiting for you":`等你确认`,Answer:`回答`,LIVE:`实时`,BROWSER:`浏览器`,"Frame no longer available":`画面已不可用`,Page:`页面`,Document:`文档`,Image:`图片`,Data:`数据`,Code:`代码`,Open:`打开`,Download:`下载`,"Type into the focused field…":`输入到当前聚焦的输入框…`,Type:`输入`,"Press Enter":`按回车`,"Open a URL…":`打开一个网址…`,Go:`前往`,"Tap the page to click. If the browser was closed, open a URL first.":`点击画面即可点击网页。如果浏览器已关闭,请先打开一个网址。`,Refresh:`刷新`,"Take over":`接管`,"This frame is no longer available.":`这一帧画面已不可用。`,"Look again":`重新查看`,"1 frame":`1 帧`,"{n} frames":`{n} 帧`,"Scroll up":`向上滚动`,"Scroll down":`向下滚动`,"You have the page. Press Done when you are finished.":`页面现在由你操作。完成后按「完成」。`,"{name} waits meanwhile, then looks at the page as you left it and carries on. Passwords you type here go to the website, never to the model.":`{name} 会先等着,然后从你离开时的页面接着做。你在这里输入的密码只发给网站,不会给模型。`,"{name} is waiting for you":`{name} 在等你`,"{name} is working":`{name} 正在工作`,"Your turn":`该你了`,"Your turn: {reason}":`该你了:{reason}`,"You took over {thing}":`你接管了{thing}`,"the browser":`浏览器`,"the phone":`手机`,"The browser":`浏览器`,"The phone":`手机`,"Do this part yourself, then press Done. {name} looks again and carries on from there.":`这一步请你自己来,做完按「完成」。{name} 会重新看一眼屏幕,从那里接着做。`,"{name} waits. Press Done when you are finished and it looks again.":`{name} 在等。你弄完后按「完成」,它会重新看一眼。`,"{name} waited ten minutes and went on without you.":`{name} 等了十分钟,没等到你,先继续了。`,"Ended when the runtime restarted.":`运行时重启,这次接管结束。`,"You did it; {name} carried on.":`你做完了,{name} 接着做了。`,"Handed back; {name} carried on.":`已交还,{name} 接着做了。`,Close:`关闭`,"Open in a new tab":`在新标签页打开`,"No preview for this file type.":`此类型文件无法预览。`,"Download it":`下载文件`,"Empty file.":`空文件。`,"Could not load the file: {error}":`无法加载文件:{error}`,"Writing…":`正在写…`,"While you were away":`你离开期间`,"Could not write posts: {error}":`无法生成动态:{error}`,"Nothing yet. Once {name} works on a goal in the background or needs your approval, it shows up here.":`暂时还没有内容。当 {name} 在后台推进目标或需要你批准时,会显示在这里。`,"Next up":`接下来`,"Background work is off. {name} only acts when you ask.":`后台工作已关闭。{name} 只在你要求时行动。`,"Turn it on":`开启`,"No goal has a next step to work on.":`没有目标有可执行的下一步。`,"Add one":`添加一个`,"Working now":`正在进行`,"Quiet hours after {time}":`免打扰时段,{time} 之后`,"Around {time}":`大约 {time}`,Soon:`即将`,overdue:`已逾期`,"{n} more in line":`还有 {n} 个排队中`,"Check-in on":`跟进`,"{n} more":`还有 {n} 个`,Reminder:`提醒`,Routine:`例程`,"Working on your goal: {title}":`推进目标:{title}`,"Check-in: {title}":`跟进:{title}`,"Reminder: {title}":`提醒:{title}`,"Routine: {title}":`例程:{title}`,"New mail: {title}":`新邮件:{title}`,"Coming up: {title}":`即将开始:{title}`,"Webhook: {title}":`Webhook:{title}`,"Tidied memory":`整理了记忆`,"{label}: nothing new":`{label}:没有新进展`,"Open chat":`打开对话`,Today:`今天`,Yesterday:`昨天`,Menu:`菜单`,Stop:`停止`,"Nothing to stop":`没有正在进行的任务`,Message:`发消息`,"An emoji instead":`改用表情符号`,"Refresh ideas":`刷新灵感`,Planning:`规划`,Research:`调研`,Money:`财务`,People:`人际`,"Files & tools":`文件与工具`,"Just for you":`专属于你`,Tracking:`追踪`,"Show {n} more":`还有 {n} 个`,Cancelled:`已取消`,"Starter ideas. Refresh once {name} knows you better.":`入门灵感。等 {name} 更了解你之后再刷新。`,"Generated {when}":`生成于 {when}`,"Could not refresh ideas: {error}":`无法刷新灵感:{error}`,"Do it for me":`帮我做`,Health:`健康`,Finance:`财务`,Career:`事业`,Learning:`学习`,Relationships:`关系`,Family:`家庭`,Home:`家居`,Travel:`旅行`,Creative:`创作`,Other:`其他`,"New goal":`新目标`,Paused:`已暂停`,Finished:`已完成`,active:`进行中`,paused:`已暂停`,done:`已完成`,cancelled:`已取消`,pending:`待处理`,blocked:`受阻`,"{done}/{total} done":`已完成 {done}/{total}`,"Next: {step}":`下一步:{step}`,"Next check-in {when}":`下次跟进 {when}`,"Due today":`今天到期`,"Due tomorrow":`明天到期`,"Due in {n} days":`{n} 天后到期`,"Was due {date}":`原定 {date} 到期`,"By {date}":`截止 {date}`,"No target date":`没有目标日期`,"No category":`未分类`,"Every day":`每天`,"Once a week":`每周一次`,"Once a month":`每月一次`,Weekdays:`工作日`,Weekly:`每周`,Monthly:`每月`,"Daily at {time}":`每天 {time}`,"Weekdays at {time}":`工作日 {time}`,"Weekly at {time}":`每周 {time}`,"{day}s at {time}":`每{day} {time}`,"Monthly on the {day} at {time}":`每月 {day} 日 {time}`,"Work on it now":`现在就推进`,"Work on {title} now":`现在推进「{title}」`,"{name} is working on “{title}” in the main chat":`{name} 正在主要聊天中推进“{title}”`,"{name} is working on it in the main chat":`{name} 正在主要聊天中处理`,"Check in with me now":`现在跟我确认进度`,"{name} will check in with you in the main chat":`{name} 会在主要聊天中跟你确认进度`,"Discuss this goal in chat →":`在对话中讨论这个目标 →`,"About my goal “{title}” ({id}): what's the status, and what should we do next?":`我们来聊聊我的目标“{title}”({id})。现在进展如何,下一步该做什么?`,Pause:`暂停`,Resume:`继续`,Done:`完成`,Delete:`删除`,"Delete goal":`删除目标`,"Delete “{title}”?":`删除“{title}”?`,Edit:`编辑`,Save:`保存`,"Saving…":`保存中…`,Saved:`已保存`,Cancel:`取消`,"Add step":`添加步骤`,"Add a step":`添加一个步骤`,"What should be done…":`要做什么…`,"Mark step {n} {status}":`把第 {n} 步标记为{status}`,"Adjust the plan for “{title}”?":`调整“{title}”的计划?`,"Keeps the 1 step already done.":`保留已完成的 1 个步骤。`,"Keeps the {n} steps already done.":`保留已完成的 {n} 个步骤。`,"New remaining steps:":`新的剩余步骤:`,"Keep my plan":`保留我的计划`,"Use {name}'s plan":`采用 {name} 的计划`,"Kept your plan":`已保留你的计划`,"Plan updated":`计划已更新`,"What do you want to achieve?":`你想实现什么?`,"Why it matters, constraints (optional)":`为什么重要、有哪些限制(可选)`,"Area of life":`生活领域`,"Target date":`目标日期`,"Steps, one per line (optional, or let {name} plan them)":`步骤,每行一个(可选,也可以让 {name} 来规划)`,"Let {name} plan it":`让 {name} 来规划`,'Create a goal for me: "{title}"{description}{extras}. Break it into concrete steps with the goals tool, then tell me the plan.':`帮我创建一个目标:“{title}”{description}{extras}。用 goals 工具把它拆成具体步骤,然后告诉我计划。`,"Day {d}":`第 {d} 天`,"Search files":`搜索文件`,"No files match.":`没有匹配的文件。`,Latest:`最新`,"Updated {when}":`更新于 {when}`,Memory:`记忆`,"What {name} remembers about you. Read it, add to it, or make {name} forget; nothing here is hidden from you.":`{name} 对你的了解都在这里。你可以翻看、补充,或让 {name} 忘掉,没有什么是瞒着你的。`,"Tell {name} something to remember, e.g. “I'm vegetarian” or “My sister's birthday is 14 May”":`告诉 {name} 要记住的事,例如“我是素食者”或“我妹妹的生日是 5 月 14 日”`,Remember:`记住`,Forget:`忘掉`,"Forget “{text}”?":`忘掉“{text}”?`,"Nothing remembered yet":`还没有记住任何内容`,"{name} saves durable facts you share in chat (preferences, people, routines) and never secrets.":`{name} 会保存你在对话中分享的长期事实(偏好、人物、习惯),绝不保存密钥或密码。`,"added by you":`由你添加`,"saved by {name}":`由 {name} 保存`,"updated {when}":`更新于{when}`,"Tidy up":`整理`,"Tidying…":`整理中…`,"Merge lines that say the same thing and drop what was never a fact about you. Every change can be undone.":`把意思相同的条目合并,删掉那些并不是你本人情况的内容。每处改动都能撤销。`,"Nothing to tidy: {n} memories, all distinct.":`无需整理:{n} 条记忆,互不重复。`,"Tidied: {merged} merged, {dropped} dropped. Undo below if needed.":`已整理:合并 {merged} 条,去掉 {dropped} 条。如有需要可在下方撤销。`,"Recent changes":`最近的改动`,Merged:`已合并`,Dropped:`已去掉`,Updated:`已更新`,restored:`已恢复`,Undo:`撤销`,profile:`个人资料`,preference:`偏好`,people:`人物`,routine:`习惯`,constraint:`限制`,general:`一般`,idle:`空闲`,working:`工作中`,waiting:`等待中`,Activity:`活动`,Approvals:`审批`,Connections:`连接`,Settings:`设置`,"Nothing is waiting for you.":`没有需要你处理的事项。`,"{n} events":`{n} 个事件`,failed:`失败`,updated:`已更新`,"background check":`后台检查`,"Every tool call goes through the Sentinel and is written to the audit log, including the ones it refused.":`每一次工具调用都经过 Sentinel 审查并写入审计日志,包括被拒绝的那些。`,"Sentinel mode:":`Sentinel 模式:`,balanced:`平衡`,cautious:`谨慎`,"hands-off":`放手`,"Safe and moderate actions run freely; anything sensitive (email, shell, purchases) waits for you.":`安全和中等风险的操作自由执行;任何敏感操作(邮件、终端命令、购买)都会等你批准。`,"Moderate and sensitive actions both wait for your approval.":`中等和敏感风险的操作都会等待你的批准。`,"Everything is approved automatically except explicit deny rules. Use with care.":`除明确的拒绝规则外,一切自动批准。请谨慎使用。`,"Always asks before: {tools}.":`以下操作总会先问你:{tools}。`,"Private data was read this session: network calls to new destinations need approval.":`本次会话已读取过私密数据:访问新的网络目标需要批准。`,"Commands run in a sandbox":`命令在沙箱中运行`,"Commands run without a sandbox":`命令未在沙箱中运行`,"Each shell or Python call gets its own namespace: only the workspace is writable, your home directory is not there, and there is no network unless the command needs it.":`每次 shell 或 Python 调用都有独立的命名空间:只有工作区可写,你的主目录不在其中,命令不需要网络就没有网络。`,"Each shell or Python call runs in the workspace with a scrubbed environment; the container is the boundary.":`每次 shell 或 Python 调用都在工作区中以清洗过的环境运行;容器就是边界。`,"Each shell or Python call runs in the workspace with a scrubbed environment. On Linux, installing bubblewrap gives each one its own namespace.":`每次 shell 或 Python 调用都在工作区中以清洗过的环境运行。在 Linux 上安装 bubblewrap 后,每次调用会有独立的命名空间。`,"After reading private data, new network destinations need approval.":`读取私密数据之后,访问新的网络目标需要批准。`,"Permissions you granted":`你授予的权限`,"No standing approvals. When you answer “always allow” to a risky step, it is listed here and can be revoked; approvals you give once are not kept.":`还没有长期批准。对有风险的操作选择“始终允许”后,会列在这里,随时可以撤回;“允许一次”的批准不会保留。`,"Nothing yet today. What you ask for and what {name} does about it shows up here.":`今天还没有动态。你提的要求和 {name} 做的事会显示在这里。`,"Share avatar":`分享形象`,"Creates a routine":`会创建一条例程`,"Creates a goal":`会创建一个目标`,"Create routine":`创建例程`,"Start goal":`开始这个目标`,"Routine set: every day at {time}. It is listed under Goals.":`例程已设好:每天 {time}。在「目标」页可以看到。`,"A morning brief":`早间简报`,"Before you leave each morning: the weather, the first thing on your plate and anything new worth knowing.":`每天出门前:天气、今天的第一件事,以及值得知道的新消息。`,"Morning brief: check today's weather, read my calendar and reminders for today, and tell me in five lines what matters.":`早间简报:查今天的天气,读我今天的日程和提醒,用五行告诉我要紧的事。`,"drawn from the picture you attached":`按你附的图片来画`,"Share my avatar":`分享我的虚拟形象`,"Pick a card. It goes out through the system share sheet, or saves as a picture where there is none.":`选一张卡片,用系统分享发出去;没有系统分享的浏览器会保存为图片。`,"Hi, I'm {name}, a personal AI agent. Meet nanoMuse: open source, runs on your phone.":`你好,我是你的个人 AI 智能体 {name}。认识一下 nanoMuse:开源,在手机上本地运行。`,"Your personal AI agent, open source · {repo}":`你的个人 AI 智能体,开源 · {repo}`,Later:`以后再说`,Share:`分享`,"Save picture":`保存图片`,"Saved the card as a picture.":`卡片已保存为图片。`,"The card could not be drawn.":`卡片没能画出来。`,"the hands in {app}":`在 {app} 里动手`,"granted {time}":`授予于 {time}`,"until {time}":`直到 {time}`,"Revoke {what}":`撤销 {what}`,"Revoked: {subject}":`已撤销:{subject}`,"Reset all granted permissions":`重置所有已授予的权限`,"Permissions reset":`权限已重置`,"Always ask (from config)":`始终询问(来自配置)`,Off:`关闭`,Low:`低`,Default:`默认`,High:`高`,"Off. {name} only works when you ask.":`已关闭。{name} 只在你要求时工作。`,"every {n} min {name} picks one active goal and works on its next step.":`每 {n} 分钟 {name} 挑选一个进行中的目标并推进它的下一步。`,"Quiet hours until {time}.":`免打扰时段直到 {time}。`,"Next around {time}.":`下一次大约在 {time}。`,"No background work in this window; anything due waits until it ends.":`此时段不进行后台工作;到期的事项会等到时段结束。`,"Level, interval and quiet hours in Settings":`在设置中调整级别、间隔和免打扰时段`,"In line":`排队中`,"No active goal has a next step. Add one in Goals and {name} will pick it up.":`没有进行中的目标有下一步。在目标中添加一个,{name} 会接手。`,"{n} queued":`{n} 个排队中`,"Check-ins":`跟进`,"Goal nudges you asked for; they arrive whatever the proactivity level, but wait out quiet hours.":`你要求的目标提醒;无论主动性级别如何都会送达,但会避开免打扰时段。`,"Reminders & routines":`提醒与例程`,"When something happens":`当某事发生时`,"mail matching “{match}”":`匹配“{match}”的邮件`,"any new mail":`任何新邮件`,"events matching “{match}”":`匹配“{match}”的日程`,"any event":`任何日程`,"{n} min before {what}":`{what}开始前 {n} 分钟`,"webhook “{match}”":`Webhook“{match}”`,webhook:`Webhook`,"Nothing yet. Tell {name} “when the landlord writes back, summarise it and draft a reply” or “half an hour before any review, brief me”.":`还没有。告诉 {name}“房东回信时,帮我总结并起草回复”或“任何评审开始前半小时,给我一份简报”。`,"fired {n}×":`触发 {n} 次`,"not fired yet":`尚未触发`,"Copy URL":`复制地址`,"Run now: {text}":`现在运行:{text}`,"Webhook URL copied":`已复制 Webhook 地址`,"The inbox could not be read: {error}":`无法读取收件箱:{error}`,"Inbox checked {when}; {name} looks every {n} min.":`收件箱{when}检查过;{name}每 {n} 分钟查看一次。`,"{name} will look at the inbox shortly, then every {n} min.":`{name}稍后会查看收件箱,之后每 {n} 分钟一次。`,"Each time it happens {name} does the work in the chat it was set from and reports in the Feed. A mail or a request is treated as data, never as instructions.":`每次触发时,{name} 会在设定它的那个对话里把事做完,再到动态里汇报。邮件和请求的内容只当资料看,绝不当作指令执行。`,"Webhook ready":`Webhook 已就绪`,"POST anything to this URL and the work starts. The key is in the URL; share it only with the program that will call it.":`向这个地址 POST 任意内容即可开始工作。密钥就在地址里,只交给要调用它的程序。`,Copy:`复制`,"New mail":`新邮件`,"Before an event":`日程开始前`,Webhook:`Webhook`,"Connect a mailbox under Connections first.":`请先在“连接”里接入邮箱。`,"Add a calendar under Connections first.":`请先在“连接”里添加日历。`,"Words in the sender or subject (empty: any mail)":`发件人或主题中的词(留空:任何邮件)`,"Words in the title or place (empty: any event)":`标题或地点中的词(留空:任何日程)`,"A name for this hook":`给这个 Webhook 起个名字`,"Minutes before":`提前分钟数`,"min before":`分钟前`,"What should be done each time…":`每次要做什么……`,"When {condition}":`当{condition}`,"Set trigger":`设置触发器`,"A time you named is kept whatever the level or the quiet hours. Reminders just say it; routines do the work and report.":`你指定的时间无论级别或免打扰时段都会遵守。提醒只是说一声;例程会执行工作并汇报。`,"No reminders":`没有提醒`,"Nothing scheduled. Tell {name} “remind me at six to call mum” or “every weekday morning, summarise my unread email”.":`没有安排。告诉 {name}“六点提醒我给妈妈打电话”或“每个工作日早上汇总我的未读邮件”。`,"{n} finished recently":`最近完成 {n} 个`,"Do “{text}” now":`现在执行“{text}”`,"Remind me now: {text}":`现在提醒我:{text}`,"Cancel: {text}":`取消:{text}`,"{name} will say it now":`{name} 现在就会说`,"+ Add":`+ 添加`,"Remind me":`提醒我`,Repeat:`重复`,"What to remind you of…":`提醒你什么…`,"Set reminder":`设置提醒`,"Set routine":`设置例程`,at:`于`,"1 approval waiting for you":`需要你批准`,"{n} approvals waiting for you":`{n} 项需要你批准`,"{n} approval":`{n} 项审批`,You:`你`,"Its name and look, how careful it is, how often it speaks up.":`名字和形象,有多谨慎,多主动。`,Name:`名字`,Avatar:`头像`,"What it calls you":`它怎么称呼你`,"Safety · Sentinel":`安全 · Sentinel`,"A separate gatekeeper reviews every action. Pick how often it should check in with you.":`一个独立的守门人审查每一次操作。选择它多久向你确认一次。`,Balanced:`平衡`,"Browse, read and write files freely; stop for anything hard to undo: email, purchases, shell commands.":`自由浏览、读写文件;遇到难以撤销的操作时停下:邮件、购买、终端命令。`,Cautious:`谨慎`,"Also ask before moderate actions like fetching web pages or writing files.":`对抓取网页或写入文件等中等风险操作也先询问。`,"Hands-off":`放手`,"Approve everything automatically except explicit deny rules. For trusted, unattended runs only.":`除明确的拒绝规则外一切自动批准。仅用于可信的无人值守运行。`,"Decides when the Sentinel asks you before a call.":`决定 Sentinel 在调用前何时向你询问。`,Proactivity:`主动性`,"Only works when you ask.":`只在你要求时工作。`,"Checks in half as often; speaks up only when a step is done or it needs you.":`检查频率减半;只在完成一步或需要你时才发声。`,"Works on goals on schedule; reports real progress, stays quiet otherwise.":`按计划推进目标;汇报实质进展,其余时间保持安静。`,"Checks in twice as often and always reports, even 'still on track'.":`检查频率加倍并总是汇报,即使只是“仍在正轨上”。`,"Background work":`后台工作`,"Check-in interval":`检查间隔`,"{n} min":`{n} 分钟`,"{n} h":`{n} 小时`,"{n} d":`{n} 天`,"Halved at this level":`此级别下减半`,"Doubled at this level":`此级别下加倍`,"Quiet hours":`免打扰时段`,From:`从`,to:`到`,Notifications:`通知`,"Approvals, questions, finished background work and check-ins; nothing while the app is on screen.":`审批、提问、后台完成的事和到点的跟进;应用在前台时不打扰。`,"Let {name} notify this device":`让 {name} 通知这台设备`,"Let {name} notify this phone":`让 {name} 通知这台手机`,"The app stays connected to your server in the background. Approvals, questions and finished background work arrive as notifications and open the right chat.":`应用在后台保持与服务器的连接。审批、提问和后台完成的工作会以通知送达,并打开对应的对话。`,"nanoMuse for Android {version}":`nanoMuse Android 版 {version}`,"Disconnect from this server":`断开此服务器`,"This device only":`仅这台设备`,"1 device subscribed":`1 台设备已订阅`,"{n} devices subscribed":`{n} 台设备已订阅`,"Send a test":`发送测试`,"Sent. It should arrive in a moment":`已发送,应该马上就到`,"Notifications need https:// (or localhost). Over plain http on your LAN the app works, this part stays off; see docs/deployment.md.":`通知需要 https://(或 localhost)。在局域网的普通 http 上应用可以使用,但这部分功能保持关闭,参见 docs/deployment.md。`,"This browser cannot receive push notifications.":`这个浏览器无法接收推送通知。`,"This browser has no push service (embedded browsers often don't). Use Chrome, Edge, Firefox or Safari 16.4+ on the phone.":`这个浏览器没有推送服务(内嵌浏览器通常没有)。请在手机上使用 Chrome、Edge、Firefox 或 Safari 16.4+。`,"Notifications are blocked for this site in the browser settings":`浏览器设置中已屏蔽此站点的通知`,"Blocked for this site. Allow notifications in the browser's site settings, then try again.":`通知在这个站点被关掉了。到浏览器的站点设置里允许通知,再试一次。`,"The server was installed without pywebpush.":`服务器安装时未包含 pywebpush。`,"On a phone, add the app to the home screen first; the icon then shows a badge and notifications open the right chat.":`手机上请先把应用添加到主屏幕;图标会显示角标,通知会打开对应的对话。`,Model:`模型`,"Provider / model":`服务商 / 模型`,"Reveal the model's reasoning under each reply when the provider exposes it.":`当服务商提供时,在每条回复下方显示模型的推理过程。`,"Reply language":`回复语言`,"What {name} writes in":`{name} 用什么语言回复`,Auto:`自动`,"Match mine":`跟随我的语言`,"App language":`应用语言`,Appearance:`外观`,Light:`浅色`,Dark:`深色`,"Follow the system":`跟随系统`,About:`关于`,"{version} is out":`{version} 已发布`,"nanoMuse {version}":`nanoMuse {version}`,"Tell {name} something to remember":`在对话里告诉 {name} 一件值得记住的事`,"Write one":`写一个`,"Latest {version}; you have it":`最新版 {version},你已经在用了`,Update:`更新`,"Check now":`现在检查`,"Checking…":`正在检查…`,"Could not check":`没能检查到最新版本`,"Checked {when}":`上次检查:{when}`,"The phone app checks for updates on its own.":`手机 App 会自己检查更新。`,"Update checks are off here.":`这里关闭了更新检查。`,"To update: pip install -U nanomuse, pull the new image, or use the desktop app's Update.":`更新方式:pip install -U nanomuse、拉取新镜像,或在桌面 App 里点“更新”。`,"Data:":`数据:`,"Workspace:":`工作区:`,"Forget this device's access token":`忘掉这台设备的访问令牌`,"does the work":`负责干活`,Calendar:`日历`,calendar:`日历`,Tomorrow:`明天`,"all day":`全天`,"{n} scheduled":`{n} 个安排`,"Nothing on the calendar today.":`今天日历上没有安排。`,"Ask about your week":`问问这周的安排`,"{name} could not be read":`{name} 读取失败`,"Your agenda, free time, and events it can draft":`你的日程、空闲时间,以及它起草的日程`,"{n} not reading":`{n} 个读取失败`,"1 event":`1 个事件`,"{n} calendars":`{n} 个日历`,"read {when}":`{when}读取`,"Calendar connected":`日历已连接`,"Reads your calendar from its private .ics link; the link stays in the vault. It never changes your calendar; an event it proposes comes as a file you add with a tap.":`通过私密 .ics 链接读取你的日历,链接存在保险库里。它不会改动你的日历;它建议的日程会做成文件给你,点一下就能加进去。`,"not read yet":`尚未读取`,"Where is the link?":`链接在哪里?`,"Settings → your calendar → Integrate calendar → Secret address in iCal format":`设置 → 你的日历 → 整合日历 → iCal 格式的私密地址`,"Settings → Calendar → Shared calendars → Publish a calendar → ICS link":`设置 → 日历 → 共享日历 → 发布日历 → ICS 链接`,"Share Calendar → Public Calendar → copy the webcal:// link":`共享日历 → 公共日历 → 复制 webcal:// 链接`,"Settings → Calendars → Export → Calendar URL":`设置 → 日历 → 导出 → 日历 URL`,"A path on the machine where nanoMuse runs, for example ~/calendar.ics":`nanoMuse 所在机器上的文件路径,例如 ~/calendar.ics`,".ics file":`.ics 文件`,Work:`工作`,"Private .ics link or file path":`私密 .ics 链接或文件路径`,"Stored encrypted in the vault as CALENDAR_{name}.":`加密保存在保险库中,名为 CALENDAR_{name}。`,"nanoMuse fetches whatever address you put here, from this machine; only paste links you trust.":`nanoMuse 会从这台机器上去取你填的任何地址,只粘贴你信任的链接。`,"Add a calendar":`添加日历`,"Added, but it could not be read: {error}":`已添加,但读取失败:{error}`,Contacts:`通讯录`,"1 person":`1 人`,"{n} people":`{n} 人`,"Address book connected":`通讯录已连接`,"Who is who, so it never guesses an address":`知道谁是谁,从不猜地址`,"told to it in chat":`在聊天中告诉它的`,"{n} address books":`{n} 个通讯录`,"Import a .vcf export from Google Contacts, iCloud, Outlook or your phone, or paste a link to one. People you mention in chat go into its own book. It looks people up before writing to them and warns when an address is unknown.":`导入 Google 通讯录、iCloud、Outlook 或手机导出的 .vcf 文件,或粘贴一个链接。你在聊天中提到的人会记进它自己的名册。写信前它会先查人,地址不认识时会提醒。`,"My contacts":`我的联系人`,"added in chat":`聊天中添加`,iPhone:`iPhone`,"A .vcf file from your phone or computer":`手机或电脑上的 .vcf 文件`,"Google Contacts: Export → vCard. iPhone: Contacts → select all → Share → Save to Files. Outlook: People → Manage → Export.":`Google 通讯录:导出 → vCard。iPhone:通讯录 → 全选 → 共享 → 存储到“文件”。Outlook:人员 → 管理 → 导出。`,"Choose a .vcf file":`选择 .vcf 文件`,"Or a link / path to one":`或一个链接 / 路径`,"A link is stored encrypted in the vault as CONTACTS_{name}.":`链接会加密保存在保险库中,名为 CONTACTS_{name}。`,"Add an address book":`添加通讯录`,"Find someone, as the agent would":`像 Agent 那样查一个人`,"No one matches.":`没有匹配的人。`,"Working hours":`工作时间`,"Free time is looked for inside these hours.":`空闲时间只在这个时段内查找。`,"Read again":`重新读取`,Event:`日程`,"No event in this file.":`这个文件里没有日程。`,"Untitled event":`未命名日程`,"Add to calendar":`加入日历`,"Opens in your calendar app, which asks before it saves anything.":`会在你的日历应用中打开,保存前会先询问你。`,"What {name} can reach; keys stay in the vault on this machine.":`{name} 能用到的东西;密钥留在这台机器的保险库里。`,"No key yet":`还没有密钥`,"Key missing from vault":`保险库中缺少密钥`,"Key in vault":`密钥已在保险库`,"Key from config":`密钥来自配置`,"No key needed":`无需密钥`,Provider:`服务商`,"Base URL":`Base URL`,"API key":`API 密钥`,"A key is in the vault. Leave blank to keep it.":`保险库中已有密钥。留空则保持不变。`,"Stored encrypted in the vault as LLM_API_KEY.":`以 LLM_API_KEY 加密存储在保险库中。`,"model name":`模型名称`,"Tool calling":`工具调用`,"Auto uses the API's function calling and falls back to describing tools in the prompt when the endpoint rejects them. Prompt: for endpoints that silently ignore tools.":`自动:使用 API 的函数调用,当端点拒绝时回退为在提示词中描述工具。提示词:用于会静默忽略工具的端点。`,Test:`测试`,"Model saved":`模型已保存`,'Replied "{reply}" in {ms} ms':`在 {ms} 毫秒内回复了“{reply}”`,"Email connected":`邮件已连接`,"Saved, but the test failed":`已保存,但测试失败`,"Email disconnected":`邮件已断开`,Incomplete:`未完成`,"Not connected":`未连接`,Email:`邮件`,"reads and sends":`读取和发送`,"Read your inbox, draft and send mail":`读取收件箱、起草和发送邮件`,"Reading is a moderate action; sending always asks you first. Use an app password where your provider offers one.":`读取是中等风险操作;发送总会先询问你。如果服务商提供应用专用密码,请使用它。`,Address:`邮箱地址`,Password:`密码`,"app password":`应用专用密码`,"A password is in the vault. Leave blank to keep it.":`保险库中已有密码。留空则保持不变。`,"Stored encrypted in the vault as EMAIL_PASSWORD.":`以 EMAIL_PASSWORD 加密存储在保险库中。`,"IMAP server":`IMAP 服务器`,Port:`端口`,"SMTP server":`SMTP 服务器`,"STARTTLS for SMTP (off for port 465)":`SMTP 使用 STARTTLS(465 端口请关闭)`,"Save & test":`保存并测试`,Disconnect:`断开`,"Signed in · {n} messages in the inbox":`已登录 · 收件箱有 {n} 封邮件`,Browser:`浏览器`,"Open pages, click, fill forms, screenshot":`打开页面、点击、填表、截图`,"Playwright is not installed on the server":`服务器上未安装 Playwright`,On:`开`,Unavailable:`不可用`,"Install it where the server runs:":`在服务器运行的机器上安装:`,"Server connected":`服务器已连接`,"MCP servers":`MCP 服务器`,"{n} of {total} connected · {tools} tools":`{total} 个中已连接 {n} 个 · {tools} 个工具`,"Add tools from any Model Context Protocol server":`从任意 Model Context Protocol 服务器添加工具`,"{n} on":`{n} 个已开启`,None:`无`,"{n} tools":`{n} 个工具`,"from config.toml":`来自 config.toml`,Remove:`移除`,Command:`命令`,"Run locally over stdio, for example: npx -y @modelcontextprotocol/server-filesystem ./workspace":`通过 stdio 在本地运行,例如:npx -y @modelcontextprotocol/server-filesystem ./workspace`,"or URL":`或 URL`,"A remote server over Streamable HTTP.":`通过 Streamable HTTP 连接的远程服务器。`,"Risk of its tools":`其工具的风险级别`,"Add a server":`添加服务器`,"Connected on {device}; sign in here to use it on this device":`已在 {device} 上连接,在这台设备上登录后即可使用`,"Sign in here":`在这里登录`,"Stored in the vault":`已存入保险库`,Vault:`保险库`,"{n} secrets · encrypted on your machine":`{n} 个密钥 · 在你的机器上加密`,"Encrypted secrets the model never sees":`模型永远看不到的加密密钥`,"Refer to a secret as":`在工具调用或配置中用`,"in a tool call or config: the value is filled in after the Sentinel approves and is redacted from everything the model reads.":`引用密钥:真实值会在 Sentinel 批准后填入,并从模型读到的所有内容中脱敏。`,"Delete {name}":`删除 {name}`,Value:`值`,Store:`存储`,"Skip setup":`跳过设置`,"Meet your nanoMuse":`认识你的 nanoMuse`,"Your name":`你的名字`,"The model behind it":`背后的模型`,"A model is already set up on the server. Keep it, or switch here.":`服务器上已经配置了模型。可以保留,也可以在这里切换。`,"Connect your mail, calendar and contacts":`连接你的邮箱、日历和通讯录`,"Optional. With a mailbox connected it can read what came in and draft replies; it will always ask before sending. With a calendar it knows your day and finds free time. With your contacts it knows who is who. The browser and MCP servers are under Connections later.":`可选。连上邮箱,它能读新邮件、起草回复,发之前一定先问你。连上日历,它知道你这一天的安排,也能找出空档。连上通讯录,它知道谁是谁。浏览器和 MCP 服务器之后在「连接」里设置。`,Back:`返回`,"Get started":`开始`,Skip:`跳过`,"Save a model to continue":`保存模型后继续`,"Skip for now":`暂时跳过`,"just now":`刚刚`,"any moment":`随时`,"in {span}":`{span}后`,"{span} ago":`{span}前`,"Checked on {label}: nothing new":`已检查 {label}:没有新进展`,"Notes from {name}":`来自 {name} 的笔记`,"Reminders from {name}":`来自 {name} 的提醒`,Once:`一次`,Plan:`计划`,Skills:`技能`,Yours:`你的`,"Built in":`内置`,Fetch:`获取`,"Use in chat":`在聊天中使用`,"Make your own copy":`复制一份改成你的`,"Edit skill":`编辑技能`,"New skill":`新建技能`,"From a link":`从链接导入`,"Files that come with it":`随附文件`,"Folders that could not be read":`无法读取的文件夹`,"Nothing of your own yet":`还没有你自己的技能`,"How {name} does a job, written down once. Start one in chat with /name, or just ask; it picks the skill that fits.":`把 {name} 做某件事的方法写下来,一次就够。在聊天里输入 /名称 直接开始,或者直接提要求,它会自己挑合适的技能。`,"After a job went well, tell {name} “save this as a skill”; it writes the steps down and asks you first. Or write one here, or paste a link to a SKILL.md.":`一件事做得顺利之后,对 {name} 说“把这个存成技能”,它会把步骤写下来,并先征求你的同意。也可以在这里手写一个,或粘贴一个 SKILL.md 的链接。`,"Switch one off to keep it out of {name}'s list. A skill of yours with the same name replaces it.":`关掉某一项,它就不会出现在 {name} 的清单里。你的同名技能会替代内置的那一个。`,"Yours live in {dir}, one folder each with a SKILL.md, the Agent Skills format, so recipes written for other agents work here too.":`你的技能保存在 {dir},每个一个文件夹,里面是一份 SKILL.md。这是 Agent Skills 通用格式,为其他智能体写的技能在这里同样可用。`,"Delete the skill “{name}”? Its folder goes with it.":`删除技能“{name}”?它的文件夹会一并删除。`,"Saving makes a copy of yours with the same name; it replaces the built-in one.":`保存后会生成一份你的同名技能,替代内置的那一个。`,"A SKILL.md: a name and a one-line description up top, then the steps in Markdown.":`一份 SKILL.md:开头是名称和一行说明,下面用 Markdown 写步骤。`,"A raw SKILL.md link, or a GitHub folder or file page.":`SKILL.md 的原始文件链接,或 GitHub 上的文件夹/文件页面。`,"Pick a name first; a template appears here.":`先起个名字,这里会出现一份模板。`,"Attach a file":`添加附件`,Attachments:`附件`,"Say what to do with it…":`说说要拿它做什么……`,"Upload failed":`上传失败`,"Web search":`网页搜索`,"Not set up":`未设置`,"{provider} at {host}":`{provider}({host})`,"{provider} needs {what}; searches use DuckDuckGo until then":`{provider}还需要{what},在此之前搜索走 DuckDuckGo`,"a key":`一个密钥`,"an instance URL":`实例地址`,"DuckDuckGo needs nothing, but it is scraped and rate-limits now and then. For searches that always work, use a provider with an API. Whichever you pick, a failed search falls back to DuckDuckGo with a note.":`DuckDuckGo 无需任何配置,但它是抓取来的结果,偶尔会被限流。想让搜索始终可用,选一个带 API 的服务。无论选哪个,搜索失败时都会退回 DuckDuckGo 并附上说明。`,"Stored encrypted in the vault as SEARCH_API_KEY.":`加密存入保险库,名为 SEARCH_API_KEY。`,"Get a key from {label}":`到 {label} 获取密钥`,"Instance URL":`实例地址`,"A SearXNG you run, with the JSON format enabled in its settings.":`你自己运行的 SearXNG,需在其设置中启用 JSON 格式。`,"{provider} · {n} results · {ms} ms":`{provider} · {n} 条结果 · {ms} 毫秒`,"Recall by meaning":`按含义召回`,"Keyword recall only":`仅按关键词召回`,"By keyword":`按关键词`,"Not reachable":`连不上`,"Not tried yet":`尚未尝试`,Mode:`模式`,Endpoint:`接口`,"Embedding model":`向量模型`,"Same as the model":`与模型相同`,"Another endpoint":`另一个接口`,"{model} at {host}":`{model}({host})`,"{model} · {n} of {total} memories indexed":`{model} · 已索引 {n}/{total} 条记忆`,"{model} · {dims} dims · {n} memories indexed · {ms} ms":`{model} · {dims} 维 · 已索引 {n} 条记忆 · {ms} 毫秒`,"Memories are embedded once and a message finds the ones that mean the same thing, in any language: “写邮件给房东” finds “the landlord is Bob Li”. Keyword recall stays; the two are fused.":`每条记忆只做一次向量化,一句话就能找到含义相同的记忆,不分语言:“写邮件给房东”能找到“the landlord is Bob Li”。关键词召回仍然保留,两者合并排序。`,"Auto uses the model's endpoint when it has embeddings and falls back to keywords when it does not. On insists and warns. Off: keywords only.":`自动:模型接口支持向量化就用,不支持就退回关键词。开:坚持使用,失败时给出警告。关:只用关键词。`,"Any OpenAI-compatible /embeddings: Ollama with an embedding model pulled, OpenAI, a gateway.":`任何 OpenAI 兼容的 /embeddings 接口:拉取了向量模型的 Ollama、OpenAI、网关。`,"The model's endpoint and key. DeepSeek has no embeddings; pick another endpoint.":`使用模型自己的接口和密钥。DeepSeek 没有向量化接口,请选另一个接口。`,"Stored encrypted in the vault as EMBEDDINGS_API_KEY. Ollama needs none.":`加密存在保险库里,名为 EMBEDDINGS_API_KEY。Ollama 不需要密钥。`,"Blank uses the endpoint's default: {model}. On Ollama: ollama pull qwen3-embedding:0.6b (reads Chinese and English).":`留空则用该接口的默认模型:{model}。Ollama 上:ollama pull qwen3-embedding:0.6b(中英文都能读)。`,Phone:`手机`,"{name} is connected":`{name} 已连接`,"A phone":`一台手机`,"No phone connected. Open the app on the phone":`没有连接的手机。在手机上打开 App`,"Tap, type and swipe in the apps on your phone":`在你手机上的 App 里点击、输入、滑动`,Waiting:`等待中`,"Operate the phone":`操作手机`,"When on, the agent can read the screen and act in the apps on the connected phone: 12306, WeChat, Alipay… It asks before paying, sending or deleting.":`打开后,智能体可以读取已连接手机的屏幕,并在上面的 App 里操作:12306、微信、支付宝……付款、发送、删除之前会先问你。`,"{name} ({platform}), {n} apps":`{name}({platform}),{n} 个 App`,Ready:`就绪`,"Not yet":`还没开`,"Not on this Android":`这个安卓版本不支持`,"Operating the screen needs Android 11 or newer; this phone can still be used for everything else.":`操作屏幕需要 Android 11 或更新;其他功能这台手机都能用。`,"Turn on the nanoMuse accessibility service; that is how it sees the screen and taps for you, only while a task runs, with a Stop button on screen.":`打开 nanoMuse 的无障碍服务,它靠这个看屏幕、替你点击,只在任务进行时工作,屏幕上始终有停止按钮。`,"Open Accessibility settings":`打开无障碍设置`,"App settings":`应用设置`,"Greyed out with “Restricted setting”? Android 13+ does that for apps installed from a download: in App settings tap ⋮ → Allow restricted settings, then come back.":`灰色且提示「受限设置」?Android 13+ 对下载安装的应用会这样:在应用设置里点 ⋮ → 允许受限设置,再回来。`,"Android may switch the service off after an update or a battery clean-up; if the phone stops answering, come back here.":`系统更新或电池清理后安卓可能会把服务关掉;手机不再响应时回到这里看看。`,"On the phone's screen: {gui} of {total} steps ({pct}%). The screen is the last resort; a skill, a fetch or the browser comes first.":`在手机屏幕上操作:{total} 步里有 {gui} 步({pct}%)。屏幕是最后一招,技能、抓取、浏览器优先。`,"last seen in {app}":`上次看到在 {app}`,"The operator's model looks at screens step by step: a small, fast model that takes pictures. The Hands model row under Chat model picks one on the same endpoint and key; the fields here are for a different endpoint. Empty = {model}.":`操作屏幕的模型一步步看截图:选一个小而快、能看图的模型。「对话模型」卡片里的「动手模型」一行在同一个接口和 key 上选;这里的字段用于另一个接口。留空 = {model}。`,"same as the chat model":`与对话模型相同`,"the chat model":`对话模型`,"Chat model":`对话模型`,"Hands model":`动手模型`,"Currently {value}":`当前为 {value}`,"The model that looks at screens when the hands run: the phone, this computer, a page the browser cannot read. Your account's hands model is {model}; the chat model above is a different pick.":`动手时看屏幕的模型:手机、这台电脑、浏览器读不了的页面。你账号的动手模型是 {model};上面的对话模型是另一项选择。`,"The model that looks at screens when the hands run: a small, fast one that takes pictures, on the same endpoint and key. Default: this provider's own hands model.":`动手时看屏幕的模型:小而快、能看图,用同一个接口和 key。默认:这个服务商自己的动手模型。`,"The model that looks at screens when the hands run. This provider has no model that sees, so the hands use your account's, {model}, unless you pick one here.":`动手时看屏幕的模型。这个服务商没有能看图的模型,所以不在这里选的话,双手用你账号里的 {model}。`,"{model} does not take pictures, so the hands would be blind with it. Pick a model that sees for them.":`{model} 不能看图,动手时会是盲的。给它选一个能看图的模型。`,"A key is in the vault; leave empty to keep it.":`保险库里已有密钥;留空则保留。`,"Set in config.toml.":`在 config.toml 里设置。`,"Leave empty to use the main model's key.":`留空则使用主模型的密钥。`,"Save and test":`保存并测试`,"The operator's model answers.":`操作手机的模型有回应。`,"A personal agent of your own. Three things to know:":`一个属于你自己的个人智能体。三件事:`,"It does things for you.":`它替你把事情做完。`,"Searches, browses, writes, books, reads mail, and hands you the result, not a list of links.":`搜索、浏览、写作、预订、读邮件,交给你的是结果,不是一堆链接。`,"It keeps working when you close the app.":`你关掉应用,它还在干活。`,"Goals move forward between your visits; it reports in the Feed and notifies you when something is worth it.":`目标在你不在的时候继续推进;它在动态里汇报,值得打扰你时才通知你。`,"It asks you first where it matters.":`要紧的事,它先问你。`,"A separate Sentinel reviews every action. Sending, paying, deleting: it stops and asks; your keys stay in a vault the model cannot read.":`独立的 Sentinel 审查每一个动作。发送、付款、删除:它会停下来问你;你的密钥放在模型读不到的保险库里。`,"Set it up":`设置一下`,"Add a model":`添加模型`,"Pick a provider and paste a key. Yours, stored in the vault.":`选一个服务商,粘贴密钥。密钥是你的,存在保险库里。`,"Connect mail, calendar, contacts":`连接邮箱、日历、通讯录`,"Connected. Tap to add more.":`已连接。点击添加更多。`,"Optional. It can read what came in, know your day, and who is who.":`可选。它就能读到来信、知道你的日程、认得谁是谁。`,Start:`开始`,"Needs a model first.":`先要有一个模型。`,"Add a model to start":`添加模型后开始`,optional:`可选`,"A line under the name, e.g. Your day, sorted.":`名字下面的一句话,例如:你的一天,安排好了。`,Tagline:`标语`,"More names":`换一批名字`,Tone:`语气`,Formal:`正式`,Casual:`随和`,Playful:`活泼`,Concise:`简洁`,"How much it says":`话说多少`,"Short replies":`回答简短`,Detailed:`详细`,"Bullet points":`要点列表`,"Anything else about how it should be":`还有什么想让它成为的样子`,"e.g. A little witty. Uses metric units. Never uses emoji.":`例如:有点风趣。用公制单位。从不用 emoji。`,"OpenAI-compatible · Chat Completions":`OpenAI 兼容 · Chat Completions`,"Responses API":`Responses API`,"Local or your own endpoint":`本地或你自己的端点`,"/v1 is added when the URL has no path.":`URL 没有路径时会自动补上 /v1。`,"The endpoint that serves /chat/completions, for example http://127.0.0.1:8000/v1.":`提供 /chat/completions 的端点,例如 http://127.0.0.1:8000/v1。`,"{n} models from the endpoint":`端点返回了 {n} 个模型`,"Asking the endpoint…":`正在询问端点…`,"Could not list the endpoint's models; these are the usual ones.":`无法列出端点的模型;这些是常见的几个。`,"Get a key from {vendor}":`去 {vendor} 获取密钥`,"No key":`无需密钥`,"No key will be sent.":`不会发送密钥。`,"Show key":`显示密钥`,"Hide key":`隐藏密钥`,"Actions {name} wants to take but cannot without you. Each one shows what will run and why; a permission you grant is bound to that exact tool and target.":`这些是 {name} 想做、但没有你点头就不能做的事。每一项都写明要运行什么、为什么;你给的许可只对那个具体的工具和对象有效。`,"Forget every permission you granted? {name} will ask again next time.":`忘掉你授予的所有权限?下次 {name} 会重新询问。`,"This phone":`这台手机`,"Keep it running":`保持运行`,"Android stops apps that seem idle. {name} runs as a foreground service and holds the phone awake only while a task runs; these switches let it keep that promise on this phone.":`安卓会停掉看起来闲着的应用。{name} 以前台服务运行,只在任务进行时让手机保持唤醒;下面这几个开关,是让它在这台手机上真能做到这一点。`,Battery:`电池`,Unrestricted:`无限制`,Optimised:`已优化`,"Optimised means Android may freeze the agent after a while with the screen off; routines and check-ins then wait until the phone wakes.":`「已优化」意味着熄屏一段时间后安卓可能冻结 Agent;例行任务和提醒要等手机醒来才跑。`,"Display over other apps":`显示在其他应用上层`,Allowed:`已允许`,"Not allowed":`未允许`,"Lets the agent bring an app to the front from the background and show its status capsule while it works in other apps.":`让 Agent 能从后台把应用调到前台,并在其他应用里工作时显示状态胶囊。`,"Alarms & reminders":`闹钟和提醒`,Exact:`精确`,Approximate:`大致`,"With exact alarms a reminder fires at the minute you named even when the phone is asleep; without them Android may deliver it up to a quarter of an hour late.":`有精确闹钟,提醒会在你说的那一分钟响起,哪怕手机在睡眠;没有的话安卓可能晚最多一刻钟送达。`,"Start after a reboot":`重启后自动启动`,"Bring the runtime back when the phone restarts, so routines and check-ins do not stop.":`手机重启后把运行时带回来,例行任务和提醒不中断。`,"Reconnect to your computer when the phone restarts, so approvals keep arriving.":`手机重启后重新连上你的电脑,审批照常送达。`,"On this phone's Android":`这台手机的安卓系统`,"Open the auto-start settings":`打开自启动设置`,"Xiaomi / Redmi / POCO: Settings → Apps → Manage apps → {name} → Autostart on; Battery saver → No restrictions; Other permissions → Display pop-up windows while running in the background on.":`小米 / Redmi / POCO:设置 → 应用设置 → 应用管理 → {name} → 自启动打开;省电策略 → 无限制;其他权限 → 后台弹出界面 允许。`,"Huawei: Settings → Battery → App launch → {name} → Manage manually, all three on (auto-launch, secondary launch, run in background); Settings → Apps → {name} → Battery → Launch: manage manually.":`华为:设置 → 电池 → 应用启动管理 → {name} → 手动管理,三项全开(自动启动、关联启动、后台活动);设置 → 应用 → {name} → 电池 → 启动管理:手动管理。`,"Honor: Settings → Battery → App launch → {name} → Manage manually, all three on; Battery → More battery settings → Stay connected while asleep on.":`荣耀:设置 → 电池 → 应用启动管理 → {name} → 手动管理,三项全开;电池 → 更多电池设置 → 休眠时始终保持网络连接 打开。`,"OPPO / realme / OnePlus: Settings → Battery → More settings → Optimise battery use → {name} → Don't optimise; Settings → Apps → {name} → Battery usage → Allow background activity, Allow auto launch.":`OPPO / realme / 一加:设置 → 电池 → 更多设置 → 应用耗电优化 → {name} → 不优化;设置 → 应用 → {name} → 耗电管理 → 允许后台活动、允许自动启动。`,"vivo / iQOO: i Manager → App manager → Autostart → {name} on; Settings → Battery → Background power consumption management → {name} → Allow high background power consumption.":`vivo / iQOO:i 管家 → 应用管理 → 自启动 → {name} 打开;设置 → 电池 → 后台耗电管理 → {name} → 允许后台高耗电。`,"Samsung: Settings → Battery → Background usage limits → {name} not in Sleeping or Deep sleeping apps (add it to Never sleeping apps); turn off Adaptive battery if it keeps stopping.":`三星:设置 → 电池 → 后台使用限制 → {name} 不在「休眠应用」或「深度休眠应用」里(加入「永不休眠的应用」);如果还是被停,关闭自适应电池。`,"Meizu: Settings → Apps → {name} → Background management → Keep running in the background; Battery → App power management → Allow.":`魅族:设置 → 应用管理 → {name} → 后台管理 → 允许后台运行;电池 → 应用耗电管理 → 允许。`,"Crashes are written to a file on this phone and nowhere else. Export bundles them with the runtime's log for someone you choose.":`崩溃只写到这台手机上的文件里,不上报任何地方。导出会把它们和运行时日志打成一个包,发给你选的人。`,"Export logs":`导出日志`,"clipboard, notifications, calendar, contacts, location, alarms, photos":`剪贴板、通知、日历、通讯录、位置、闹钟、照片`,Devices:`设备`,"Only this one":`只有这一台`,Idle:`空闲`,"A chat addressed to a device runs there; you see every step here and answer its approvals.":`对着某台设备的对话在那台设备上执行;每一步都在这里看得到,审批也在这里答。`,"nanoMuse Cloud":`nanoMuse Cloud`,"Free. One account for all your devices, and a model to start with.":`免费。一个账号连起你所有设备,还附带一个可以先用起来的模型。`,"Signed in":`已登录`,"Not signed in":`未登录`,"Not signed in.":`未登录。`,"Signed out":`已退出`,"{hint} · hub":`{hint} · 中继`,"{hint} · model and hub":`{hint} · 模型和中继`,"Signed in as {hint}. Your devices meet here; the Cloud model comes with a free allowance.":`已登录:{hint}。你的设备在这里互相看见;Cloud 模型自带一份免费额度。`,"Use the Cloud model":`使用 Cloud 模型`,"The Cloud model is in use.":`已切换到 Cloud 模型。`,"Sign out":`退出登录`,"Sign out of nanoMuse Cloud on this device? The hub and the Cloud model stop working here until you sign in again.":`在这台设备上退出 nanoMuse Cloud?重新登录之前,这里的中继和 Cloud 模型都会停用。`,"Mainland China phone number or e-mail":`中国大陆手机号或邮箱`,"138 0000 0000 or you@example.com":`138 0000 0000 或 you@example.com`,"One free account. It is what lets your phone and computers work as one and brings a model to start with.":`一个免费账号。有了它,手机和电脑就是同一个 nanoMuse,还自带一个可以先用起来的模型。`,"It uses your phone and computers for you":`替你操作手机和电脑`,"The relay keeps an account id, a masked identifier, usage counts and your agent's name and look; what else, and what is yours to switch off, is in the":`中继保存账号 id、打码后的手机号或邮箱、用量计数和你的智能体的名字与形象;其余保存什么、哪些由你决定,见`,"privacy policy":`隐私政策`,"Free, open source, non-profit":`免费、开源、非营利`,"nanoMuse is a non-profit open-source community project, free forever.":`nanoMuse 是非营利的开源社区项目,永久免费。`,"Chat apps":`聊天入口`,"nanoMuse is a non-profit open-source community project, free forever. Sign in with a phone number or an e-mail and the model comes with a free allowance, paid by the developer; when it is gone, use your own key (Alibaba Cloud Bailian in mainland China, OpenRouter elsewhere). Nothing is sold; what the relay keeps is in the privacy policy, and Settings → Data controls is yours. Delete the account whenever you like.":`nanoMuse 是非营利的开源社区项目,永久免费。用手机号或邮箱登录,模型自带一份免费额度,费用由开发者承担;用完可以换自己的 key(中国大陆用阿里云百炼,海外用 OpenRouter)。数据不会出售;服务器保存什么写在隐私政策里,「设置 → 数据控制」由你决定。账号随时可以删除。`,"The people building it use it every day. Report a bug, ask for a feature, send a pull request: that is what moves the project. A star on GitHub helps others find it.":`做它的人每天都在用。欢迎反馈问题、提需求、贡献代码,项目就是这样往前走的。在 GitHub 点个 Star,能让更多人找到它。`,"Star on GitHub":`去 GitHub 点个 Star`,"Report a bug or ask for a feature":`反馈问题 / 提需求`,"Data controls":`数据控制`,"Help improve nanoMuse's AI models":`帮助改进 nanoMuse 的 AI 模型`,"While this is on, the text of your chats with the nanoMuse Cloud models (what you wrote, what it answered and the tools it chose to call) is kept on the relay to train the community's own open model. Not your memory or SOUL (the system prompt), not what tools returned, not pictures, and never next to who you are. Your own API key never passes through the relay.":`开启后,你与 nanoMuse Cloud 模型对话的文字(你写的、它回答的,以及它选择调用的工具)会保存在中继上,用来训练社区自己的开源模型。不保存你的记忆和 SOUL(系统提示)、工具返回的内容和图片,也不和你的身份放在一起。用自己的 API key 时,对话不经过中继。`,"New accounts start with it on.":`新账号默认开启。`,"New accounts start with it off.":`新账号默认关闭。`,"Sign in to nanoMuse Cloud to use it.":`登录 nanoMuse Cloud 后可用。`,"{n} turns kept so far.":`目前已保存 {n} 轮对话。`,"{n} turns kept so far":`已保存 {n} 轮对话`,"{n} turns":`{n} 轮`,"On. Turn it off here at any time.":`已开启。随时可以在这里关闭。`,"Off. Nothing more is kept.":`已关闭。之后的对话不再保存。`,"Delete the kept conversations":`删除已保存的对话`,"Removes every turn kept from this account, whether the switch is on or off now. Turning the switch off keeps what was kept until you delete it here.":`删除这个账号已保存的全部对话,不管开关现在是开是关。只关掉开关不会删除已保存的内容,要在这里删。`,"The kept conversations are removed from the server. This cannot be undone.":`已保存的对话会从服务器上删除,不可恢复。`,"{n} turns deleted":`已删除 {n} 轮`,"Set a password":`设一个密码`,"Your account is in. With a password, your phone and your other computers sign in at once, without waiting for a code. Optional; you can set one later under Account.":`账号已登录。设了密码,手机和其他电脑就能直接登录,不用再等验证码。可选,以后也可以在「账号」里设置。`,"At least 8 characters":`至少 8 个字符`,"Set the password":`设置密码`,"Not now":`以后再说`,"I already starred":`已经点过了`,"Free allowance":`免费额度`,"left of ¥{grant}":`剩余 / 共 ¥{grant}`,"¥{spent} used{usd}; the allowance does not reset.":`已用 ¥{spent}{usd};额度不按天重置。`,"No limit on this account.":`这个账号不限额度。`,"¥{allowance} to start, +¥{invite} for each friend you invite, and +¥{invite} for them; after that, your own key keeps the model going.":`起始 ¥{allowance},每邀请一位朋友你 +¥{invite}、对方也 +¥{invite};用完后换自己的 key 继续。`,"The free allowance is used up.":`免费额度已用完。`,"The image provider is busy right now; try again in a minute.":`生图服务现在有点忙,请过一分钟再试。`,"Nearly used up: ¥{left} of ¥{grant} left.":`额度快用完了:还剩 ¥{left}(共 ¥{grant})。`,"Invite a friend (+¥{invite} for each of you) or bring your own key; your sign-in keeps working either way.":`邀请一位新用户(你和对方各 +¥{invite}),或者换成自己的 key;无论哪种,登录都不受影响。`,"See the ways":`看看怎么办`,Dismiss:`关闭`,"Three ways on; your sign-in and your devices keep working whichever you pick.":`三个办法继续用;无论选哪个,登录和多设备功能都不受影响。`,"Use your own model key":`换成自己的 key`,"Alibaba Cloud Bailian is a good start: a new account comes with a free quota, set-up takes about two minutes, and one key covers chat, the hands, pictures and clips.":`推荐阿里云百炼:新用户有免费额度,开通约 2 分钟,一个 key 就能对话、动手、画图、生成视频。`,"Alibaba Cloud Bailian only signs up accounts from mainland China. Outside, OpenRouter is the easy way: one account, one key, pay as you go, for chat, the hands and pictures; clips need Bailian.":`海外用户用不了百炼,推荐 OpenRouter:一个账号一把 key,按量付费,对话、动手、画图都行;生成视频需要百炼。`,"Other providers and what each key covers":`其他服务商,以及各自的 key 能做什么`,"Get a key":`去申请 key`,"covers {list}":`支持{list}`,", ":`、`," or ":`或`,"Sign in with a plan you already pay for":`用你已经在付费的套餐登录`,"{plans}: the plan's models answer here, no key to make. ChatGPT works on every device, the others on the phones. A ChatGPT sign-in covers chat and the hands; pictures and clips still want a key.":`{plans}:套餐里的模型直接在这里回答,不用申请 key。ChatGPT 在每台设备上都可以,其他的在手机上。ChatGPT 登录只覆盖对话和动手;画图和生成视频仍需要一把 key。`,"Sign in with ChatGPT":`用 ChatGPT 登录`,"Or sign in with a ChatGPT plan":`或者用 ChatGPT 套餐登录`,"Covers chat and the hands. Pictures and clips are not part of it; those need a provider with image or video models.":`覆盖对话和动手。画图和生成视频不在其中,那两项需要一个有图像或视频模型的服务商。`,"OpenAI's terms cover using a ChatGPT plan inside OpenAI's own Codex; other apps have had this access cut off before (OpenCode, January 2026). If it stops working, an API key does.":`OpenAI 的条款只允许在它自家的 Codex 里使用 ChatGPT 套餐;其他应用曾被切断过这条路(OpenCode,2026 年 1 月)。哪天它不能用了,API key 仍然可以。`,"This nanoMuse has no sign-in route yet. In a terminal on this computer, run":`这个 nanoMuse 还没有登录接口。在这台电脑的终端里运行`,"and reload this page.":`然后刷新本页。`,"Signed in with {label}.":`已用 {label} 登录。`,"Use it for the chat":`让它来回答对话`,"Sign out of ChatGPT":`退出 ChatGPT`,"A page from OpenAI opened in a new tab. Sign in there; this card follows on its own.":`已在新标签页打开 OpenAI 的页面。在那里登录,这张卡片会自己跟上。`,"Open the page again":`再次打开页面`,"The sign-in did not finish in ten minutes. Try again.":`登录十分钟内没有完成。再试一次。`,"A page from OpenAI opened in a new tab. Sign in there; when the browser ends on an address that will not load, paste that address below.":`已在新标签页打开 OpenAI 的页面。在那里登录;浏览器最后停在一个打不开的地址时,把那个地址粘贴到下面。`,"The address the browser ended on":`浏览器最后停在的地址`,"Use this address":`用这个地址`,"This nanoMuse runs where the browser cannot reach port 1455, so it cannot pick the sign-in up by itself.":`这个 nanoMuse 运行的机器上,浏览器连不到 1455 端口,所以它没法自己接住登录结果。`,"That address belongs to another sign-in attempt. Open the page again and paste the address it ends on.":`这个地址属于另一次登录尝试。再次打开页面,粘贴它最后停在的地址。`,"ChatGPT answers the chat now.":`现在由 ChatGPT 回答对话。`,"Pictures need a provider with image models: {providers}.":`画图需要一个有图像模型的服务商:{providers}。`,"Clips need a provider with video models: {providers}.":`生成视频需要一个有视频模型的服务商:{providers}。`,"The hands need a model that sees pictures: {providers}.":`动手需要一个能看图的模型:{providers}。`,"Chat needs a model: {providers}.":`对话需要一个模型:{providers}。`,How:`怎么做`,"Automatic · {model}":`自动 · {model}`,"E-mail (or a mainland China phone number)":`邮箱(或中国大陆手机号)`,"Text-message codes reach mainland-China numbers only. Use an e-mail address instead.":`短信验证码只能发到中国大陆手机号。其他地区请用邮箱登录。`,"Step-by-step guide":`图文教程`,"Invite a friend: +¥{bonus} for you and +¥{bonus} for them, for each new person who signs up with your link.":`邀请朋友:每有一位新用户通过你的链接注册,你 +¥{bonus},对方也 +¥{bonus}。`,"Your invite link is under Account":`邀请链接在「账号」页`,"Try nanoMuse with me, a fully open-source personal agent, free to use. Sign up with my link: {link}":`来和我一起用 nanoMuse,完全开源的个人智能体,免费使用。用我的链接注册:{link}`,"Invite code (optional)":`邀请码(选填)`,"A friend's code counts for a new account: you both get ¥{invite} more allowance.":`朋友的邀请码只对新账号有效:你和对方的额度各 +¥{invite}。`,"Have an invite code?":`有邀请码?`,"Invite a friend":`邀请朋友`,"Each new person who signs up with your code adds ¥{bonus} to your allowance, and ¥{bonus} to theirs. It never expires.":`每有一位新用户用你的邀请码注册,你的额度 +¥{bonus},对方也 +¥{bonus},不过期。`,"Your code":`邀请码`,Copied:`已复制`,"Share the link":`分享链接`,"Copy the link":`复制链接`,"Try nanoMuse with me, a fully open-source personal agent, free to use. Sign up with my code {code}: {link}":`来和我一起用 nanoMuse,完全开源的个人智能体,免费使用。用我的邀请码 {code} 注册:{link}`,"{n} friends joined":`已邀请 {n} 位`,"¥{amount} added by invitations":`邀请带来 ¥{amount}`,"The code you received":`收到的验证码`,"Send again":`重新发送`,"Send me a code":`发送验证码`,"Sign in":`登录`,"Sign in and use its model":`登录并使用它的模型`,"Signed in to nanoMuse Cloud.":`已登录 nanoMuse Cloud。`,"Or bring your own key":`或者用你自己的密钥`,"This device":`这台设备`,"A name your other devices will see":`其他设备看到的名字`,"On the hub":`已连上中继`,"Reachable by your other devices while this runs.":`运行期间,你的其他设备可以找到它。`,"Sign in first.":`先登录。`,"My other devices may operate it":`允许我的其他设备操作它`,"They can run commands, read files and see its screen here; each step still goes through the Sentinel.":`其他设备可以在这里运行命令、读文件、看屏幕;每一步仍经 Sentinel 审核。`,Refused:`被拒绝`,"Connecting…":`连接中…`,"Connecting to the hub…":`正在连接中继…`,"The hub refused this device. Sign in again.":`中继拒绝了这台设备。请重新登录。`,"The hub is off on this device.":`这台设备没有开启中继。`,"Sign in above to see them.":`先在上面登录,就能看到。`,"{n} online":`{n} 台在线`,online:`在线`,Ask:`去问它`,"Ask one of your devices":`让某台设备去做`,"Every device signed in to your account is a Muse of its own, on the same conversations. Type @ and a device's name in the chat to hand it work; a computer lends its hands.":`登录你账号的每台设备都是一个自己的 Muse,看到的是同一批对话。在聊天里输入 @ 加设备名,就能把活交给它;电脑还能出借它的双手。`,"1 device":`1 台设备`,"{n} devices":`{n} 台设备`,"Other devices":`其他设备`,Online:`在线`,"Last seen {when}":`最后在线 {when}`,Tasks:`任务`,Commands:`命令`,Screenshot:`截屏`,"Open links":`打开链接`,Hands:`双手`,"More about {name}":`{name} 的更多操作`,"Forget this device":`移除这台设备`,"Type @{name} in the chat to hand it work.":`在聊天里输入 @{name},就能把活交给它。`,"Add a device":`添加一台设备`,"No other device yet":`还没有其他设备`,"Install nanoMuse on your phone, Mac or PC and sign in as {hint}; it appears here on its own.":`在手机、Mac 或 PC 上安装 nanoMuse,用 {hint} 登录,它就会自己出现在这里。`,"Install nanoMuse on your phone, Mac or PC and sign in with the same account; it appears here on its own.":`在手机、Mac 或 PC 上安装 nanoMuse,用同一个账号登录,它就会自己出现在这里。`,"Get the apps":`下载应用`,"Forget {name}? It can join again by signing in.":`忘掉 {name}?它重新登录后还可以加入。`,"on {device}":`在 {device} 上`,"from {device}":`来自 {device}`,"asked from {device}":`从 {device} 发来`,"{name} on {device} wants to":`{device} 上的 {name} 想要`,"Hands on this computer":`操作这台电脑`,"On the screen now":`正在操作屏幕`,"Nothing can drive this screen yet.":`目前没有能驱动这块屏幕的组件。`,'On a Mac, allow nanoMuse under System Settings → Privacy & Security → Accessibility and Screen Recording when macOS asks; without them clicks do nothing and the screenshot is black. The first action in each app asks you once ("Let {name} use Safari?") and the answer is kept under Permissions.':`Mac 上,macOS 弹窗询问时请在「系统设置 → 隐私与安全性」的「辅助功能」和「屏幕录制」里允许 nanoMuse;不允许的话点击没有反应,截图也是黑的。每个应用的第一步会先问你一次(「让 {name} 使用 Safari 吗?」),答复记在「权限」里。`,Where:`范围`,"One window":`单个窗口`,"Whole screen":`整个屏幕`,"Working in {app}'s window; the mouse stays yours.":`正在 {app} 的窗口里操作;鼠标仍归你用。`,"On the whole screen for now: {reason}":`暂时在整个屏幕上操作:{reason}`,"One window: the hands work inside the app they were given, send clicks and keys to it alone and leave your mouse alone. Whole screen: the system mouse, like other platforms. Auto picks one window as soon as an app is named.":`单个窗口:只在指定的应用里操作,点击和按键只发给它,不动你的鼠标。整个屏幕:用系统鼠标,和其他平台一样。自动:一旦指定了应用就用单个窗口。`,"It looks at a screenshot and clicks by position; paying, sending and deleting ask you first.":`它看截图、按位置点击;支付、发送、删除前都会先问你。`,Driver:`驱动`,Working:`工作中`,"Stop the hands":`停止操作`,"{name} is using this computer":`{name} 正在操作这台电脑`,"Hands done":`操作完成`,"Hands stopped":`操作已停止`,"{n} steps":`{n} 步`,Clicked:`点击`,"Clicked {label}":`点击了 {label}`,"Double-clicked":`双击`,"Double-clicked {label}":`双击了 {label}`,"Right-clicked":`右键点击`,"Right-clicked {label}":`右键点击了 {label}`,"Pointed at {label}":`指向了 {label}`,"Moved the mouse":`移动了鼠标`,"Typed {n} characters":`输入了 {n} 个字符`,"Pressed {keys}":`按下了 {keys}`,Scrolled:`滚动`,Dragged:`拖动`,"Opened {label}":`打开了 {label}`,"Opened an application":`打开了一个应用`,Waited:`等待`,"The dragon":`小龙`,"The face drawn for you":`为你画的形象`,"Draw four":`画四张`,send_email:`发邮件`,shell:`运行命令`,"E-mail, calendar, browser, MCP servers":`邮件、日历、浏览器、MCP 服务器`,"Rename this device":`给这台设备改名`,"Use my own API key or a plan I pay for":`用我自己的 API key,或我在付费的套餐`,"{first} first, then {others}":`首选 {first},其次 {others}`,"DeepSeek, Kimi, OpenAI, ChatGPT…":`DeepSeek、Kimi、OpenAI、ChatGPT…`,"OpenAI, ChatGPT, Gemini, DeepSeek…":`OpenAI、ChatGPT、Gemini、DeepSeek…`,"Which model answers?":`让哪个模型来回答?`,"Your account already brings one. You can add your own API key as well and switch at any time.":`你的账号已经自带了一个。也可以加上自己的 API key,随时切换。`,"DeepSeek for the chat and Qwen for the hands, with a free allowance per account paid by the developer. Nothing to configure.":`对话用 DeepSeek,动手用 Qwen;每个账号都有一份由开发者承担的免费额度,不用配置。`,"I have my own API key":`我有自己的 API key`,"Alibaba Cloud Bailian first (one key covers chat, the hands, pictures and clips), then DeepSeek, Kimi, Zhipu, OpenAI, OpenRouter and any OpenAI-compatible endpoint. The key stays on this device.":`首选阿里云百炼(一个 key 就能对话、动手、画图、生成视频),其次是 DeepSeek、Kimi、智谱、OpenAI、OpenRouter,以及任何兼容 OpenAI 接口的服务。key 只留在这台设备上。`,"OpenRouter first (one account, one key, pay as you go), then OpenAI, Anthropic, Gemini, DeepSeek and any OpenAI-compatible endpoint. The key stays on this device.":`首选 OpenRouter(一个账号一把 key,按量付费),其次是 OpenAI、Anthropic、Gemini、DeepSeek,以及任何兼容 OpenAI 接口的服务。key 只留在这台设备上。`,"A ChatGPT plan signs in from Connections and answers the chat and the hands. Pictures and clips still want a key.":`ChatGPT 套餐可在「连接」里登录,回答对话并驱动双手。画图和生成视频仍需要一把 key。`,"3D toy (Muse)":`3D 玩偶(Muse)`,Flat:`扁平`,"3D clay":`3D 黏土`,Watercolour:`水彩`,Pixel:`像素`,Line:`线条`,Sticker:`贴纸`,Draw:`画`,"Making pictures":`生成图片`,"Making clips":`生成视频`,"Portraits of your Muse.":`形象的肖像。`,"Short clips of your Muse.":`形象的短视频。`,"The chat model's provider":`对话模型的服务商`,"Your key":`你的 key`,"Add a provider":`添加服务商`,"Other OpenAI-compatible endpoint":`其他 OpenAI 兼容接口`,"The endpoint that serves /images/generations, for example https://host/v1.":`提供 /images/generations 的接口,例如 https://host/v1。`,"Stored encrypted in the vault as {name}.":`以 {name} 加密存储在保险库中。`,"Uses the chat model's key.":`用对话模型的 key。`,"Your phone can now operate this computer: run commands, fetch files, hand over whole tasks. Each risky step still asks here first.":`你的手机现在可以操作这台电脑了:跑命令、取文件、把整件事交给它。有风险的每一步仍会先在这里问你。`,"Picture model":`图片模型`,"Clip model":`短片模型`,"Other model…":`其他模型…`,"More models on your account":`账号可用的更多模型`,"Search models":`搜索模型`,"No model matches":`没有匹配的模型`,"reads pictures":`能看图`,"Type a model id…":`手动输入模型 id…`,"Pick from the list":`从列表里选`,"{n} models your account may use: the menu first, then everything else the provider lists under the Cloud key. Pick one; the ones beyond the menu are priced as the dearest menu model of their kind.":`账号可用的模型共 {n} 个:先是菜单,然后是服务商在 Cloud 这把 key 下列出的其他模型。直接选就行;菜单之外的按同类里最贵的菜单模型计费。`,"Your account may name any model the provider has, not only these: type its id (a chat model here, a picture or clip model below) and it goes through as typed.":`你的账号可以使用服务商的任意模型,不限于这几个:直接输入模型 id(对话模型填在这里,图片或短片模型填在下面),会原样转发。`,Automatic:`自动`,"{n} pictures":`{n} 张图`,"{n} pictures and {c} clips":`{n} 张图加 {c} 段短片`,"{what}, made with your own key at your provider's prices.":`{what},用你自己的 key 按服务商价格计费。`,"The cost could not be checked: {error}":`费用暂时查不到:{error}`,"Checking the cost…":`正在查费用…`,"About ¥{cny} for {what}; your account has no limit.":`{what}约 ¥{cny};你的账号没有额度限制。`,"About ¥{cny} for {what}, more than the ¥{left} left in your allowance.":`{what}约 ¥{cny},超过了额度里剩下的 ¥{left}。`,"About ¥{cny} for {what}; ¥{left} left in your allowance.":`{what}约 ¥{cny};额度还剩 ¥{left}。`,"A new look for {name}":`给{name}换个形象`,"Drawing four to choose from…":`正在画四个供你挑选…`,"Pick one: tap it, or say which":`选一个:点它,或者说第几个`,"Drawing the poses…":`正在画各种姿态…`,"The new look is on; making the clips…":`新形象已经换上,正在做短片…`,"The new look is on":`新形象已经换上`,"Not this time":`这次先不换`,"That did not work":`没成功`,"Candidate {n}":`第 {n} 个`,Redraw:`重画一组`,"Idle, working, waiting, happy, sorry: the face follows what {name} is doing.":`待机、工作、等待、开心、抱歉:形象会跟着 {name} 正在做的事变化。`,"Four more pictures from the one you picked; this takes a minute or two.":`根据你选的这张再画四张;需要一两分钟。`,"Some poses could not be drawn and show the idle picture instead.":`有几个姿态没画出来,先用待机图代替。`,"The face is already on; four short clips are being made from the poses, a few minutes.":`形象已经换上了;正在根据这几张姿态图做四段短片,需要几分钟。`,"Some clips could not be made; those moods stay still.":`有几段短片没做出来,这些状态就用静态图。`,"The new look is on; the clips are being made.":`新形象已经换上;短片正在做。`,"The new look is on.":`新形象已经换上。`,"Not this time.":`这次先不换。`,"New look: {description}. Say what to change any time, or pick another under Settings.":`新形象:{description}。想改随时说,也可以在「设置」里换别的。`,"Join the hub":`加入中继`,"This chat goes to {device}.":`这个对话发给 {device}。`,"Whatever you ask here, the {name} on {device} does where it is: its shell, its files, its screen. Every step shows up here, and anything that needs an approval asks you here.":`在这里说的每件事,都由 {device} 上的 {name} 在它那边完成:它的命令行、它的文件、它的屏幕。每一步都显示在这里,需要批准的事也在这里问你。`,"What is on your screen right now?":`你屏幕上现在是什么?`,"Which folder are you in, and what is in it?":`你在哪个目录,里面有什么?`,"Check for updates and tell me what needs a restart":`检查一下更新,告诉我哪些需要重启`,Account:`账号`,"Account deleted.":`账号已删除。`,"Account id":`账号 ID`,"Sign in to nanoMuse Cloud":`登录 nanoMuse Cloud`,"Sign in to {name}":`登录 {name}`,"nanoMuse Cloud · one account for all your devices":`nanoMuse Cloud · 一个账号,所有设备`,"Every device of yours, one nanoMuse":`你的每台设备,同一个 nanoMuse`,"A model with a free allowance, or your own key":`自带免费额度的模型,或用你自己的 key`,"Keys in your vault; nothing you say is kept on the relay":`key 留在你的保险库里;你说的内容不会留在中继上`,"Free. One account for all your devices, with a model and ¥{allowance} of use to start; a code the first time, a password afterwards if you like.":`免费。一个账号连起你所有设备,自带模型和 ¥{allowance} 的起始额度;第一次用验证码登录,之后可以设密码。`,"With a code":`验证码登录`,"With a password":`密码登录`,"No password yet? Use a code first; set one under Account.":`还没有密码?先用验证码登录,再到「账号」里设置。`,"E-mail":`邮箱`,"Mobile number":`手机号`,"since {date}":`{date} 起`,Unlimited:`不限量`,"All time":`累计`,Usage:`用量`,"Every kind of use is counted, not just the chat model.":`每一类用量都会统计,不只是对话模型。`,Pictures:`图片`,Clips:`视频`,Calls:`通话`,"Nothing yet":`还没有`,"{n} answers · {tokens} tokens":`{n} 次回答 · {tokens} tokens`,"{n} requests · {tokens} tokens":`{n} 次请求 · {tokens} tokens`,"{n} requests":`{n} 次请求`,"By model, all time":`按模型(累计)`,"A password is set":`已设置密码`,"No password yet":`还没有密码`,"Sign in with it on a new device, or with a code as before.":`新设备可以用密码登录,也可以像以前一样用验证码。`,"Optional. With one, a new device can sign in without waiting for a code.":`可选。设置后,新设备不用等验证码就能登录。`,Change:`修改`,Set:`设置`,"Current password":`当前密码`,"New password (8 characters or more)":`新密码(至少 8 位)`,"Once more":`再输一次`,"The two do not match.":`两次输入不一致。`,"Change password":`修改密码`,"Set password":`设置密码`,"Password set.":`密码已设置。`,"Password changed.":`密码已修改。`,"Password removed.":`密码已移除。`,"Signed in on":`已登录的设备`,"Unnamed device":`未命名设备`,"This one":`本机`,code:`验证码`,password:`密码`,"used {when}":`{when}用过`,"Sign out {device}? It will need to sign in again.":`让 {device} 退出登录?它需要重新登录。`,"Recent activity":`最近动态`,"Show all {n}":`全部 {n} 条`,"Show less":`收起`,"Account created":`账号已创建`,"Signed in with a code":`用验证码登录`,"Signed in with the password":`用密码登录`,"A sign-in attempt failed":`一次登录失败`,"Signed out everywhere":`已在所有设备退出`,"Password removed":`密码已移除`,"Password changed":`密码已修改`,"Password set":`密码已设置`,"A request was refused: the allowance is used up":`一次请求被拒绝:免费额度已用完`,"Call ended":`通话结束`,"The model provider returned an error":`模型服务返回了错误`,"Allowance added":`额度已增加`,"Allowance adjusted":`额度已调整`,"Signed up with a friend's code":`用朋友的邀请码注册`,"A friend signed up with your code":`一位朋友用你的邀请码注册`,"An invite code was not recognised":`邀请码无法识别`,"Data controls: on for new accounts":`数据控制:新账号默认开启`,"Data controls: help improve turned on":`数据控制:已开启「帮助改进」`,"Data controls: help improve turned off":`数据控制:已关闭「帮助改进」`,"Data controls: kept conversations deleted":`数据控制:已删除保存的对话`,"Agent's name and look saved":`已保存智能体的名字与形象`,"Agent's name and look cleared":`已清除智能体的名字与形象`,"Sign out everywhere":`在所有设备退出`,"Sign out on every device, including this one?":`在所有设备退出登录,包括这一台?`,"Delete the account? The relay forgets your identifier, your devices and your usage. This cannot be undone.":`删除账号?中继会忘掉你的标识、设备和用量记录,且无法恢复。`,"Really delete it?":`真的要删除吗?`,"Signed out.":`已退出登录。`,"Delete the account":`删除账号`,"The Cloud model is in use; after signing out, pick another under Connections.":`当前使用的是 Cloud 模型;退出后请到「连接」里换一个。`,"{n} min ago":`{n} 分钟前`,"{n} h ago":`{n} 小时前`,"{n} d ago":`{n} 天前`,"Use the nanoMuse Cloud model":`使用 nanoMuse Cloud 模型`,"Signed in as {hint}. A free allowance, nothing to paste. Recommended to start.":`已登录 {hint}。自带免费额度,无需粘贴任何 key,推荐先用它。`,"Your account brings a model with a free allowance, nothing to set up. Or paste a key of your own; it is stored encrypted in the vault on the server, never shown to the model, and nothing you say passes through the relay.":`你的账号自带一个有免费额度的模型,不用再设置什么。也可以粘贴自己的 key:它加密存在服务端的保险库里,不会给模型看到,你说的内容也不经过中继。`,"Voice input":`语音输入`,"Stop voice input":`停止语音输入`,"The microphone is not allowed. Allow it in the browser and try again.":`没有拿到麦克风权限。在浏览器里允许后再试一次。`,"Voice input stopped ({code}).":`语音输入中断了({code})。`,"said on a call":`通话中说的`,"Coding agents":`编程助手`,"Cursor, Codex and Claude Code: see what they are doing, and tell them things from anywhere.":`Cursor、Codex 和 Claude Code:随时看它们在做什么,在任何地方给它们发消息。`,Coding:`编程`,"This computer":`这台电脑`,"This one · {name}":`本机 · {name}`,installed:`已安装`,"chats only":`仅记录`,"not found":`未找到`,"{agent} chats":`{agent} 的对话`,"Recent chats":`最近的对话`,"New chat":`新对话`,"No coding agent found on this computer. Install Cursor, Codex or Claude Code and their chats appear here.":`这台电脑上没有找到编程助手。安装 Cursor、Codex 或 Claude Code 后,它们的对话会出现在这里。`,"No chats yet.":`还没有对话。`,"Untitled chat":`未命名对话`,"{n} messages":`{n} 条消息`,"Sent through nanoMuse":`经 nanoMuse 发送的`,stopped:`已停止`,"Sent to {agent}.":`已发给 {agent}。`,"{agent} is working…":`{agent} 正在处理…`,"Tell {agent}…":`对 {agent} 说…`,"Nothing readable in this chat yet.":`这个对话里还没有可读的内容。`,"via nanoMuse":`经 nanoMuse`,"Continued as a new chat: the agent could not reopen the old one.":`原来的对话打不开了,已经另起一个新对话接着聊。`,"Made in the IDE: your message starts a new chat in the same workspace, with the last exchange quoted.":`这是 IDE 里的对话:你的消息会在同一工作区开一个新对话,并带上上一轮的内容。`,"Continue in a new chat…":`在新对话里接着说…`,"starting…":`启动中…`,"Send to {agent}":`发给 {agent}`,"Project folder":`项目目录`,"What to do":`要做什么`,"Add tests for the parser and run them":`给解析器补上测试并跑一遍`,"The agent runs on that computer with its own permissions; nanoMuse only carries the message and brings the answer back.":`助手在那台电脑上以它自己的权限运行;nanoMuse 只负责传话和带回结果。`,"The file is larger than {n} MB.":`文件超过了 {n} MB。`,"empty file":`文件是空的`,"thread is busy":`这个对话正忙`,"the main chat cannot be deleted":`主对话不能删除`,"no pending approval with that id":`这张卡片已经不在等待中`,"the device did not take the answer":`那台设备没有接受这个回答`,"already finished":`已经结束了`,"already cancelled":`已经取消了`,"memory is disabled":`记忆已关闭`,"memory is off":`记忆已关闭`,"recall by meaning is off":`按含义回忆已关闭`,"nothing proposed":`没有待处理的提议`,"that frame is gone":`这一帧已经不在了`,"no such file":`没有这个文件`,"no such post":`没有这条动态`,"no such skill of yours (built-in skills are switched off, not removed)":`没有这个你自己的技能(内置技能只能关闭,不能删除)`,"the file is larger than 16 MB":`文件超过了 16 MB`,"body too large (64 KB max)":`内容太大(最多 64 KB)`,"fill in the servers, the address and the password first":`先填好服务器、地址和密码`,"add a calendar link first":`先添加一个日历链接`,"signed out":`未登录`,"Sign in to nanoMuse Cloud first.":`请先登录 nanoMuse Cloud。`,"Enter the password.":`请输入密码。`,"The relay returned no key.":`中继没有返回 key。`,Details:`详情`,"Hide details":`收起详情`,"Today's share of the free allowance is used up; it comes back tomorrow. Your own model key under Connections keeps you going now.":`今天的免费额度用完了,明天恢复。在「连接」里填上你自己的模型 key,现在就能继续。`,"The free allowance is used up. Invite a friend (the relay adds to both your allowances) or add your own model key under Connections; your sign-in and your devices keep working either way.":`免费额度已用完。邀请一位新用户(你和对方的额度都会增加),或者在「连接」里填上自己的模型 key;无论选哪个,登录和多设备功能都不受影响。`,"The account's free allowance is used up. Add your own model key under Connections to keep going.":`这个账号的免费额度已经用完。在「连接」里填上你自己的模型 key 就能继续。`,"Too many requests at once; wait a moment and try again.":`请求太密集了,稍等一下再试。`,"The model provider is busy; try again in a moment.":`模型服务商正忙,稍后再试。`,"The model provider's content check declined this request; try different words.":`模型服务商的内容审核没有放行这次请求,换个说法再试。`,"The relay's model provider refused its key; the operator has been told. Your own key under Connections works meanwhile.":`中继的模型服务商拒绝了它的 key,运营者已收到通知。这期间可以在「连接」里用你自己的 key。`,"The model provider does not know this model right now; pick another under Connections.":`模型服务商暂时不认识这个模型,在「连接」里换一个。`,"nanoMuse Cloud has no model key configured; the operator has been told.":`nanoMuse Cloud 还没有配置模型 key,运营者已收到通知。`,"This nanoMuse Cloud account is disabled.":`这个 nanoMuse Cloud 账号已被停用。`,"The nanoMuse Cloud sign-in is no longer valid; sign in again under Account.":`nanoMuse Cloud 的登录已失效,请在「账号」里重新登录。`,"That model is not offered by nanoMuse Cloud; pick another under Connections.":`nanoMuse Cloud 不提供这个模型,在「连接」里换一个。`,"That message is too large for the model's window. Shorten it, leave out some attachments, or start a new chat.":`这条消息超出了模型的上下文窗口。精简一下、去掉部分附件,或者开一个新对话。`,"This relay takes new accounts by invitation only; sign in with an invite code under Account.":`这个中继只接受邀请注册;在「账号」里用邀请码登录。`,"Too many turns are running on this account at once; wait for one to finish and try again.":`这个账号同时进行的对话太多了,等一轮结束后再试。`,"New sign-ups are paused on this relay for now; existing accounts keep working. Try again later.":`这个中继暂时停止了新注册,已有账号照常使用。稍后再试。`,"nanoMuse Cloud is paused by its operator for now; your sign-in and your data are kept. Try again later.":`nanoMuse Cloud 被运营者暂时停用了,你的登录和数据都保留着。稍后再试。`,"Conversation sync is paused on this relay for now; what is stored is kept and your devices keep working on their own.":`这个中继暂时停止了对话同步,已存的内容保留着,各设备各自继续使用。`,"The device hub is paused on this relay for now; each device keeps working on its own.":`这个中继暂时停止了设备互联,各设备各自继续使用。`,"The free allowance is paused on this relay for now, not used up. Your own model key under Connections keeps you going; your sign-in, your devices and what is left stay as they are.":`这个中继暂时停发了免费额度,不是用完了。在「连接」里填上你自己的模型 key 就能继续;你的登录、设备和剩余额度都保持原样。`,"This demo Muse has used its share of the model for this visit. Start over for a new one, or install nanoMuse and use your own key.":`这个演示 Muse 这一次的模型额度用完了。点「重新开始」再来一个,或者安装 nanoMuse,用你自己的 key。`,"The showcase has used today's share of the model; it comes back tomorrow. Install nanoMuse and use your own key to keep going.":`在线体验今天的模型额度用完了,明天会恢复。安装 nanoMuse,用你自己的 key 可以继续。`,"The model provider is having trouble; try again in a moment.":`模型服务商出了点问题,稍后再试。`,"The model provider refused the API key. Check it under Connections.":`模型服务商拒绝了这个 API key,去「连接」里检查一下。`,"The endpoint does not know this model. Pick another under Connections.":`这个接口不认识这个模型,在「连接」里换一个。`,"The model provider is rate-limiting this key; wait a moment and try again.":`模型服务商正在限制这个 key 的请求频率,稍等一下再试。`,"The model took too long to answer. Try again.":`模型回答超时了,再试一次。`,"Could not reach the model provider. Check the connection and try again.":`连不上模型服务商,检查一下网络再试。`,"This conversation is too long for the model. Start a new one, or pick a model with a larger context.":`这段对话对模型来说太长了。开一个新对话,或者换一个上下文更大的模型。`,"Enter a phone number or an e-mail address.":`请输入手机号或邮箱。`,"Enter a mainland phone number or an e-mail address":`请输入中国大陆手机号或邮箱`,"Enter a mainland phone number or an e-mail address.":`请输入中国大陆手机号或邮箱。`,"Codes reach mainland China numbers only for now; elsewhere, sign in with an e-mail address.":`短信验证码目前只支持中国大陆手机号,海外用户请用邮箱登录。`,"That code is not right.":`验证码不对。`,"That code has expired; ask for a new one.":`验证码已过期,重新获取一个。`,"Too many codes were sent; wait a few minutes.":`验证码发得太频繁了,几分钟后再试。`,"This relay is private; that address is not on its list.":`这个中继是私有的,这个邮箱不在它的名单上。`,"The code could not be sent; try again in a moment.":`验证码没能发出,稍后再试。`,"Sign in again.":`请重新登录。`,"This account has used its tokens.":`这个账号的额度已经用完。`,"This account is disabled.":`这个账号已被停用。`,"That model is not offered here.":`这里不提供这个模型。`,"Too many requests; slow down a little.":`请求太频繁了,稍微慢一点。`,"The free allowance is used up. Invite a friend (the relay adds to both your allowances) or add your own model key; your sign-in and your devices keep working either way.":`免费额度已用完。邀请一位新用户(你和对方的额度都会增加),或者换成自己的 key;无论选哪个,登录和多设备功能都不受影响。`,"Today's token quota is used up; it comes back tomorrow.":`今天的 token 配额用完了,明天恢复。`,"The model provider did not answer.":`模型服务商没有响应。`,"nanoMuse Cloud has no model key configured.":`nanoMuse Cloud 还没有配置模型 key。`,"nanoMuse Cloud cannot be reached.":`连不上 nanoMuse Cloud。`,"That address and password do not match.":`邮箱与密码不匹配。`,"This account has no password yet; sign in with a code and set one under Account.":`这个账号还没有设置密码:先用验证码登录,再在「账号」里设置。`,"Too many wrong passwords; wait a while or sign in with a code.":`密码错误次数太多,等一会儿再试,或者改用验证码登录。`,"Use at least 8 characters.":`至少 8 个字符。`,"Choose a stronger password.":`换一个更强的密码。`,"That is not the current password.":`当前密码不正确。`,"Enter the current password.":`请输入当前密码。`,"That sign-in is already gone.":`那个登录已经不存在了。`,"Cannot reach your nanoMuse right now.":`现在连不上你的 nanoMuse。`,"Your nanoMuse hit a problem; try again in a moment.":`你的 nanoMuse 出了点问题,稍后再试。`,"Your nanoMuse could not do that.":`你的 nanoMuse 没能完成这个操作。`,"Could not reach your nanoMuse.":`连不上你的 nanoMuse。`,"Connecting to your nanoMuse…":`正在连接你的 nanoMuse…`,"Try again":`再试一次`,"Could not load.":`没能加载出来。`,"Use /{name}":`使用 /{name}`,Retry:`重试`,"Could not load the conversation. Pull to retry.":`对话没能加载出来,下拉重试。`,"Could not load the connections.":`连接信息没能加载出来。`,"Your account":`你的账号`,"your account's model, with a free allowance":`账号自带的模型,带免费额度`,"on this machine, no key":`跑在本机,不用 key`,"vLLM, LM Studio, a gateway, anything with /v1":`vLLM、LM Studio、网关,任何带 /v1 的服务`,"Your account's model":`账号自带的模型`,"Your account's model, or a key of your own.":`用账号自带的模型,或者你自己的 key。`,"Your account's model, with its free allowance. Keep it, or switch to a key of your own here.":`账号自带的模型,带免费额度。可以保留,也可以在这里换成你自己的 key。`,"Avatar studio":`形象工坊`,"Avatar studio…":`形象工坊…`,"Draw a look with your image model; it moves with what it is doing.":`用你的图像模型画一个形象;它会随着工作状态动起来。`,More:`更多`,"Name & style":`名字与风格`,"Image model":`图像模型`,"Redraw the poses":`重画状态`,"Back to the built-in look":`换回内置形象`,"Back to the built-in look.":`已换回内置形象。`,"Something went wrong":`出了点问题`,"Drawing the poses… {done}/{total}":`正在画各个状态… {done}/{total}`,"The new look is on; making the clips… {done}/{total}":`新形象已经用上;正在生成动态片段… {done}/{total}`,"All five poses are in.":`五个状态都画好了。`,"{done} of {total} poses are in; the rest show the main picture.":`画好了 {total} 个状态里的 {done} 个,其余先用主图。`,"Describe a new look":`描述一个新形象`,"One sentence is enough: what it is, what it wears, its air. Pick a style and your image model draws four to choose from.":`一句话就够:它是什么、穿什么、什么气质。选一种风格,你的图像模型会画四张让你挑。`,"a round, custard-yellow baby dragon with small orange horns and folded little wings":`一只圆滚滚的奶黄色小龙,橙色小角,折着小翅膀`,"Drawing…":`正在画…`,"Draw four more":`再画四张`,"Drawn by {provider} · {model}":`由 {provider} · {model} 绘制`,"Pick one":`挑一张`,"Draw four more any time; the old ones stay until you do.":`随时可以再画四张;没重画之前旧的会留着。`,"Use this one":`就用这个`,"Next, its poses are drawn from it in the background: working, waiting for you, done, something wrong.":`接下来会在后台以它为底画出各个状态:干活、等你、搞定、出错。`,"Keep the current look":`先不换了`,"Nothing came back.":`什么也没生成出来。`,"The pictures stay in this computer's workspace under avatar/. Each new look asks your provider for eight pictures (four to choose from and four poses) and four short clips where there is a video model.":`图片存在这台电脑的工作区 avatar/ 下。每换一次形象会向你的服务商要八张图(四张供你挑选,四个状态),有视频模型时还会生成四段短动画。`,"Or just say it in the chat: “change your avatar to a corgi”.":`也可以直接在对话里说:“把虚拟形象改成一只柯基”。`,"Change your avatar to ":`把虚拟形象改成`,"Alibaba Cloud Bailian":`阿里云百炼`,Zhipu:`智谱`,"Volcano Ark":`火山方舟`,"this computer":`这台电脑`,"Change model":`更换`,Search:`搜索`,"Search chats":`搜索对话`,"Side chats":`旁聊`,"Start a side chat":`发起旁聊`,"Side chats are an optional way to keep conversations organised by topic.":`旁聊是按主题整理对话的可选方式。`,Keep:`保留`,"No chats match.":`没有匹配的对话。`,"A side chat keeps one topic apart from the rest.":`一个旁聊,把一个话题和其他的分开。`,"Report a bug":`报告问题`,"Developer tools":`开发者工具`,Developer:`开发者`,"The Coding screen (Cursor, Codex and the other coding agents on this computer) in the sidebar, and the runtime's address below. This device only.":`在侧栏显示「编程」(这台电脑上的 Cursor、Codex 等编程智能体),并在下面显示运行时的地址。仅此设备。`,"Runtime:":`运行时:`,"the token is in the server_token file in the data folder":`令牌在数据目录的 server_token 文件里`,"The command line and the API":`命令行与 API`,"nanoMuse on DeepSeek Harness":`nanoMuse 的 DeepSeek Harness 版`,"Desktop app":`桌面应用`,"Start with the computer":`开机自动启动`,"Opens in the tray at sign-in; the agent's goals and check-ins run from then on.":`登录系统后在托盘里启动;从那时起,它的目标和定时检查就开始跑了。`,"In the tray":`托盘图标`,"The icon by the clock shows what the hands are doing and has Stop; closing the window keeps the agent running.":`时钟旁的图标显示它正在操作什么,并带「停止」;关掉窗口后它仍在后台运行。`,Shortcuts:`快捷键`,"Quick chat":`快速对话`,"Show the window":`打开窗口`,"Feed settings":`动态设置`,"About the feed":`动态版块说明`,"Your feed is driven by the instruction below. Any edit you make here applies to every post from now on.":`动态由下面这句话来定。在这里改动它,今后的每一条帖子都会照着来。`,"Build me a feed about what I care about. Keep it short and direct, easy to skim, no clickbait.":`给我做一个关于我关心的事的动态。短一点、直接一点,扫一眼就能看完,别搞标题党。`,"Got it":`知道了`,"Write it now":`现在写一版`,"Nothing in the feed yet":`动态里还没有内容`,"As we get to know each other, new posts will show up here. Every day at {time} I read what I remember about you (your memory files, the last week of diary, your goals) and write a few short posts.":`随着我们相互了解,新的帖子会显示在这里。每天 {time},我会读一遍记得的关于你的东西(记忆文件、最近一周的日记、你的目标),然后写几条简短的帖子。`,"Steer it with one sentence":`一句话就能调整`,"Tap the sliders at the top right to tell me what you want more of, switch the daily routine off, or have me write the first day now.":`点右上角的滑杆,告诉我你想多看什么、关掉每天的例程,或者让我现在就写第一天。`,"Short posts your agent writes for you from what it remembers: your memory files, the last week of diary, your goals. The sentence below steers every post from now on; edit it any time.":`这里是你的智能体为你写的短帖子,取材于它记得的东西:记忆文件、最近一周的日记、你的目标。下面这句话决定今后每一条帖子的方向,随时可以改。`,"Write it every day":`每天自动写`,"Time of day":`时间`,"Add a model first; the feed is written by your agent.":`先添加一个模型,动态由你的智能体来写。`,Discuss:`讨论`,"About this post":`这条帖子的信息`,"Delete this post":`删除这条`,Written:`写于`,Note:`随记`,Files:`文件`,Fun:`休闲`,"About this post from my feed:":`聊聊我动态里的这一条:`,"Post type":`类型`,morning:`上午`,afternoon:`下午`,evening:`晚上`,"{weekday} {part}":`{weekday}{part}`,"Starts a conversation":`会开始一段对话`,"Send to chat":`发到聊天`,"Nothing tracked yet":`尚未追踪任何内容`,"Create a goal":`创建目标`,"Pick a category and tell me the goal you have in mind. I'll shape a plan with you and keep improving it as you go.":`选一个类别,告诉我你心里的目标。我会和你一起定出计划,并在推进过程中不断调整。`,"Create a {category} goal":`创建{category}目标`,"First, we'll shape the goal together in the chat. I'll ask a few questions so I understand exactly what you're after.":`首先,我们将在聊天中一起完善目标。我会问几个问题,准确了解你的目标。`,"Once it's set, I'll track your progress here.":`目标设置后,我会在这里追踪你的进度。`,"I'd like to create a {category} goal. Ask me a few short questions, one at a time (what exactly I want, why and by when, how often to check in), then create it with concrete steps using the goals tool.":`我想创建一个{category}目标。请一次问我一个简短的问题(我具体想达成什么、为什么以及什么时候、多久检查一次),然后用 goals 工具把它建成带具体步骤的目标。`,"Mark as done":`标记为已完成`,"Mark as not done":`标记为未完成`,"Plan my week":`规划我的一周`,"Tell me what's on your plate and I'll turn it into a realistic plan with the important things first.":`告诉我你手头有什么,我把它排成一份切实可行的计划,重要的事放前面。`,"Help me plan my week. Ask me what I need to get done, then propose a schedule.":`帮我规划这一周。先问我有哪些事要做,然后给出一份日程安排。`,"Research & compare options":`调研并比较选项`,"Laptops, flights, insurance, a new phone plan: I'll gather the facts and compare them for you.":`笔记本、机票、保险、新的手机套餐,我帮你收集事实并逐项比较。`,"I need to make a purchase decision. Ask me what I'm choosing between, then research and compare the options.":`我想买个东西,拿不定主意。先问我在哪几个里面挑,然后帮我查一查、比一比。`,"Set up a long-term goal":`建立一个长期目标`,"Share a goal (learn a language, run a 10k, save for a trip) and I'll break it into steps and keep track.":`说一个目标(学一门语言、跑完 10 公里、攒一次旅行的钱),我把它拆成步骤并持续跟进。`,"I want to set up a long-term goal. Ask me about it, then create a plan with concrete steps and track it.":`我想建立一个长期目标。先问问我,然后制定一份带具体步骤的计划并跟进。`,"Tell me about yourself":`介绍一下你自己`,"The more I know about your preferences, routines and constraints, the more useful I get. I'll remember what matters.":`我越了解你的偏好、作息和限制,就越能帮上忙。重要的事我会记住。`,"Ask me a few questions about myself so you can help me better, and remember the answers.":`问我几个关于我的问题,好更了解我,然后把答案记住。`,"Build a quick tracker":`做一个简单的追踪表`,"Spending, habits, workouts, reading: I can write a small script or document to track it for you.":`开支、习惯、锻炼、阅读,我可以写一个小脚本或文档帮你记录。`,"Build me a simple tracker. Ask me what I want to track and how, then create it in the workspace.":`帮我做一个简单的追踪表。先问我想记录什么、怎么记,然后在工作区里建好。`,Artifacts:`构件`,Media:`影音内容`,"Nothing created yet":`还没有创建任何内容`,"Documents, tables and pages I write for you will show up here.":`我为你写的文档、表格和页面会显示在这里。`,"No media yet":`还没有影音内容`,"Photos, screenshots and recordings I produce will show up here.":`我生成的图片、截图和录音会显示在这里。`,"No model yet":`还没有模型`,"Add a provider and pick its models":`添加一个服务商并选择模型`,"Image & video models":`图像与视频模型`,"Name & personality":`名字与人格`,"About nanoMuse":`关于 nanoMuse`,"Privacy policy":`隐私政策`,Feedback:`反馈问题`,none:`无`,"Change avatar":`更换虚拟形象`,"Edit name":`编辑名称`,Daily:`每日`,"Soul & memory":`SOUL 与记忆`,"Handle with care":`请谨慎访问`,"This device's name":`这台设备的名字`,"Sync conversations between my devices":`在我的设备之间同步对话`,"The text of your chats is kept on nanoMuse Cloud so every device shows the same conversations. Files and images stay on the device they were made on.":`对话文字会保存在 nanoMuse Cloud,让每台设备看到同样的对话。文件和图片只留在产生它们的设备上。`,"Paused: sign in again to continue.":`已暂停:重新登录后继续。`,"{c} chats, {m} messages kept so far.":`目前保存了 {c} 个对话、{m} 条消息。`,"Delete synced conversations":`删除已同步的对话`,"{n} chats":`{n} 个对话`,"Removes what nanoMuse Cloud stores for this account; the chats on each device stay, and the switch stays on. Deleting a chat on one device deletes it on all of them.":`删除 nanoMuse Cloud 为这个账号保存的内容;每台设备上的对话保留,开关也保持打开。在一台设备上删除某个对话,会在所有设备上一起删除。`,"Off deletes the synced conversations from nanoMuse Cloud. The chats on each device stay.":`关闭后会从 nanoMuse Cloud 删除已同步的对话。每台设备上的对话保留。`,"On. Your devices show the same conversations from now on.":`已打开。从现在起,你的设备会看到同样的对话。`,"Off. Nothing is kept on nanoMuse Cloud any more.":`已关闭。nanoMuse Cloud 不再保存任何对话。`,"The synced conversations are removed from nanoMuse Cloud. The chats on each device stay. This cannot be undone.":`已同步的对话将从 nanoMuse Cloud 删除。每台设备上的对话保留。此操作无法撤销。`,"Synced conversations deleted.":`已删除已同步的对话。`,"Also sync side chats":`同时同步旁聊`,"Off: side chats stay on this device. On: this device's side chats go to the account and the other devices' side chats come here.":`关:旁聊只留在本机。开:本机的旁聊上传到账号,其他设备的旁聊也会同步过来。`,"On. This device's side chats go to the account; the other devices' are on their way.":`已打开。本机的旁聊会上传到账号,其他设备的旁聊正在同步过来。`,"Off. Side chats stay on this device from now on.":`已关闭。从现在起,旁聊只留在本机。`,"{device} is working…":`{device} 正在处理…`,"From {device}":`来自 {device}`,"to {device}":`发给 {device}`,"This goes to {device}.":`这条会发给 {device}。`,"Runs this there and reports back":`在那台设备上执行并汇报结果`,Offline:`离线`,"There is no form to fill in: once it has a model, it introduces itself in the chat and asks what to call you.":`不用填表:有了模型之后,它会在聊天里介绍自己,并问你希望怎么称呼你。`,"A model, then the chat. A minute.":`先接一个模型,再去聊天。一分钟。`,"Open the chat. It introduces itself and asks your name.":`打开聊天。它会介绍自己,并问你的名字。`,"Pick a name for me, or type one":`给我挑一个名字,或者自己输入一个`,"Something else":`自己起一个`,"Proxy (optional)":`代理(可选)`,"Only this provider's requests go through it. nanoMuse Cloud never does.":`只有这个服务商的请求走代理;nanoMuse Cloud 的请求从不经过它。`,"Talk to your Muse from the chat apps you already use. Nothing needs a public address: each app keeps a long connection open.":`在你已经在用的聊天软件里和 Muse 对话。不需要公网地址:每个应用各自保持一条长连接。`,"Waiting for a yes":`等待通过`,"{name} wrote to the bot. Approve to let them talk to your Muse.":`{name} 给机器人发了消息。通过后对方就能和 Muse 对话。`,Approve:`通过`,"Code {code}":`配对码 {code}`,"Needs settings":`还缺设置`,"Not installed":`未安装`,Error:`出错`,Missing:`缺少`,"Switched on":`已开启`,"Install on the computer running nanoMuse, then switch it on again:":`在运行 nanoMuse 的电脑上安装,再重新开启:`,"Saved.":`已保存。`,Saving:`保存中`,"Set; leave blank to keep":`已设置,留空则保持不变`,"Clear the saved value":`清除已保存的值`,"In groups, reply":`在群里回复`,"only when @-mentioned":`只在被 @ 时`,"to every message":`每条消息`,"Always allowed (ids, one per line)":`免配对的 ID(每行一个)`,"People listed here never need a pairing code. A lone * lets anyone in; do that only on a bot nobody else can reach.":`列在这里的人不需要配对码。单独一个 * 表示放行所有人,只在别人找不到的机器人上这样做。`,"Paired chats":`已配对的聊天`,"Nobody yet. Write to the bot from the app; a pairing code comes back, approve it here.":`还没有人。在聊天软件里给机器人发条消息,会收到配对码,在这里通过即可。`,"Deliver here":`推送到这里`,"Chats with “deliver here” on also get what the Muse does on its own: check-ins, reminders, the results of background work, and the questions it needs answered.":`开了「推送到这里」的聊天还会收到 Muse 主动做的事:问候、提醒、后台任务的结果,以及需要你回答的问题。`,"Remove {name}? They will need a new pairing code.":`移除 {name}?对方需要重新配对。`,"Send a test message":`发送测试消息`,Sending:`发送中`,"Create the bot by QR code":`扫码创建机器人`,"Open in Feishu":`在飞书里打开`,"Scan with Feishu, confirm the new bot, and the App ID and Secret are saved for you.":`用飞书扫码,确认创建机器人,App ID 和 Secret 会自动保存。`,"Lark (international) instead of 飞书":`用 Lark(国际版)而不是飞书`,"Waiting for the scan…":`等待扫码…`,"The bot was created and is connecting.":`机器人已创建,正在连接。`,"The login did not finish ({error}).":`登录没有完成({error})。`,"Set up":`设置步骤`,"Open the console":`打开控制台`,"Then write to the bot from the app. The first message gets a pairing code; approve it here or run":`然后在聊天软件里给机器人发消息。第一条消息会收到配对码,在这里通过,或运行`,"Each chat is one conversation of your Muse; its replies stream back as they are written.":`每个聊天对应 Muse 的一个会话;回复会边写边发回来。`,"In the Feishu developer console create a custom app and add the Bot capability.":`在飞书开放平台创建企业自建应用,添加「机器人」能力。`,"Permissions: im:message, im:message.p2p_msg:readonly, im:message.group_at_msg:readonly, im:resource.":`权限:im:message、im:message.p2p_msg:readonly、im:message.group_at_msg:readonly、im:resource。`,"Events & callbacks: subscription mode Long connection; add im.message.receive_v1; callback mode Long connection; add card.action.trigger.":`事件与回调:订阅方式选「长连接」,添加 im.message.receive_v1;回调方式选「长连接」,添加 card.action.trigger。`,"Copy App ID and App Secret from Credentials & Basic Info, then publish a version.":`在「凭证与基础信息」复制 App ID 和 App Secret,然后发布版本。`,"In the DingTalk developer console create an internal app and add the Robot capability.":`在钉钉开放平台创建企业内部应用,添加「机器人」能力。`,"Set the message receive mode to Stream.":`消息接收模式选「Stream 模式」。`,"Copy Client ID (AppKey) and Client Secret (AppSecret) from Credentials & Basic Info.":`在「凭证与基础信息」复制 Client ID(AppKey)和 Client Secret(AppSecret)。`,"Add the robot send-message permission and publish the version.":`添加机器人发消息权限,发布版本。`,"In the WeCom admin console open Intelligent robot and create a robot in API mode with a long connection.":`在企业微信管理后台打开「智能机器人」,创建 API 模式、长连接的机器人。`,"Copy the Bot ID and Secret.":`复制 Bot ID 和 Secret。`,"Add the robot to the chats where it should listen.":`把机器人加到需要它在的聊天里。`,"In Telegram talk to @BotFather, send /newbot and copy the token.":`在 Telegram 里找 @BotFather,发送 /newbot,复制 token。`,"Direct messages work at once. For a group, add the bot to it; with Group Privacy on it only hears @-mentions and replies.":`私聊立即可用。群聊需要先把机器人拉进群;开着 Group Privacy 时它只听 @ 和回复。`,"If api.telegram.org is out of reach from this computer, set a proxy below.":`如果这台电脑连不上 api.telegram.org,在下面填一个代理。`,"Use nanoMuse Cloud models":`使用 nanoMuse Cloud 模型`,"nanoMuse Cloud is one of the sources for the chat, the hands, pictures and clips; what runs on it comes off your allowance.":`nanoMuse Cloud 是聊天、双手、图片和短片的来源之一;在它上面运行的内容会消耗你的额度。`,"Off: nothing runs on nanoMuse Cloud unless you choose it yourself. You stay signed in for sync and your devices.":`关闭后,除非你自己选择,否则不会有任何内容在 nanoMuse Cloud 上运行。账号保持登录,用于同步和你的设备。`,"Add a provider of your own first; with nanoMuse Cloud off, nothing else could answer.":`先添加一个自己的服务商;关掉 nanoMuse Cloud 后没有别的模型能回答。`,"Use your own API key instead":`改用自己的 API key`,"You can sign in later under Connections, for sync and your devices.":`之后可以在「连接」里登录,用于同步和你的设备。`,"Add an endpoint":`添加接口`,"Add endpoint":`添加接口`,"An endpoint joins your list with its own key and stays there; add as many as you use. Pick one as the chat model, or use its models for the hands, pictures and clips.":`接口带着自己的密钥加入列表并一直保留;用几个就加几个。可以选一个作为对话模型,也可以把它的模型用于双手、图片和短片。`,"Name (optional)":`名字(可选)`,"How the endpoint reads in the lists; its host when left empty.":`接口在列表里显示的名字;留空则显示主机名。`,"for example: my gateway":`例如:我的网关`,"Stored encrypted in the vault under this endpoint's own name.":`加密保存在保险库里,以这个接口自己的名字命名。`,"Models (optional)":`模型(可选)`,"Leave empty when the endpoint lists its models at /models. Otherwise type their ids, separated by commas.":`接口能在 /models 列出模型时留空;否则输入模型 id,用逗号分隔。`,"Endpoint added":`已添加接口`,"Endpoint renamed":`已给接口改名`,"Endpoint removed":`已移除接口`,"Key saved":`密钥已保存`,"Models saved":`模型已保存`,Models:`模型`,Rename:`改名`,"Change key":`换密钥`,"Edit models":`编辑模型`,"Ask for its models":`重新获取模型`,"{n} models":`{n} 个模型`,"{n} models saved with this endpoint":`这个接口保存了 {n} 个模型`,"Used by {slots}":`用于{slots}`,"the hands":`双手`,pictures:`图片`,clips:`短片`,"The ids of the models this endpoint serves, separated by commas; what it lists at /models is added after them.":`这个接口提供的模型 id,用逗号分隔;它在 /models 列出的模型会接在后面。`,"The endpoint did not list its models; the saved list stands.":`接口没有列出模型;沿用已保存的列表。`,"The chat model answers through this endpoint; pick another chat model first.":`对话模型正通过这个接口回答;请先换一个对话模型。`,"Its key goes with it, and the hands, pictures or clips set on it go back to automatic.":`它的密钥会一起删除;设在它上面的双手、图片或短片会回到自动。`,"Uses the key saved with this endpoint.":`使用这个接口保存的密钥。`,"Your endpoints":`你的接口`,"The model that looks at screens when the hands run: a small, fast one that takes pictures. Pick one of this provider's, or one from another endpoint of your list, which then lends its address and key.":`双手运行时看屏幕的模型:一个小而快、能看图的模型。可以选这个服务商的,也可以选你列表里另一个接口的,那个接口的地址和密钥会一并使用。`,"the endpoint did not list its models (GET /models); type the ids of the models it serves, separated by commas":`接口没有列出模型(GET /models);请输入它提供的模型 id,用逗号分隔`,"the chat model answers through this endpoint; pick another chat model first":`对话模型正通过这个接口回答;请先换一个对话模型`,"the address must start with http:// or https://":`地址必须以 http:// 或 https:// 开头`,"that is nanoMuse Cloud; it is the account, not an endpoint":`那是 nanoMuse Cloud;它是账号,不是接口`,"a key has no spaces in it":`密钥里不会有空格`},ne=[{value:`auto`,label:`Auto`},{value:`en`,label:`English`},{value:`zh-CN`,label:`简体中文`}],j=`nanomuse_locale`,M={en:{},"zh-CN":A};function re(){try{let e=localStorage.getItem(j);if(e===`en`||e===`zh-CN`||e===`auto`)return e}catch{}return`auto`}var N=re(),P=new Set;function ie(){return(typeof navigator>`u`?[]:[navigator.language,...navigator.languages??[]]).some(e=>/^zh\b/i.test(e??``))?`zh-CN`:`en`}function ae(){return N}function F(){return N===`auto`?ie():N}function oe(e){N=e;try{localStorage.setItem(j,e)}catch{}se(),P.forEach(e=>e())}function se(){typeof document<`u`&&(document.documentElement.lang=F())}function ce(e){return P.add(e),()=>P.delete(e)}function le(){return(0,f.useSyncExternalStore)(ce,F,F)}function ue(){return(0,f.useSyncExternalStore)(ce,ae,ae)}function de(e,t){return t?e.replace(/\{(\w+)\}/g,(e,n)=>n in t?String(t[n]):e):e}function I(e,t){let n=M[F()];return de(n[e]??e,t)}function fe(e){let t=t=>({title:e.slice(t.length)});return e.startsWith(`Working on your goal: `)?I(`Working on your goal: {title}`,t(`Working on your goal: `)):e.startsWith(`Check-in: `)?I(`Check-in: {title}`,t(`Check-in: `)):e.startsWith(`Reminder: `)?I(`Reminder: {title}`,t(`Reminder: `)):e.startsWith(`Routine: `)?I(`Routine: {title}`,t(`Routine: `)):e.startsWith(`New mail: `)?I(`New mail: {title}`,t(`New mail: `)):e.startsWith(`Coming up: `)?I(`Coming up: {title}`,t(`Coming up: `)):e.startsWith(`Webhook: `)?I(`Webhook: {title}`,t(`Webhook: `)):e===`Tidied memory`?I(`Tidied memory`):e}function pe(e){let t=/^'([^']+)' is in always_ask_tools$/.exec(e);return t?I(`{tool} is on your always-ask list`,{tool:t[1]}):(t=/^'([^']+)' is in always_allow_tools$/.exec(e),t?I(`{tool} is on your always-allow list`,{tool:t[1]}):(t=/^'([^']+)' is in sentinel\.deny_tools$/.exec(e),t?I(`{tool} is switched off in your settings`,{tool:t[1]}):(t=/^risk level is '(\w+)' \(mode=(\w+)\)$/.exec(e),t?I(`an action rated {risk}, in {mode} mode`,{risk:I(t[1]),mode:I(t[2])}):e===`auto mode: approval skipped`?I(`auto mode: not asked`):(t=/^covered by your '([^']+)' permission for (.+)$/.exec(e),t?I(`covered by your {scope} permission for {key}`,{scope:I(t[1]),key:t[2]}):(t=/^private data was read earlier in this conversation and '([^']+)' can send data to (.+), which is not on sentinel\.egress_allowlist$/.exec(e),t?I(`private data was read earlier in this conversation, and {tool} could send it to {target}, which is not on your allowed list`,{tool:t[1],target:t[2]}):I(e))))))}function me(e){let t=/^the file is larger than (\d+) MB$/.exec(e);return t?I(`The file is larger than {n} MB.`,{n:t[1]}):I(e)}function he(){return le(),I}function L(){return F()===`zh-CN`?`zh-CN`:`en-US`}function ge(e){if(!e)return``;let t=new Date(e);if(Number.isNaN(t.getTime()))return``;let n=new Date,r=t.toDateString()===n.toDateString(),i=t.toLocaleTimeString(L(),{hour:`2-digit`,minute:`2-digit`});return r?i:`${t.toLocaleDateString(L(),{month:`short`,day:`numeric`})} ${i}`}function _e(e){if(!e)return``;let t=new Date(e);if(Number.isNaN(t.getTime()))return``;let n=t.toLocaleTimeString(L(),{hour:`numeric`,minute:`2-digit`}),r=new Date,i=new Date(r);return i.setDate(r.getDate()-1),t.toDateString()===r.toDateString()?`${I(`Today`)} ${n}`:t.toDateString()===i.toDateString()?`${I(`Yesterday`)} ${n}`:`${ve(e)} ${n}`}function ve(e,t={}){if(!e)return``;let n=new Date(e);if(Number.isNaN(n.getTime()))return``;let r=n.getFullYear()===new Date().getFullYear();return n.toLocaleDateString(L(),{month:`short`,day:`numeric`,...r?{}:{year:`numeric`},...t})}function ye(e){if(!e)return``;let t=Date.now()-new Date(e).getTime();if(Number.isNaN(t))return``;let n=Math.round(Math.abs(t)/1e3);if(n<45)return I(t>=0?`just now`:`any moment`);let r=Math.round(n/60),i=Math.round(r/60),a=Math.round(i/24),o=r<60?I(`{n} min`,{n:r}):i<24?I(`{n} h`,{n:i}):I(`{n} d`,{n:a});return I(t>=0?`{span} ago`:`in {span}`,{span:o})}function be(e){let t=Math.max(0,Math.floor(Date.now()/1e3-e));return t<60?I(`just now`):t<3600?I(`{n} min ago`,{n:Math.floor(t/60)}):t<86400?I(`{n} h ago`,{n:Math.floor(t/3600)}):t<604800?I(`{n} d ago`,{n:Math.floor(t/86400)}):new Date(e*1e3).toLocaleDateString(L())}function R(e){try{return localStorage.getItem(e)}catch{return null}}function z(e,t){try{t===null?localStorage.removeItem(e):localStorage.setItem(e,t)}catch{}}function B(...e){return e.filter(Boolean).join(` `)}function xe(e){try{return decodeURIComponent(e)}catch{return e}}function Se(e){let t=e.toLowerCase().split(`.`).pop()??``;return t===`ics`?`event`:[`md`,`txt`,`log`,`rtf`].includes(t)?`text`:[`py`,`js`,`ts`,`tsx`,`jsx`,`sh`,`toml`,`yaml`,`yml`,`sql`,`rs`,`go`,`java`,`c`,`cpp`].includes(t)?`code`:[`html`,`htm`].includes(t)?`html`:[`png`,`jpg`,`jpeg`,`gif`,`webp`,`svg`].includes(t)?`image`:t===`pdf`?`pdf`:[`csv`,`json`,`xlsx`,`xls`,`parquet`].includes(t)?`data`:`other`}var V=`nanomuse_token`,H=class extends Error{constructor(){super(`unauthorized`)}};function Ce(e){let t=e.hash.replace(/^#/,``).split(`&`).filter(Boolean),n=t.findIndex(e=>e.startsWith(`token=`));if(n>=0){let r=decodeURIComponent(t[n].slice(6));return t.splice(n,1),e.hash=t.length?`#${t.join(`&`)}`:``,r||null}let r=e.searchParams.get(`token`);return r?(e.searchParams.delete(`token`),r):null}function U(){let e=new URL(window.location.href),t=Ce(e);return t&&(z(V,t),window.history.replaceState(null,``,e.pathname+e.search+e.hash)),R(V)??``}function we(e){z(V,e||null)}function W(e,t=!1){let n=U(),r=n?T(n,`/api/files/${e}`):new URLSearchParams;t&&r.set(`download`,`1`);let i=r.toString();return`/api/files/${e.split(`/`).map(encodeURIComponent).join(`/`)}${i?`?${i}`:``}`}function Te(e,t){let n=U(),r=n?`?${T(n,`/api/browser/${e}/frames/${t}.jpg`)}`:``;return`/api/browser/${encodeURIComponent(e)}/frames/${encodeURIComponent(t)}.jpg${r}`}async function G(e,t={}){let n={...t.headers},r=U();r&&(n.Authorization=`Bearer ${r}`),t.body&&!n[`Content-Type`]&&(n[`Content-Type`]=`application/json`);let i;try{i=await fetch(e,{...t,headers:n})}catch{throw Error(`Cannot reach your nanoMuse right now.`)}if(i.status===401)throw new H;if(!i.ok){let e;try{e=await i.json()}catch{}throw Error(Ee(i.status,e))}return await i.json()}function Ee(e,t){let n=t&&typeof t==`object`?t.detail:void 0;return typeof n==`string`&&n.trim()?n:e>=500?`Your nanoMuse hit a problem; try again in a moment.`:`Your nanoMuse could not do that.`}var K=e=>({method:`POST`,body:JSON.stringify(e)}),q={state:()=>G(`/api/state`),cloud:()=>G(`/api/cloud`),cloudCode:e=>G(`/api/cloud/code`,K({identifier:e})),cloudVerify:(e,t,n=``)=>G(`/api/cloud/verify`,K(n?{identifier:e,code:t,invite:n}:{identifier:e,code:t})),cloudSignOut:()=>G(`/api/cloud/sign-out`,K({})),cloudModels:e=>G(`/api/cloud/models`,K({on:e})),cloudLogin:(e,t)=>G(`/api/cloud/login`,K({identifier:e,password:t})),cloudPassword:(e,t)=>G(`/api/cloud/password`,K({password:e,current:t??null})),cloudSessions:()=>G(`/api/cloud/sessions`),cloudRevokeSession:e=>G(`/api/cloud/sessions/${encodeURIComponent(e)}`,{method:`DELETE`}),cloudSignOutAll:(e=!1)=>G(`/api/cloud/sign-out-all`,K({all:e})),cloudEvents:(e=50)=>G(`/api/cloud/events?limit=${e}`),cloudDelete:()=>G(`/api/cloud/delete`,K({})),cloudMe:()=>G(`/api/cloud/me`),cloudConfig:()=>G(`/api/cloud/config`),cloudContribute:e=>G(`/api/cloud/contribute`,K({on:e})),cloudDeleteSamples:()=>G(`/api/cloud/samples`,{method:`DELETE`}),cloudUseAsModel:(e=``)=>G(`/api/cloud/use-as-model`,K({model:e})),syncState:()=>G(`/api/sync/state`),syncSetState:e=>G(`/api/sync/state`,{method:`PUT`,body:JSON.stringify({enabled:e})}),syncSetSideChats:e=>G(`/api/sync/state`,{method:`PUT`,body:JSON.stringify({side_chats:e})}),syncDelete:()=>G(`/api/sync/delete`,K({})),syncPull:()=>G(`/api/sync/pull`,K({})),avatarView:()=>G(`/api/avatar`),avatarBegin:(e,t=`main`,n=`muse`)=>G(`/api/avatar/begin`,K({description:e,thread:t,style:n})),avatarStart:e=>G(`/api/avatar/start`,K({session:e})),avatarChoose:(e,t)=>G(`/api/avatar/choose`,K({session:e,index:t})),avatarCancel:e=>G(`/api/avatar/cancel`,K({session:e})),avatarMoods:()=>G(`/api/avatar/moods`,K({})),coding:(e=``)=>G(`/api/coding${e?`?device=${encodeURIComponent(e)}`:``}`),codingSessions:(e={})=>{let t=new URLSearchParams;e.agent&&t.set(`agent`,e.agent),e.limit&&t.set(`limit`,String(e.limit)),e.workspace&&t.set(`workspace`,e.workspace),e.device&&t.set(`device`,e.device);let n=t.toString();return G(`/api/coding/sessions${n?`?${n}`:``}`)},codingSession:(e,t,n=``)=>G(`/api/coding/sessions/${encodeURIComponent(e)}/${encodeURIComponent(t)}${n?`?device=${encodeURIComponent(n)}`:``}`),codingSend:e=>G(`/api/coding/send`,K(e)),codingStop:(e,t=``)=>G(`/api/coding/stop`,K({run:e,device:t})),hub:()=>G(`/api/hub`),updateHub:e=>G(`/api/hub`,{method:`PUT`,body:JSON.stringify(e)}),joinHub:()=>G(`/api/hub/join`,K({})),leaveHub:()=>G(`/api/hub/leave`,K({})),refreshHub:()=>G(`/api/hub/refresh`,K({})),forgetDevice:e=>G(`/api/hub/devices/${encodeURIComponent(e)}`,{method:`DELETE`}),askDevice:(e,t=``)=>G(`/api/hub/ask`,K({device:e,text:t})),hands:()=>G(`/api/hands`),setHands:e=>G(`/api/connections/hands`,{method:`PUT`,body:JSON.stringify(e)}),stopHands:()=>G(`/api/hands/stop`,K({})),holds:()=>G(`/api/holds`),openHold:(e,t,n=``)=>G(`/api/holds`,K({thread:e,tool:t,reason:n})),doneHold:e=>G(`/api/holds/${encodeURIComponent(e)}/done`,K({})),health:()=>G(`/api/health`),threads:()=>G(`/api/threads`),createThread:e=>G(`/api/threads`,K({title:e})),renameThread:(e,t)=>G(`/api/threads/${e}`,{method:`PATCH`,body:JSON.stringify({title:t})}),deleteThread:e=>G(`/api/threads/${e}`,{method:`DELETE`}),clearThread:e=>G(`/api/threads/${e}/clear`,{method:`POST`}),stopThread:e=>G(`/api/threads/${e}/stop`,{method:`POST`}),events:(e,t=200,n)=>G(`/api/threads/${e}/events?limit=${t}${n?`&before=${encodeURIComponent(n)}`:``}`),send:(e,t,n=[],r=``,i=``)=>G(`/api/threads/${e}/send`,K(i?{text:t,files:n,language:r,via:i}:{text:t,files:n,language:r})),upload:e=>G(`/api/files/upload?name=${encodeURIComponent(e.name||`photo.jpg`)}`,{method:`POST`,headers:{"Content-Type":e.type||`application/octet-stream`},body:e}),decide:(e,t,n=`once`,r=``)=>G(`/api/approvals/${e}`,K({approved:t,scope:n,reason:r})),resetApprovals:()=>G(`/api/approvals`,{method:`DELETE`}),revokeGrant:e=>G(`/api/approvals/grants/${encodeURIComponent(e)}`,{method:`DELETE`}),goals:()=>G(`/api/goals`),createGoal:e=>G(`/api/goals`,K(e)),patchGoal:(e,t)=>G(`/api/goals/${e}`,{method:`PATCH`,body:JSON.stringify(t)}),addStep:(e,t)=>G(`/api/goals/${e}/steps`,K({title:t})),advanceGoal:e=>G(`/api/goals/${e}/advance`,{method:`POST`}),checkInGoal:e=>G(`/api/goals/${e}/check-in`,{method:`POST`}),acceptProposal:e=>G(`/api/goals/${e}/proposal/accept`,{method:`POST`}),dismissProposal:e=>G(`/api/goals/${e}/proposal`,{method:`DELETE`}),deleteGoal:e=>G(`/api/goals/${e}`,{method:`DELETE`}),memory:()=>G(`/api/memory`),addMemory:(e,t)=>G(`/api/memory`,K({content:e,category:t})),forgetMemory:e=>G(`/api/memory/${e}`,{method:`DELETE`}),tidyMemory:()=>G(`/api/memory/tidy`,{method:`POST`}),memoryChanges:(e=30)=>G(`/api/memory/changes?limit=${e}`),restoreMemoryChange:e=>G(`/api/memory/changes/${e}/restore`,{method:`POST`}),ideas:(e=!1)=>G(`/api/ideas${e?`?refresh=1`:``}`),activity:(e=150)=>G(`/api/activity?n=${e}`),feed:(e=60)=>G(`/api/feed?limit=${e}`),feedPosts:()=>G(`/api/feed/posts`),setFeedInstructions:e=>G(`/api/feed/instructions`,{method:`PUT`,body:JSON.stringify(e)}),refreshFeedPosts:()=>G(`/api/feed/posts/refresh`,{method:`POST`}),deleteFeedPost:e=>G(`/api/feed/posts/${e}`,{method:`DELETE`}),upcoming:()=>G(`/api/upcoming`),reminders:(e=!1)=>G(`/api/reminders${e?`?all=1`:``}`),createReminder:e=>G(`/api/reminders`,{method:`POST`,body:JSON.stringify(e)}),fireReminder:e=>G(`/api/reminders/${e}/fire`,{method:`POST`}),cancelReminder:e=>G(`/api/reminders/${e}`,{method:`DELETE`}),triggers:()=>G(`/api/triggers`),createTrigger:e=>G(`/api/triggers`,{method:`POST`,body:JSON.stringify(e)}),fireTrigger:e=>G(`/api/triggers/${e}/fire`,{method:`POST`}),cancelTrigger:e=>G(`/api/triggers/${e}`,{method:`DELETE`}),files:(e=300)=>G(`/api/files?limit=${e}`),fileText:async e=>{let t={},n=U();n&&(t.Authorization=`Bearer ${n}`);let r=await fetch(`/api/files/${e.split(`/`).map(encodeURIComponent).join(`/`)}`,{headers:t});if(r.status===401)throw new H;if(!r.ok)throw Error(Ee(r.status,await r.json().catch(()=>void 0)));return r.text()},settings:()=>G(`/api/settings`),update:(e=!1)=>G(`/api/update${e?`?refresh=1`:``}`),nudges:()=>G(`/api/nudges`),updateSettings:e=>G(`/api/settings`,{method:`PUT`,body:JSON.stringify(e)}),connections:()=>G(`/api/connections`),providers:e=>G(`/api/providers${e?`?region=${encodeURIComponent(e)}`:``}`),chatgptLogin:()=>G(`/api/chatgpt/login`,K({})),chatgptStatus:()=>G(`/api/chatgpt/status`),chatgptCallback:e=>G(`/api/chatgpt/callback`,K({url:e})),chatgptLogout:()=>G(`/api/chatgpt/logout`,K({})),setLLM:e=>G(`/api/connections/llm`,{method:`PUT`,body:JSON.stringify(e)}),testLLM:()=>G(`/api/connections/llm/test`,{method:`POST`}),llmModels:e=>G(`/api/llm/models`,K(e)),addEndpoint:e=>G(`/api/connections/endpoints`,K(e)),updateEndpoint:(e,t)=>G(`/api/connections/endpoints/${encodeURIComponent(e)}`,{method:`PUT`,body:JSON.stringify(t)}),removeEndpoint:e=>G(`/api/connections/endpoints/${encodeURIComponent(e)}`,{method:`DELETE`}),refreshEndpointModels:e=>G(`/api/connections/endpoints/${encodeURIComponent(e)}/models`,K({})),setEmbeddings:e=>G(`/api/connections/embeddings`,{method:`PUT`,body:JSON.stringify(e)}),testEmbeddings:()=>G(`/api/connections/embeddings/test`,{method:`POST`}),setSearch:e=>G(`/api/connections/search`,{method:`PUT`,body:JSON.stringify(e)}),testSearch:()=>G(`/api/connections/search/test`,{method:`POST`}),setEmail:e=>G(`/api/connections/email`,{method:`PUT`,body:JSON.stringify(e)}),disconnectEmail:()=>G(`/api/connections/email`,{method:`DELETE`}),testEmail:()=>G(`/api/connections/email/test`,{method:`POST`}),calendar:()=>G(`/api/calendar`),setCalendar:e=>G(`/api/connections/calendar`,{method:`PUT`,body:JSON.stringify(e)}),addCalendarFeed:(e,t)=>G(`/api/connections/calendar/feeds`,K({name:e,url:t})),removeCalendarFeed:e=>G(`/api/connections/calendar/feeds/${encodeURIComponent(e)}`,{method:`DELETE`}),testCalendar:()=>G(`/api/connections/calendar/test`,{method:`POST`}),contacts:(e=``,t=8)=>G(`/api/contacts?q=${encodeURIComponent(e)}&limit=${t}`),setContacts:e=>G(`/api/connections/contacts`,{method:`PUT`,body:JSON.stringify(e)}),addContactsSource:(e,t)=>G(`/api/connections/contacts/sources`,K({name:e,url:t})),importContacts:(e,t)=>G(`/api/connections/contacts/import?name=${encodeURIComponent(e)}`,{method:`POST`,headers:{"Content-Type":`text/vcard; charset=utf-8`},body:t}),removeContactsSource:e=>G(`/api/connections/contacts/sources/${encodeURIComponent(e)}`,{method:`DELETE`}),testContacts:()=>G(`/api/connections/contacts/test`,{method:`POST`}),skills:()=>G(`/api/skills`),skill:e=>G(`/api/skills/${encodeURIComponent(e)}`),saveSkill:(e,t)=>G(`/api/skills/${encodeURIComponent(e)}`,{method:`PUT`,body:JSON.stringify({content:t})}),deleteSkill:e=>G(`/api/skills/${encodeURIComponent(e)}`,{method:`DELETE`}),setSkillEnabled:(e,t)=>G(`/api/skills/${encodeURIComponent(e)}/enabled`,K({enabled:t})),importSkill:e=>G(`/api/skills/import`,K({url:e})),setGui:e=>G(`/api/connections/gui`,{method:`PUT`,body:JSON.stringify(e)}),testGui:()=>G(`/api/connections/gui/test`,{method:`POST`}),media:e=>G(`/api/connections/${e}`),setMedia:(e,t)=>G(`/api/connections/${e}`,{method:`PUT`,body:JSON.stringify(t)}),setBrowser:e=>G(`/api/connections/browser`,{method:`PUT`,body:JSON.stringify({enabled:e})}),addMCP:e=>G(`/api/connections/mcp`,K(e)),removeMCP:e=>G(`/api/connections/mcp/${encodeURIComponent(e)}`,{method:`DELETE`}),vaultSet:(e,t)=>G(`/api/vault/${encodeURIComponent(e)}`,{method:`PUT`,body:JSON.stringify({value:t})}),vaultDelete:e=>G(`/api/vault/${encodeURIComponent(e)}`,{method:`DELETE`}),onboarded:(e=!0)=>G(`/api/onboarded`,K({done:e})),firstrun:e=>G(`/api/firstrun?lang=${encodeURIComponent(e)}`),firstrunStart:e=>G(`/api/firstrun/start`,K({lang:e})),firstrunPick:e=>G(`/api/firstrun/pick`,K({name:e})),firstrunDismiss:()=>G(`/api/firstrun/dismiss`,K({})),browserControl:(e,t)=>G(`/api/browser/${encodeURIComponent(e)}/control`,K(t)),push:()=>G(`/api/push`),pushSubscribe:e=>G(`/api/push/subscribe`,K({subscription:e})),pushUnsubscribe:e=>G(`/api/push/unsubscribe`,K({endpoint:e})),pushTest:()=>G(`/api/push/test`,{method:`POST`})};function De(e){return e===4401?`auth`:e===4404?`gone`:`retry`}function Oe(e){let t=null,n=!1,r=0,i,a=()=>{let o=window.location.protocol===`https:`?`wss`:`ws`;t=new WebSocket(`${o}://${window.location.host}/ws`),t.onopen=()=>{let n=U();n&&t?.send(JSON.stringify({kind:`auth`,token:n})),r=0,e.onOpen?.()},t.onmessage=t=>{try{e.onMessage(JSON.parse(t.data))}catch{}},t.onclose=t=>{e.onClose?.();let o=De(t.code);if(o===`auth`){e.onAuthError?.();return}if(o===`gone`){n=!0,e.onGone?.();return}if(n)return;let s=Math.min(15e3,500*2**r++);i=window.setTimeout(a,s)},t.onerror=()=>t?.close()};return a(),{send:e=>t&&t.readyState===WebSocket.OPEN?(t.send(JSON.stringify(e)),!0):!1,close:()=>{n=!0,i&&window.clearTimeout(i),t?.close()}}}var ke=o((e=>{var t=d(),n=Symbol.for(`react.element`),r=Symbol.for(`react.fragment`),i=Object.prototype.hasOwnProperty,a=t.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.ReactCurrentOwner,o={key:!0,ref:!0,__self:!0,__source:!0};function s(e,t,r){var s,c={},l=null,u=null;for(s in r!==void 0&&(l=``+r),t.key!==void 0&&(l=``+t.key),t.ref!==void 0&&(u=t.ref),t)i.call(t,s)&&!o.hasOwnProperty(s)&&(c[s]=t[s]);if(e&&e.defaultProps)for(s in t=e.defaultProps,t)c[s]===void 0&&(c[s]=t[s]);return{$$typeof:n,type:e,key:l,ref:u,props:c,_owner:a.current}}e.Fragment=r,e.jsx=s,e.jsxs=s})),Ae=o(((e,t)=>{t.exports=ke()})),je=6e5;function Me(e,t=Date.now()){let n={};for(let r of e??[])t-r.at*1e3<6e5&&(n[r.thread]=r);return n}function Ne(){return`serviceWorker`in navigator&&`PushManager`in window&&`Notification`in window}async function Pe(){if(!(`serviceWorker`in navigator)||!window.isSecureContext)return null;try{return await navigator.serviceWorker.register(`/sw.js`)}catch{return null}}async function Fe(){if(!Ne())return`unsupported`;if(!window.isSecureContext)return`insecure`;if(Notification.permission===`denied`)return`denied`;let e=await navigator.serviceWorker.getRegistration();return e&&await e.pushManager.getSubscription()?`on`:`off`}function Ie(e){let t=`=`.repeat((4-e.length%4)%4),n=atob((e+t).replace(/-/g,`+`).replace(/_/g,`/`)),r=new Uint8Array(new ArrayBuffer(n.length));for(let e=0;e0?t.setAppBadge?.(e):t.clearAppBadge?.()}catch{}}var Be=`nanomuse_theme`,Ve={light:`#fcfcfc`,dark:`#181819`};function He(){try{let e=localStorage.getItem(Be);if(e===`light`||e===`dark`||e===`system`)return e}catch{}return`light`}var J=He(),Y=new Set,Ue=typeof matchMedia==`function`?matchMedia(`(prefers-color-scheme: dark)`):null;function We(){return Ue?.matches?`dark`:`light`}function Ge(){return J}function X(){return J===`system`?We():J}function Ke(e){J=e;try{localStorage.setItem(Be,e)}catch{}Z(),Y.forEach(e=>e())}function Z(){if(typeof document>`u`)return;let e=X();document.documentElement.dataset.theme=e;let t=document.querySelector(`meta[name="theme-color"]`);t&&t.setAttribute(`content`,Ve[e])}Ue?.addEventListener?.(`change`,()=>{J===`system`&&(Z(),Y.forEach(e=>e()))});function qe(e){return Y.add(e),()=>Y.delete(e)}function Je(){return(0,f.useSyncExternalStore)(qe,Ge,Ge)}function Ye(){return(0,f.useSyncExternalStore)(qe,X,X)}var Q=Ae();function Xe(){if(window.parent===window)return null;let e=window.location.ancestorOrigins;if(e&&e.length>0&&e[0]!==`null`)return e[0];if(document.referrer)try{return new URL(document.referrer).origin}catch{return null}return null}function Ze(e){let t=Xe();t&&window.parent.postMessage(e,t)}var Qe=[`chat`,`feed`,`ideas`,`goals`,`library`,`memory`,`devices`,`connections`,`channels`,`skills`,`you`,`account`,`coding`,`avatar`],$e=`nanomuse_feed_seen`,et=`nanomuse_sign_in_skipped`,tt=`nanomuse.ui.lite`;function nt(){try{let e=new URL(window.location.href);return e.searchParams.get(`ui`)===`lite`?(sessionStorage.setItem(tt,`1`),!0):e.searchParams.get(`ui`)===`full`?(sessionStorage.removeItem(tt),!1):sessionStorage.getItem(tt)===`1`}catch{return!1}}var rt={connected:!1,loaded:!1,authError:!1,gone:!1,error:null,version:``,profile:null,status:{state:`idle`,detail:``,thread:`main`},threads:[],activeThread:`main`,events:{},hasMore:{},streams:{},goals:[],settings:null,goalsVersion:0,memoryVersion:0,remindersVersion:0,calendarVersion:0,pendingApprovals:[],feedVersion:0,feedSeenAt:R($e)??``,viewer:null,draft:null,draftFiles:null,connectionsVersion:0,skillsVersion:0,onboardingDismissed:!1,signInSkipped:R(et)===`1`,tab:`chat`,toast:null,drawer:!1,finishedAt:0,mishapAt:0,hub:null,codingLive:{},lite:nt(),hands:null,holds:[],handsLive:null,studio:null,working:{},firstrun:null};function it(e,t){if(t.type!==`approval`)return e;let n=e.filter(e=>e.id!==t.id);return t.status===`pending`?[...n,t]:n}function at(e){return e.type===`approval`||e.type===`question`||e.source===`background`||e.source===`goal`}function ot(e){let t=e.ts;return typeof t==`number`?{...e,ts:new Date(t*1e3).toISOString()}:e}function st(e,t){let n=e??[],r=n.findIndex(e=>e.id===t.id);if(r>=0){let e=n.slice();return e[r]=t,e}if(t.synced&&t.ts&&n.length>0&&(n[n.length-1]?.ts??``)>t.ts){let e=n.length;for(;e>0&&(n[e-1]?.ts??``)>t.ts;)--e;return[...n.slice(0,e),t,...n.slice(e)]}return[...n,t]}function ct(e,t){let n=e.filter(e=>e.id!==t.id);return t.status===`on`?[...n,t]:n}function lt(e,t){let n=e.findIndex(e=>e.id===t.id);if(n>=0){let r=e.slice();return r[n]=t,r}return[...e,t]}function ut(e,t){switch(t.type){case`hello`:{let n=t.state;for(let e of Object.keys($))delete $[e];return{...e,loaded:!0,authError:!1,version:n.version,profile:n.profile,status:n.status,streams:{},threads:n.threads,goals:n.goals,settings:n.settings,pendingApprovals:n.pending_approvals,feedVersion:e.feedVersion+1,activeThread:n.threads.some(t=>t.id===e.activeThread)?e.activeThread:`main`,hub:n.hub??e.hub,hands:n.hands??e.hands,holds:(n.holds??[]).map(ot),working:Me(n.working),firstrun:n.firstrun??e.firstrun}}case`connection`:return{...e,connected:t.connected};case`authError`:return{...e,authError:!0,connected:!1};case`gone`:return{...e,gone:!0,connected:!1};case`error`:return{...e,error:t.error};case`events`:{let n=e.events[t.thread]??[],r=t.events.map(ot),i=t.prepend?[...r,...n.filter(e=>!r.some(t=>t.id===e.id))]:r;return{...e,events:{...e.events,[t.thread]:i},hasMore:{...e.hasMore,[t.thread]:t.hasMore}}}case`eventsFailed`:return{...e,events:{...e.events,[t.thread]:e.events[t.thread]??[]},toast:I(`Could not load the conversation. Pull to retry.`)};case`activeThread`:return{...e,activeThread:t.thread,tab:`chat`};case`goals`:return{...e,goals:t.goals};case`settings`:return{...e,settings:t.settings,profile:t.settings.profile};case`tab`:return{...e,tab:t.tab};case`drawer`:return{...e,drawer:t.open};case`feedSeen`:return z($e,t.at),{...e,feedSeenAt:t.at};case`viewer`:return{...e,viewer:t.path};case`draft`:return{...e,draft:t.text};case`draftFiles`:return{...e,draftFiles:t.files};case`onboardingDismissed`:return{...e,onboardingDismissed:!0};case`signInSkipped`:return{...e,signInSkipped:!0};case`toast`:return{...e,toast:t.toast};case`ws`:return dt(e,t.msg);default:return e}}function dt(e,t){switch(t.kind){case`hello`:return ut(e,{type:`hello`,state:t.state});case`event`:case`update`:{let n=ot(t.event),r={...e.streams},i=r[n.thread];n.type===`assistant`&&i&&i.id===n.id&&(r[n.thread]=void 0);let a=e.threads.map(e=>e.id===n.thread&&t.kind===`event`?{...e,updated_at:n.ts}:e),o=e.events[n.thread]!==void 0,s=n.type===`tool`&&(n.status===`error`||n.status===`blocked`)||n.type===`notice`&&n.level===`error`,c=e.working,l=c[n.thread];return l&&n.type===`assistant`&&n.synced&&n.via_device===l.device&&(c={...c,[n.thread]:void 0}),{...e,streams:r,threads:a,working:c,events:o?{...e.events,[n.thread]:st(e.events[n.thread],n)}:e.events,holds:n.type===`hold`?ct(e.holds,n):e.holds,pendingApprovals:it(e.pendingApprovals,n),feedVersion:at(n)?e.feedVersion+1:e.feedVersion,mishapAt:s?Date.now():e.mishapAt}}case`stream_start`:return{...e,streams:{...e.streams,[t.thread]:{id:t.id,text:``,ended:!1}}};case`delta`:{let n=e.streams[t.thread],r=n&&n.id===t.id?{...n,text:n.text+t.text}:{id:t.id,text:t.text,ended:!1};return{...e,streams:{...e.streams,[t.thread]:r}}}case`stream_end`:{let n=e.streams[t.thread];return!n||n.id!==t.id?e:t.discard||!n.text.trim()?{...e,streams:{...e.streams,[t.thread]:void 0}}:{...e,streams:{...e.streams,[t.thread]:{...n,ended:!0}}}}case`status`:{let n=t.status,r={...e.streams};r[n.thread]?.ended&&n.state!==`working`&&(r[n.thread]=void 0);let i=ft(e.status,n),a=e.status.state===`working`&&i.state===`idle`;return{...e,status:i,streams:r,finishedAt:a?Date.now():e.finishedAt}}case`thread`:return{...e,threads:lt(e.threads,t.thread)};case`thread_deleted`:{let n={...e.events};return delete n[t.thread],{...e,events:n,holds:e.holds.filter(e=>e.thread!==t.thread),threads:e.threads.filter(e=>e.id!==t.thread),pendingApprovals:e.pendingApprovals.filter(e=>e.thread!==t.thread),activeThread:e.activeThread===t.thread?`main`:e.activeThread}}case`thread_cleared`:return{...e,events:{...e.events,[t.thread]:[]},holds:e.holds.filter(e=>e.thread!==t.thread),pendingApprovals:e.pendingApprovals.filter(e=>e.thread!==t.thread)};case`event_removed`:{let n=e.events[t.thread];return n?{...e,events:{...e.events,[t.thread]:n.filter(e=>e.id!==t.id)}}:e}case`firstrun`:return{...e,firstrun:t.firstrun};case`working`:{let{kind:n,working:r,...i}=t,a=e.working[i.thread];return r?{...e,working:{...e.working,[i.thread]:i}}:!a||a.device!==i.device?e:{...e,working:{...e.working,[i.thread]:void 0}}}case`goals`:return{...e,goalsVersion:e.goalsVersion+1};case`memory`:return{...e,memoryVersion:e.memoryVersion+1};case`reminders`:case`triggers`:return{...e,remindersVersion:e.remindersVersion+1};case`calendar`:return{...e,calendarVersion:e.calendarVersion+1};case`feed_posts`:return{...e,feedVersion:e.feedVersion+1};case`profile`:return{...e,profile:t.profile,settings:e.settings?{...e.settings,profile:t.profile}:e.settings};case`settings`:return{...e,settings:t.settings,profile:t.settings.profile};case`connections`:return{...e,connectionsVersion:e.connectionsVersion+1};case`hub`:return{...e,hub:t.hub};case`coding`:{let n=t.run?.id??t.event.run;if(!n)return e;let r=e.codingLive[n],i=t.run??r?.run;if(!i)return e;let a=t.event.kind===`run`?r?.events??[]:[...r?.events??[],t.event].slice(-400),o=r?.current??``;t.event.kind===`text`&&(o=t.event.partial?o+(t.event.text??``):``),(t.event.kind===`done`||t.event.kind===`error`)&&(o=``);let s={...e.codingLive,[n]:{run:{...i,device:t.device??i.device},events:a,current:o}},c=Object.keys(s);if(c.length>20)for(let e of c.sort((e,t)=>s[e].run.started_at-s[t].run.started_at).slice(0,c.length-20))delete s[e];return{...e,codingLive:s}}case`hands_state`:return{...e,hands:t.hands};case`studio`:return{...e,studio:t.current};case`hands`:{let{kind:n,...r}=t,i=r.event===`end`||r.event===`stop`;return{...e,handsLive:i?null:r}}case`skills`:return{...e,skillsVersion:e.skillsVersion+1};case`error`:return{...e,toast:I(t.error)};case`pong`:return{...e,status:t.status};default:return e}}var $={};function ft(e,t){$[t.thread]=t;let n=Object.values($).filter(e=>e.state!==`idle`);return n.length?(n.sort((e,t)=>Number(e.thread!==`main`)-Number(t.thread!==`main`)),n[0]??e):{state:`idle`,detail:``,thread:`main`}}var pt=(0,f.createContext)(null);function mt({children:e}){let[t,n]=(0,f.useReducer)(ut,rt),r=(0,f.useRef)(null);(0,f.useEffect)(()=>{U();let e=[],t=0,i=()=>{t=0;let r=e.splice(0);for(let e of r)n({type:`ws`,msg:e})},a=Oe({onMessage:n=>{e.push(n),t||=window.setTimeout(i,0)},onOpen:()=>n({type:`connection`,connected:!0}),onClose:()=>n({type:`connection`,connected:!1}),onAuthError:()=>n({type:`authError`}),onGone:()=>n({type:`gone`})});return r.current=a,q.state().then(e=>n({type:`hello`,state:e})).catch(e=>{e instanceof H?n({type:`authError`}):n({type:`error`,error:String(e.message??e)})}),()=>{t&&window.clearTimeout(t),a.close()}},[]);let i=(0,f.useRef)({}),a=(0,f.useCallback)(async(e,t)=>{let r=t?void 0:i.current[e]=(i.current[e]??0)+1;try{let a=await q.events(e,150,t);if(r!==void 0&&i.current[e]!==r)return;n({type:`events`,thread:e,events:a.events,hasMore:a.has_more,prepend:!!t})}catch(t){t instanceof H?n({type:`authError`}):n({type:`eventsFailed`,thread:e})}},[]),o=(0,f.useCallback)(async()=>{try{n({type:`ws`,msg:{kind:`hub`,hub:await q.hub()}})}catch{}},[]);(0,f.useEffect)(()=>{t.loaded&&a(t.activeThread)},[t.loaded,t.activeThread,a]);let s=(0,f.useRef)(!1);(0,f.useEffect)(()=>{t.connected&&s.current&&t.loaded&&a(t.activeThread),s.current=t.connected},[t.connected,t.loaded,t.activeThread,a]);let c=(0,f.useCallback)(async()=>{try{n({type:`goals`,goals:await q.goals()})}catch{}},[]);(0,f.useEffect)(()=>{t.loaded&&c()},[t.goalsVersion,t.loaded,c]);let l=(0,f.useCallback)(async()=>{try{n({type:`settings`,settings:await q.settings()})}catch{}},[]);(0,f.useEffect)(()=>{if(!t.toast)return;let e=window.setTimeout(()=>n({type:`toast`,toast:null}),3500);return()=>window.clearTimeout(e)},[t.toast]),(0,f.useEffect)(()=>{Pe();let e=e=>{let t=new URL(e,window.location.origin),r=t.searchParams.get(`thread`),i=t.searchParams.get(`tab`);r&&n({type:`activeThread`,thread:r}),i&&Qe.includes(i)&&!r?n({type:`tab`,tab:i}):n({type:`tab`,tab:`chat`});let a=t.searchParams.get(`draft`);a&&n({type:`draft`,text:a});let o=t.searchParams.get(`attach`);if(o)try{let e=JSON.parse(o);Array.isArray(e)&&e.length&&n({type:`draftFiles`,files:e.filter(e=>e&&typeof e.path==`string`)})}catch{}},t=new URL(window.location.href);if([`thread`,`tab`,`draft`,`attach`,`ui`].some(e=>t.searchParams.has(e))){e(t.href);for(let e of[`thread`,`tab`,`draft`,`attach`,`ui`])t.searchParams.delete(e);window.history.replaceState({},``,t.toString())}let r=t=>{t.data&&t.data.type===`open`&&e(String(t.data.url||`/`))};navigator.serviceWorker?.addEventListener(`message`,r);let i=e=>{if(window.parent===window||e.source!==window.parent)return;let t=e.data;t&&t.type===`nanomuse:draft`&&typeof t.text==`string`&&(n({type:`tab`,tab:`chat`}),n({type:`draft`,text:t.text.slice(0,4e3)}))};return window.addEventListener(`message`,i),()=>{navigator.serviceWorker?.removeEventListener(`message`,r),window.removeEventListener(`message`,i)}},[]);let u=Ye();(0,f.useEffect)(()=>{t.loaded&&Ze({type:`nanomuse:ready`,name:t.profile?.name??``,theme:u})},[t.loaded,t.profile?.name]),(0,f.useEffect)(()=>{t.loaded&&Ze({type:`nanomuse:theme`,theme:u})},[t.loaded,u]),(0,f.useEffect)(()=>{t.loaded&&ze(t.pendingApprovals.length)},[t.loaded,t.pendingApprovals.length]);let d=(0,f.useMemo)(()=>({state:t,dispatch:n,send:async(e,t,i=[])=>{if(!t.trim()&&i.length===0)return;let a=F();try{(i.length>0||!r.current?.send({kind:`send`,thread:e,text:t,language:a}))&&await q.send(e,t,i,a)}catch(e){throw e instanceof H&&n({type:`authError`}),e}},sendViaCloud:async(e,t,r=[])=>{if(t.trim()||r.length!==0)try{await q.send(e,t,r,F(),`cloud`)}catch(e){throw e instanceof H&&n({type:`authError`}),e}},decide:async(e,t,i=`once`)=>{try{r.current?.send({kind:`approval`,id:e,approved:t,scope:i})||await q.decide(e,t,i)}catch(e){throw e instanceof H&&n({type:`authError`}),e}},loadEvents:a,refreshGoals:c,refreshSettings:l,refreshHub:o,setTab:e=>n({type:`tab`,tab:e}),setDrawer:e=>n({type:`drawer`,open:e}),openThread:e=>n({type:`activeThread`,thread:e}),markFeedSeen:e=>n({type:`feedSeen`,at:e}),openFile:e=>n({type:`viewer`,path:e}),draftFiles:e=>n({type:`draftFiles`,files:e}),draft:e=>{n({type:`draft`,text:e}),e!==null&&n({type:`tab`,tab:`chat`})},dismissOnboarding:()=>n({type:`onboardingDismissed`}),skipSignIn:()=>{z(et,`1`),n({type:`signInSkipped`})},toast:e=>n({type:`toast`,toast:I(e)})}),[t,a,c,l,o]);return(0,Q.jsx)(pt.Provider,{value:d,children:e})}function ht(){let e=(0,f.useContext)(pt);if(!e)throw Error(`useStore outside provider`);return e}var gt=`dragon`,_t=new Set([`panda`,`sunny`,`moss`,`sky`,`fox`,`bolt`,`plum`]);function vt(e){return!e||e===`dragon`||_t.has(e)}function yt(e,t){return W(`avatar/${e}/${t===`working`||t===`waiting`||t===`happy`||t===`error`?t:`idle`}.webp`)}function bt(e){return`/avatars/dragon-${e===`working`||e===`waiting`||e===`happy`||e===`error`?e:`idle`}.webp`}function xt(e){return e===`working`||e===`waiting`||e===`happy`?e:`idle`}function St(e){return e===`error`?null:`/avatars/dragon-${xt(e)}.mp4`}function Ct(e,t){return t===`error`?null:W(`avatar/${e}/${xt(t)}.mp4`)}var wt=3e3,Tt=4e3;function Et(e){let{state:t}=ht(),n=Dt(e?[t.mishapAt+Tt,t.finishedAt+wt]:[]);return e?t.loaded&&!t.connected?`sleepy`:e.state===`waiting`?`waiting`:e.state===`working`?`working`:t.mishapAt&&n-t.mishapAt<4e3?`error`:t.finishedAt&&n-t.finishedAt<3e3?`happy`:`idle`:`idle`}function Dt(e){let[t,n]=(0,f.useState)(()=>Date.now()),r=e.join(`,`);(0,f.useEffect)(()=>n(Date.now()),[r]);let i=Math.min(...e.filter(e=>e>t),1/0);return(0,f.useEffect)(()=>{if(!Number.isFinite(i))return;let e=window.setTimeout(()=>n(Date.now()),Math.max(0,i-Date.now())+20);return()=>window.clearTimeout(e)},[i]),t}var Ot=44,kt=new Set,At=typeof window<`u`&&typeof window.matchMedia==`function`&&window.matchMedia(`(prefers-reduced-motion: reduce)`).matches;function jt({profile:e,status:t,size:n=40,onClick:r,still:i=!1,className:a}){let[o,s]=(0,f.useState)(!1),[,c]=(0,f.useState)(0);(0,f.useEffect)(()=>{if(!o)return;let e=window.setTimeout(()=>s(!1),900);return()=>window.clearTimeout(e)},[o]);let l=Et(t),u=t?.state??`idle`,d=e?.color??`#0064d4`,p=!e||vt(e.avatar),m=!p&&e?.avatar?e.avatar:null,h=o?`happy`:i?`idle`:l,g=i||At||n{kt.add(_),c(e=>e+1)},className:`h-full w-full object-cover`},_):p||m?(0,Q.jsx)(`img`,{src:y,alt:``,draggable:!1,className:`h-full w-full object-cover`}):(0,Q.jsx)(`span`,{className:`flex h-full w-full items-center justify-center leading-none drop-shadow-sm`,style:{fontSize:n*.5},children:e?.emoji??`✨`})}),t&&u!==`idle`&&(0,Q.jsx)(`span`,{className:B(`absolute -bottom-0.5 -right-0.5 rounded-full border-2 border-bg`,u===`working`?`bg-amber-400`:`bg-rose-500`),style:{width:Math.max(10,n*.28),height:Math.max(10,n*.28)}})]});return r?(0,Q.jsx)(`button`,{type:`button`,onClick:()=>{s(!0),r()},"aria-label":b,className:B(x,`transition active:scale-95`),style:{width:n,height:n},children:S}):(0,Q.jsx)(`span`,{role:`img`,"aria-label":b,onClick:()=>s(!0),className:x,style:{width:n,height:n},children:S})}function Mt({profile:e,status:t,name:n,statusLine:r,statusTone:i=`muted`,spinning:a=!1,badge:o,onAvatar:s,onName:c,leading:l,trailing:u,under:d,size:f=72,className:p}){return(0,Q.jsxs)(`header`,{className:B(`safe-top relative shrink-0 bg-bg pt-1.5 pb-1`,p),children:[(0,Q.jsxs)(`div`,{className:`flex flex-col items-center px-16`,children:[(0,Q.jsxs)(`button`,{type:`button`,onClick:s,"aria-label":n,className:`relative rounded-full`,children:[(0,Q.jsx)(jt,{profile:e,status:t,size:f}),o!==void 0&&o>0&&(0,Q.jsx)(`span`,{className:`pointer-events-none absolute -right-0.5 top-0 flex h-[18px] min-w-[18px] items-center justify-center rounded-full border-2 border-bg bg-rose-500 px-1 text-[10.5px] font-bold text-white`,children:o})]}),(0,Q.jsxs)(`div`,{className:`relative z-10 -mt-2.5 flex min-h-[44px] flex-col items-center`,children:[(0,Q.jsx)(Nt,{name:n,statusLine:r,statusTone:i,spinning:a,onClick:c??s}),d&&(0,Q.jsx)(`div`,{className:`mt-1.5 flex max-w-full items-center`,children:d})]})]}),l&&(0,Q.jsx)(`div`,{className:`absolute left-4 top-1.5 safe-top`,children:l}),u&&(0,Q.jsx)(`div`,{className:`absolute right-4 top-1.5 safe-top flex items-center gap-2`,children:u})]})}function Nt({name:e,statusLine:t,statusTone:n=`muted`,spinning:r=!1,onClick:i}){let a=(0,Q.jsxs)(Q.Fragment,{children:[(0,Q.jsx)(`span`,{className:`max-w-[240px] truncate text-[14px] leading-[18px] text-fg`,children:e}),t&&(0,Q.jsxs)(`span`,{className:B(`mt-0.5 flex max-w-[240px] items-center gap-1 text-[11.5px] leading-[14px]`,n===`accent`?`text-accent`:`text-muted`),children:[r&&(0,Q.jsx)(`span`,{className:`h-2.5 w-2.5 shrink-0 animate-spin rounded-full border-[1.5px] border-current border-t-transparent`}),(0,Q.jsx)(`span`,{className:`truncate`,children:t})]})]}),o=`flex flex-col items-center rounded-[14px] bg-surface px-3 py-1 shadow-[0_1px_4px_rgba(0,0,0,0.16)] dark:border dark:border-border dark:shadow-none`;return i?(0,Q.jsx)(`button`,{type:`button`,onClick:i,className:o,children:a}):(0,Q.jsx)(`div`,{className:o,children:a})}function Pt({onClick:e,label:t,children:n,dot:r=!1,small:i=!1,className:a,disabled:o=!1,expanded:s}){return(0,Q.jsxs)(`button`,{type:`button`,onClick:e,"aria-label":t,"aria-expanded":s,disabled:o,className:B(`relative flex items-center justify-center rounded-full bg-surface text-fg shadow-[0_1px_4px_rgba(0,0,0,0.14)] hover:bg-surface-2 disabled:opacity-50 dark:border dark:border-border dark:shadow-none`,i?`h-10 w-10`:`h-11 w-11`,a),children:[n,r&&(0,Q.jsx)(`span`,{className:`absolute right-[3px] top-[3px] h-[9px] w-[9px] rounded-full border-[1.5px] border-surface bg-accent`})]})}function Ft({children:e,className:t}){return(0,Q.jsx)(`h1`,{className:B(`px-5 pt-1.5 pb-1.5 text-[26px] font-bold leading-8 tracking-tight`,t),children:e})}export{ye as A,fe as B,Te as C,Se as D,B as E,ne as F,ue as G,oe as H,se as I,b as J,he as K,F as L,_e as M,ge as N,R as O,z as P,l as Q,L as R,W as S,we as T,I as U,pe as V,le as W,o as X,d as Y,s as Z,Le as _,gt as a,Ae as b,vt as c,mt as d,ht as f,Re as g,Je as h,jt as i,xe as j,be as k,Ct as l,Ke as m,Ft as n,St as o,Z as p,x as q,Pt as r,bt as s,Mt as t,yt as u,Fe as v,G as w,q as x,je as y,me as z}; \ No newline at end of file diff --git a/nanomuse/server/static/assets/Onboarding-CtVO6gdK.js b/nanomuse/server/static/assets/Onboarding-CtVO6gdK.js deleted file mode 100644 index b4d23db46..000000000 --- a/nanomuse/server/static/assets/Onboarding-CtVO6gdK.js +++ /dev/null @@ -1 +0,0 @@ -import{E as e,J as t,K as n,L as r,Q as i,Y as a,a as o,b as s,f as c,i as l,q as u,x as d}from"./MuseHeader-Pw-NI98v.js";import{A as f}from"./StarNudge-DjXecvWj.js";import{n as p}from"./external-link-Xj5fjR8v.js";import"./Form-DwKuBk1V.js";import{r as m}from"./IdentityForm-BTGczGT_.js";import{Et as h,bt as g,t as _,vt as v}from"./index-CIdGZ5PB.js";import{t as y}from"./AvatarPicker-gR2knlot.js";import{CalendarCard as b,ContactsCard as x,EmailCard as S,ModelCard as C}from"./ConnectionsScreen-CMt7GOff.js";var w=t(`lock`,[[`rect`,{width:`18`,height:`11`,x:`3`,y:`11`,rx:`2`,ry:`2`,key:`1w4ew1`}],[`path`,{d:`M7 11V7a5 5 0 0 1 10 0v4`,key:`fwvmzm`}]]),T=i(a(),1),E=s();function D(){let{state:t,setTab:i,dismissOnboarding:a,refreshSettings:s,toast:p}=c(),[w,D]=(0,T.useState)(`welcome`),[M,N]=(0,T.useState)(null),[P,F]=(0,T.useState)(!1),[I,L]=(0,T.useState)(!1),R=n(),z=async()=>{L(!0);try{await d.cloudUseAsModel(),p(R(`The Cloud model is in use.`)),await H()}catch(e){p(e.message)}finally{L(!1)}},[B,V]=(0,T.useState)(null),H=async()=>{try{V(null),N(await d.connections())}catch(e){V(R(e.message)||R(`Could not load the connections.`))}};(0,T.useEffect)(()=>{H()},[t.connectionsVersion]);let U=async()=>{try{await d.onboarded(!0),await s()}catch{}a(),i(`chat`)},W=async()=>{F(!0);try{await d.firstrunStart(r()===`zh-CN`?`zh`:`en`)}catch{await d.onboarded(!0).catch(()=>void 0)}try{await s()}catch{}F(!1),a(),i(`chat`)},G={...m(t.profile,o,y[0]),proactivity:`default`,proactive:!0,goal_interval_minutes:60,quiet_hours:``},K=M?M.llm.key_source===`vault`||M.llm.key_source===`config`||!!M.providers[j(M)]?.no_key:!1,q=!!M&&(M.email.configured||M.calendar.feeds.length>0||M.contacts.sources.length>0),J=[`welcome`,`list`],Y=w===`welcome`?0:1;return(0,E.jsxs)(`div`,{className:`mx-auto flex h-[100dvh] max-w-[760px] flex-col bg-bg sm:border-x sm:border-border`,children:[(0,E.jsx)(`div`,{className:`titlebar-room`}),(0,E.jsxs)(`header`,{className:`safe-top shrink-0 px-5 pt-4 pb-2 flex items-center justify-between`,children:[(0,E.jsx)(`div`,{className:`flex gap-1`,children:J.map((t,n)=>(0,E.jsx)(`span`,{className:e(`h-1.5 rounded-full transition-all`,n<=Y?`w-5 bg-accent`:`w-1.5 bg-border`)},t))}),(0,E.jsx)(`button`,{type:`button`,onClick:()=>void U(),className:`text-[13px] text-muted`,children:R(`Skip setup`)})]}),(0,E.jsxs)(`div`,{className:`flex-1 overflow-y-auto px-5 pb-6`,children:[w===`welcome`&&(0,E.jsxs)(`div`,{className:`flex h-full flex-col items-center justify-center text-center`,children:[(0,E.jsx)(l,{profile:G,size:96}),(0,E.jsx)(`h1`,{className:`mt-6 text-[28px] font-bold tracking-tight`,children:R(`Meet your nanoMuse`)}),(0,E.jsx)(`p`,{className:`mt-2 text-[15px] text-muted`,children:R(`A personal agent of your own. Three things to know:`)}),(0,E.jsxs)(`ul`,{className:`mt-6 w-full max-w-sm space-y-2.5 text-left`,children:[(0,E.jsx)(O,{n:1,title:R(`It does things for you.`),body:R(`Searches, browses, writes, books, reads mail, and hands you the result, not a list of links.`)}),(0,E.jsx)(O,{n:2,title:R(`It keeps working when you close the app.`),body:R(`Goals move forward between your visits; it reports in the Feed and notifies you when something is worth it.`)}),(0,E.jsx)(O,{n:3,title:R(`It asks you first where it matters.`),body:R(`A separate Sentinel reviews every action. Sending, paying, deleting: it stops and asks; your keys stay in a vault the model cannot read.`)})]}),(0,E.jsx)(`p`,{className:`mt-5 max-w-sm text-[13px] text-muted`,children:R(`There is no form to fill in: once it has a model, it introduces itself in the chat and asks what to call you.`)}),(0,E.jsx)(`p`,{className:`mt-2 max-w-sm text-[13px] text-muted`,children:(0,E.jsx)(`a`,{href:`https://nanomuse.cn/#open-source`,target:`_blank`,rel:`noreferrer`,className:`underline decoration-dotted underline-offset-2 hover:text-accent`,children:R(`nanoMuse is a non-profit open-source community project, free forever.`)})})]}),w===`list`&&(0,E.jsxs)(`div`,{className:`pt-6`,children:[(0,E.jsxs)(`div`,{className:`flex items-center gap-3`,children:[(0,E.jsx)(l,{profile:G,size:56}),(0,E.jsxs)(`div`,{className:`min-w-0`,children:[(0,E.jsx)(`h1`,{className:`text-[24px] font-bold tracking-tight truncate`,children:R(`Set it up`)}),(0,E.jsx)(`p`,{className:`text-[13.5px] text-muted truncate`,children:R(`A model, then the chat. A minute.`)})]})]}),(0,E.jsxs)(`ol`,{className:`mt-6 space-y-2`,children:[(0,E.jsx)(k,{done:K,title:R(`Add a model`),body:K?M?.llm.cloud?`nanoMuse Cloud · ${M.llm.model}`:`${M?.llm.model} · ${A(M?.llm.base_url??``)}`:t.hub?.account.signed_in?R(`Your account's model, or a key of your own.`):R(`Pick a provider and paste a key. Yours, stored in the vault.`),onClick:()=>D(`model`)}),(0,E.jsx)(k,{done:q,optional:!0,title:R(`Connect mail, calendar, contacts`),body:R(q?`Connected. Tap to add more.`:`Optional. It can read what came in, know your day, and who is who.`),onClick:()=>D(`connect`)}),(0,E.jsx)(k,{locked:!K,done:!1,title:R(`Start`),body:R(K?`Open the chat. It introduces itself and asks your name.`:`Needs a model first.`),onClick:()=>K&&!P&&void W()})]})]}),w===`model`&&(0,E.jsxs)(`div`,{className:`pt-6 space-y-4`,children:[(0,E.jsxs)(`div`,{children:[(0,E.jsx)(`h1`,{className:`text-[26px] font-bold tracking-tight`,children:R(`The model behind it`)}),(0,E.jsx)(`p`,{className:`mt-1 text-[14px] text-muted`,children:K?M?.llm.cloud?R(`Your account's model, with its free allowance. Keep it, or switch to a key of your own here.`):R(`A model is already set up on the server. Keep it, or switch here.`):R(`Your account brings a model with a free allowance, nothing to set up. Or paste a key of your own; it is stored encrypted in the vault on the server, never shown to the model, and nothing you say passes through the relay.`)})]}),M?(0,E.jsxs)(E.Fragment,{children:[!K&&t.hub?.account.signed_in&&(0,E.jsxs)(`button`,{type:`button`,disabled:I,onClick:()=>void z(),className:`flex w-full items-center gap-3 rounded-3xl border border-accent/30 bg-accent/5 px-4 py-3.5 text-left`,children:[(0,E.jsx)(`span`,{className:`flex h-10 w-10 shrink-0 items-center justify-center rounded-2xl bg-accent text-white`,children:I?(0,E.jsx)(u,{size:18,className:`animate-spin`}):(0,E.jsx)(v,{size:18})}),(0,E.jsxs)(`span`,{className:`min-w-0 flex-1`,children:[(0,E.jsx)(`span`,{className:`block text-[15px] font-medium`,children:R(`Use the nanoMuse Cloud model`)}),(0,E.jsx)(`span`,{className:`block text-[12.5px] text-muted`,children:R(`Signed in as {hint}. A free allowance, nothing to paste. Recommended to start.`,{hint:t.hub.account.hint})})]}),(0,E.jsx)(g,{size:16,className:`shrink-0 text-muted`})]}),!K&&!t.hub?.account.signed_in&&(0,E.jsx)(`div`,{className:`rounded-3xl border border-border/70 bg-surface p-4`,children:(0,E.jsx)(_,{onSignedIn:()=>void H(),useAsModel:!0})}),!K&&(0,E.jsxs)(`p`,{className:`px-1 text-[12.5px] text-muted`,children:[(0,E.jsx)(`span`,{className:`font-medium`,children:R(`Or bring your own key`)}),` · `,f(R,t.hub?.account)]}),(0,E.jsx)(C,{data:M,onChange:()=>void H(),compact:!0})]}):B?(0,E.jsxs)(`div`,{className:`rounded-3xl border border-border/70 bg-surface p-4 text-center`,children:[(0,E.jsx)(`p`,{className:`text-[13.5px] text-muted`,children:B}),(0,E.jsx)(`button`,{type:`button`,onClick:()=>void H(),className:`mt-3 rounded-full bg-surface-2 px-4 py-1.5 text-[13px] font-medium`,children:R(`Retry`)})]}):(0,E.jsx)(`div`,{className:`flex justify-center py-8 text-muted`,children:(0,E.jsx)(u,{className:`animate-spin`,size:20})})]}),w===`connect`&&(0,E.jsxs)(`div`,{className:`pt-6 space-y-4`,children:[(0,E.jsxs)(`div`,{children:[(0,E.jsx)(`h1`,{className:`text-[26px] font-bold tracking-tight`,children:R(`Connect your mail, calendar and contacts`)}),(0,E.jsx)(`p`,{className:`mt-1 text-[14px] text-muted`,children:R(`Optional. With a mailbox connected it can read what came in and draft replies; it will always ask before sending. With a calendar it knows your day and finds free time. With your contacts it knows who is who. The browser and MCP servers are under Connections later.`)})]}),M?(0,E.jsxs)(E.Fragment,{children:[(0,E.jsx)(S,{data:M,onChange:()=>void H(),compact:!0}),(0,E.jsx)(b,{data:M,onChange:()=>void H(),compact:!0}),(0,E.jsx)(x,{data:M,onChange:()=>void H(),compact:!0})]}):B?(0,E.jsxs)(`div`,{className:`rounded-3xl border border-border/70 bg-surface p-4 text-center`,children:[(0,E.jsx)(`p`,{className:`text-[13.5px] text-muted`,children:B}),(0,E.jsx)(`button`,{type:`button`,onClick:()=>void H(),className:`mt-3 rounded-full bg-surface-2 px-4 py-1.5 text-[13px] font-medium`,children:R(`Retry`)})]}):(0,E.jsx)(`div`,{className:`flex justify-center py-8 text-muted`,children:(0,E.jsx)(u,{className:`animate-spin`,size:20})})]})]}),(0,E.jsxs)(`footer`,{className:`safe-bottom shrink-0 px-5 pb-5 pt-2 flex gap-2`,children:[(w===`model`||w===`connect`)&&(0,E.jsx)(`button`,{type:`button`,onClick:()=>D(`list`),className:`flex items-center justify-center gap-1.5 rounded-2xl border border-border px-4 py-2.5 text-[14px] font-medium text-muted disabled:opacity-40`,children:R(`Back`)}),w===`welcome`&&(0,E.jsxs)(`button`,{type:`button`,onClick:()=>D(`list`),className:e(`flex items-center justify-center gap-1.5 rounded-2xl bg-accent text-accent-fg px-4 py-2.5 text-[14px] font-medium disabled:opacity-40`,`flex-1 py-3`),children:[R(`Get started`),` `,(0,E.jsx)(h,{size:16})]}),w===`list`&&(0,E.jsxs)(`button`,{type:`button`,disabled:!K||P,onClick:()=>void W(),className:e(`flex items-center justify-center gap-1.5 rounded-2xl bg-accent text-accent-fg px-4 py-2.5 text-[14px] font-medium disabled:opacity-40`,`flex-1 py-3`),children:[P?(0,E.jsx)(u,{size:16,className:`animate-spin`}):null,` `,R(K?`Start`:`Add a model to start`),` `,(0,E.jsx)(h,{size:16})]}),w===`model`&&(0,E.jsxs)(`button`,{type:`button`,disabled:!K,onClick:()=>D(`list`),className:e(`flex items-center justify-center gap-1.5 rounded-2xl bg-accent text-accent-fg px-4 py-2.5 text-[14px] font-medium disabled:opacity-40`,`flex-1 py-3`),children:[R(K?`Done`:`Save a model to continue`),` `,(0,E.jsx)(h,{size:16})]}),w===`connect`&&(0,E.jsxs)(`button`,{type:`button`,onClick:()=>D(`list`),className:e(`flex items-center justify-center gap-1.5 rounded-2xl bg-accent text-accent-fg px-4 py-2.5 text-[14px] font-medium disabled:opacity-40`,`flex-1 py-3`),children:[R(q?`Done`:`Skip for now`),` `,(0,E.jsx)(h,{size:16})]})]})]})}function O({n:e,title:t,body:n}){return(0,E.jsxs)(`li`,{className:`flex gap-3 rounded-3xl bg-surface border border-border/70 p-4`,children:[(0,E.jsx)(`span`,{className:`flex h-7 w-7 shrink-0 items-center justify-center rounded-full bg-accent/12 text-[13px] font-semibold text-accent`,children:e}),(0,E.jsxs)(`div`,{className:`text-[13.5px] leading-relaxed`,children:[(0,E.jsx)(`div`,{className:`font-medium text-fg`,children:t}),(0,E.jsx)(`div`,{className:`text-muted`,children:n})]})]})}function k({done:t,locked:r,optional:i,title:a,body:o,onClick:s}){let c=n();return(0,E.jsx)(`li`,{children:(0,E.jsxs)(`button`,{type:`button`,onClick:s,disabled:r,"aria-disabled":r,className:e(`w-full flex items-center gap-3 rounded-3xl border px-4 py-3.5 text-left transition-colors`,t?`border-accent/30 bg-accent/5`:`border-border/70 bg-surface`,r&&`opacity-50`),children:[(0,E.jsx)(`span`,{className:e(`flex h-7 w-7 shrink-0 items-center justify-center rounded-full`,t?`bg-accent text-white`:r?`bg-surface-2 text-muted`:`border border-border text-muted`),children:t?(0,E.jsx)(p,{size:15,strokeWidth:3}):r?(0,E.jsx)(w,{size:13}):null}),(0,E.jsxs)(`span`,{className:`min-w-0 flex-1`,children:[(0,E.jsxs)(`span`,{className:`flex items-center gap-2 text-[15px] font-medium`,children:[(0,E.jsx)(`span`,{className:`truncate`,children:a}),i&&(0,E.jsx)(`span`,{className:`rounded-full bg-surface-2 px-2 py-0.5 text-[10.5px] font-medium text-muted`,children:c(`optional`)})]}),(0,E.jsx)(`span`,{className:`block truncate text-[12.5px] text-muted`,children:o})]}),!r&&(0,E.jsx)(g,{size:16,className:`shrink-0 text-muted`})]})})}function A(e){try{return new URL(e).host}catch{return e}}function j(e){return Object.entries(e.providers).find(([t,n])=>t!==`custom`&&n.base_url&&e.llm.base_url.startsWith(n.base_url))?.[0]??`custom`}export{D as Onboarding}; \ No newline at end of file diff --git a/nanomuse/server/static/assets/Onboarding-D3RCeowq.js b/nanomuse/server/static/assets/Onboarding-D3RCeowq.js new file mode 100644 index 000000000..1aef65160 --- /dev/null +++ b/nanomuse/server/static/assets/Onboarding-D3RCeowq.js @@ -0,0 +1 @@ +import{E as e,J as t,K as n,L as r,Q as i,Y as a,a as o,b as s,f as c,i as l,q as u,x as d}from"./MuseHeader-BDWXHKHT.js";import{A as f}from"./StarNudge-B8P2bPEz.js";import{n as p}from"./external-link-CZH-rQLq.js";import"./Form-B3Ejw5aI.js";import{r as m}from"./IdentityForm-BweNfU4E.js";import{Et as h,bt as g,t as _,vt as v}from"./index-DKrXW2Qj.js";import{t as y}from"./AvatarPicker-CwYa9V6R.js";import{CalendarCard as b,ContactsCard as x,EmailCard as S,ModelCard as C}from"./ConnectionsScreen-DzFdAyKl.js";var w=t(`lock`,[[`rect`,{width:`18`,height:`11`,x:`3`,y:`11`,rx:`2`,ry:`2`,key:`1w4ew1`}],[`path`,{d:`M7 11V7a5 5 0 0 1 10 0v4`,key:`fwvmzm`}]]),T=i(a(),1),E=s();function D(){let{state:t,setTab:i,dismissOnboarding:a,refreshSettings:s,toast:p}=c(),[w,D]=(0,T.useState)(`welcome`),[M,N]=(0,T.useState)(null),[P,F]=(0,T.useState)(!1),[I,L]=(0,T.useState)(!1),R=n(),z=async()=>{L(!0);try{await d.cloudUseAsModel(),p(R(`The Cloud model is in use.`)),await H()}catch(e){p(e.message)}finally{L(!1)}},[B,V]=(0,T.useState)(null),H=async()=>{try{V(null),N(await d.connections())}catch(e){V(R(e.message)||R(`Could not load the connections.`))}};(0,T.useEffect)(()=>{H()},[t.connectionsVersion]);let U=async()=>{try{await d.onboarded(!0),await s()}catch{}a(),i(`chat`)},W=async()=>{F(!0);try{await d.firstrunStart(r()===`zh-CN`?`zh`:`en`)}catch{await d.onboarded(!0).catch(()=>void 0)}try{await s()}catch{}F(!1),a(),i(`chat`)},G={...m(t.profile,o,y[0]),proactivity:`default`,proactive:!0,goal_interval_minutes:60,quiet_hours:``},K=M?M.llm.key_source===`vault`||M.llm.key_source===`config`||!!M.providers[j(M)]?.no_key||!!M.llm.endpoint&&M.llm.key_source===`none`:!1,q=!!M&&(M.email.configured||M.calendar.feeds.length>0||M.contacts.sources.length>0),J=[`welcome`,`list`],Y=w===`welcome`?0:1;return(0,E.jsxs)(`div`,{className:`mx-auto flex h-[100dvh] max-w-[760px] flex-col bg-bg sm:border-x sm:border-border`,children:[(0,E.jsx)(`div`,{className:`titlebar-room`}),(0,E.jsxs)(`header`,{className:`safe-top shrink-0 px-5 pt-4 pb-2 flex items-center justify-between`,children:[(0,E.jsx)(`div`,{className:`flex gap-1`,children:J.map((t,n)=>(0,E.jsx)(`span`,{className:e(`h-1.5 rounded-full transition-all`,n<=Y?`w-5 bg-accent`:`w-1.5 bg-border`)},t))}),(0,E.jsx)(`button`,{type:`button`,onClick:()=>void U(),className:`text-[13px] text-muted`,children:R(`Skip setup`)})]}),(0,E.jsxs)(`div`,{className:`flex-1 overflow-y-auto px-5 pb-6`,children:[w===`welcome`&&(0,E.jsxs)(`div`,{className:`flex h-full flex-col items-center justify-center text-center`,children:[(0,E.jsx)(l,{profile:G,size:96}),(0,E.jsx)(`h1`,{className:`mt-6 text-[28px] font-bold tracking-tight`,children:R(`Meet your nanoMuse`)}),(0,E.jsx)(`p`,{className:`mt-2 text-[15px] text-muted`,children:R(`A personal agent of your own. Three things to know:`)}),(0,E.jsxs)(`ul`,{className:`mt-6 w-full max-w-sm space-y-2.5 text-left`,children:[(0,E.jsx)(O,{n:1,title:R(`It does things for you.`),body:R(`Searches, browses, writes, books, reads mail, and hands you the result, not a list of links.`)}),(0,E.jsx)(O,{n:2,title:R(`It keeps working when you close the app.`),body:R(`Goals move forward between your visits; it reports in the Feed and notifies you when something is worth it.`)}),(0,E.jsx)(O,{n:3,title:R(`It asks you first where it matters.`),body:R(`A separate Sentinel reviews every action. Sending, paying, deleting: it stops and asks; your keys stay in a vault the model cannot read.`)})]}),(0,E.jsx)(`p`,{className:`mt-5 max-w-sm text-[13px] text-muted`,children:R(`There is no form to fill in: once it has a model, it introduces itself in the chat and asks what to call you.`)}),(0,E.jsx)(`p`,{className:`mt-2 max-w-sm text-[13px] text-muted`,children:(0,E.jsx)(`a`,{href:`https://nanomuse.cn/#open-source`,target:`_blank`,rel:`noreferrer`,className:`underline decoration-dotted underline-offset-2 hover:text-accent`,children:R(`nanoMuse is a non-profit open-source community project, free forever.`)})})]}),w===`list`&&(0,E.jsxs)(`div`,{className:`pt-6`,children:[(0,E.jsxs)(`div`,{className:`flex items-center gap-3`,children:[(0,E.jsx)(l,{profile:G,size:56}),(0,E.jsxs)(`div`,{className:`min-w-0`,children:[(0,E.jsx)(`h1`,{className:`text-[24px] font-bold tracking-tight truncate`,children:R(`Set it up`)}),(0,E.jsx)(`p`,{className:`text-[13.5px] text-muted truncate`,children:R(`A model, then the chat. A minute.`)})]})]}),(0,E.jsxs)(`ol`,{className:`mt-6 space-y-2`,children:[(0,E.jsx)(k,{done:K,title:R(`Add a model`),body:K?M?.llm.cloud?`nanoMuse Cloud · ${M.llm.model}`:`${M?.llm.model} · ${A(M?.llm.base_url??``)}`:t.hub?.account.signed_in?R(`Your account's model, or a key of your own.`):R(`Pick a provider and paste a key. Yours, stored in the vault.`),onClick:()=>D(`model`)}),(0,E.jsx)(k,{done:q,optional:!0,title:R(`Connect mail, calendar, contacts`),body:R(q?`Connected. Tap to add more.`:`Optional. It can read what came in, know your day, and who is who.`),onClick:()=>D(`connect`)}),(0,E.jsx)(k,{locked:!K,done:!1,title:R(`Start`),body:R(K?`Open the chat. It introduces itself and asks your name.`:`Needs a model first.`),onClick:()=>K&&!P&&void W()})]})]}),w===`model`&&(0,E.jsxs)(`div`,{className:`pt-6 space-y-4`,children:[(0,E.jsxs)(`div`,{children:[(0,E.jsx)(`h1`,{className:`text-[26px] font-bold tracking-tight`,children:R(`The model behind it`)}),(0,E.jsx)(`p`,{className:`mt-1 text-[14px] text-muted`,children:K?M?.llm.cloud?R(`Your account's model, with its free allowance. Keep it, or switch to a key of your own here.`):R(`A model is already set up on the server. Keep it, or switch here.`):R(`Your account brings a model with a free allowance, nothing to set up. Or paste a key of your own; it is stored encrypted in the vault on the server, never shown to the model, and nothing you say passes through the relay.`)})]}),M?(0,E.jsxs)(E.Fragment,{children:[!K&&t.hub?.account.signed_in&&(0,E.jsxs)(`button`,{type:`button`,disabled:I,onClick:()=>void z(),className:`flex w-full items-center gap-3 rounded-3xl border border-accent/30 bg-accent/5 px-4 py-3.5 text-left`,children:[(0,E.jsx)(`span`,{className:`flex h-10 w-10 shrink-0 items-center justify-center rounded-2xl bg-accent text-white`,children:I?(0,E.jsx)(u,{size:18,className:`animate-spin`}):(0,E.jsx)(v,{size:18})}),(0,E.jsxs)(`span`,{className:`min-w-0 flex-1`,children:[(0,E.jsx)(`span`,{className:`block text-[15px] font-medium`,children:R(`Use the nanoMuse Cloud model`)}),(0,E.jsx)(`span`,{className:`block text-[12.5px] text-muted`,children:R(`Signed in as {hint}. A free allowance, nothing to paste. Recommended to start.`,{hint:t.hub.account.hint})})]}),(0,E.jsx)(g,{size:16,className:`shrink-0 text-muted`})]}),!K&&!t.hub?.account.signed_in&&(0,E.jsx)(`div`,{className:`rounded-3xl border border-border/70 bg-surface p-4`,children:(0,E.jsx)(_,{onSignedIn:()=>void H(),useAsModel:!0})}),!K&&(0,E.jsxs)(`p`,{className:`px-1 text-[12.5px] text-muted`,children:[(0,E.jsx)(`span`,{className:`font-medium`,children:R(`Or bring your own key`)}),` · `,f(R,t.hub?.account)]}),(0,E.jsx)(C,{data:M,onChange:()=>void H(),compact:!0})]}):B?(0,E.jsxs)(`div`,{className:`rounded-3xl border border-border/70 bg-surface p-4 text-center`,children:[(0,E.jsx)(`p`,{className:`text-[13.5px] text-muted`,children:B}),(0,E.jsx)(`button`,{type:`button`,onClick:()=>void H(),className:`mt-3 rounded-full bg-surface-2 px-4 py-1.5 text-[13px] font-medium`,children:R(`Retry`)})]}):(0,E.jsx)(`div`,{className:`flex justify-center py-8 text-muted`,children:(0,E.jsx)(u,{className:`animate-spin`,size:20})})]}),w===`connect`&&(0,E.jsxs)(`div`,{className:`pt-6 space-y-4`,children:[(0,E.jsxs)(`div`,{children:[(0,E.jsx)(`h1`,{className:`text-[26px] font-bold tracking-tight`,children:R(`Connect your mail, calendar and contacts`)}),(0,E.jsx)(`p`,{className:`mt-1 text-[14px] text-muted`,children:R(`Optional. With a mailbox connected it can read what came in and draft replies; it will always ask before sending. With a calendar it knows your day and finds free time. With your contacts it knows who is who. The browser and MCP servers are under Connections later.`)})]}),M?(0,E.jsxs)(E.Fragment,{children:[(0,E.jsx)(S,{data:M,onChange:()=>void H(),compact:!0}),(0,E.jsx)(b,{data:M,onChange:()=>void H(),compact:!0}),(0,E.jsx)(x,{data:M,onChange:()=>void H(),compact:!0})]}):B?(0,E.jsxs)(`div`,{className:`rounded-3xl border border-border/70 bg-surface p-4 text-center`,children:[(0,E.jsx)(`p`,{className:`text-[13.5px] text-muted`,children:B}),(0,E.jsx)(`button`,{type:`button`,onClick:()=>void H(),className:`mt-3 rounded-full bg-surface-2 px-4 py-1.5 text-[13px] font-medium`,children:R(`Retry`)})]}):(0,E.jsx)(`div`,{className:`flex justify-center py-8 text-muted`,children:(0,E.jsx)(u,{className:`animate-spin`,size:20})})]})]}),(0,E.jsxs)(`footer`,{className:`safe-bottom shrink-0 px-5 pb-5 pt-2 flex gap-2`,children:[(w===`model`||w===`connect`)&&(0,E.jsx)(`button`,{type:`button`,onClick:()=>D(`list`),className:`flex items-center justify-center gap-1.5 rounded-2xl border border-border px-4 py-2.5 text-[14px] font-medium text-muted disabled:opacity-40`,children:R(`Back`)}),w===`welcome`&&(0,E.jsxs)(`button`,{type:`button`,onClick:()=>D(`list`),className:e(`flex items-center justify-center gap-1.5 rounded-2xl bg-accent text-accent-fg px-4 py-2.5 text-[14px] font-medium disabled:opacity-40`,`flex-1 py-3`),children:[R(`Get started`),` `,(0,E.jsx)(h,{size:16})]}),w===`list`&&(0,E.jsxs)(`button`,{type:`button`,disabled:!K||P,onClick:()=>void W(),className:e(`flex items-center justify-center gap-1.5 rounded-2xl bg-accent text-accent-fg px-4 py-2.5 text-[14px] font-medium disabled:opacity-40`,`flex-1 py-3`),children:[P?(0,E.jsx)(u,{size:16,className:`animate-spin`}):null,` `,R(K?`Start`:`Add a model to start`),` `,(0,E.jsx)(h,{size:16})]}),w===`model`&&(0,E.jsxs)(`button`,{type:`button`,disabled:!K,onClick:()=>D(`list`),className:e(`flex items-center justify-center gap-1.5 rounded-2xl bg-accent text-accent-fg px-4 py-2.5 text-[14px] font-medium disabled:opacity-40`,`flex-1 py-3`),children:[R(K?`Done`:`Save a model to continue`),` `,(0,E.jsx)(h,{size:16})]}),w===`connect`&&(0,E.jsxs)(`button`,{type:`button`,onClick:()=>D(`list`),className:e(`flex items-center justify-center gap-1.5 rounded-2xl bg-accent text-accent-fg px-4 py-2.5 text-[14px] font-medium disabled:opacity-40`,`flex-1 py-3`),children:[R(q?`Done`:`Skip for now`),` `,(0,E.jsx)(h,{size:16})]})]})]})}function O({n:e,title:t,body:n}){return(0,E.jsxs)(`li`,{className:`flex gap-3 rounded-3xl bg-surface border border-border/70 p-4`,children:[(0,E.jsx)(`span`,{className:`flex h-7 w-7 shrink-0 items-center justify-center rounded-full bg-accent/12 text-[13px] font-semibold text-accent`,children:e}),(0,E.jsxs)(`div`,{className:`text-[13.5px] leading-relaxed`,children:[(0,E.jsx)(`div`,{className:`font-medium text-fg`,children:t}),(0,E.jsx)(`div`,{className:`text-muted`,children:n})]})]})}function k({done:t,locked:r,optional:i,title:a,body:o,onClick:s}){let c=n();return(0,E.jsx)(`li`,{children:(0,E.jsxs)(`button`,{type:`button`,onClick:s,disabled:r,"aria-disabled":r,className:e(`w-full flex items-center gap-3 rounded-3xl border px-4 py-3.5 text-left transition-colors`,t?`border-accent/30 bg-accent/5`:`border-border/70 bg-surface`,r&&`opacity-50`),children:[(0,E.jsx)(`span`,{className:e(`flex h-7 w-7 shrink-0 items-center justify-center rounded-full`,t?`bg-accent text-white`:r?`bg-surface-2 text-muted`:`border border-border text-muted`),children:t?(0,E.jsx)(p,{size:15,strokeWidth:3}):r?(0,E.jsx)(w,{size:13}):null}),(0,E.jsxs)(`span`,{className:`min-w-0 flex-1`,children:[(0,E.jsxs)(`span`,{className:`flex items-center gap-2 text-[15px] font-medium`,children:[(0,E.jsx)(`span`,{className:`truncate`,children:a}),i&&(0,E.jsx)(`span`,{className:`rounded-full bg-surface-2 px-2 py-0.5 text-[10.5px] font-medium text-muted`,children:c(`optional`)})]}),(0,E.jsx)(`span`,{className:`block truncate text-[12.5px] text-muted`,children:o})]}),!r&&(0,E.jsx)(g,{size:16,className:`shrink-0 text-muted`})]})})}function A(e){try{return new URL(e).host}catch{return e}}function j(e){return Object.entries(e.providers).find(([t,n])=>t!==`custom`&&n.base_url&&e.llm.base_url.startsWith(n.base_url))?.[0]??`custom`}export{D as Onboarding}; \ No newline at end of file diff --git a/nanomuse/server/static/assets/SettingsScreen-CHVg61To.js b/nanomuse/server/static/assets/SettingsScreen-xI3hlacs.js similarity index 98% rename from nanomuse/server/static/assets/SettingsScreen-CHVg61To.js rename to nanomuse/server/static/assets/SettingsScreen-xI3hlacs.js index 1761d74a0..39aa30785 100644 --- a/nanomuse/server/static/assets/SettingsScreen-CHVg61To.js +++ b/nanomuse/server/static/assets/SettingsScreen-xI3hlacs.js @@ -1 +1 @@ -import{A as e,E as t,F as n,G as r,H as i,J as a,K as o,L as s,Q as c,T as l,Y as u,_ as d,a as f,b as p,f as m,g as h,h as g,m as _,v,x as y}from"./MuseHeader-Pw-NI98v.js";import{C as b,E as ee,T as te,_ as x,j as S,u as C,w}from"./StarNudge-DjXecvWj.js";import{n as ne}from"./external-link-Xj5fjR8v.js";import{n as T}from"./Form-DwKuBk1V.js";import{t as E}from"./clapperboard-BokpXv9J.js";import{t as re}from"./database-zap-CzaFBl6C.js";import{t as D}from"./plug-Bj_5EEV3.js";import{n as ie,r as O,t as ae}from"./IdentityForm-BTGczGT_.js";import{D as k,E as A,K as j,L as M,M as oe,O as se,R as N,St as P,U as ce,W as F,_t as I,a as L,at as R,bt as z,ct as le,d as ue,dt as B,ft as V,i as H,k as de,n as fe,nt as U,o as W,q as G,r as pe,rt as me,s as K,tt as he,u as ge,vt as _e,wt as ve}from"./index-CIdGZ5PB.js";import{t as q}from"./BackBar-Dl56jHZM.js";import{t as J}from"./AvatarPicker-gR2knlot.js";var ye=a(`battery-full`,[[`path`,{d:`M10 10v4`,key:`1mb2ec`}],[`path`,{d:`M14 10v4`,key:`1nt88p`}],[`path`,{d:`M22 14v-4`,key:`14q9d5`}],[`path`,{d:`M6 10v4`,key:`1n77qd`}],[`rect`,{x:`2`,y:`6`,width:`16`,height:`12`,rx:`2`,key:`13zb55`}]]),be=a(`box`,[[`path`,{d:`M21 8a2 2 0 0 0-1-1.73l-7-4a2 2 0 0 0-2 0l-7 4A2 2 0 0 0 3 8v8a2 2 0 0 0 1 1.73l7 4a2 2 0 0 0 2 0l7-4A2 2 0 0 0 21 16Z`,key:`hh9hay`}],[`path`,{d:`m3.3 7 8.7 5 8.7-5`,key:`g66t2b`}],[`path`,{d:`M12 22V12`,key:`d0xqtd`}]]),xe=a(`chart-column`,[[`path`,{d:`M3 3v16a2 2 0 0 0 2 2h16`,key:`c24i48`}],[`path`,{d:`M18 17V9`,key:`2bz60n`}],[`path`,{d:`M13 17V5`,key:`1frdt8`}],[`path`,{d:`M8 17v-3`,key:`17ska0`}]]),Se=a(`message-square-warning`,[[`path`,{d:`M22 17a2 2 0 0 1-2 2H6.828a2 2 0 0 0-1.414.586l-2.202 2.202A.71.71 0 0 1 2 21.286V5a2 2 0 0 1 2-2h16a2 2 0 0 1 2 2z`,key:`18887p`}],[`path`,{d:`M12 15h.01`,key:`q59x07`}],[`path`,{d:`M12 7v4`,key:`xawao1`}]]),Ce=a(`puzzle`,[[`path`,{d:`M15.39 4.39a1 1 0 0 0 1.68-.474 2.5 2.5 0 1 1 3.014 3.015 1 1 0 0 0-.474 1.68l1.683 1.682a2.414 2.414 0 0 1 0 3.414L19.61 15.39a1 1 0 0 1-1.68-.474 2.5 2.5 0 1 0-3.014 3.015 1 1 0 0 1 .474 1.68l-1.683 1.682a2.414 2.414 0 0 1-3.414 0L8.61 19.61a1 1 0 0 0-1.68.474 2.5 2.5 0 1 1-3.014-3.015 1 1 0 0 0 .474-1.68l-1.683-1.682a2.414 2.414 0 0 1 0-3.414L4.39 8.61a1 1 0 0 1 1.68.474 2.5 2.5 0 1 0 3.014-3.015 1 1 0 0 1-.474-1.68l1.683-1.682a2.414 2.414 0 0 1 3.414 0z`,key:`w46dr5`}]]),we=a(`shield`,[[`path`,{d:`M20 13c0 5-3.5 7.5-7.66 8.95a1 1 0 0 1-.67-.01C7.5 20.5 4 18 4 13V6a1 1 0 0 1 1-1c2 0 4.5-1.2 6.24-2.72a1.17 1.17 0 0 1 1.52 0C14.51 3.81 17 5 19 5a1 1 0 0 1 1 1z`,key:`oel41y`}]]),Te=a(`smile`,[[`circle`,{cx:`12`,cy:`12`,r:`10`,key:`1mglay`}],[`path`,{d:`M8 14s1.5 2 4 2 4-2 4-2`,key:`1y1vjs`}],[`line`,{x1:`9`,x2:`9.01`,y1:`9`,y2:`9`,key:`yxxnd0`}],[`line`,{x1:`15`,x2:`15.01`,y1:`9`,y2:`9`,key:`1p4y9e`}]]),Ee=a(`zap`,[[`path`,{d:`M4 14a1 1 0 0 1-.78-1.63l9.9-10.2a.5.5 0 0 1 .86.46l-1.92 6.02A1 1 0 0 0 13 10h7a1 1 0 0 1 .78 1.63l-9.9 10.2a.5.5 0 0 1-.86-.46l1.92-6.02A1 1 0 0 0 11 14z`,key:`1xq2db`}]]),Y=c(u(),1),De=`(min-width: 64rem)`;function Oe(){return typeof window>`u`?!1:document.documentElement.classList.contains(`desktop`)?!0:typeof window.matchMedia==`function`&&window.matchMedia(De).matches}function ke(){let[e,t]=(0,Y.useState)(Oe);return(0,Y.useEffect)(()=>{if(typeof window.matchMedia!=`function`)return;let e=window.matchMedia(De),n=()=>t(Oe());return e.addEventListener(`change`,n),()=>e.removeEventListener(`change`,n)},[]),e}var X=p(),Ae=`w-full rounded-2xl bg-surface-2 px-3.5 py-2.5 outline-none focus:ring-2 focus:ring-accent/40`,je=[{id:`ask`,title:`Balanced`,text:`Browse, read and write files freely; stop for anything hard to undo: email, purchases, shell commands.`,icon:(0,X.jsx)(j,{size:18})},{id:`strict`,title:`Cautious`,text:`Also ask before moderate actions like fetching web pages or writing files.`,icon:(0,X.jsx)(we,{size:18})},{id:`auto`,title:`Hands-off`,text:`Approve everything automatically except explicit deny rules. For trusted, unattended runs only.`,icon:(0,X.jsx)(G,{size:18})}];function Me(){let{state:e,refreshSettings:a,setTab:s,toast:c}=m(),u=e.settings,[d,p]=(0,Y.useState)(()=>O(e.profile,f,J[0])),[h,v]=(0,Y.useState)(!1),b=o(),te=r(),x=g(),[w,E]=(0,Y.useState)(null),[re,D]=(0,Y.useState)(!1);(0,Y.useEffect)(()=>{u||a()},[u,a]);let j=(0,Y.useCallback)(async(e=!1)=>{D(!0);try{E(await y.update(e))}catch{E(null)}finally{D(!1)}},[]);(0,Y.useEffect)(()=>{j()},[j]),(0,Y.useEffect)(()=>{e.profile&&p(O(e.profile,``,J[0]))},[e.profile]);let M=async(e,t)=>{v(!0);try{await y.updateSettings(e),await a(),t&&c(t)}catch(e){c(e.message)}finally{v(!1)}},P=O(e.profile,``,J[0]),ce=!!e.profile&&Object.keys(d).some(e=>d[e]!==P[e]),F=e.profile?.name??`nanoMuse`,I=de(),L=ue(),R=ke()&&!e.lite,[B,V]=(0,Y.useState)(null),H=[{id:`who`,title:F},{id:`sentinel`,title:b(`Safety · Sentinel`)},{id:`proactivity`,title:b(`Proactivity`)},{id:`notifications`,title:b(`Notifications`)},...k()?[{id:`keep-running`,title:b(`Keep it running`)}]:[],{id:`model`,title:b(`Model`)},{id:`appearance`,title:b(`Appearance`)},...N()?[{id:`desktop`,title:b(`Desktop app`)}]:[],{id:`data`,title:b(`Data controls`)},{id:`developer`,title:b(`Developer`)},{id:`about`,title:b(`About`)}],U=e=>R||B===e,[W,G]=(0,Y.useState)(()=>{let e=window.location.hash.slice(1);return Ne.includes(e)?e:null});if((0,Y.useEffect)(()=>{if(W&&u){if(G(null),history.replaceState(null,``,window.location.pathname+window.location.search),!R){V(W);return}requestAnimationFrame(()=>document.getElementById(W)?.scrollIntoView({behavior:`smooth`,block:`start`}))}},[W,u,R]),!R&&B===null)return(0,X.jsx)(Fe,{release:w,onOpen:V});let pe=H.find(e=>e.id===B);return(0,X.jsxs)(`div`,{className:`flex h-full flex-col`,children:[R?(0,X.jsx)(q,{title:b(`Settings`),description:b(`Its name and look, how careful it is, how often it speaks up.`)}):(0,X.jsx)(q,{title:pe?.title??b(`Settings`),onBack:()=>V(null),backLabel:b(`Settings`)}),(0,X.jsxs)(`div`,{className:`flex min-h-0 flex-1`,children:[R&&(0,X.jsx)(`nav`,{className:`flex w-[188px] shrink-0 flex-col gap-0.5 self-start pl-4 pr-2 pt-1`,"aria-label":b(`Settings`),children:H.map(e=>(0,X.jsx)(`button`,{type:`button`,onClick:()=>document.getElementById(e.id)?.scrollIntoView({behavior:`smooth`,block:`start`}),className:`truncate rounded-xl px-3 py-1.5 text-left text-[13px] font-medium text-fg/75 hover:bg-surface-2 hover:text-fg`,children:e.title},e.id))}),(0,X.jsxs)(`div`,{className:`flex-1 overflow-y-auto px-4 pb-8 space-y-5`,children:[U(`who`)&&(0,X.jsxs)($,{title:F,id:`who`,plain:!R,children:[(0,X.jsx)(ae,{value:d,onChange:p,suggestions:!1,inputCls:Ae,onStudio:()=>s(`avatar`)}),(0,X.jsx)(`button`,{type:`button`,disabled:!ce||h,onClick:()=>void M({profile:ie(d)},b(`Saved`)),className:`w-full rounded-2xl bg-accent text-accent-fg py-2.5 font-medium disabled:opacity-40`,children:b(`Save`)})]}),U(`sentinel`)&&(0,X.jsxs)($,{title:b(`Safety · Sentinel`),id:`sentinel`,plain:!R,children:[(0,X.jsx)(`p`,{className:`text-[13px] text-muted -mt-1`,children:b(`A separate gatekeeper reviews every action. Pick how often it should check in with you.`)}),(0,X.jsx)(`div`,{className:`space-y-2`,children:je.map(e=>(0,X.jsxs)(`button`,{type:`button`,onClick:()=>void M({sentinel_mode:e.id}),"aria-pressed":u?.sentinel.mode===e.id,className:t(`w-full text-left rounded-2xl border px-3.5 py-3 flex items-start gap-3 transition`,u?.sentinel.mode===e.id?`border-accent bg-accent/8`:`border-border`),children:[(0,X.jsx)(`div`,{className:t(`mt-0.5`,e.id===`auto`?`text-rose-500`:`text-accent`),children:e.icon}),(0,X.jsxs)(`div`,{className:`flex-1`,children:[(0,X.jsx)(`div`,{className:`font-medium text-[14.5px]`,children:b(e.title)}),(0,X.jsx)(`div`,{className:`text-[12.5px] text-muted leading-snug mt-0.5`,children:b(e.text)})]}),u?.sentinel.mode===e.id&&(0,X.jsx)(ne,{size:18,className:`text-accent mt-0.5`})]},e.id))}),u&&(0,X.jsxs)(`div`,{className:`text-[12.5px] text-muted leading-relaxed`,children:[b(`Always asks before: {tools}.`,{tools:u.sentinel.always_ask_tools.map(e=>b(e)).join(`, `)||`—`}),` `,u.sentinel.taint_tracking&&b(`After reading private data, new network destinations need approval.`)]}),u?.sandbox&&(0,X.jsxs)(`div`,{className:`flex items-start gap-2.5 rounded-2xl bg-surface-2/60 px-3.5 py-2.5 text-[12.5px] leading-snug`,children:[(0,X.jsx)(be,{size:15,className:t(`shrink-0 mt-[2px]`,u.sandbox.active?`text-emerald-500`:`text-muted`)}),(0,X.jsxs)(`div`,{children:[(0,X.jsxs)(`div`,{className:`font-medium text-fg`,children:[u.sandbox.active?b(`Commands run in a sandbox`):b(`Commands run without a sandbox`),(0,X.jsxs)(`span`,{className:`text-muted font-normal`,children:[` · `,u.sandbox.status]})]}),(0,X.jsx)(`div`,{className:`text-muted mt-0.5`,children:u.sandbox.active?b(`Each shell or Python call gets its own namespace: only the workspace is writable, your home directory is not there, and there is no network unless the command needs it.`):u.sandbox.status.includes(`container`)?b(`Each shell or Python call runs in the workspace with a scrubbed environment; the container is the boundary.`):b(`Each shell or Python call runs in the workspace with a scrubbed environment. On Linux, installing bubblewrap gives each one its own namespace.`)})]})]})]}),U(`proactivity`)&&(0,X.jsxs)($,{title:b(`Proactivity`),id:`proactivity`,plain:!R,children:[(0,X.jsx)(ze,{value:e.profile?.proactivity??`default`,onChange:e=>void M({profile:{proactivity:e}})}),(0,X.jsxs)(`div`,{className:`flex items-center gap-3`,children:[(0,X.jsxs)(`label`,{className:`text-[13.5px] flex-1`,children:[b(`Check-in interval`),e.profile&&e.profile.proactivity!=="default"&&e.profile.proactivity!==`off`&&(0,X.jsx)(`span`,{className:`block text-[12px] text-muted`,children:e.profile.proactivity===`low`?b(`Doubled at this level`):b(`Halved at this level`)})]}),(0,X.jsx)(`select`,{value:e.profile?.goal_interval_minutes??60,onChange:e=>void M({profile:{goal_interval_minutes:Number(e.target.value)}}),className:`rounded-2xl bg-surface-2 px-3 py-2 text-[13.5px] outline-none`,children:[...new Set([15,30,60,120,240,480,1440,e.profile?.goal_interval_minutes??60])].sort((e,t)=>e-t).map(e=>(0,X.jsx)(`option`,{value:e,children:e<60?b(`{n} min`,{n:e}):e%60?`${b(`{n} h`,{n:Math.floor(e/60)})} ${b(`{n} min`,{n:e%60})}`:b(`{n} h`,{n:e/60})},e))})]}),(0,X.jsx)(Be,{value:e.profile?.quiet_hours??``,onChange:e=>void M({profile:{quiet_hours:e}})})]}),U(`notifications`)&&(0,X.jsx)($,{title:b(`Notifications`),id:`notifications`,plain:!R,children:A()?(0,X.jsx)(Ie,{name:e.profile?.name??`nanoMuse`}):(0,X.jsx)(Re,{name:e.profile?.name??`nanoMuse`})}),k()&&U(`keep-running`)&&(0,X.jsx)($,{title:b(`Keep it running`),id:`keep-running`,plain:!R,children:(0,X.jsx)(Le,{name:e.profile?.name??`nanoMuse`})}),U(`model`)&&(0,X.jsxs)($,{title:b(`Model`),id:`model`,plain:!R,children:[u&&(0,X.jsxs)(`button`,{type:`button`,onClick:()=>s(`connections`),className:`w-full text-[13.5px] flex items-center justify-between`,children:[(0,X.jsx)(`span`,{className:`text-muted`,children:b(`Provider / model`)}),(0,X.jsxs)(`span`,{className:`font-mono text-[12.5px] flex items-center gap-1`,children:[u.llm.model,` `,(0,X.jsx)(z,{size:14,className:`text-muted`})]})]}),u?.llm.cloud&&(0,X.jsxs)(`button`,{type:`button`,onClick:()=>oe(s,S(e.hub?.account).preset),className:`w-full text-[13.5px] flex items-center justify-between`,children:[(0,X.jsx)(`span`,{className:`text-muted`,children:b(`Use my own API key or a plan I pay for`)}),(0,X.jsxs)(`span`,{className:`text-[12.5px] text-muted flex items-center gap-1`,children:[b(`{first} first, then {others}`,{first:S(e.hub?.account).label,others:ee(e.hub?.account)?b(`DeepSeek, Kimi, OpenAI, ChatGPT…`):b(`OpenAI, ChatGPT, Gemini, DeepSeek…`)}),` `,(0,X.jsx)(z,{size:14})]})]}),(0,X.jsxs)(`button`,{type:`button`,onClick:()=>s(`connections`),className:`w-full text-[13.5px] flex items-center justify-between`,children:[(0,X.jsx)(`span`,{className:`text-muted`,children:b(`Connections`)}),(0,X.jsxs)(`span`,{className:`text-[12.5px] text-muted flex items-center gap-1`,children:[b(`E-mail, calendar, browser, MCP servers`),` `,(0,X.jsx)(z,{size:14})]})]})]}),U(`appearance`)&&(0,X.jsxs)($,{title:b(`Appearance`),id:`appearance`,plain:!R,children:[(0,X.jsx)(T,{label:b(`Show the agent's steps`),hint:b(`Every tool it uses becomes a chip in the chat. Off, the chat keeps to the conversation and the line under the name says what it is on. This device only.`),checked:L,onChange:ge}),(0,X.jsx)(T,{label:b(`Show thinking`),hint:b(`Reveal the model's reasoning under each reply when the provider exposes it.`),checked:!!u?.agent.show_thinking,onChange:e=>void M({show_thinking:e})}),(0,X.jsxs)(`div`,{className:`flex items-center gap-3`,children:[(0,X.jsxs)(`label`,{className:`text-[13.5px] flex-1`,children:[b(`Appearance`),(0,X.jsx)(`span`,{className:`block text-[12px] text-muted`,children:b(`This device only`)})]}),(0,X.jsxs)(`select`,{value:x,onChange:e=>_(e.target.value),className:`rounded-2xl bg-surface-2 px-3 py-2 text-[13.5px] outline-none`,children:[(0,X.jsx)(`option`,{value:`light`,children:b(`Light`)}),(0,X.jsx)(`option`,{value:`dark`,children:b(`Dark`)}),(0,X.jsx)(`option`,{value:`system`,children:b(`Follow the system`)})]})]}),(0,X.jsxs)(`div`,{className:`flex items-center gap-3`,children:[(0,X.jsxs)(`label`,{className:`text-[13.5px] flex-1`,children:[b(`App language`),(0,X.jsx)(`span`,{className:`block text-[12px] text-muted`,children:b(`This device only`)})]}),(0,X.jsx)(`select`,{value:te,onChange:e=>i(e.target.value),className:`rounded-2xl bg-surface-2 px-3 py-2 text-[13.5px] outline-none`,children:n.map(e=>(0,X.jsx)(`option`,{value:e.value,children:e.value===`auto`?b(`Auto`):e.label},e.value))})]}),(0,X.jsxs)(`div`,{className:`flex items-center gap-3`,children:[(0,X.jsxs)(`label`,{className:`text-[13.5px] flex-1`,children:[b(`Reply language`),(0,X.jsx)(`span`,{className:`block text-[12px] text-muted`,children:b(`What {name} writes in`,{name:e.profile?.name??`nanoMuse`})})]}),(0,X.jsxs)(`select`,{value:u?.agent.language??`auto`,onChange:e=>void M({language:e.target.value}),className:`rounded-2xl bg-surface-2 px-3 py-2 text-[13.5px] outline-none`,children:[(0,X.jsx)(`option`,{value:`auto`,children:b(`Match mine`)}),(0,X.jsx)(`option`,{value:`English`,children:`English`}),(0,X.jsx)(`option`,{value:`中文`,children:`中文`}),(0,X.jsx)(`option`,{value:`日本語`,children:`日本語`}),(0,X.jsx)(`option`,{value:`Español`,children:`Español`}),(0,X.jsx)(`option`,{value:`Deutsch`,children:`Deutsch`}),(0,X.jsx)(`option`,{value:`Français`,children:`Français`})]})]})]}),N()&&U(`desktop`)&&(0,X.jsx)($,{title:b(`Desktop app`),id:`desktop`,plain:!R,children:(0,X.jsx)(Ve,{})}),U(`data`)&&(0,X.jsx)($,{title:b(`Data controls`),id:`data`,plain:!R,children:(0,X.jsx)(fe,{flush:!0})}),U(`developer`)&&(0,X.jsxs)($,{title:b(`Developer`),id:`developer`,plain:!R,children:[(0,X.jsx)(T,{label:b(`Developer tools`),hint:b(`The Coding screen (Cursor, Codex and the other coding agents on this computer) in the sidebar, and the runtime's address below. This device only.`),checked:I,onChange:se}),I&&(0,X.jsxs)(`div`,{className:`text-[13px] text-muted space-y-1`,children:[(0,X.jsxs)(`div`,{className:`break-all`,children:[b(`Runtime:`),` `,window.location.origin,` · `,(0,X.jsx)(`span`,{className:`text-fg/70`,children:b(`the token is in the server_token file in the data folder`)})]}),(0,X.jsxs)(`div`,{children:[(0,X.jsx)(`a`,{href:`https://github.com/nano-muse/nanoMuse/blob/main/docs/cli.md`,target:`_blank`,rel:`noreferrer`,className:`text-accent underline-offset-2 hover:underline`,children:b(`The command line and the API`)}),` · `,(0,X.jsx)(`a`,{href:`https://github.com/nano-muse/nanoMuse/blob/main/docs/harness.md`,target:`_blank`,rel:`noreferrer`,className:`text-accent underline-offset-2 hover:underline`,children:b(`nanoMuse on DeepSeek Harness`)})]})]})]}),U(`about`)&&(0,X.jsxs)($,{title:b(`About`),id:`about`,plain:!R,children:[(0,X.jsx)(C,{}),(0,X.jsx)(Pe,{installed:e.version,release:w,checking:re,onCheck:()=>void j(!0)}),(0,X.jsxs)(`div`,{className:`text-[13px] text-muted space-y-1`,children:[u&&(0,X.jsxs)(`div`,{className:`break-all`,children:[b(`Data:`),` `,u.data_dir]}),u&&(0,X.jsxs)(`div`,{className:`break-all`,children:[b(`Workspace:`),` `,u.agent.workspace]}),(0,X.jsx)(`div`,{children:e.connected?b(`Connected`):b(`Reconnecting…`)})]}),(0,X.jsxs)(`button`,{type:`button`,onClick:()=>{let e=A();if(e){e.disconnect();return}l(``),window.location.reload()},className:`w-full rounded-2xl border border-border py-2.5 text-[14px] font-medium flex items-center justify-center gap-2 text-muted`,children:[(0,X.jsx)(le,{size:16}),` `,A()?b(`Disconnect from this server`):b(`Forget this device's access token`)]})]})]})]})]})}var Ne=[`who`,`sentinel`,`proactivity`,`notifications`,`keep-running`,`model`,`appearance`,`desktop`,`data`,`developer`,`about`];function Pe({installed:t,release:n,checking:r,onCheck:i}){let a=o(),s=!!A(),c=(0,X.jsx)(`button`,{type:`button`,onClick:i,disabled:r,className:`text-accent underline-offset-2 hover:underline disabled:opacity-60`,children:a(r?`Checking…`:`Check now`)}),l;return l=s?a(`The phone app checks for updates on its own.`):n&&!n.enabled?a(`Update checks are off here.`):r&&!n?a(`Checking…`):n?.latest&&n.newer?(0,X.jsxs)(X.Fragment,{children:[a(`{version} is out`,{version:n.latest}),` · `,(0,X.jsx)(`a`,{href:n.download_url||n.url,target:`_blank`,rel:`noreferrer`,className:`font-medium text-accent underline-offset-2 hover:underline`,children:a(`Update`)})]}):n?.latest?(0,X.jsxs)(X.Fragment,{children:[a(`Latest {version}; you have it`,{version:n.latest}),` · `,c]}):(0,X.jsxs)(X.Fragment,{children:[a(`Could not check`),` · `,c]}),(0,X.jsxs)(`div`,{className:`rounded-2xl bg-surface-2/60 px-3.5 py-2.5 text-[13px]`,children:[(0,X.jsx)(`div`,{className:`font-medium`,children:a(`nanoMuse {version}`,{version:t})}),(0,X.jsx)(`div`,{className:`mt-0.5 text-muted`,children:l}),!s&&n?.latest&&n.newer&&(0,X.jsx)(`div`,{className:`mt-1 text-[12px] text-muted`,children:a(`To update: pip install -U nanomuse, pull the new image, or use the desktop app's Update.`)}),!s&&n?.checked_at&&(0,X.jsx)(`div`,{className:`mt-1 text-[12px] text-muted`,children:a(`Checked {when}`,{when:e(n.checked_at)})})]})}function Fe({release:e,onOpen:t}){let{state:n,setTab:r}=m(),i=o(),a=n.settings,c=n.hub,l=te(),u=n.profile?.name??`nanoMuse`,d=g(),f=c?.devices.filter(e=>!e.this&&e.kind!==`web`)??[],p=f.filter(e=>e.kind===`computer`),h=f.filter(e=>e.online&&e.actions?.includes(`coding.sessions`)),_=a?.sentinel.mode,v=_===`ask`?i(`Balanced`):_===`strict`?i(`Cautious`):_===`auto`?i(`Hands-off`):``,y=n.profile?.proactivity??`default`,ee=i(y===`off`?`Off`:y===`low`?`Low`:y===`high`?`High`:`Default`),S=i(d===`dark`?`Dark`:d===`light`?`Light`:`Follow the system`),C=i(`none`);return(0,X.jsxs)(`div`,{className:`flex h-full flex-col`,children:[(0,X.jsx)(q,{title:i(`Settings`)}),(0,X.jsxs)(`div`,{className:`flex-1 overflow-y-auto pb-8 pt-2`,children:[(0,X.jsxs)(L,{className:`mb-3`,children:[(0,X.jsxs)(`button`,{type:`button`,onClick:()=>r(`connections`),className:`flex w-full items-center gap-3 px-4 py-3.5 text-left hover:bg-surface-2/60`,children:[(0,X.jsxs)(`span`,{className:`min-w-0 flex-1`,children:[(0,X.jsx)(`span`,{className:`block truncate text-[16px] font-medium leading-[21px]`,children:a?.llm.model||i(`No model yet`)}),(0,X.jsx)(`span`,{className:`mt-0.5 block truncate text-[12.5px] leading-4 text-muted`,children:a?a.llm.cloud?`nanoMuse Cloud`:a.llm.provider:i(`Add a provider and pick its models`)})]}),(0,X.jsx)(`span`,{className:`text-[14px] font-medium text-accent`,children:i(`Change`)})]}),(0,X.jsx)(W,{}),(0,X.jsx)(K,{icon:(0,X.jsx)(_e,{size:22}),label:`nanoMuse Cloud`,value:c?.account.signed_in?c.account.hint:i(`Sign in`),onClick:()=>r(`account`)}),(0,X.jsx)(W,{}),(0,X.jsx)(K,{icon:(0,X.jsx)(E,{size:22}),label:i(`Image & video models`),value:x(l,`image`)===!1?w(i,`image`,b(c?.account),s()):x(l,`video`)===!1?w(i,`video`,b(c?.account),s()):void 0,onClick:()=>r(`connections`)}),(0,X.jsx)(W,{}),(0,X.jsx)(K,{icon:(0,X.jsx)(xe,{size:22}),label:i(`Usage`),onClick:()=>r(`account`)})]}),(0,X.jsxs)(L,{className:`mb-3`,children:[(0,X.jsx)(K,{icon:(0,X.jsx)(F,{size:22}),label:i(`Name & personality`),value:u,onClick:()=>t(`who`)}),(0,X.jsx)(W,{}),(0,X.jsx)(K,{icon:(0,X.jsx)(Te,{size:22}),label:i(`Avatar`),onClick:()=>r(`avatar`)}),(0,X.jsx)(W,{}),(0,X.jsx)(K,{icon:(0,X.jsx)(P,{size:22}),label:i(`Memory`),onClick:()=>r(`memory`)}),a?.skills?.enabled!==!1&&(0,X.jsxs)(X.Fragment,{children:[(0,X.jsx)(W,{}),(0,X.jsx)(K,{icon:(0,X.jsx)(Ce,{size:22}),label:i(`Skills`),value:a?String(a.skills.count):void 0,onClick:()=>r(`skills`)})]}),(0,X.jsx)(W,{}),(0,X.jsx)(K,{icon:(0,X.jsx)(D,{size:22}),label:i(`Connections`),value:a?.connectors.mcp.length?`${a.connectors.mcp.length} MCP`:void 0,onClick:()=>r(`connections`)}),(0,X.jsx)(W,{}),(0,X.jsx)(K,{icon:(0,X.jsx)(R,{size:22}),label:i(`Chat apps`),onClick:()=>r(`channels`)}),(0,X.jsx)(W,{}),(0,X.jsx)(K,{icon:(0,X.jsx)(me,{size:22}),label:i(`Devices`),value:p.length?String(p.length):C,onClick:()=>r(`devices`)}),(0,X.jsx)(W,{}),(0,X.jsx)(K,{icon:(0,X.jsx)(ce,{size:22}),label:i(`Coding agents`),value:h.length?String(h.length):C,onClick:()=>r(`coding`)})]}),(0,X.jsxs)(L,{className:`mb-3`,children:[(0,X.jsx)(K,{icon:(0,X.jsx)(j,{size:22}),label:i(`Safety · Sentinel`),value:v,onClick:()=>t(`sentinel`)}),(0,X.jsx)(W,{}),(0,X.jsx)(K,{icon:(0,X.jsx)(Ee,{size:22}),label:i(`Proactivity`),value:ee,onClick:()=>t(`proactivity`)}),(0,X.jsx)(W,{}),(0,X.jsx)(K,{icon:(0,X.jsx)(ve,{size:22}),label:i(`Notifications`),onClick:()=>t(`notifications`)}),k()&&(0,X.jsxs)(X.Fragment,{children:[(0,X.jsx)(W,{}),(0,X.jsx)(K,{icon:(0,X.jsx)(ye,{size:22}),label:i(`Keep it running`),onClick:()=>t(`keep-running`)})]})]}),(0,X.jsxs)(L,{className:`mb-3`,children:[(0,X.jsx)(K,{icon:(0,X.jsx)(he,{size:22}),label:i(`Appearance`),value:S,onClick:()=>t(`appearance`)}),N()&&(0,X.jsxs)(X.Fragment,{children:[(0,X.jsx)(W,{}),(0,X.jsx)(K,{icon:(0,X.jsx)(me,{size:22}),label:i(`Desktop app`),onClick:()=>t(`desktop`)})]}),(0,X.jsx)(W,{}),(0,X.jsx)(K,{icon:(0,X.jsx)(re,{size:22}),label:i(`Data controls`),onClick:()=>t(`data`)}),(0,X.jsx)(W,{}),(0,X.jsx)(K,{icon:(0,X.jsx)(I,{size:22}),label:i(`Developer`),onClick:()=>t(`developer`)})]}),(0,X.jsxs)(L,{className:`mb-3`,children:[(0,X.jsx)(K,{icon:(0,X.jsx)(B,{size:22}),label:i(`About nanoMuse`),value:e?.newer&&e.latest?i(`{version} is out`,{version:e.latest}):void 0,onClick:()=>t(`about`)}),(0,X.jsx)(W,{}),(0,X.jsx)(K,{icon:(0,X.jsx)(V,{size:22}),label:i(`Privacy policy`),onClick:()=>window.open(pe,`_blank`,`noopener`),external:!0}),(0,X.jsx)(W,{}),(0,X.jsx)(K,{icon:(0,X.jsx)(Se,{size:22}),label:i(`Feedback`),onClick:()=>window.open(`https://github.com/nano-muse/nanoMuse/issues/new/choose`,`_blank`,`noopener`),external:!0})]}),(0,X.jsxs)(H,{children:[`nanoMuse `,n.version]})]})]})}function Ie({name:e}){let t=o(),n=A(),[r,i]=(0,Y.useState)(()=>n?.notificationsEnabled()??!1);return n?(0,X.jsxs)(X.Fragment,{children:[(0,X.jsx)(T,{label:t(`Let {name} notify this phone`,{name:e}),hint:t(`The app stays connected to your server in the background. Approvals, questions and finished background work arrive as notifications and open the right chat.`),checked:r,onChange:e=>{n.setNotificationsEnabled(e),i(e)}}),(0,X.jsx)(`div`,{className:`text-[12.5px] text-muted`,children:t(`nanoMuse for Android {version}`,{version:n.version()})})]}):null}function Le({name:e}){let t=o(),n=A(),[r,i]=(0,Y.useState)(k);if((0,Y.useEffect)(()=>{let e=()=>i(k());return document.addEventListener(`visibilitychange`,e),window.addEventListener(`focus`,e),()=>{document.removeEventListener(`visibilitychange`,e),window.removeEventListener(`focus`,e)}},[]),!n||!r)return null;let a=e=>n.openKeepRunning?.(e),s={xiaomi:t(`Xiaomi / Redmi / POCO: Settings → Apps → Manage apps → {name} → Autostart on; Battery saver → No restrictions; Other permissions → Display pop-up windows while running in the background on.`),huawei:t(`Huawei: Settings → Battery → App launch → {name} → Manage manually, all three on (auto-launch, secondary launch, run in background); Settings → Apps → {name} → Battery → Launch: manage manually.`),honor:t(`Honor: Settings → Battery → App launch → {name} → Manage manually, all three on; Battery → More battery settings → Stay connected while asleep on.`),oppo:t(`OPPO / realme / OnePlus: Settings → Battery → More settings → Optimise battery use → {name} → Don't optimise; Settings → Apps → {name} → Battery usage → Allow background activity, Allow auto launch.`),vivo:t(`vivo / iQOO: i Manager → App manager → Autostart → {name} on; Settings → Battery → Background power consumption management → {name} → Allow high background power consumption.`),samsung:t(`Samsung: Settings → Battery → Background usage limits → {name} not in Sleeping or Deep sleeping apps (add it to Never sleeping apps); turn off Adaptive battery if it keeps stopping.`),meizu:t(`Meizu: Settings → Apps → {name} → Background management → Keep running in the background; Battery → App power management → Allow.`)}[r.vendor];return(0,X.jsxs)(X.Fragment,{children:[(0,X.jsx)(`p`,{className:`text-[12.5px] text-muted leading-snug`,children:t(`Android stops apps that seem idle. {name} runs as a foreground service and holds the phone awake only while a task runs; these switches let it keep that promise on this phone.`,{name:e})}),(0,X.jsx)(Z,{label:t(`Battery`),value:r.battery_unrestricted?t(`Unrestricted`):t(`Optimised`),ok:r.battery_unrestricted,hint:t(`Optimised means Android may freeze the agent after a while with the screen off; routines and check-ins then wait until the phone wakes.`),action:r.battery_unrestricted?void 0:{label:t(`Allow`),onClick:()=>a(`battery`)}}),(0,X.jsx)(Z,{label:t(`Display over other apps`),value:r.overlay?t(`Allowed`):t(`Not allowed`),ok:r.overlay,hint:t(`Lets the agent bring an app to the front from the background and show its status capsule while it works in other apps.`),action:r.overlay?void 0:{label:t(`Allow`),onClick:()=>a(`overlay`)}}),r.exact_alarms!==`n/a`&&r.local&&(0,X.jsx)(Z,{label:t(`Alarms & reminders`),value:r.exact_alarms===`granted`?t(`Exact`):t(`Approximate`),ok:r.exact_alarms===`granted`,hint:t(`With exact alarms a reminder fires at the minute you named even when the phone is asleep; without them Android may deliver it up to a quarter of an hour late.`),action:r.exact_alarms===`granted`?void 0:{label:t(`Allow`),onClick:()=>a(`alarms`)}}),(0,X.jsx)(T,{label:t(`Start after a reboot`),hint:r.local?t(`Bring the runtime back when the phone restarts, so routines and check-ins do not stop.`):t(`Reconnect to your computer when the phone restarts, so approvals keep arriving.`),checked:r.boot_start,onChange:e=>{n.setStartOnBoot?.(e),i({...r,boot_start:e})}}),s&&(0,X.jsxs)(`div`,{className:`rounded-2xl bg-surface-2 px-3 py-2.5 text-[12.5px] leading-snug space-y-2`,children:[(0,X.jsx)(`div`,{className:`font-medium`,children:t(`On this phone's Android`)}),(0,X.jsx)(`div`,{className:`text-muted`,children:s}),r.autostart_settings&&(0,X.jsx)(`button`,{type:`button`,onClick:()=>a(`autostart`),className:`rounded-full border border-border px-3 py-1.5 text-[12.5px]`,children:t(`Open the auto-start settings`)})]}),(0,X.jsxs)(`div`,{className:`flex items-center justify-between gap-3 pt-1`,children:[(0,X.jsx)(`div`,{className:`text-[12.5px] text-muted leading-snug`,children:t(`Crashes are written to a file on this phone and nowhere else. Export bundles them with the runtime's log for someone you choose.`)}),(0,X.jsx)(`button`,{type:`button`,onClick:()=>n.exportLogs?.(),className:`shrink-0 rounded-full border border-border px-3 py-1.5 text-[12.5px]`,children:t(`Export logs`)})]})]})}function Z({label:e,value:n,ok:r,hint:i,action:a}){return(0,X.jsxs)(`div`,{className:`flex items-start gap-3`,children:[(0,X.jsxs)(`div`,{className:`flex-1`,children:[(0,X.jsxs)(`div`,{className:`flex items-center gap-2 text-[14px]`,children:[(0,X.jsx)(`span`,{children:e}),(0,X.jsx)(`span`,{className:t(`rounded-full px-2 py-0.5 text-[11px] font-medium`,r?`bg-emerald-500/12 text-emerald-700 dark:text-emerald-300`:`bg-amber-500/15 text-amber-700 dark:text-amber-300`),children:n})]}),i&&(0,X.jsx)(`div`,{className:`text-[12.5px] text-muted leading-snug`,children:i})]}),a&&(0,X.jsx)(`button`,{type:`button`,onClick:a.onClick,className:`shrink-0 rounded-full bg-accent px-3 py-1.5 text-[12.5px] font-medium text-white`,children:a.label})]})}function Re({name:e}){let{toast:t}=m(),[n,r]=(0,Y.useState)(null),[i,a]=(0,Y.useState)(`off`),[s,c]=(0,Y.useState)(!1),l=o(),u=async()=>{a(await v());try{r(await y.push())}catch{}};(0,Y.useEffect)(()=>{u()},[]);let f=async()=>{if(n){c(!0);try{let e=i===`on`?await h():await d(n.public_key);a(e),e===`denied`&&t(l(`Notifications are blocked for this site in the browser settings`)),await u()}catch(e){let n=e;t(n.name===`AbortError`?l(`This browser has no push service (embedded browsers often don't). Use Chrome, Edge, Firefox or Safari 16.4+ on the phone.`):n.message)}finally{c(!1)}}},p=async()=>{try{let e=await y.pushTest();t(e.ok?l(`Sent. It should arrive in a moment`):e.error??l(`Could not send`))}catch(e){t(e.message)}},g=i===`unsupported`?l(`This browser cannot receive push notifications.`):i===`insecure`?l(`Notifications need https:// (or localhost). Over plain http on your LAN the app works, this part stays off; see docs/deployment.md.`):i===`denied`?l(`Blocked for this site. Allow notifications in the browser's site settings, then try again.`):n&&!n.available?l(`The server was installed without pywebpush.`):``;return(0,X.jsxs)(X.Fragment,{children:[(0,X.jsx)(T,{label:l(`Let {name} notify this device`,{name:e}),hint:l(`Approvals, questions, finished background work and check-ins; nothing while the app is on screen.`),checked:i===`on`,onChange:()=>void f(),disabled:s||!!g}),g&&(0,X.jsx)(`div`,{className:`text-[12.5px] text-muted`,children:g}),n&&n.subscriptions>0&&(0,X.jsxs)(`div`,{className:`flex items-center justify-between text-[12.5px] text-muted`,children:[(0,X.jsx)(`span`,{children:n.subscriptions===1?l(`1 device subscribed`):l(`{n} devices subscribed`,{n:n.subscriptions})}),(0,X.jsx)(`button`,{type:`button`,onClick:()=>void p(),className:`text-accent font-medium`,children:l(`Send a test`)})]}),!N()&&(0,X.jsx)(`div`,{className:`text-[12.5px] text-muted`,children:l(`On a phone, add the app to the home screen first; the icon then shows a badge and notifications open the right chat.`)})]})}var Q=[{id:`off`,title:`Off`,text:`Only works when you ask.`},{id:`low`,title:`Low`,text:`Checks in half as often; speaks up only when a step is done or it needs you.`},{id:`default`,title:`Default`,text:`Works on goals on schedule; reports real progress, stays quiet otherwise.`},{id:`high`,title:`High`,text:`Checks in twice as often and always reports, even 'still on track'.`}];function ze({value:e,onChange:n}){let r=o(),i=Q.find(t=>t.id===e)??Q[2];return(0,X.jsxs)(`div`,{children:[(0,X.jsx)(`div`,{className:`flex items-center gap-3`,children:(0,X.jsx)(`div`,{className:`flex-1 text-[13px] text-muted leading-snug`,children:r(i.text)})}),(0,X.jsx)(`div`,{className:`mt-2 grid grid-cols-4 gap-1 rounded-2xl bg-surface-2 p-1`,children:Q.map(i=>(0,X.jsx)(`button`,{type:`button`,onClick:()=>n(i.id),"aria-pressed":e===i.id,className:t(`rounded-xl py-1.5 text-[13px] font-medium transition`,e===i.id?`bg-surface shadow-sm text-accent`:`text-muted`),children:r(i.title)},i.id))})]})}function Be({value:e,onChange:n}){let[r,i]=e?e.split(`-`):[``,``],a=!!e,s=o(),c=(e,t)=>n(e&&t?`${e}-${t}`:``);return(0,X.jsxs)(`div`,{children:[(0,X.jsxs)(`label`,{className:`flex items-start gap-3 cursor-pointer`,children:[(0,X.jsxs)(`div`,{className:`flex-1`,children:[(0,X.jsxs)(`div`,{className:`text-[14px] flex items-center gap-1.5`,children:[(0,X.jsx)(U,{size:15,className:`text-muted`}),` `,s(`Quiet hours`)]}),(0,X.jsx)(`div`,{className:`text-[12.5px] text-muted leading-snug`,children:s(`No background work in this window; anything due waits until it ends.`)})]}),(0,X.jsx)(`button`,{type:`button`,role:`switch`,"aria-checked":a,onClick:()=>c(a?``:`22:00`,a?``:`08:00`),className:t(`relative mt-0.5 h-7 w-12 shrink-0 rounded-full transition`,a?`bg-accent`:`bg-surface-2 border border-border`),children:(0,X.jsx)(`span`,{className:t(`absolute top-0.5 h-6 w-6 rounded-full bg-white shadow transition`,a?`left-[22px]`:`left-0.5`)})})]}),a&&(0,X.jsxs)(`div`,{className:`mt-2 flex items-center gap-2 text-[13.5px]`,children:[(0,X.jsx)(`span`,{className:`text-muted`,children:s(`From`)}),(0,X.jsx)(`input`,{type:`time`,value:r,onChange:e=>c(e.target.value,i),className:`rounded-xl bg-surface-2 px-2.5 py-1.5 outline-none`}),(0,X.jsx)(`span`,{className:`text-muted`,children:s(`to`)}),(0,X.jsx)(`input`,{type:`time`,value:i,onChange:e=>c(r,e.target.value),className:`rounded-xl bg-surface-2 px-2.5 py-1.5 outline-none`})]})]})}function Ve(){let e=o(),t=M(),[n,r]=(0,Y.useState)(null);(0,Y.useEffect)(()=>{let e=!0;return t?.loginItem?.().then(t=>{e&&r(t)}),()=>{e=!1}},[t]);let i=t?.platform===`darwin`,a=[[e(`Quick chat`),i?`⌥ Space`:`Ctrl+Shift+Space`],[e(`Show the window`),i?`⌘⇧M`:`Ctrl+Shift+M`],[e(`Stop the hands`),i?`⌘⇧Esc`:`Ctrl+Shift+Esc`]];return(0,X.jsxs)(X.Fragment,{children:[t?.setLoginItem&&n!==null&&t.platform!==`linux`&&(0,X.jsx)(T,{label:e(`Start with the computer`),hint:e(`Opens in the tray at sign-in; the agent's goals and check-ins run from then on.`),checked:n,onChange:e=>{r(e),t.setLoginItem?.(e)}}),(0,X.jsxs)(`div`,{className:`text-[13.5px]`,children:[e(`In the tray`),(0,X.jsx)(`span`,{className:`block text-[12px] text-muted`,children:e(`The icon by the clock shows what the hands are doing and has Stop; closing the window keeps the agent running.`)})]}),(0,X.jsxs)(`div`,{className:`space-y-1`,children:[(0,X.jsx)(`div`,{className:`text-[13.5px]`,children:e(`Shortcuts`)}),a.map(([e,t])=>(0,X.jsxs)(`div`,{className:`flex items-center justify-between text-[13px]`,children:[(0,X.jsx)(`span`,{className:`text-muted`,children:e}),(0,X.jsx)(`kbd`,{className:`rounded-md border border-border bg-surface-2 px-1.5 py-0.5 font-sans text-[12px] text-fg/80`,children:t})]},e))]})]})}function $({title:e,children:n,id:r,plain:i=!1}){return(0,X.jsxs)(`section`,{id:r,className:t(`space-y-3 scroll-mt-4`,i?`pt-1`:`rounded-3xl bg-surface border border-border/70 shadow-sm p-4`),children:[!i&&(0,X.jsx)(`h2`,{className:`text-[12px] font-semibold uppercase tracking-wide text-muted`,children:e}),n]})}export{Me as SettingsScreen}; \ No newline at end of file +import{A as e,E as t,F as n,G as r,H as i,J as a,K as o,L as s,Q as c,T as l,Y as u,_ as d,a as f,b as p,f as m,g as h,h as g,m as _,v,x as y}from"./MuseHeader-BDWXHKHT.js";import{C as b,E as ee,T as te,_ as x,j as S,u as C,w}from"./StarNudge-B8P2bPEz.js";import{n as ne}from"./external-link-CZH-rQLq.js";import{n as T}from"./Form-B3Ejw5aI.js";import{t as E}from"./clapperboard-C1_tjTS2.js";import{t as re}from"./database-zap-6Cufqig1.js";import{t as D}from"./plug-Cn-mgW7a.js";import{n as ie,r as O,t as ae}from"./IdentityForm-BweNfU4E.js";import{D as k,E as A,K as j,L as M,M as oe,O as se,R as N,St as P,U as ce,W as F,_t as I,a as L,at as R,bt as z,ct as le,d as ue,dt as B,ft as V,i as H,k as de,n as fe,nt as U,o as W,q as G,r as pe,rt as me,s as K,tt as he,u as ge,vt as _e,wt as ve}from"./index-DKrXW2Qj.js";import{t as q}from"./BackBar-DqcCClHf.js";import{t as J}from"./AvatarPicker-CwYa9V6R.js";var ye=a(`battery-full`,[[`path`,{d:`M10 10v4`,key:`1mb2ec`}],[`path`,{d:`M14 10v4`,key:`1nt88p`}],[`path`,{d:`M22 14v-4`,key:`14q9d5`}],[`path`,{d:`M6 10v4`,key:`1n77qd`}],[`rect`,{x:`2`,y:`6`,width:`16`,height:`12`,rx:`2`,key:`13zb55`}]]),be=a(`box`,[[`path`,{d:`M21 8a2 2 0 0 0-1-1.73l-7-4a2 2 0 0 0-2 0l-7 4A2 2 0 0 0 3 8v8a2 2 0 0 0 1 1.73l7 4a2 2 0 0 0 2 0l7-4A2 2 0 0 0 21 16Z`,key:`hh9hay`}],[`path`,{d:`m3.3 7 8.7 5 8.7-5`,key:`g66t2b`}],[`path`,{d:`M12 22V12`,key:`d0xqtd`}]]),xe=a(`chart-column`,[[`path`,{d:`M3 3v16a2 2 0 0 0 2 2h16`,key:`c24i48`}],[`path`,{d:`M18 17V9`,key:`2bz60n`}],[`path`,{d:`M13 17V5`,key:`1frdt8`}],[`path`,{d:`M8 17v-3`,key:`17ska0`}]]),Se=a(`message-square-warning`,[[`path`,{d:`M22 17a2 2 0 0 1-2 2H6.828a2 2 0 0 0-1.414.586l-2.202 2.202A.71.71 0 0 1 2 21.286V5a2 2 0 0 1 2-2h16a2 2 0 0 1 2 2z`,key:`18887p`}],[`path`,{d:`M12 15h.01`,key:`q59x07`}],[`path`,{d:`M12 7v4`,key:`xawao1`}]]),Ce=a(`puzzle`,[[`path`,{d:`M15.39 4.39a1 1 0 0 0 1.68-.474 2.5 2.5 0 1 1 3.014 3.015 1 1 0 0 0-.474 1.68l1.683 1.682a2.414 2.414 0 0 1 0 3.414L19.61 15.39a1 1 0 0 1-1.68-.474 2.5 2.5 0 1 0-3.014 3.015 1 1 0 0 1 .474 1.68l-1.683 1.682a2.414 2.414 0 0 1-3.414 0L8.61 19.61a1 1 0 0 0-1.68.474 2.5 2.5 0 1 1-3.014-3.015 1 1 0 0 0 .474-1.68l-1.683-1.682a2.414 2.414 0 0 1 0-3.414L4.39 8.61a1 1 0 0 1 1.68.474 2.5 2.5 0 1 0 3.014-3.015 1 1 0 0 1-.474-1.68l1.683-1.682a2.414 2.414 0 0 1 3.414 0z`,key:`w46dr5`}]]),we=a(`shield`,[[`path`,{d:`M20 13c0 5-3.5 7.5-7.66 8.95a1 1 0 0 1-.67-.01C7.5 20.5 4 18 4 13V6a1 1 0 0 1 1-1c2 0 4.5-1.2 6.24-2.72a1.17 1.17 0 0 1 1.52 0C14.51 3.81 17 5 19 5a1 1 0 0 1 1 1z`,key:`oel41y`}]]),Te=a(`smile`,[[`circle`,{cx:`12`,cy:`12`,r:`10`,key:`1mglay`}],[`path`,{d:`M8 14s1.5 2 4 2 4-2 4-2`,key:`1y1vjs`}],[`line`,{x1:`9`,x2:`9.01`,y1:`9`,y2:`9`,key:`yxxnd0`}],[`line`,{x1:`15`,x2:`15.01`,y1:`9`,y2:`9`,key:`1p4y9e`}]]),Ee=a(`zap`,[[`path`,{d:`M4 14a1 1 0 0 1-.78-1.63l9.9-10.2a.5.5 0 0 1 .86.46l-1.92 6.02A1 1 0 0 0 13 10h7a1 1 0 0 1 .78 1.63l-9.9 10.2a.5.5 0 0 1-.86-.46l1.92-6.02A1 1 0 0 0 11 14z`,key:`1xq2db`}]]),Y=c(u(),1),De=`(min-width: 64rem)`;function Oe(){return typeof window>`u`?!1:document.documentElement.classList.contains(`desktop`)?!0:typeof window.matchMedia==`function`&&window.matchMedia(De).matches}function ke(){let[e,t]=(0,Y.useState)(Oe);return(0,Y.useEffect)(()=>{if(typeof window.matchMedia!=`function`)return;let e=window.matchMedia(De),n=()=>t(Oe());return e.addEventListener(`change`,n),()=>e.removeEventListener(`change`,n)},[]),e}var X=p(),Ae=`w-full rounded-2xl bg-surface-2 px-3.5 py-2.5 outline-none focus:ring-2 focus:ring-accent/40`,je=[{id:`ask`,title:`Balanced`,text:`Browse, read and write files freely; stop for anything hard to undo: email, purchases, shell commands.`,icon:(0,X.jsx)(j,{size:18})},{id:`strict`,title:`Cautious`,text:`Also ask before moderate actions like fetching web pages or writing files.`,icon:(0,X.jsx)(we,{size:18})},{id:`auto`,title:`Hands-off`,text:`Approve everything automatically except explicit deny rules. For trusted, unattended runs only.`,icon:(0,X.jsx)(G,{size:18})}];function Me(){let{state:e,refreshSettings:a,setTab:s,toast:c}=m(),u=e.settings,[d,p]=(0,Y.useState)(()=>O(e.profile,f,J[0])),[h,v]=(0,Y.useState)(!1),b=o(),te=r(),x=g(),[w,E]=(0,Y.useState)(null),[re,D]=(0,Y.useState)(!1);(0,Y.useEffect)(()=>{u||a()},[u,a]);let j=(0,Y.useCallback)(async(e=!1)=>{D(!0);try{E(await y.update(e))}catch{E(null)}finally{D(!1)}},[]);(0,Y.useEffect)(()=>{j()},[j]),(0,Y.useEffect)(()=>{e.profile&&p(O(e.profile,``,J[0]))},[e.profile]);let M=async(e,t)=>{v(!0);try{await y.updateSettings(e),await a(),t&&c(t)}catch(e){c(e.message)}finally{v(!1)}},P=O(e.profile,``,J[0]),ce=!!e.profile&&Object.keys(d).some(e=>d[e]!==P[e]),F=e.profile?.name??`nanoMuse`,I=de(),L=ue(),R=ke()&&!e.lite,[B,V]=(0,Y.useState)(null),H=[{id:`who`,title:F},{id:`sentinel`,title:b(`Safety · Sentinel`)},{id:`proactivity`,title:b(`Proactivity`)},{id:`notifications`,title:b(`Notifications`)},...k()?[{id:`keep-running`,title:b(`Keep it running`)}]:[],{id:`model`,title:b(`Model`)},{id:`appearance`,title:b(`Appearance`)},...N()?[{id:`desktop`,title:b(`Desktop app`)}]:[],{id:`data`,title:b(`Data controls`)},{id:`developer`,title:b(`Developer`)},{id:`about`,title:b(`About`)}],U=e=>R||B===e,[W,G]=(0,Y.useState)(()=>{let e=window.location.hash.slice(1);return Ne.includes(e)?e:null});if((0,Y.useEffect)(()=>{if(W&&u){if(G(null),history.replaceState(null,``,window.location.pathname+window.location.search),!R){V(W);return}requestAnimationFrame(()=>document.getElementById(W)?.scrollIntoView({behavior:`smooth`,block:`start`}))}},[W,u,R]),!R&&B===null)return(0,X.jsx)(Fe,{release:w,onOpen:V});let pe=H.find(e=>e.id===B);return(0,X.jsxs)(`div`,{className:`flex h-full flex-col`,children:[R?(0,X.jsx)(q,{title:b(`Settings`),description:b(`Its name and look, how careful it is, how often it speaks up.`)}):(0,X.jsx)(q,{title:pe?.title??b(`Settings`),onBack:()=>V(null),backLabel:b(`Settings`)}),(0,X.jsxs)(`div`,{className:`flex min-h-0 flex-1`,children:[R&&(0,X.jsx)(`nav`,{className:`flex w-[188px] shrink-0 flex-col gap-0.5 self-start pl-4 pr-2 pt-1`,"aria-label":b(`Settings`),children:H.map(e=>(0,X.jsx)(`button`,{type:`button`,onClick:()=>document.getElementById(e.id)?.scrollIntoView({behavior:`smooth`,block:`start`}),className:`truncate rounded-xl px-3 py-1.5 text-left text-[13px] font-medium text-fg/75 hover:bg-surface-2 hover:text-fg`,children:e.title},e.id))}),(0,X.jsxs)(`div`,{className:`flex-1 overflow-y-auto px-4 pb-8 space-y-5`,children:[U(`who`)&&(0,X.jsxs)($,{title:F,id:`who`,plain:!R,children:[(0,X.jsx)(ae,{value:d,onChange:p,suggestions:!1,inputCls:Ae,onStudio:()=>s(`avatar`)}),(0,X.jsx)(`button`,{type:`button`,disabled:!ce||h,onClick:()=>void M({profile:ie(d)},b(`Saved`)),className:`w-full rounded-2xl bg-accent text-accent-fg py-2.5 font-medium disabled:opacity-40`,children:b(`Save`)})]}),U(`sentinel`)&&(0,X.jsxs)($,{title:b(`Safety · Sentinel`),id:`sentinel`,plain:!R,children:[(0,X.jsx)(`p`,{className:`text-[13px] text-muted -mt-1`,children:b(`A separate gatekeeper reviews every action. Pick how often it should check in with you.`)}),(0,X.jsx)(`div`,{className:`space-y-2`,children:je.map(e=>(0,X.jsxs)(`button`,{type:`button`,onClick:()=>void M({sentinel_mode:e.id}),"aria-pressed":u?.sentinel.mode===e.id,className:t(`w-full text-left rounded-2xl border px-3.5 py-3 flex items-start gap-3 transition`,u?.sentinel.mode===e.id?`border-accent bg-accent/8`:`border-border`),children:[(0,X.jsx)(`div`,{className:t(`mt-0.5`,e.id===`auto`?`text-rose-500`:`text-accent`),children:e.icon}),(0,X.jsxs)(`div`,{className:`flex-1`,children:[(0,X.jsx)(`div`,{className:`font-medium text-[14.5px]`,children:b(e.title)}),(0,X.jsx)(`div`,{className:`text-[12.5px] text-muted leading-snug mt-0.5`,children:b(e.text)})]}),u?.sentinel.mode===e.id&&(0,X.jsx)(ne,{size:18,className:`text-accent mt-0.5`})]},e.id))}),u&&(0,X.jsxs)(`div`,{className:`text-[12.5px] text-muted leading-relaxed`,children:[b(`Always asks before: {tools}.`,{tools:u.sentinel.always_ask_tools.map(e=>b(e)).join(`, `)||`—`}),` `,u.sentinel.taint_tracking&&b(`After reading private data, new network destinations need approval.`)]}),u?.sandbox&&(0,X.jsxs)(`div`,{className:`flex items-start gap-2.5 rounded-2xl bg-surface-2/60 px-3.5 py-2.5 text-[12.5px] leading-snug`,children:[(0,X.jsx)(be,{size:15,className:t(`shrink-0 mt-[2px]`,u.sandbox.active?`text-emerald-500`:`text-muted`)}),(0,X.jsxs)(`div`,{children:[(0,X.jsxs)(`div`,{className:`font-medium text-fg`,children:[u.sandbox.active?b(`Commands run in a sandbox`):b(`Commands run without a sandbox`),(0,X.jsxs)(`span`,{className:`text-muted font-normal`,children:[` · `,u.sandbox.status]})]}),(0,X.jsx)(`div`,{className:`text-muted mt-0.5`,children:u.sandbox.active?b(`Each shell or Python call gets its own namespace: only the workspace is writable, your home directory is not there, and there is no network unless the command needs it.`):u.sandbox.status.includes(`container`)?b(`Each shell or Python call runs in the workspace with a scrubbed environment; the container is the boundary.`):b(`Each shell or Python call runs in the workspace with a scrubbed environment. On Linux, installing bubblewrap gives each one its own namespace.`)})]})]})]}),U(`proactivity`)&&(0,X.jsxs)($,{title:b(`Proactivity`),id:`proactivity`,plain:!R,children:[(0,X.jsx)(ze,{value:e.profile?.proactivity??`default`,onChange:e=>void M({profile:{proactivity:e}})}),(0,X.jsxs)(`div`,{className:`flex items-center gap-3`,children:[(0,X.jsxs)(`label`,{className:`text-[13.5px] flex-1`,children:[b(`Check-in interval`),e.profile&&e.profile.proactivity!=="default"&&e.profile.proactivity!==`off`&&(0,X.jsx)(`span`,{className:`block text-[12px] text-muted`,children:e.profile.proactivity===`low`?b(`Doubled at this level`):b(`Halved at this level`)})]}),(0,X.jsx)(`select`,{value:e.profile?.goal_interval_minutes??60,onChange:e=>void M({profile:{goal_interval_minutes:Number(e.target.value)}}),className:`rounded-2xl bg-surface-2 px-3 py-2 text-[13.5px] outline-none`,children:[...new Set([15,30,60,120,240,480,1440,e.profile?.goal_interval_minutes??60])].sort((e,t)=>e-t).map(e=>(0,X.jsx)(`option`,{value:e,children:e<60?b(`{n} min`,{n:e}):e%60?`${b(`{n} h`,{n:Math.floor(e/60)})} ${b(`{n} min`,{n:e%60})}`:b(`{n} h`,{n:e/60})},e))})]}),(0,X.jsx)(Be,{value:e.profile?.quiet_hours??``,onChange:e=>void M({profile:{quiet_hours:e}})})]}),U(`notifications`)&&(0,X.jsx)($,{title:b(`Notifications`),id:`notifications`,plain:!R,children:A()?(0,X.jsx)(Ie,{name:e.profile?.name??`nanoMuse`}):(0,X.jsx)(Re,{name:e.profile?.name??`nanoMuse`})}),k()&&U(`keep-running`)&&(0,X.jsx)($,{title:b(`Keep it running`),id:`keep-running`,plain:!R,children:(0,X.jsx)(Le,{name:e.profile?.name??`nanoMuse`})}),U(`model`)&&(0,X.jsxs)($,{title:b(`Model`),id:`model`,plain:!R,children:[u&&(0,X.jsxs)(`button`,{type:`button`,onClick:()=>s(`connections`),className:`w-full text-[13.5px] flex items-center justify-between`,children:[(0,X.jsx)(`span`,{className:`text-muted`,children:b(`Provider / model`)}),(0,X.jsxs)(`span`,{className:`font-mono text-[12.5px] flex items-center gap-1`,children:[u.llm.model,` `,(0,X.jsx)(z,{size:14,className:`text-muted`})]})]}),u?.llm.cloud&&(0,X.jsxs)(`button`,{type:`button`,onClick:()=>oe(s,S(e.hub?.account).preset),className:`w-full text-[13.5px] flex items-center justify-between`,children:[(0,X.jsx)(`span`,{className:`text-muted`,children:b(`Use my own API key or a plan I pay for`)}),(0,X.jsxs)(`span`,{className:`text-[12.5px] text-muted flex items-center gap-1`,children:[b(`{first} first, then {others}`,{first:S(e.hub?.account).label,others:ee(e.hub?.account)?b(`DeepSeek, Kimi, OpenAI, ChatGPT…`):b(`OpenAI, ChatGPT, Gemini, DeepSeek…`)}),` `,(0,X.jsx)(z,{size:14})]})]}),(0,X.jsxs)(`button`,{type:`button`,onClick:()=>s(`connections`),className:`w-full text-[13.5px] flex items-center justify-between`,children:[(0,X.jsx)(`span`,{className:`text-muted`,children:b(`Connections`)}),(0,X.jsxs)(`span`,{className:`text-[12.5px] text-muted flex items-center gap-1`,children:[b(`E-mail, calendar, browser, MCP servers`),` `,(0,X.jsx)(z,{size:14})]})]})]}),U(`appearance`)&&(0,X.jsxs)($,{title:b(`Appearance`),id:`appearance`,plain:!R,children:[(0,X.jsx)(T,{label:b(`Show the agent's steps`),hint:b(`Every tool it uses becomes a chip in the chat. Off, the chat keeps to the conversation and the line under the name says what it is on. This device only.`),checked:L,onChange:ge}),(0,X.jsx)(T,{label:b(`Show thinking`),hint:b(`Reveal the model's reasoning under each reply when the provider exposes it.`),checked:!!u?.agent.show_thinking,onChange:e=>void M({show_thinking:e})}),(0,X.jsxs)(`div`,{className:`flex items-center gap-3`,children:[(0,X.jsxs)(`label`,{className:`text-[13.5px] flex-1`,children:[b(`Appearance`),(0,X.jsx)(`span`,{className:`block text-[12px] text-muted`,children:b(`This device only`)})]}),(0,X.jsxs)(`select`,{value:x,onChange:e=>_(e.target.value),className:`rounded-2xl bg-surface-2 px-3 py-2 text-[13.5px] outline-none`,children:[(0,X.jsx)(`option`,{value:`light`,children:b(`Light`)}),(0,X.jsx)(`option`,{value:`dark`,children:b(`Dark`)}),(0,X.jsx)(`option`,{value:`system`,children:b(`Follow the system`)})]})]}),(0,X.jsxs)(`div`,{className:`flex items-center gap-3`,children:[(0,X.jsxs)(`label`,{className:`text-[13.5px] flex-1`,children:[b(`App language`),(0,X.jsx)(`span`,{className:`block text-[12px] text-muted`,children:b(`This device only`)})]}),(0,X.jsx)(`select`,{value:te,onChange:e=>i(e.target.value),className:`rounded-2xl bg-surface-2 px-3 py-2 text-[13.5px] outline-none`,children:n.map(e=>(0,X.jsx)(`option`,{value:e.value,children:e.value===`auto`?b(`Auto`):e.label},e.value))})]}),(0,X.jsxs)(`div`,{className:`flex items-center gap-3`,children:[(0,X.jsxs)(`label`,{className:`text-[13.5px] flex-1`,children:[b(`Reply language`),(0,X.jsx)(`span`,{className:`block text-[12px] text-muted`,children:b(`What {name} writes in`,{name:e.profile?.name??`nanoMuse`})})]}),(0,X.jsxs)(`select`,{value:u?.agent.language??`auto`,onChange:e=>void M({language:e.target.value}),className:`rounded-2xl bg-surface-2 px-3 py-2 text-[13.5px] outline-none`,children:[(0,X.jsx)(`option`,{value:`auto`,children:b(`Match mine`)}),(0,X.jsx)(`option`,{value:`English`,children:`English`}),(0,X.jsx)(`option`,{value:`中文`,children:`中文`}),(0,X.jsx)(`option`,{value:`日本語`,children:`日本語`}),(0,X.jsx)(`option`,{value:`Español`,children:`Español`}),(0,X.jsx)(`option`,{value:`Deutsch`,children:`Deutsch`}),(0,X.jsx)(`option`,{value:`Français`,children:`Français`})]})]})]}),N()&&U(`desktop`)&&(0,X.jsx)($,{title:b(`Desktop app`),id:`desktop`,plain:!R,children:(0,X.jsx)(Ve,{})}),U(`data`)&&(0,X.jsx)($,{title:b(`Data controls`),id:`data`,plain:!R,children:(0,X.jsx)(fe,{flush:!0})}),U(`developer`)&&(0,X.jsxs)($,{title:b(`Developer`),id:`developer`,plain:!R,children:[(0,X.jsx)(T,{label:b(`Developer tools`),hint:b(`The Coding screen (Cursor, Codex and the other coding agents on this computer) in the sidebar, and the runtime's address below. This device only.`),checked:I,onChange:se}),I&&(0,X.jsxs)(`div`,{className:`text-[13px] text-muted space-y-1`,children:[(0,X.jsxs)(`div`,{className:`break-all`,children:[b(`Runtime:`),` `,window.location.origin,` · `,(0,X.jsx)(`span`,{className:`text-fg/70`,children:b(`the token is in the server_token file in the data folder`)})]}),(0,X.jsxs)(`div`,{children:[(0,X.jsx)(`a`,{href:`https://github.com/nano-muse/nanoMuse/blob/main/docs/cli.md`,target:`_blank`,rel:`noreferrer`,className:`text-accent underline-offset-2 hover:underline`,children:b(`The command line and the API`)}),` · `,(0,X.jsx)(`a`,{href:`https://github.com/nano-muse/nanoMuse/blob/main/docs/harness.md`,target:`_blank`,rel:`noreferrer`,className:`text-accent underline-offset-2 hover:underline`,children:b(`nanoMuse on DeepSeek Harness`)})]})]})]}),U(`about`)&&(0,X.jsxs)($,{title:b(`About`),id:`about`,plain:!R,children:[(0,X.jsx)(C,{}),(0,X.jsx)(Pe,{installed:e.version,release:w,checking:re,onCheck:()=>void j(!0)}),(0,X.jsxs)(`div`,{className:`text-[13px] text-muted space-y-1`,children:[u&&(0,X.jsxs)(`div`,{className:`break-all`,children:[b(`Data:`),` `,u.data_dir]}),u&&(0,X.jsxs)(`div`,{className:`break-all`,children:[b(`Workspace:`),` `,u.agent.workspace]}),(0,X.jsx)(`div`,{children:e.connected?b(`Connected`):b(`Reconnecting…`)})]}),(0,X.jsxs)(`button`,{type:`button`,onClick:()=>{let e=A();if(e){e.disconnect();return}l(``),window.location.reload()},className:`w-full rounded-2xl border border-border py-2.5 text-[14px] font-medium flex items-center justify-center gap-2 text-muted`,children:[(0,X.jsx)(le,{size:16}),` `,A()?b(`Disconnect from this server`):b(`Forget this device's access token`)]})]})]})]})]})}var Ne=[`who`,`sentinel`,`proactivity`,`notifications`,`keep-running`,`model`,`appearance`,`desktop`,`data`,`developer`,`about`];function Pe({installed:t,release:n,checking:r,onCheck:i}){let a=o(),s=!!A(),c=(0,X.jsx)(`button`,{type:`button`,onClick:i,disabled:r,className:`text-accent underline-offset-2 hover:underline disabled:opacity-60`,children:a(r?`Checking…`:`Check now`)}),l;return l=s?a(`The phone app checks for updates on its own.`):n&&!n.enabled?a(`Update checks are off here.`):r&&!n?a(`Checking…`):n?.latest&&n.newer?(0,X.jsxs)(X.Fragment,{children:[a(`{version} is out`,{version:n.latest}),` · `,(0,X.jsx)(`a`,{href:n.download_url||n.url,target:`_blank`,rel:`noreferrer`,className:`font-medium text-accent underline-offset-2 hover:underline`,children:a(`Update`)})]}):n?.latest?(0,X.jsxs)(X.Fragment,{children:[a(`Latest {version}; you have it`,{version:n.latest}),` · `,c]}):(0,X.jsxs)(X.Fragment,{children:[a(`Could not check`),` · `,c]}),(0,X.jsxs)(`div`,{className:`rounded-2xl bg-surface-2/60 px-3.5 py-2.5 text-[13px]`,children:[(0,X.jsx)(`div`,{className:`font-medium`,children:a(`nanoMuse {version}`,{version:t})}),(0,X.jsx)(`div`,{className:`mt-0.5 text-muted`,children:l}),!s&&n?.latest&&n.newer&&(0,X.jsx)(`div`,{className:`mt-1 text-[12px] text-muted`,children:a(`To update: pip install -U nanomuse, pull the new image, or use the desktop app's Update.`)}),!s&&n?.checked_at&&(0,X.jsx)(`div`,{className:`mt-1 text-[12px] text-muted`,children:a(`Checked {when}`,{when:e(n.checked_at)})})]})}function Fe({release:e,onOpen:t}){let{state:n,setTab:r}=m(),i=o(),a=n.settings,c=n.hub,l=te(),u=n.profile?.name??`nanoMuse`,d=g(),f=c?.devices.filter(e=>!e.this&&e.kind!==`web`)??[],p=f.filter(e=>e.kind===`computer`),h=f.filter(e=>e.online&&e.actions?.includes(`coding.sessions`)),_=a?.sentinel.mode,v=_===`ask`?i(`Balanced`):_===`strict`?i(`Cautious`):_===`auto`?i(`Hands-off`):``,y=n.profile?.proactivity??`default`,ee=i(y===`off`?`Off`:y===`low`?`Low`:y===`high`?`High`:`Default`),S=i(d===`dark`?`Dark`:d===`light`?`Light`:`Follow the system`),C=i(`none`);return(0,X.jsxs)(`div`,{className:`flex h-full flex-col`,children:[(0,X.jsx)(q,{title:i(`Settings`)}),(0,X.jsxs)(`div`,{className:`flex-1 overflow-y-auto pb-8 pt-2`,children:[(0,X.jsxs)(L,{className:`mb-3`,children:[(0,X.jsxs)(`button`,{type:`button`,onClick:()=>r(`connections`),className:`flex w-full items-center gap-3 px-4 py-3.5 text-left hover:bg-surface-2/60`,children:[(0,X.jsxs)(`span`,{className:`min-w-0 flex-1`,children:[(0,X.jsx)(`span`,{className:`block truncate text-[16px] font-medium leading-[21px]`,children:a?.llm.model||i(`No model yet`)}),(0,X.jsx)(`span`,{className:`mt-0.5 block truncate text-[12.5px] leading-4 text-muted`,children:a?a.llm.cloud?`nanoMuse Cloud`:a.llm.provider:i(`Add a provider and pick its models`)})]}),(0,X.jsx)(`span`,{className:`text-[14px] font-medium text-accent`,children:i(`Change`)})]}),(0,X.jsx)(W,{}),(0,X.jsx)(K,{icon:(0,X.jsx)(_e,{size:22}),label:`nanoMuse Cloud`,value:c?.account.signed_in?c.account.hint:i(`Sign in`),onClick:()=>r(`account`)}),(0,X.jsx)(W,{}),(0,X.jsx)(K,{icon:(0,X.jsx)(E,{size:22}),label:i(`Image & video models`),value:x(l,`image`)===!1?w(i,`image`,b(c?.account),s()):x(l,`video`)===!1?w(i,`video`,b(c?.account),s()):void 0,onClick:()=>r(`connections`)}),(0,X.jsx)(W,{}),(0,X.jsx)(K,{icon:(0,X.jsx)(xe,{size:22}),label:i(`Usage`),onClick:()=>r(`account`)})]}),(0,X.jsxs)(L,{className:`mb-3`,children:[(0,X.jsx)(K,{icon:(0,X.jsx)(F,{size:22}),label:i(`Name & personality`),value:u,onClick:()=>t(`who`)}),(0,X.jsx)(W,{}),(0,X.jsx)(K,{icon:(0,X.jsx)(Te,{size:22}),label:i(`Avatar`),onClick:()=>r(`avatar`)}),(0,X.jsx)(W,{}),(0,X.jsx)(K,{icon:(0,X.jsx)(P,{size:22}),label:i(`Memory`),onClick:()=>r(`memory`)}),a?.skills?.enabled!==!1&&(0,X.jsxs)(X.Fragment,{children:[(0,X.jsx)(W,{}),(0,X.jsx)(K,{icon:(0,X.jsx)(Ce,{size:22}),label:i(`Skills`),value:a?String(a.skills.count):void 0,onClick:()=>r(`skills`)})]}),(0,X.jsx)(W,{}),(0,X.jsx)(K,{icon:(0,X.jsx)(D,{size:22}),label:i(`Connections`),value:a?.connectors.mcp.length?`${a.connectors.mcp.length} MCP`:void 0,onClick:()=>r(`connections`)}),(0,X.jsx)(W,{}),(0,X.jsx)(K,{icon:(0,X.jsx)(R,{size:22}),label:i(`Chat apps`),onClick:()=>r(`channels`)}),(0,X.jsx)(W,{}),(0,X.jsx)(K,{icon:(0,X.jsx)(me,{size:22}),label:i(`Devices`),value:p.length?String(p.length):C,onClick:()=>r(`devices`)}),(0,X.jsx)(W,{}),(0,X.jsx)(K,{icon:(0,X.jsx)(ce,{size:22}),label:i(`Coding agents`),value:h.length?String(h.length):C,onClick:()=>r(`coding`)})]}),(0,X.jsxs)(L,{className:`mb-3`,children:[(0,X.jsx)(K,{icon:(0,X.jsx)(j,{size:22}),label:i(`Safety · Sentinel`),value:v,onClick:()=>t(`sentinel`)}),(0,X.jsx)(W,{}),(0,X.jsx)(K,{icon:(0,X.jsx)(Ee,{size:22}),label:i(`Proactivity`),value:ee,onClick:()=>t(`proactivity`)}),(0,X.jsx)(W,{}),(0,X.jsx)(K,{icon:(0,X.jsx)(ve,{size:22}),label:i(`Notifications`),onClick:()=>t(`notifications`)}),k()&&(0,X.jsxs)(X.Fragment,{children:[(0,X.jsx)(W,{}),(0,X.jsx)(K,{icon:(0,X.jsx)(ye,{size:22}),label:i(`Keep it running`),onClick:()=>t(`keep-running`)})]})]}),(0,X.jsxs)(L,{className:`mb-3`,children:[(0,X.jsx)(K,{icon:(0,X.jsx)(he,{size:22}),label:i(`Appearance`),value:S,onClick:()=>t(`appearance`)}),N()&&(0,X.jsxs)(X.Fragment,{children:[(0,X.jsx)(W,{}),(0,X.jsx)(K,{icon:(0,X.jsx)(me,{size:22}),label:i(`Desktop app`),onClick:()=>t(`desktop`)})]}),(0,X.jsx)(W,{}),(0,X.jsx)(K,{icon:(0,X.jsx)(re,{size:22}),label:i(`Data controls`),onClick:()=>t(`data`)}),(0,X.jsx)(W,{}),(0,X.jsx)(K,{icon:(0,X.jsx)(I,{size:22}),label:i(`Developer`),onClick:()=>t(`developer`)})]}),(0,X.jsxs)(L,{className:`mb-3`,children:[(0,X.jsx)(K,{icon:(0,X.jsx)(B,{size:22}),label:i(`About nanoMuse`),value:e?.newer&&e.latest?i(`{version} is out`,{version:e.latest}):void 0,onClick:()=>t(`about`)}),(0,X.jsx)(W,{}),(0,X.jsx)(K,{icon:(0,X.jsx)(V,{size:22}),label:i(`Privacy policy`),onClick:()=>window.open(pe,`_blank`,`noopener`),external:!0}),(0,X.jsx)(W,{}),(0,X.jsx)(K,{icon:(0,X.jsx)(Se,{size:22}),label:i(`Feedback`),onClick:()=>window.open(`https://github.com/nano-muse/nanoMuse/issues/new/choose`,`_blank`,`noopener`),external:!0})]}),(0,X.jsxs)(H,{children:[`nanoMuse `,n.version]})]})]})}function Ie({name:e}){let t=o(),n=A(),[r,i]=(0,Y.useState)(()=>n?.notificationsEnabled()??!1);return n?(0,X.jsxs)(X.Fragment,{children:[(0,X.jsx)(T,{label:t(`Let {name} notify this phone`,{name:e}),hint:t(`The app stays connected to your server in the background. Approvals, questions and finished background work arrive as notifications and open the right chat.`),checked:r,onChange:e=>{n.setNotificationsEnabled(e),i(e)}}),(0,X.jsx)(`div`,{className:`text-[12.5px] text-muted`,children:t(`nanoMuse for Android {version}`,{version:n.version()})})]}):null}function Le({name:e}){let t=o(),n=A(),[r,i]=(0,Y.useState)(k);if((0,Y.useEffect)(()=>{let e=()=>i(k());return document.addEventListener(`visibilitychange`,e),window.addEventListener(`focus`,e),()=>{document.removeEventListener(`visibilitychange`,e),window.removeEventListener(`focus`,e)}},[]),!n||!r)return null;let a=e=>n.openKeepRunning?.(e),s={xiaomi:t(`Xiaomi / Redmi / POCO: Settings → Apps → Manage apps → {name} → Autostart on; Battery saver → No restrictions; Other permissions → Display pop-up windows while running in the background on.`),huawei:t(`Huawei: Settings → Battery → App launch → {name} → Manage manually, all three on (auto-launch, secondary launch, run in background); Settings → Apps → {name} → Battery → Launch: manage manually.`),honor:t(`Honor: Settings → Battery → App launch → {name} → Manage manually, all three on; Battery → More battery settings → Stay connected while asleep on.`),oppo:t(`OPPO / realme / OnePlus: Settings → Battery → More settings → Optimise battery use → {name} → Don't optimise; Settings → Apps → {name} → Battery usage → Allow background activity, Allow auto launch.`),vivo:t(`vivo / iQOO: i Manager → App manager → Autostart → {name} on; Settings → Battery → Background power consumption management → {name} → Allow high background power consumption.`),samsung:t(`Samsung: Settings → Battery → Background usage limits → {name} not in Sleeping or Deep sleeping apps (add it to Never sleeping apps); turn off Adaptive battery if it keeps stopping.`),meizu:t(`Meizu: Settings → Apps → {name} → Background management → Keep running in the background; Battery → App power management → Allow.`)}[r.vendor];return(0,X.jsxs)(X.Fragment,{children:[(0,X.jsx)(`p`,{className:`text-[12.5px] text-muted leading-snug`,children:t(`Android stops apps that seem idle. {name} runs as a foreground service and holds the phone awake only while a task runs; these switches let it keep that promise on this phone.`,{name:e})}),(0,X.jsx)(Z,{label:t(`Battery`),value:r.battery_unrestricted?t(`Unrestricted`):t(`Optimised`),ok:r.battery_unrestricted,hint:t(`Optimised means Android may freeze the agent after a while with the screen off; routines and check-ins then wait until the phone wakes.`),action:r.battery_unrestricted?void 0:{label:t(`Allow`),onClick:()=>a(`battery`)}}),(0,X.jsx)(Z,{label:t(`Display over other apps`),value:r.overlay?t(`Allowed`):t(`Not allowed`),ok:r.overlay,hint:t(`Lets the agent bring an app to the front from the background and show its status capsule while it works in other apps.`),action:r.overlay?void 0:{label:t(`Allow`),onClick:()=>a(`overlay`)}}),r.exact_alarms!==`n/a`&&r.local&&(0,X.jsx)(Z,{label:t(`Alarms & reminders`),value:r.exact_alarms===`granted`?t(`Exact`):t(`Approximate`),ok:r.exact_alarms===`granted`,hint:t(`With exact alarms a reminder fires at the minute you named even when the phone is asleep; without them Android may deliver it up to a quarter of an hour late.`),action:r.exact_alarms===`granted`?void 0:{label:t(`Allow`),onClick:()=>a(`alarms`)}}),(0,X.jsx)(T,{label:t(`Start after a reboot`),hint:r.local?t(`Bring the runtime back when the phone restarts, so routines and check-ins do not stop.`):t(`Reconnect to your computer when the phone restarts, so approvals keep arriving.`),checked:r.boot_start,onChange:e=>{n.setStartOnBoot?.(e),i({...r,boot_start:e})}}),s&&(0,X.jsxs)(`div`,{className:`rounded-2xl bg-surface-2 px-3 py-2.5 text-[12.5px] leading-snug space-y-2`,children:[(0,X.jsx)(`div`,{className:`font-medium`,children:t(`On this phone's Android`)}),(0,X.jsx)(`div`,{className:`text-muted`,children:s}),r.autostart_settings&&(0,X.jsx)(`button`,{type:`button`,onClick:()=>a(`autostart`),className:`rounded-full border border-border px-3 py-1.5 text-[12.5px]`,children:t(`Open the auto-start settings`)})]}),(0,X.jsxs)(`div`,{className:`flex items-center justify-between gap-3 pt-1`,children:[(0,X.jsx)(`div`,{className:`text-[12.5px] text-muted leading-snug`,children:t(`Crashes are written to a file on this phone and nowhere else. Export bundles them with the runtime's log for someone you choose.`)}),(0,X.jsx)(`button`,{type:`button`,onClick:()=>n.exportLogs?.(),className:`shrink-0 rounded-full border border-border px-3 py-1.5 text-[12.5px]`,children:t(`Export logs`)})]})]})}function Z({label:e,value:n,ok:r,hint:i,action:a}){return(0,X.jsxs)(`div`,{className:`flex items-start gap-3`,children:[(0,X.jsxs)(`div`,{className:`flex-1`,children:[(0,X.jsxs)(`div`,{className:`flex items-center gap-2 text-[14px]`,children:[(0,X.jsx)(`span`,{children:e}),(0,X.jsx)(`span`,{className:t(`rounded-full px-2 py-0.5 text-[11px] font-medium`,r?`bg-emerald-500/12 text-emerald-700 dark:text-emerald-300`:`bg-amber-500/15 text-amber-700 dark:text-amber-300`),children:n})]}),i&&(0,X.jsx)(`div`,{className:`text-[12.5px] text-muted leading-snug`,children:i})]}),a&&(0,X.jsx)(`button`,{type:`button`,onClick:a.onClick,className:`shrink-0 rounded-full bg-accent px-3 py-1.5 text-[12.5px] font-medium text-white`,children:a.label})]})}function Re({name:e}){let{toast:t}=m(),[n,r]=(0,Y.useState)(null),[i,a]=(0,Y.useState)(`off`),[s,c]=(0,Y.useState)(!1),l=o(),u=async()=>{a(await v());try{r(await y.push())}catch{}};(0,Y.useEffect)(()=>{u()},[]);let f=async()=>{if(n){c(!0);try{let e=i===`on`?await h():await d(n.public_key);a(e),e===`denied`&&t(l(`Notifications are blocked for this site in the browser settings`)),await u()}catch(e){let n=e;t(n.name===`AbortError`?l(`This browser has no push service (embedded browsers often don't). Use Chrome, Edge, Firefox or Safari 16.4+ on the phone.`):n.message)}finally{c(!1)}}},p=async()=>{try{let e=await y.pushTest();t(e.ok?l(`Sent. It should arrive in a moment`):e.error??l(`Could not send`))}catch(e){t(e.message)}},g=i===`unsupported`?l(`This browser cannot receive push notifications.`):i===`insecure`?l(`Notifications need https:// (or localhost). Over plain http on your LAN the app works, this part stays off; see docs/deployment.md.`):i===`denied`?l(`Blocked for this site. Allow notifications in the browser's site settings, then try again.`):n&&!n.available?l(`The server was installed without pywebpush.`):``;return(0,X.jsxs)(X.Fragment,{children:[(0,X.jsx)(T,{label:l(`Let {name} notify this device`,{name:e}),hint:l(`Approvals, questions, finished background work and check-ins; nothing while the app is on screen.`),checked:i===`on`,onChange:()=>void f(),disabled:s||!!g}),g&&(0,X.jsx)(`div`,{className:`text-[12.5px] text-muted`,children:g}),n&&n.subscriptions>0&&(0,X.jsxs)(`div`,{className:`flex items-center justify-between text-[12.5px] text-muted`,children:[(0,X.jsx)(`span`,{children:n.subscriptions===1?l(`1 device subscribed`):l(`{n} devices subscribed`,{n:n.subscriptions})}),(0,X.jsx)(`button`,{type:`button`,onClick:()=>void p(),className:`text-accent font-medium`,children:l(`Send a test`)})]}),!N()&&(0,X.jsx)(`div`,{className:`text-[12.5px] text-muted`,children:l(`On a phone, add the app to the home screen first; the icon then shows a badge and notifications open the right chat.`)})]})}var Q=[{id:`off`,title:`Off`,text:`Only works when you ask.`},{id:`low`,title:`Low`,text:`Checks in half as often; speaks up only when a step is done or it needs you.`},{id:`default`,title:`Default`,text:`Works on goals on schedule; reports real progress, stays quiet otherwise.`},{id:`high`,title:`High`,text:`Checks in twice as often and always reports, even 'still on track'.`}];function ze({value:e,onChange:n}){let r=o(),i=Q.find(t=>t.id===e)??Q[2];return(0,X.jsxs)(`div`,{children:[(0,X.jsx)(`div`,{className:`flex items-center gap-3`,children:(0,X.jsx)(`div`,{className:`flex-1 text-[13px] text-muted leading-snug`,children:r(i.text)})}),(0,X.jsx)(`div`,{className:`mt-2 grid grid-cols-4 gap-1 rounded-2xl bg-surface-2 p-1`,children:Q.map(i=>(0,X.jsx)(`button`,{type:`button`,onClick:()=>n(i.id),"aria-pressed":e===i.id,className:t(`rounded-xl py-1.5 text-[13px] font-medium transition`,e===i.id?`bg-surface shadow-sm text-accent`:`text-muted`),children:r(i.title)},i.id))})]})}function Be({value:e,onChange:n}){let[r,i]=e?e.split(`-`):[``,``],a=!!e,s=o(),c=(e,t)=>n(e&&t?`${e}-${t}`:``);return(0,X.jsxs)(`div`,{children:[(0,X.jsxs)(`label`,{className:`flex items-start gap-3 cursor-pointer`,children:[(0,X.jsxs)(`div`,{className:`flex-1`,children:[(0,X.jsxs)(`div`,{className:`text-[14px] flex items-center gap-1.5`,children:[(0,X.jsx)(U,{size:15,className:`text-muted`}),` `,s(`Quiet hours`)]}),(0,X.jsx)(`div`,{className:`text-[12.5px] text-muted leading-snug`,children:s(`No background work in this window; anything due waits until it ends.`)})]}),(0,X.jsx)(`button`,{type:`button`,role:`switch`,"aria-checked":a,onClick:()=>c(a?``:`22:00`,a?``:`08:00`),className:t(`relative mt-0.5 h-7 w-12 shrink-0 rounded-full transition`,a?`bg-accent`:`bg-surface-2 border border-border`),children:(0,X.jsx)(`span`,{className:t(`absolute top-0.5 h-6 w-6 rounded-full bg-white shadow transition`,a?`left-[22px]`:`left-0.5`)})})]}),a&&(0,X.jsxs)(`div`,{className:`mt-2 flex items-center gap-2 text-[13.5px]`,children:[(0,X.jsx)(`span`,{className:`text-muted`,children:s(`From`)}),(0,X.jsx)(`input`,{type:`time`,value:r,onChange:e=>c(e.target.value,i),className:`rounded-xl bg-surface-2 px-2.5 py-1.5 outline-none`}),(0,X.jsx)(`span`,{className:`text-muted`,children:s(`to`)}),(0,X.jsx)(`input`,{type:`time`,value:i,onChange:e=>c(r,e.target.value),className:`rounded-xl bg-surface-2 px-2.5 py-1.5 outline-none`})]})]})}function Ve(){let e=o(),t=M(),[n,r]=(0,Y.useState)(null);(0,Y.useEffect)(()=>{let e=!0;return t?.loginItem?.().then(t=>{e&&r(t)}),()=>{e=!1}},[t]);let i=t?.platform===`darwin`,a=[[e(`Quick chat`),i?`⌥ Space`:`Ctrl+Shift+Space`],[e(`Show the window`),i?`⌘⇧M`:`Ctrl+Shift+M`],[e(`Stop the hands`),i?`⌘⇧Esc`:`Ctrl+Shift+Esc`]];return(0,X.jsxs)(X.Fragment,{children:[t?.setLoginItem&&n!==null&&t.platform!==`linux`&&(0,X.jsx)(T,{label:e(`Start with the computer`),hint:e(`Opens in the tray at sign-in; the agent's goals and check-ins run from then on.`),checked:n,onChange:e=>{r(e),t.setLoginItem?.(e)}}),(0,X.jsxs)(`div`,{className:`text-[13.5px]`,children:[e(`In the tray`),(0,X.jsx)(`span`,{className:`block text-[12px] text-muted`,children:e(`The icon by the clock shows what the hands are doing and has Stop; closing the window keeps the agent running.`)})]}),(0,X.jsxs)(`div`,{className:`space-y-1`,children:[(0,X.jsx)(`div`,{className:`text-[13.5px]`,children:e(`Shortcuts`)}),a.map(([e,t])=>(0,X.jsxs)(`div`,{className:`flex items-center justify-between text-[13px]`,children:[(0,X.jsx)(`span`,{className:`text-muted`,children:e}),(0,X.jsx)(`kbd`,{className:`rounded-md border border-border bg-surface-2 px-1.5 py-0.5 font-sans text-[12px] text-fg/80`,children:t})]},e))]})]})}function $({title:e,children:n,id:r,plain:i=!1}){return(0,X.jsxs)(`section`,{id:r,className:t(`space-y-3 scroll-mt-4`,i?`pt-1`:`rounded-3xl bg-surface border border-border/70 shadow-sm p-4`),children:[!i&&(0,X.jsx)(`h2`,{className:`text-[12px] font-semibold uppercase tracking-wide text-muted`,children:e}),n]})}export{Me as SettingsScreen}; \ No newline at end of file diff --git a/nanomuse/server/static/assets/SkillsScreen-Dr-d7iS7.js b/nanomuse/server/static/assets/SkillsScreen-qZE6bdL9.js similarity index 98% rename from nanomuse/server/static/assets/SkillsScreen-Dr-d7iS7.js rename to nanomuse/server/static/assets/SkillsScreen-qZE6bdL9.js index d6a9f8cc7..6570a5470 100644 --- a/nanomuse/server/static/assets/SkillsScreen-Dr-d7iS7.js +++ b/nanomuse/server/static/assets/SkillsScreen-qZE6bdL9.js @@ -1,4 +1,4 @@ -import{A as e,E as t,J as n,K as r,Q as i,Y as a,b as o,f as s,q as c,r as l,x as u}from"./MuseHeader-Pw-NI98v.js";import{B as d,C as f,F as p,Q as m,V as h,Z as g,bt as _,et as v}from"./index-CIdGZ5PB.js";import{t as y}from"./BackBar-Dl56jHZM.js";var b=n(`file-code-corner`,[[`path`,{d:`M4 12.15V4a2 2 0 0 1 2-2h8a2.4 2.4 0 0 1 1.706.706l3.588 3.588A2.4 2.4 0 0 1 20 8v12a2 2 0 0 1-2 2h-3.35`,key:`1wthlu`}],[`path`,{d:`M14 2v5a1 1 0 0 0 1 1h5`,key:`wfsgrz`}],[`path`,{d:`m5 16-3 3 3 3`,key:`331omg`}],[`path`,{d:`m9 22 3-3-3-3`,key:`lsp7cz`}]]),x=n(`link-2`,[[`path`,{d:`M9 17H7A5 5 0 0 1 7 7h2`,key:`8i5ue5`}],[`path`,{d:`M15 7h2a5 5 0 1 1 0 10h-2`,key:`1b9ql8`}],[`line`,{x1:`8`,x2:`16`,y1:`12`,y2:`12`,key:`1jonct`}]]),S=i(a(),1),C=o(),w=e=>`--- +import{A as e,E as t,J as n,K as r,Q as i,Y as a,b as o,f as s,q as c,r as l,x as u}from"./MuseHeader-BDWXHKHT.js";import{B as d,C as f,F as p,Q as m,V as h,Z as g,bt as _,et as v}from"./index-DKrXW2Qj.js";import{t as y}from"./BackBar-DqcCClHf.js";var b=n(`file-code-corner`,[[`path`,{d:`M4 12.15V4a2 2 0 0 1 2-2h8a2.4 2.4 0 0 1 1.706.706l3.588 3.588A2.4 2.4 0 0 1 20 8v12a2 2 0 0 1-2 2h-3.35`,key:`1wthlu`}],[`path`,{d:`M14 2v5a1 1 0 0 0 1 1h5`,key:`wfsgrz`}],[`path`,{d:`m5 16-3 3 3 3`,key:`331omg`}],[`path`,{d:`m9 22 3-3-3-3`,key:`lsp7cz`}]]),x=n(`link-2`,[[`path`,{d:`M9 17H7A5 5 0 0 1 7 7h2`,key:`8i5ue5`}],[`path`,{d:`M15 7h2a5 5 0 1 1 0 10h-2`,key:`1b9ql8`}],[`line`,{x1:`8`,x2:`16`,y1:`12`,y2:`12`,key:`1jonct`}]]),S=i(a(),1),C=o(),w=e=>`--- name: ${e} description: What this does, and when to use it; the model picks the skill from this line. --- diff --git a/nanomuse/server/static/assets/StarNudge-DjXecvWj.js b/nanomuse/server/static/assets/StarNudge-B8P2bPEz.js similarity index 99% rename from nanomuse/server/static/assets/StarNudge-DjXecvWj.js rename to nanomuse/server/static/assets/StarNudge-B8P2bPEz.js index e5e43a829..f590ee478 100644 --- a/nanomuse/server/static/assets/StarNudge-DjXecvWj.js +++ b/nanomuse/server/static/assets/StarNudge-B8P2bPEz.js @@ -1 +1 @@ -import{E as e,J as t,K as n,L as r,Q as i,W as a,Y as o,b as s,x as c}from"./MuseHeader-Pw-NI98v.js";import{t as ee}from"./external-link-Xj5fjR8v.js";import{a as l,i as te}from"./Form-DwKuBk1V.js";var u=t(`bug`,[[`path`,{d:`M12 20v-9`,key:`1qisl0`}],[`path`,{d:`M14 7a4 4 0 0 1 4 4v3a6 6 0 0 1-12 0v-3a4 4 0 0 1 4-4z`,key:`uouzyp`}],[`path`,{d:`M14.12 3.88 16 2`,key:`qol33r`}],[`path`,{d:`M21 21a4 4 0 0 0-3.81-4`,key:`1b0z45`}],[`path`,{d:`M21 5a4 4 0 0 1-3.55 3.97`,key:`5cxbf6`}],[`path`,{d:`M22 13h-4`,key:`1jl80f`}],[`path`,{d:`M3 21a4 4 0 0 1 3.81-4`,key:`1fjd4g`}],[`path`,{d:`M3 5a4 4 0 0 0 3.55 3.97`,key:`1d7oge`}],[`path`,{d:`M6 13H2`,key:`82j7cp`}],[`path`,{d:`m8 2 1.88 1.88`,key:`fmnt4t`}],[`path`,{d:`M9 7.13V6a3 3 0 1 1 6 0v1.13`,key:`1vgav8`}]]),ne=t(`github`,[[`path`,{d:`M15 22v-4a4.8 4.8 0 0 0-1-3.5c3 0 6-2 6-5.5.08-1.25-.27-2.48-1-3.5.28-1.15.28-2.35 0-3.5 0 0-1 0-3 1.5-2.64-.5-5.36-.5-8 0C6 2 5 2 5 2c-.3 1.15-.3 2.35 0 3.5A5.403 5.403 0 0 0 4 9c0 3.5 3 5.5 6 5.5-.39.49-.68 1.05-.85 1.65-.17.6-.22 1.23-.15 1.85v4`,key:`tonef`}],[`path`,{d:`M9 18c-4.51 2-5-2-7-2`,key:`9comsn`}]]),d=t(`heart-handshake`,[[`path`,{d:`M19.414 14.414C21 12.828 22 11.5 22 9.5a5.5 5.5 0 0 0-9.591-3.676.6.6 0 0 1-.818.001A5.5 5.5 0 0 0 2 9.5c0 2.3 1.5 4 3 5.5l5.535 5.362a2 2 0 0 0 2.879.052 2.12 2.12 0 0 0-.004-3 2.124 2.124 0 1 0 3-3 2.124 2.124 0 0 0 3.004 0 2 2 0 0 0 0-2.828l-1.881-1.882a2.41 2.41 0 0 0-3.409 0l-1.71 1.71a2 2 0 0 1-2.828 0 2 2 0 0 1 0-2.828l2.823-2.762`,key:`17lmqv`}]]),f=t(`star`,[[`path`,{d:`M11.525 2.295a.53.53 0 0 1 .95 0l2.31 4.679a2.123 2.123 0 0 0 1.595 1.16l5.166.756a.53.53 0 0 1 .294.904l-3.736 3.638a2.123 2.123 0 0 0-.611 1.878l.882 5.14a.53.53 0 0 1-.771.56l-4.618-2.428a2.122 2.122 0 0 0-1.973 0L6.396 21.01a.53.53 0 0 1-.77-.56l.881-5.139a2.122 2.122 0 0 0-.611-1.879L2.16 9.795a.53.53 0 0 1 .294-.906l5.165-.755a2.122 2.122 0 0 0 1.597-1.16z`,key:`r04s7s`}]]),p=i(o(),1),m={version:1,updated:`2026-10`,capabilities:[`chat`,`vision`,`image`,`video`],auth_kinds:[`key`,`none`,`oauth-chatgpt`,`oauth-claude`,`oauth-openrouter`,`device-kimi`],providers:[{id:`bailian`,name:`Alibaba Cloud Bailian`,name_zh:`阿里云百炼`,protocol:`openai`,base_url:`https://dashscope.aliyuncs.com/compatible-mode/v1`,key_url:`https://bailian.console.aliyun.com/?apiKey=1`,key_hint:`sk-…`,auth:[`key`],regions:[`cn`],capabilities:[`chat`,`vision`,`image`,`video`],defaults:{chat:`deepseek-v4.1-flash`,hands:`qwen3.8-27b`,image:`qwen-image-3.0`,video:`wan2.2-i2v-flash`},note:`One key for chat, hands, pictures and clips. Signs up accounts with a mainland China identity only; the international edition (dashscope-intl) does not carry these models. Pictures and clips go through Model Studio's own API, which nanoMuse speaks.`,note_zh:`一把 key 覆盖对话、手、画图和视频。只给中国大陆身份注册;国际版(dashscope-intl)没有这几个模型。画图和视频走百炼自己的接口,nanoMuse 已支持。`,verified:`2026-10`},{id:`deepseek`,name:`DeepSeek`,name_zh:`DeepSeek(深度求索)`,protocol:`openai`,base_url:`https://api.deepseek.com/v1`,key_url:`https://platform.deepseek.com/api_keys`,key_hint:`sk-…`,auth:[`key`],regions:[`cn`,`global`],capabilities:[`chat`,`vision`],defaults:{chat:`deepseek-flash`,hands:`deepseek-flash`},note:`deepseek-flash (DeepSeek-V4.1-Flash) reads pictures; deepseek-v4-pro is text only. No image or video models.`,note_zh:`deepseek-flash(DeepSeek-V4.1-Flash)能看图;deepseek-v4-pro 只处理文字。没有图像和视频模型。`,verified:`2026-10`,reasoning:{doc:`https://api-docs.deepseek.com/guides/thinking_mode`,wire:`thinking+reasoning_effort`,rules:[{models:`^deepseek-`,levels:[`low`,`high`,`max`],default:`high`}]}},{id:`moonshot`,name:`Kimi (Moonshot AI)`,name_zh:`Kimi(月之暗面)`,protocol:`openai`,base_url:`https://api.moonshot.cn/v1`,base_url_global:`https://api.moonshot.ai/v1`,key_url:`https://platform.moonshot.cn/console/api-keys`,key_url_global:`https://platform.kimi.ai/console`,key_hint:`sk-…`,auth:[`key`,`device-kimi`],regions:[`cn`,`global`],capabilities:[`chat`,`vision`],defaults:{chat:`kimi-k2.6`,hands:`kimi-k2.6`},note:`Two editions: api.moonshot.cn for mainland China, api.moonshot.ai elsewhere, each with its own console and keys. kimi-k2.6 and kimi-k3 read pictures. The phone apps can sign in with a Kimi account (device code) instead of a key.`,note_zh:`两个版本:中国大陆用 api.moonshot.cn,海外用 api.moonshot.ai,各自有控制台和 key。kimi-k2.6、kimi-k3 能看图。手机 App 可以用 Kimi 账号登录(设备码),不用贴 key。`,verified:`2026-10`,reasoning:{doc:`https://platform.moonshot.ai/docs/api/chat`,wire:`reasoning_effort`,rules:[{models:`^kimi-k3`,levels:[`low`,`high`,`max`],default:`max`}]}},{id:`zhipu`,name:`Zhipu GLM`,name_zh:`智谱 GLM`,protocol:`openai`,base_url:`https://open.bigmodel.cn/api/paas/v4`,key_url:`https://open.bigmodel.cn/usercenter/apikeys`,key_hint:`xxxxxxxx.xxxxxxxx`,auth:[`key`],regions:[`cn`],capabilities:[`chat`,`vision`,`image`],defaults:{chat:`glm-5.3`,hands:`glm-4.6v`,image:`glm-image`},note:`glm-4.6v reads pictures; pictures are drawn by glm-image or cogview-4 through /images/generations.`,note_zh:`glm-4.6v 能看图;画图用 glm-image 或 cogview-4,走 /images/generations。`,verified:`2026-10`,reasoning:{doc:`https://docs.bigmodel.cn/api-reference/%E6%A8%A1%E5%9E%8B-api/%E5%AF%B9%E8%AF%9D%E8%A1%A5%E5%85%A8`,wire:`thinking+reasoning_effort`,rules:[{models:`^glm-5\\.3`,levels:[`low`,`high`,`max`],default:`max`},{models:`^glm-5\\.2`,levels:[`high`,`max`],default:`max`}]}},{id:`siliconflow`,name:`SiliconFlow`,name_zh:`硅基流动`,protocol:`openai`,base_url:`https://api.siliconflow.cn/v1`,key_url:`https://cloud.siliconflow.cn/account/ak`,key_hint:`sk-…`,auth:[`key`],regions:[`cn`],capabilities:[`chat`,`vision`,`image`],defaults:{chat:`deepseek-ai/DeepSeek-V4-Flash`,hands:`Qwen/Qwen3-VL-32B-Instruct`,image:`Qwen/Qwen-Image`},note:`Many open models behind one key; model ids carry the maker's prefix. Pictures through /images/generations (Qwen-Image, Kolors, FLUX).`,note_zh:`一把 key 后面是许多开源模型,模型 id 带厂商前缀。画图走 /images/generations(Qwen-Image、Kolors、FLUX)。`,verified:`2026-10`,reasoning:{doc:`https://docs.siliconflow.cn/cn/api-reference/chat-completions/chat-completions`,wire:`reasoning_effort`,rules:[{models:`^(Pro/)?deepseek-ai/DeepSeek-V4(-|$)`,levels:[`high`,`max`],default:`high`},{models:`^Pro/zai-org/GLM-5\\.2`,levels:[`high`,`max`],default:`high`}]}},{id:`volcengine`,name:`Volcengine Ark (Doubao)`,name_zh:`火山方舟(豆包)`,protocol:`openai`,base_url:`https://ark.cn-beijing.volces.com/api/v3`,key_url:`https://console.volcengine.com/ark/region:ark+cn-beijing/apiKey`,key_hint:`xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx`,auth:[`key`],regions:[`cn`],capabilities:[`chat`,`vision`,`image`],defaults:{chat:`doubao-seed-2-0-pro-260215`,hands:`doubao-seed-2-0-pro-260215`,image:`doubao-seedream-5-0-lite-260128`},note:`Model ids are dated deployments; the live list has the exact ones. Doubao Seed 2.0 reads pictures; Seedream draws them through /images/generations. Seedance video uses Ark's own task API, which nanoMuse does not speak, so clips are left out.`,note_zh:`模型 id 带日期后缀,以实时列表为准。豆包 Seed 2.0 能看图;Seedream 画图走 /images/generations。Seedance 视频走方舟自己的任务接口,nanoMuse 还不支持,所以不列视频。`,verified:`2026-10`,reasoning:{doc:`https://docs.volcengine.com/docs/ark/model-parameter-support?lang=zh`,wire:`reasoning_effort`,rules:[{models:`^doubao-seed-2-`,levels:[`minimal`,`low`,`medium`,`high`],default:`high`},{models:`^deepseek-v4-`,levels:[`low`,`high`,`max`],default:`high`},{models:`^glm-5-2`,levels:[`high`,`max`],default:`max`}]}},{id:`minimax`,name:`MiniMax`,name_zh:`MiniMax(稀宇科技)`,protocol:`openai`,base_url:`https://api.minimaxi.com/v1`,base_url_global:`https://api.minimax.io/v1`,key_url:`https://platform.minimaxi.com/user-center/basic-information/interface-key`,key_hint:`eyJ…`,auth:[`key`],regions:[`cn`,`global`],capabilities:[`chat`,`vision`],defaults:{chat:`MiniMax-M3`,hands:`MiniMax-M3`},note:`Two editions: api.minimaxi.com for mainland China, api.minimax.io elsewhere. MiniMax-M3 reads pictures; the M2 series is text only.`,note_zh:`两个版本:中国大陆用 api.minimaxi.com,海外用 api.minimax.io。MiniMax-M3 能看图;M2 系列只处理文字。`,verified:`2026-10`,reasoning:{doc:`https://platform.minimax.io/docs/api-reference/text-chat`,wire:`reasoning_effort`,rules:[{models:`^MiniMax-M3\\.1`,levels:[`low`,`medium`,`high`,`xhigh`,`max`],default:`max`}]}},{id:`openrouter`,name:`OpenRouter`,name_zh:`OpenRouter`,protocol:`openai`,base_url:`https://openrouter.ai/api/v1`,key_url:`https://openrouter.ai/keys`,key_hint:`sk-or-v1-…`,auth:[`key`,`oauth-openrouter`],regions:[`global`],capabilities:[`chat`,`vision`,`image`],defaults:{chat:`deepseek/deepseek-v4.1-flash`,hands:`qwen/qwen3.8-27b`,image:`openai/gpt-image-2`},note:`One account, one key, pay as you go, international cards; models carry the maker's prefix. Pictures only through image-output models (openai/gpt-image-2, google/gemini-2.5-flash-image, bytedance-seed/seedream-4.5) on OpenRouter's Image API (/api/v1/images). The phone apps can sign in to OpenRouter instead of pasting a key.`,note_zh:`一个账号一把 key,按量付费,国际信用卡;模型带厂商前缀。画图只能用出图模型(openai/gpt-image-2、google/gemini-2.5-flash-image、bytedance-seed/seedream-4.5),走 OpenRouter 的图像接口(/api/v1/images)。手机 App 可以直接登录 OpenRouter,不用贴 key。`,verified:`2026-10`,reasoning:{doc:`https://openrouter.ai/docs/use-cases/reasoning-tokens`,wire:`reasoning.effort`,listed:!0,rules:[]}},{id:`openai`,name:`OpenAI`,name_zh:`OpenAI`,protocol:`openai`,base_url:`https://api.openai.com/v1`,key_url:`https://platform.openai.com/api-keys`,key_hint:`sk-proj-…`,auth:[`key`,`oauth-chatgpt`],auth_capabilities:{"oauth-chatgpt":[`chat`,`vision`]},regions:[`global`],capabilities:[`chat`,`vision`,`image`],defaults:{chat:`gpt-5.4-mini`,hands:`gpt-5.4`,image:`gpt-image-2.5-flare`},note:`With an API key: chat, hands and pictures (gpt-image-2.5-flare / gpt-image-2 through /images/generations). Signed in with a ChatGPT plan (the Codex OAuth): chat and hands only; the Codex backend has no image or video endpoints. OpenAI's terms cover using a ChatGPT plan inside OpenAI's own Codex; other apps have had this access cut off before (OpenCode, January 2026). If it stops working, an API key does.`,note_zh:`用 API key:对话、手、画图(gpt-image-2.5-flare / gpt-image-2,走 /images/generations)。用 ChatGPT 订阅登录(Codex 的 OAuth):只有对话和手,Codex 后端没有图像和视频接口。OpenAI 的条款只允许在它自己的 Codex 里使用 ChatGPT 订阅;其他应用的这条路曾被切断过(OpenCode,2026 年 1 月)。如果哪天不能用了,API key 还能用。`,verified:`2026-10`,reasoning:{doc:`https://developers.openai.com/api/docs/guides/reasoning`,wire:`reasoning_effort`,rules:[{models:`^o[1-9]`,levels:[`low`,`medium`,`high`],default:`medium`},{models:`^gpt-5(-|$)`,levels:[`minimal`,`low`,`medium`,`high`],default:`medium`},{models:`^gpt-5\\.1(-|$)`,levels:[`low`,`medium`,`high`],default:`none`},{models:`^gpt-5\\.4`,levels:[`low`,`medium`,`high`,`xhigh`],default:`none`},{models:`^gpt-5\\.[235-9]`,levels:[`low`,`medium`,`high`,`xhigh`]},{models:`^gpt-6`,levels:[`low`,`medium`,`high`,`xhigh`]}]}},{id:`anthropic`,name:`Anthropic Claude`,name_zh:`Anthropic Claude`,protocol:`anthropic`,base_url:`https://api.anthropic.com`,key_url:`https://platform.claude.com/settings/keys`,key_hint:`sk-ant-…`,auth:[`key`,`oauth-claude`],regions:[`global`],capabilities:[`chat`,`vision`],defaults:{chat:`claude-sonnet-5-5`,hands:`claude-sonnet-5-5`},note:`The Messages API, not OpenAI's shape; every current Claude model reads pictures. No image or video models. The phone apps can sign in with a Claude account instead of a key.`,note_zh:`用的是 Messages 接口,不是 OpenAI 格式;现行 Claude 模型都能看图。没有图像和视频模型。手机 App 可以用 Claude 账号登录,不用贴 key。`,verified:`2026-10`,reasoning:{doc:`https://docs.claude.com/en/docs/build-with-claude/effort`,wire:`output_config.effort`,rules:[{models:`^claude-(opus|haiku)-5-5`,levels:[`low`,`medium`,`high`,`xhigh`,`max`],default:`medium`},{models:`^claude-(opus|sonnet)-4-6`,levels:[`low`,`medium`,`high`,`max`],default:`high`},{models:`^claude-(opus-4-[78]|opus-5|sonnet-5|haiku-5|fable-5|mythos-5)`,levels:[`low`,`medium`,`high`,`xhigh`,`max`],default:`high`}]}},{id:`gemini`,name:`Google Gemini`,name_zh:`Google Gemini`,protocol:`gemini`,base_url:`https://generativelanguage.googleapis.com/v1beta/openai`,key_url:`https://aistudio.google.com/apikey`,key_hint:`AIza…`,auth:[`key`],regions:[`global`],capabilities:[`chat`,`vision`,`image`],defaults:{chat:`gemini-3.8-flash`,hands:`gemini-3.8-flash`,image:`gemini-2.5-flash-image`},note:`Google's OpenAI-compatible layer. Gemini models read pictures. Pictures through /images/generations work with gemini-2.5-flash-image and gemini-3-pro-image-preview only; the newer 3.1 image models are not served there. Veo video is not on the compatible layer, so clips are left out.`,note_zh:`Google 的 OpenAI 兼容层。Gemini 模型能看图。走 /images/generations 画图只支持 gemini-2.5-flash-image 和 gemini-3-pro-image-preview,更新的 3.1 出图模型不在兼容层上。Veo 视频不走兼容层,所以不列视频。`,verified:`2026-10`,reasoning:{doc:`https://ai.google.dev/gemini-api/docs/openai`,wire:`reasoning_effort`,rules:[{models:`^gemini-(2\\.5|3)`,levels:[`low`,`medium`,`high`]}]}},{id:`xai`,name:`xAI Grok`,name_zh:`xAI Grok`,protocol:`openai`,base_url:`https://api.x.ai/v1`,key_url:`https://console.x.ai`,key_hint:`xai-…`,auth:[`key`],regions:[`global`],capabilities:[`chat`,`vision`,`image`],defaults:{chat:`grok-4.7`,hands:`grok-4.7`,image:`grok-imagine-image-2.0`},note:`grok-4.7 reads pictures (JPEG and PNG). Pictures through /images/generations with grok-imagine-image-2.0. Grok Imagine video uses xAI's own endpoints, so clips are left out.`,note_zh:`grok-4.7 能看图(JPEG、PNG)。画图走 /images/generations,模型 grok-imagine-image-2.0。Grok Imagine 视频走 xAI 自己的接口,所以不列视频。`,verified:`2026-10`,reasoning:{doc:`https://docs.x.ai/docs/guides/reasoning`,wire:`reasoning_effort`,rules:[{models:`^grok-4\\.5`,levels:[`low`,`medium`,`high`],default:`high`},{models:`^grok-4\\.[6-9]`,levels:[`low`,`medium`,`high`,`xhigh`],default:`high`}]}},{id:`groq`,name:`Groq`,name_zh:`Groq`,protocol:`openai`,base_url:`https://api.groq.com/openai/v1`,key_url:`https://console.groq.com/keys`,key_hint:`gsk_…`,auth:[`key`],regions:[`global`],capabilities:[`chat`,`vision`],defaults:{chat:`openai/gpt-oss-120b`,hands:`qwen/qwen3.8-27b`},note:`Fast hosting of open models. qwen/qwen3.8-27b reads pictures; gpt-oss and Llama do not. No image or video models.`,note_zh:`开源模型的高速托管。qwen/qwen3.8-27b 能看图;gpt-oss 和 Llama 不能。没有图像和视频模型。`,verified:`2026-10`,reasoning:{doc:`https://console.groq.com/docs/reasoning`,wire:`reasoning_effort`,rules:[{models:`^openai/gpt-oss-`,levels:[`low`,`medium`,`high`]},{models:`^qwen/qwen3\\.8`,levels:[`low`,`medium`,`high`],default:`none`}]}},{id:`mistral`,name:`Mistral AI`,name_zh:`Mistral AI`,protocol:`openai`,base_url:`https://api.mistral.ai/v1`,key_url:`https://console.mistral.ai/api-keys`,key_hint:`…`,auth:[`key`],regions:[`global`],capabilities:[`chat`,`vision`],defaults:{chat:`mistral-medium-2508`,hands:`mistral-medium-2508`},note:`mistral-large-2512, mistral-medium-2508, mistral-small-2506 and the Ministral 3 models read pictures. No image or video models.`,note_zh:`mistral-large-2512、mistral-medium-2508、mistral-small-2506 和 Ministral 3 系列能看图。没有图像和视频模型。`,verified:`2026-10`,reasoning:{doc:`https://docs.mistral.ai/capabilities/reasoning/`,wire:`reasoning_effort`,rules:[{models:`^mistral-(small-latest|medium-3-5|large-4-0)`,levels:[`high`],default:`none`},{models:`^zai-glm-5-3`,levels:[`low`,`high`,`max`]}]}},{id:`opencode-zen`,name:`OpenCode Zen`,name_zh:`OpenCode Zen`,protocol:`openai`,base_url:`https://opencode.ai/zen/v1`,key_url:`https://opencode.ai/auth`,auth:[`key`],regions:[`global`],capabilities:[`chat`],defaults:{chat:`deepseek-v4.1-flash`},note:`OpenCode's own gateway: pay per request from a balance, a key made in the OpenCode console, and a few free models beside the paid ones. Chat answers on the OpenAI shape; the GPT, Claude and Gemini ids on the same host speak the Responses, Messages and Google shapes, which this entry does not reach, and the vision model OpenCode lists is deepseek-v4-flash-vision-exp, the id DeepSeek has retired on its own platform, so the hands are not claimed here. OpenCode publishes no plan sign-in, only a key.`,note_zh:`OpenCode 自己的网关:按请求从余额里扣费,key 在 OpenCode 控制台申请,付费模型之外还有几个免费的。对话走 OpenAI 格式;同一域名上的 GPT、Claude、Gemini 走 Responses、Messages 和 Google 格式,本条目到不了;它列的视觉模型是 deepseek-v4-flash-vision-exp,这个 id 在 DeepSeek 自家平台上已经退役,所以「动手」不列入。OpenCode 没有套餐登录,只有 key。`,verified:`2026-10`},{id:`opencode-go`,name:`OpenCode Go`,name_zh:`OpenCode Go`,protocol:`openai`,base_url:`https://opencode.ai/zen/go/v1`,key_url:`https://opencode.ai/auth`,auth:[`key`],regions:[`global`],capabilities:[`chat`],defaults:{chat:`deepseek-v4.1-flash`},session_header:`x-opencode-session`,note:`A subscription for coding agents: Go ($10 a month) or Go Plus ($40) in the OpenCode console, then a key made there; usage is counted per model against monthly, weekly and five hour limits. OpenCode asks every client to name itself and to send one stable id per conversation in x-opencode-session: the runtime sends both, the desktop reaches Go through its model adapter's own OpenCode Go route, which sends the id and speaks each model's shape, and the phone apps send an id per chat (a hash of its first message, the same on every turn). Outside the desktop only the OpenAI shape is reached, which is where the open coding models answer; the GPT, Grok, Claude, MiniMax and Qwen ids speak the Responses and Messages shapes. The one vision model OpenCode lists (deepseek-v4-flash-vision-exp) is an id DeepSeek has retired on its own platform, so the hands are not claimed here. OpenCode publishes no plan sign-in, only a key.`,note_zh:`面向编程智能体的订阅:在 OpenCode 控制台订阅 Go(每月 10 美元)或 Go Plus(每月 40 美元),再在那里申请 key;用量按模型计,分每月、每周和每 5 小时三档上限。OpenCode 要求每个客户端说明自己是谁,并在 x-opencode-session 里为每个对话带上一个固定的 id:运行时两样都发;桌面版通过模型适配器自带的 OpenCode Go 路由访问,这条路由会带上 id,也按每个模型自己的格式说话;手机端为每个聊天带一个 id(由第一条消息算出,每一轮都一样)。桌面版以外只走 OpenAI 格式,开源编程模型都在这个格式上;GPT、Grok、Claude、MiniMax 和 Qwen 走 Responses 和 Messages 格式。它列的那个视觉模型(deepseek-v4-flash-vision-exp)在 DeepSeek 自家平台上已经退役,所以「动手」不列入。OpenCode 没有套餐登录,只有 key。`,verified:`2026-10`},{id:`ollama`,name:`Ollama`,name_zh:`Ollama(本机)`,protocol:`openai`,base_url:`http://127.0.0.1:11434/v1`,key_url:`https://ollama.com/download`,auth:[`none`],regions:[`cn`,`global`],capabilities:[`chat`],defaults:{chat:`qwen3:8b`},note:`Runs on this machine, no key, nothing leaves it. Hands need a model that reads pictures (a vision model such as a Qwen VL build); the model list says which.`,note_zh:`跑在本机,不要 key,什么都不出去。手需要能看图的模型(例如 Qwen 的 VL 版本),模型列表里能看出来。`,verified:`2026-10`,reasoning:{doc:`https://docs.ollama.com/api/openai-compatibility`,wire:`reasoning_effort`,rules:[{models:`gpt-oss`,levels:[`low`,`medium`,`high`]}]}},{id:`lm-studio`,name:`LM Studio`,name_zh:`LM Studio(本机)`,protocol:`openai`,base_url:`http://127.0.0.1:1234/v1`,key_url:`https://lmstudio.ai`,auth:[`none`],regions:[`cn`,`global`],capabilities:[`chat`],defaults:{},note:`LM Studio's local server, OpenAI-compatible, no key. Vision only if the loaded model has it.`,note_zh:`LM Studio 的本地服务,OpenAI 兼容,不要 key。装了能看图的模型才能用手。`,verified:`2026-10`},{id:`vllm`,name:`vLLM`,name_zh:`vLLM(自建)`,protocol:`openai`,base_url:`http://127.0.0.1:8000/v1`,key_url:`https://docs.vllm.ai`,auth:[`none`,`key`],regions:[`cn`,`global`],capabilities:[`chat`],defaults:{},note:`A vLLM server you run yourself; a key only if you started it with one. Vision only if the served model has it.`,note_zh:`自己跑的 vLLM 服务;启动时设了 key 才需要填。服务的模型能看图才能用手。`,verified:`2026-10`,reasoning:{doc:`https://docs.vllm.ai/en/latest/features/reasoning_outputs/`,wire:`reasoning_effort`,rules:[{models:`gpt-oss`,levels:[`low`,`medium`,`high`]}]}},{id:`custom`,name:`Any OpenAI-compatible endpoint`,name_zh:`任何 OpenAI 兼容接口`,protocol:`openai`,base_url:``,key_url:``,auth:[`key`,`none`],regions:[`cn`,`global`],capabilities:[`chat`],user_capabilities:!0,defaults:{},note:`A gateway, a relay, a server of your own: paste the address (usually ending in /v1) and say what it can do; the person sets the capabilities.`,note_zh:`网关、中转、自己的服务:贴地址(一般以 /v1 结尾),再说明它能做什么,能力由你勾选。`,verified:`2026-10`}]};function h(e){return e?.region?e.region===`cn`:e?.signed_in&&e.channel===`sms`?!0:r()===`zh-CN`}function re(e){return/^\s*(\+|00)(?!86\b)\d/.test(e)}var ie=new Map(m.providers.map(e=>[e.id,e]));function g(e,t){let n=ie.get(e);if(!n)throw Error(`providers.json has no ${e}`);return{id:e,preset:t,label:n.name,keyUrl:n.key_url,baseUrl:n.base_url,chatModel:n.defaults.chat??``,guiModel:n.defaults.hands??n.defaults.chat??``,covers:n.capabilities}}var ae=g(`bailian`,`qwen`),oe=g(`openrouter`,`openrouter`);function _(e){return h(e)?ae:oe}function se(e,t){return h(t)?e(`Alibaba Cloud Bailian is a good start: a new account comes with a free quota, set-up takes about two minutes, and one key covers chat, the hands, pictures and clips.`):e(`Alibaba Cloud Bailian only signs up accounts from mainland China. Outside, OpenRouter is the easy way: one account, one key, pay as you go, for chat, the hands and pictures; clips need Bailian.`)}function ce(e){let t=(e||``).toLowerCase().split(`/`).pop()??``;return t?t.startsWith(`deepseek`)?/v4\.1|vision|ocr/.test(t):t.startsWith(`qwen`)&&(t.includes(`-vl`)||t.startsWith(`qwen3.8`))?!0:null:null}function le(e,t,n){let r=_(n).preset;if(!e.includes(r))return e;let i=h(n),a=e.filter(e=>e!==r);if(i)return[r,...a];let o=a.filter(e=>t[e]?.region===`cn`);return[r,...a.filter(e=>!o.includes(e)),...o]}var ue=[`chat`,`vision`,`image`,`video`],v=m.providers,de=[`ollama`,`lm-studio`,`vllm`],fe={cn:[`bailian`],global:[`openrouter`,`openai`]},y={bailian:`qwen`,moonshot:`kimi`,zhipu:`glm`,volcengine:`doubao`};function pe(e){return y[e]??e}function me(e){return Object.entries(y).find(([,t])=>t===e)?.[0]??(e===`openai_responses`?`openai`:e)}function he(e){return h(e)?`cn`:`global`}function b(e,t){return t===`zh-CN`&&e.name_zh||e.name}function ge(e,t){return t===`global`&&e.regions.includes(`global`)&&e.base_url_global?{base_url:e.base_url_global,key_url:e.key_url_global||e.key_url}:{base_url:e.base_url,key_url:e.key_url}}function x(e,t){return e.regions.includes(t)}function S(e,t,n=v){let r=new Map(n.map(e=>[e.id,e])),i=fe[e].map(e=>r.get(e)).filter(t=>!!t&&x(t,e)),a=n.filter(t=>!i.includes(t)&&!de.includes(t.id)&&t.id!==`custom`&&x(t,e)).sort((e,t)=>t.capabilities.length-e.capabilities.length),o=[...i,...a];return t?o.filter(e=>e.capabilities.includes(t)):o}function _e(e=v){let t=[{id:`chatgpt`,provider:`openai`,name:`ChatGPT`,auth:`oauth-chatgpt`,here:!0},{id:`claude`,provider:`anthropic`,name:`Claude`,auth:`oauth-claude`,here:!1},{id:`kimi`,provider:`moonshot`,name:`Kimi`,auth:`device-kimi`,here:!1},{id:`openrouter`,provider:`openrouter`,name:`OpenRouter`,auth:`oauth-openrouter`,here:!1}],n=[];for(let r of t){let t=e.find(e=>e.id===r.provider);t&&t.auth.includes(r.auth)&&n.push({...r,covers:t.auth_capabilities?.[r.auth]??t.capabilities})}return n}function ve(e,t){switch(t){case`chat`:return e(`Chat`);case`vision`:return e(`Hands`);case`image`:return e(`Pictures`);case`video`:return e(`Clips`)}}function ye(e,t){return e(`covers {list}`,{list:ue.filter(e=>t.includes(e)).map(t=>ve(e,t).toLowerCase()).join(e(`, `))})}function be(e,t,n,r,i=v){let a=S(n,t,i).slice(0,4).map(e=>b(e,r)),o=a.pop()??``,s=a.length?`${a.join(e(`, `))}${e(` or `)}${o}`:o;switch(t){case`image`:return e(`Pictures need a provider with image models: {providers}.`,{providers:s});case`video`:return e(`Clips need a provider with video models: {providers}.`,{providers:s});case`vision`:return e(`The hands need a model that sees pictures: {providers}.`,{providers:s});case`chat`:return e(`Chat needs a model: {providers}.`,{providers:s})}}var xe=`https://nanomuse.cn/own-key`,C=null,w=null;async function Se(e=!1){return C&&!e?C:(w&&!e||(w=c.providers().then(e=>({...e,capabilities:e.capabilities??null,source:`runtime`})).catch(()=>({providers:v,region:``,configured:{},capabilities:null,unavailable:{},source:`bundled`})).then(e=>(C=e,w=null,e))),w)}function Ce(){C=null}function we(e=0){let[t,n]=(0,p.useState)(C);return(0,p.useEffect)(()=>{let t=!0;return Se(e>0).then(e=>t&&n(e)),()=>{t=!1}},[e]),t}function Te(e,t){return!e||e.capabilities===null?null:e.capabilities.includes(t)}var T={version:1,star:{enabled:!0,url:`https://github.com/nano-muse/nanoMuse`,moments:{signed_in:!0,tasks:[3,10,30],new_look:!0,exhausted:!0,days_used:[7,30],goal_done:!0},cooldown_days:7,max_asks:4,text:``,text_zh:``}},Ee=864e5;function E(e){if(typeof e!=`string`)return``;let t=e.trim();return t.length<=200?t:``}function De(e,t,n){let{text:r,text_zh:i}=e.star;return t&&i?i:r||n}var D=e=>typeof e==`object`&&!!e&&!Array.isArray(e),O=(e,t)=>typeof e==`boolean`?e:t,k=(e,t,n,r)=>typeof e==`number`&&Number.isFinite(e)&&Math.trunc(e)>=t&&Math.trunc(e)<=n?Math.trunc(e):r;function A(e,t){if(!Array.isArray(e))return t;let n=new Set;for(let r of e){if(typeof r!=`number`||!Number.isFinite(r)||Math.trunc(r)<1)return t;n.add(Math.trunc(r))}return[...n].sort((e,t)=>e-t)}function Oe(e){let t=T.star;if(!D(e))return structuredClone(T);let n=k(e.version,1,1e9,1),r=D(e.star)?e.star:{},i=D(r.moments)?r.moments:{},a=typeof r.url==`string`&&/^https?:\/\//.test(r.url)&&r.url.length<=200?r.url:t.url;return{version:n,star:{enabled:O(r.enabled,t.enabled),url:a,moments:{signed_in:O(i.signed_in,t.moments.signed_in),tasks:A(i.tasks,t.moments.tasks),new_look:O(i.new_look,t.moments.new_look),exhausted:O(i.exhausted,t.moments.exhausted),days_used:A(i.days_used,t.moments.days_used),goal_done:O(i.goal_done,t.moments.goal_done)},cooldown_days:k(r.cooldown_days,0,365,t.cooldown_days),max_asks:k(r.max_asks,0,50,t.max_asks),text:E(r.text),text_zh:E(r.text_zh)}}}var j={starred:`nm.star.starred`,tasks:`nm.star.tasks`,asks:`nm.star.asks`,lastAsk:`nm.star.last_ask`,shown:`nm.star.shown`,days:`nm.star.days`,lastDay:`nm.star.last_day`,migrated:`nm.star.v2`},ke=[`signed_in`,`first_task`,`tenth_task`,`new_look`],M=e=>{let t=Number(e);return Number.isFinite(t)&&t>=0?Math.trunc(t):0};function N(e){let t=[];try{let n=JSON.parse(e.getItem(j.shown)??`[]`);Array.isArray(n)&&(t=n.filter(e=>typeof e==`string`))}catch{t=[]}let n=e.getItem(j.lastAsk);return{starred:e.getItem(j.starred)===`1`,tasks:M(e.getItem(j.tasks)),asks:M(e.getItem(j.asks)),lastAsk:n&&M(n)||null,shown:t,days:M(e.getItem(j.days)),lastDay:e.getItem(j.lastDay)??``}}function P(e,t){e.setItem(j.starred,t.starred?`1`:`0`),e.setItem(j.tasks,String(t.tasks)),e.setItem(j.asks,String(t.asks)),t.lastAsk?e.setItem(j.lastAsk,String(t.lastAsk)):e.removeItem(j.lastAsk),e.setItem(j.shown,JSON.stringify(t.shown)),e.setItem(j.days,String(t.days)),e.setItem(j.lastDay,t.lastDay)}function Ae(e){let t=N(e);if(e.getItem(j.migrated)===`1`)return t;for(let n of ke){let r=`nm.star.${n}`;e.getItem(r)===`1`&&!t.shown.includes(n)&&(t.shown.push(n),t.asks+=1),e.removeItem(r)}return P(e,t),e.setItem(j.migrated,`1`),t}var F=(e,t)=>e===`tasks`||e===`days_used`?`${e}:${t??0}`:e;function je(e,t,n){let r=e.star;return!r.enabled||t.starred||t.asks>=r.max_asks?!1:t.lastAsk===null||n-t.lastAsk>=r.cooldown_days*Ee}function Me(e,t,n,r,i){if(!je(t,n,r))return!1;let a=t.star.moments;return(e===`tasks`||e===`days_used`?i!==void 0&&a[e].includes(i):a[e])&&!n.shown.includes(F(e,i))}function Ne(e,t,n){let r=N(e);return r.shown.includes(t)||(r.shown.push(t),r.asks+=1,r.lastAsk=n,P(e,r)),r}function Pe(e){let t=N(e);t.starred=!0,P(e,t)}function Fe(e){let t=N(e);return t.tasks+=1,P(e,t),t.tasks}var Ie=e=>`${e.getFullYear()}-${String(e.getMonth()+1).padStart(2,`0`)}-${String(e.getDate()).padStart(2,`0`)}`;function Le(e,t){let n=N(e),r=Ie(t);return n.lastDay===r?{days:n.days,fresh:!1}:(n.days+=1,n.lastDay=r,P(e,n),{days:n.days,fresh:!0})}var I=s(),Re=`https://github.com/nano-muse/nanoMuse`,ze=`https://github.com/nano-muse/nanoMuse/issues/new/choose`,L=`https://nanomuse.cn/#open-source`;function Be({compact:t=!1,className:r}){let i=n();return(0,I.jsxs)(`section`,{className:e(`rounded-[22px] border border-accent/25 bg-accent/[0.06] p-4 dark:bg-accent/[0.10]`,r),children:[(0,I.jsxs)(`a`,{href:L,target:`_blank`,rel:`noreferrer`,className:`flex items-start gap-2 text-[13.5px] font-semibold hover:text-accent`,children:[(0,I.jsx)(d,{size:16,className:`mt-0.5 shrink-0 text-accent`}),(0,I.jsx)(`span`,{className:`min-w-0 flex-1 leading-snug`,children:i(`Free, open source, non-profit`)}),(0,I.jsx)(ee,{size:12,className:`mt-1 shrink-0 text-muted`})]}),(0,I.jsx)(`p`,{className:e(`mt-1.5 leading-relaxed text-fg/85`,t?`text-[12.5px]`:`text-[13px]`),children:i(`nanoMuse is a non-profit open-source community project, free forever. Sign in with a phone number or an e-mail and the model comes with a free allowance, paid by the developer; when it is gone, use your own key (Alibaba Cloud Bailian in mainland China, OpenRouter elsewhere). Nothing is sold; what the relay keeps is in the privacy policy, and Settings → Data controls is yours. Delete the account whenever you like.`)}),(0,I.jsx)(`p`,{className:e(`mt-1.5 leading-relaxed text-fg/85`,t?`text-[12.5px]`:`text-[13px]`),children:i(`The people building it use it every day. Report a bug, ask for a feature, send a pull request: that is what moves the project. A star on GitHub helps others find it.`)}),(0,I.jsxs)(`div`,{className:`mt-3 flex flex-wrap gap-2 text-[12.5px] font-medium`,children:[(0,I.jsxs)(`a`,{href:Re,target:`_blank`,rel:`noreferrer`,onClick:K,className:`inline-flex items-center gap-1.5 rounded-full bg-fg px-3 py-1.5 text-bg hover:opacity-90`,children:[(0,I.jsx)(ne,{size:13}),` `,i(`Star on GitHub`)]}),(0,I.jsxs)(`a`,{href:ze,target:`_blank`,rel:`noreferrer`,className:`inline-flex items-center gap-1.5 rounded-full border border-border bg-surface px-3 py-1.5 text-fg hover:bg-surface-2`,children:[(0,I.jsx)(u,{size:13}),` `,i(`Report a bug or ask for a feature`)]})]})]})}var R=new Map,z={getItem:e=>{try{return localStorage.getItem(e)}catch{return R.get(e)??null}},setItem:(e,t)=>{try{localStorage.setItem(e,t)}catch{R.set(e,t)}},removeItem:e=>{try{localStorage.removeItem(e)}catch{R.delete(e)}}},B=!1;function Ve(){return B?N(z):(B=!0,Ae(z))}var V=T,H=!1,U=null,W=new Set;function He(){return U??=c.nudges().then(e=>{V=Oe(e?.policy)}).catch(()=>{V=T}).finally(()=>{H=!0,W.forEach(e=>e())}),U}function G(){let[,e]=(0,p.useState)(0);return(0,p.useEffect)(()=>{let t=()=>e(e=>e+1);return W.add(t),He(),()=>{W.delete(t)}},[]),{policy:V,ready:H}}var Ue=()=>Fe(z),We=()=>Le(z,new Date),Ge=(e,t)=>H&&Me(e,V,Ve(),Date.now(),t),Ke=(e,t)=>{Ne(z,F(e,t),Date.now())},K=()=>Pe(z);function q(e){K(),window.open(e||V.star.url||`https://github.com/nano-muse/nanoMuse`,`_blank`,`noopener,noreferrer`)}function J(e,t,n){switch(t){case`signed_in`:return e(`Welcome. nanoMuse is free, open source and non-profit, a personal agent for anyone who runs it. If that is worth something to you, a star on GitHub is how the next person finds it.`);case`tasks`:return n===3?e(`Three tasks done. If nanoMuse is useful, a star on GitHub helps the next person find it.`):n===10?e(`Ten tasks together. If nanoMuse has become part of your day, a star on GitHub tells others it is worth a try.`):e(`{n} tasks done. If nanoMuse is useful, a star on GitHub helps the next person find it.`,{n:n??0});case`new_look`:return e(`A new face, drawn for you. If you like where nanoMuse is going, a star on GitHub helps more people find it.`);case`exhausted`:return e(`The free allowance is used up. Thank you for coming this far. If nanoMuse has earned it, a star on GitHub keeps the project in view for the next person.`);case`days_used`:return n===7?e(`A week with nanoMuse. If it has earned a place in your day, a star on GitHub helps the next person find it.`):n===30?e(`A month with nanoMuse. If it has become part of your routine, a star on GitHub tells others it is worth a try.`):e(`{n} days with nanoMuse. If it has earned a place in your day, a star on GitHub helps the next person find it.`,{n:n??0});case`goal_done`:return e(`Goal reached. If nanoMuse helped you get there, a star on GitHub tells the people building it that it did.`)}}var Y=null,X=null;function Z(){let[e,t]=(0,p.useState)(Y??{});return(0,p.useEffect)(()=>{if(Y)return;X??=c.cloudConfig().then(e=>Y=e&&typeof e==`object`?e:{}).catch(()=>Y={});let e=!0;return X.then(n=>e&&t(n)),()=>{e=!1}},[]),e}function Q(e){let{policy:t}=G();return De(t,a()===`zh-CN`,e)}function qe({text:t,onDone:r,className:i}){let a=n(),o=Z(),s=Q(t);return(0,I.jsxs)(`section`,{className:e(`rounded-[22px] border border-amber-400/40 bg-amber-50/70 p-4 dark:bg-amber-400/[0.08]`,i),children:[(0,I.jsxs)(`div`,{className:`flex items-start gap-2.5`,children:[(0,I.jsx)(f,{size:18,className:`mt-0.5 shrink-0 text-amber-500`}),(0,I.jsxs)(`div`,{className:`min-w-0 flex-1`,children:[(0,I.jsx)(`div`,{className:`text-[14px] font-semibold leading-snug`,children:a(`A star on GitHub helps`)}),(0,I.jsx)(`p`,{className:`mt-1 text-[13px] leading-relaxed text-fg/85`,children:s})]})]}),(0,I.jsxs)(`div`,{className:`mt-3 flex flex-wrap gap-2 pl-7`,children:[(0,I.jsx)(`button`,{type:`button`,className:e(te,`!w-auto !py-1.5 !px-3.5 text-[13px]`),onClick:()=>{q(o.repo_url),r()},children:a(`Star on GitHub`)}),(0,I.jsx)(`button`,{type:`button`,className:e(l,`!w-auto !py-1.5 !px-3.5 text-[13px]`),onClick:r,children:a(`Not now`)}),(0,I.jsx)(`button`,{type:`button`,className:e(l,`!w-auto !py-1.5 !px-3.5 text-[13px]`),onClick:()=>{K(),r()},children:a(`I already starred`)})]})]})}function Je({moment:e,n:t,text:r,className:i,due:a=!0}){let o=n(),[s,c]=$(e,a,t);return s?(0,I.jsx)(qe,{text:r??J(o,e,t),onDone:()=>c(!1),className:i}):null}function $(e,t=!0,n){let{ready:r}=G(),[i,a]=(0,p.useState)(!1);return(0,p.useEffect)(()=>{t&&r&&!i&&Ge(e,n)&&(Ke(e,n),a(!0))},[t,r,e,n,i]),[i,a]}export{se as A,he as C,re as D,h as E,f as M,d as N,ce as O,u as P,S,we as T,Te as _,q as a,pe as b,$ as c,L as d,v as f,ge as g,ye as h,K as i,_ as j,le as k,Q as l,me as m,We as n,J as o,xe as p,Ue as r,Z as s,Je as t,Be as u,Ce as v,be as w,b as x,_e as y}; \ No newline at end of file +import{E as e,J as t,K as n,L as r,Q as i,W as a,Y as o,b as s,x as c}from"./MuseHeader-BDWXHKHT.js";import{t as ee}from"./external-link-CZH-rQLq.js";import{a as l,i as te}from"./Form-B3Ejw5aI.js";var u=t(`bug`,[[`path`,{d:`M12 20v-9`,key:`1qisl0`}],[`path`,{d:`M14 7a4 4 0 0 1 4 4v3a6 6 0 0 1-12 0v-3a4 4 0 0 1 4-4z`,key:`uouzyp`}],[`path`,{d:`M14.12 3.88 16 2`,key:`qol33r`}],[`path`,{d:`M21 21a4 4 0 0 0-3.81-4`,key:`1b0z45`}],[`path`,{d:`M21 5a4 4 0 0 1-3.55 3.97`,key:`5cxbf6`}],[`path`,{d:`M22 13h-4`,key:`1jl80f`}],[`path`,{d:`M3 21a4 4 0 0 1 3.81-4`,key:`1fjd4g`}],[`path`,{d:`M3 5a4 4 0 0 0 3.55 3.97`,key:`1d7oge`}],[`path`,{d:`M6 13H2`,key:`82j7cp`}],[`path`,{d:`m8 2 1.88 1.88`,key:`fmnt4t`}],[`path`,{d:`M9 7.13V6a3 3 0 1 1 6 0v1.13`,key:`1vgav8`}]]),ne=t(`github`,[[`path`,{d:`M15 22v-4a4.8 4.8 0 0 0-1-3.5c3 0 6-2 6-5.5.08-1.25-.27-2.48-1-3.5.28-1.15.28-2.35 0-3.5 0 0-1 0-3 1.5-2.64-.5-5.36-.5-8 0C6 2 5 2 5 2c-.3 1.15-.3 2.35 0 3.5A5.403 5.403 0 0 0 4 9c0 3.5 3 5.5 6 5.5-.39.49-.68 1.05-.85 1.65-.17.6-.22 1.23-.15 1.85v4`,key:`tonef`}],[`path`,{d:`M9 18c-4.51 2-5-2-7-2`,key:`9comsn`}]]),d=t(`heart-handshake`,[[`path`,{d:`M19.414 14.414C21 12.828 22 11.5 22 9.5a5.5 5.5 0 0 0-9.591-3.676.6.6 0 0 1-.818.001A5.5 5.5 0 0 0 2 9.5c0 2.3 1.5 4 3 5.5l5.535 5.362a2 2 0 0 0 2.879.052 2.12 2.12 0 0 0-.004-3 2.124 2.124 0 1 0 3-3 2.124 2.124 0 0 0 3.004 0 2 2 0 0 0 0-2.828l-1.881-1.882a2.41 2.41 0 0 0-3.409 0l-1.71 1.71a2 2 0 0 1-2.828 0 2 2 0 0 1 0-2.828l2.823-2.762`,key:`17lmqv`}]]),f=t(`star`,[[`path`,{d:`M11.525 2.295a.53.53 0 0 1 .95 0l2.31 4.679a2.123 2.123 0 0 0 1.595 1.16l5.166.756a.53.53 0 0 1 .294.904l-3.736 3.638a2.123 2.123 0 0 0-.611 1.878l.882 5.14a.53.53 0 0 1-.771.56l-4.618-2.428a2.122 2.122 0 0 0-1.973 0L6.396 21.01a.53.53 0 0 1-.77-.56l.881-5.139a2.122 2.122 0 0 0-.611-1.879L2.16 9.795a.53.53 0 0 1 .294-.906l5.165-.755a2.122 2.122 0 0 0 1.597-1.16z`,key:`r04s7s`}]]),p=i(o(),1),m={version:1,updated:`2026-10`,capabilities:[`chat`,`vision`,`image`,`video`],auth_kinds:[`key`,`none`,`oauth-chatgpt`,`oauth-claude`,`oauth-openrouter`,`device-kimi`],providers:[{id:`bailian`,name:`Alibaba Cloud Bailian`,name_zh:`阿里云百炼`,protocol:`openai`,base_url:`https://dashscope.aliyuncs.com/compatible-mode/v1`,key_url:`https://bailian.console.aliyun.com/?apiKey=1`,key_hint:`sk-…`,auth:[`key`],regions:[`cn`],capabilities:[`chat`,`vision`,`image`,`video`],defaults:{chat:`deepseek-v4.1-flash`,hands:`qwen3.8-27b`,image:`qwen-image-3.0`,video:`wan2.2-i2v-flash`},note:`One key for chat, hands, pictures and clips. Signs up accounts with a mainland China identity only; the international edition (dashscope-intl) does not carry these models. Pictures and clips go through Model Studio's own API, which nanoMuse speaks.`,note_zh:`一把 key 覆盖对话、手、画图和视频。只给中国大陆身份注册;国际版(dashscope-intl)没有这几个模型。画图和视频走百炼自己的接口,nanoMuse 已支持。`,verified:`2026-10`},{id:`deepseek`,name:`DeepSeek`,name_zh:`DeepSeek(深度求索)`,protocol:`openai`,base_url:`https://api.deepseek.com/v1`,key_url:`https://platform.deepseek.com/api_keys`,key_hint:`sk-…`,auth:[`key`],regions:[`cn`,`global`],capabilities:[`chat`,`vision`],defaults:{chat:`deepseek-flash`,hands:`deepseek-flash`},note:`deepseek-flash (DeepSeek-V4.1-Flash) reads pictures; deepseek-v4-pro is text only. No image or video models.`,note_zh:`deepseek-flash(DeepSeek-V4.1-Flash)能看图;deepseek-v4-pro 只处理文字。没有图像和视频模型。`,verified:`2026-10`,reasoning:{doc:`https://api-docs.deepseek.com/guides/thinking_mode`,wire:`thinking+reasoning_effort`,rules:[{models:`^deepseek-`,levels:[`low`,`high`,`max`],default:`high`}]}},{id:`moonshot`,name:`Kimi (Moonshot AI)`,name_zh:`Kimi(月之暗面)`,protocol:`openai`,base_url:`https://api.moonshot.cn/v1`,base_url_global:`https://api.moonshot.ai/v1`,key_url:`https://platform.moonshot.cn/console/api-keys`,key_url_global:`https://platform.kimi.ai/console`,key_hint:`sk-…`,auth:[`key`,`device-kimi`],regions:[`cn`,`global`],capabilities:[`chat`,`vision`],defaults:{chat:`kimi-k2.6`,hands:`kimi-k2.6`},note:`Two editions: api.moonshot.cn for mainland China, api.moonshot.ai elsewhere, each with its own console and keys. kimi-k2.6 and kimi-k3 read pictures. The phone apps can sign in with a Kimi account (device code) instead of a key.`,note_zh:`两个版本:中国大陆用 api.moonshot.cn,海外用 api.moonshot.ai,各自有控制台和 key。kimi-k2.6、kimi-k3 能看图。手机 App 可以用 Kimi 账号登录(设备码),不用贴 key。`,verified:`2026-10`,reasoning:{doc:`https://platform.moonshot.ai/docs/api/chat`,wire:`reasoning_effort`,rules:[{models:`^kimi-k3`,levels:[`low`,`high`,`max`],default:`max`}]}},{id:`zhipu`,name:`Zhipu GLM`,name_zh:`智谱 GLM`,protocol:`openai`,base_url:`https://open.bigmodel.cn/api/paas/v4`,key_url:`https://open.bigmodel.cn/usercenter/apikeys`,key_hint:`xxxxxxxx.xxxxxxxx`,auth:[`key`],regions:[`cn`],capabilities:[`chat`,`vision`,`image`],defaults:{chat:`glm-5.3`,hands:`glm-4.6v`,image:`glm-image`},note:`glm-4.6v reads pictures; pictures are drawn by glm-image or cogview-4 through /images/generations.`,note_zh:`glm-4.6v 能看图;画图用 glm-image 或 cogview-4,走 /images/generations。`,verified:`2026-10`,reasoning:{doc:`https://docs.bigmodel.cn/api-reference/%E6%A8%A1%E5%9E%8B-api/%E5%AF%B9%E8%AF%9D%E8%A1%A5%E5%85%A8`,wire:`thinking+reasoning_effort`,rules:[{models:`^glm-5\\.3`,levels:[`low`,`high`,`max`],default:`max`},{models:`^glm-5\\.2`,levels:[`high`,`max`],default:`max`}]}},{id:`siliconflow`,name:`SiliconFlow`,name_zh:`硅基流动`,protocol:`openai`,base_url:`https://api.siliconflow.cn/v1`,key_url:`https://cloud.siliconflow.cn/account/ak`,key_hint:`sk-…`,auth:[`key`],regions:[`cn`],capabilities:[`chat`,`vision`,`image`],defaults:{chat:`deepseek-ai/DeepSeek-V4-Flash`,hands:`Qwen/Qwen3-VL-32B-Instruct`,image:`Qwen/Qwen-Image`},note:`Many open models behind one key; model ids carry the maker's prefix. Pictures through /images/generations (Qwen-Image, Kolors, FLUX).`,note_zh:`一把 key 后面是许多开源模型,模型 id 带厂商前缀。画图走 /images/generations(Qwen-Image、Kolors、FLUX)。`,verified:`2026-10`,reasoning:{doc:`https://docs.siliconflow.cn/cn/api-reference/chat-completions/chat-completions`,wire:`reasoning_effort`,rules:[{models:`^(Pro/)?deepseek-ai/DeepSeek-V4(-|$)`,levels:[`high`,`max`],default:`high`},{models:`^Pro/zai-org/GLM-5\\.2`,levels:[`high`,`max`],default:`high`}]}},{id:`volcengine`,name:`Volcengine Ark (Doubao)`,name_zh:`火山方舟(豆包)`,protocol:`openai`,base_url:`https://ark.cn-beijing.volces.com/api/v3`,key_url:`https://console.volcengine.com/ark/region:ark+cn-beijing/apiKey`,key_hint:`xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx`,auth:[`key`],regions:[`cn`],capabilities:[`chat`,`vision`,`image`],defaults:{chat:`doubao-seed-2-0-pro-260215`,hands:`doubao-seed-2-0-pro-260215`,image:`doubao-seedream-5-0-lite-260128`},note:`Model ids are dated deployments; the live list has the exact ones. Doubao Seed 2.0 reads pictures; Seedream draws them through /images/generations. Seedance video uses Ark's own task API, which nanoMuse does not speak, so clips are left out.`,note_zh:`模型 id 带日期后缀,以实时列表为准。豆包 Seed 2.0 能看图;Seedream 画图走 /images/generations。Seedance 视频走方舟自己的任务接口,nanoMuse 还不支持,所以不列视频。`,verified:`2026-10`,reasoning:{doc:`https://docs.volcengine.com/docs/ark/model-parameter-support?lang=zh`,wire:`reasoning_effort`,rules:[{models:`^doubao-seed-2-`,levels:[`minimal`,`low`,`medium`,`high`],default:`high`},{models:`^deepseek-v4-`,levels:[`low`,`high`,`max`],default:`high`},{models:`^glm-5-2`,levels:[`high`,`max`],default:`max`}]}},{id:`minimax`,name:`MiniMax`,name_zh:`MiniMax(稀宇科技)`,protocol:`openai`,base_url:`https://api.minimaxi.com/v1`,base_url_global:`https://api.minimax.io/v1`,key_url:`https://platform.minimaxi.com/user-center/basic-information/interface-key`,key_hint:`eyJ…`,auth:[`key`],regions:[`cn`,`global`],capabilities:[`chat`,`vision`],defaults:{chat:`MiniMax-M3`,hands:`MiniMax-M3`},note:`Two editions: api.minimaxi.com for mainland China, api.minimax.io elsewhere. MiniMax-M3 reads pictures; the M2 series is text only.`,note_zh:`两个版本:中国大陆用 api.minimaxi.com,海外用 api.minimax.io。MiniMax-M3 能看图;M2 系列只处理文字。`,verified:`2026-10`,reasoning:{doc:`https://platform.minimax.io/docs/api-reference/text-chat`,wire:`reasoning_effort`,rules:[{models:`^MiniMax-M3\\.1`,levels:[`low`,`medium`,`high`,`xhigh`,`max`],default:`max`}]}},{id:`openrouter`,name:`OpenRouter`,name_zh:`OpenRouter`,protocol:`openai`,base_url:`https://openrouter.ai/api/v1`,key_url:`https://openrouter.ai/keys`,key_hint:`sk-or-v1-…`,auth:[`key`,`oauth-openrouter`],regions:[`global`],capabilities:[`chat`,`vision`,`image`],defaults:{chat:`deepseek/deepseek-v4.1-flash`,hands:`qwen/qwen3.8-27b`,image:`openai/gpt-image-2`},note:`One account, one key, pay as you go, international cards; models carry the maker's prefix. Pictures only through image-output models (openai/gpt-image-2, google/gemini-2.5-flash-image, bytedance-seed/seedream-4.5) on OpenRouter's Image API (/api/v1/images). The phone apps can sign in to OpenRouter instead of pasting a key.`,note_zh:`一个账号一把 key,按量付费,国际信用卡;模型带厂商前缀。画图只能用出图模型(openai/gpt-image-2、google/gemini-2.5-flash-image、bytedance-seed/seedream-4.5),走 OpenRouter 的图像接口(/api/v1/images)。手机 App 可以直接登录 OpenRouter,不用贴 key。`,verified:`2026-10`,reasoning:{doc:`https://openrouter.ai/docs/use-cases/reasoning-tokens`,wire:`reasoning.effort`,listed:!0,rules:[]}},{id:`openai`,name:`OpenAI`,name_zh:`OpenAI`,protocol:`openai`,base_url:`https://api.openai.com/v1`,key_url:`https://platform.openai.com/api-keys`,key_hint:`sk-proj-…`,auth:[`key`,`oauth-chatgpt`],auth_capabilities:{"oauth-chatgpt":[`chat`,`vision`]},regions:[`global`],capabilities:[`chat`,`vision`,`image`],defaults:{chat:`gpt-5.4-mini`,hands:`gpt-5.4`,image:`gpt-image-2.5-flare`},note:`With an API key: chat, hands and pictures (gpt-image-2.5-flare / gpt-image-2 through /images/generations). Signed in with a ChatGPT plan (the Codex OAuth): chat and hands only; the Codex backend has no image or video endpoints. OpenAI's terms cover using a ChatGPT plan inside OpenAI's own Codex; other apps have had this access cut off before (OpenCode, January 2026). If it stops working, an API key does.`,note_zh:`用 API key:对话、手、画图(gpt-image-2.5-flare / gpt-image-2,走 /images/generations)。用 ChatGPT 订阅登录(Codex 的 OAuth):只有对话和手,Codex 后端没有图像和视频接口。OpenAI 的条款只允许在它自己的 Codex 里使用 ChatGPT 订阅;其他应用的这条路曾被切断过(OpenCode,2026 年 1 月)。如果哪天不能用了,API key 还能用。`,verified:`2026-10`,reasoning:{doc:`https://developers.openai.com/api/docs/guides/reasoning`,wire:`reasoning_effort`,rules:[{models:`^o[1-9]`,levels:[`low`,`medium`,`high`],default:`medium`},{models:`^gpt-5(-|$)`,levels:[`minimal`,`low`,`medium`,`high`],default:`medium`},{models:`^gpt-5\\.1(-|$)`,levels:[`low`,`medium`,`high`],default:`none`},{models:`^gpt-5\\.4`,levels:[`low`,`medium`,`high`,`xhigh`],default:`none`},{models:`^gpt-5\\.[235-9]`,levels:[`low`,`medium`,`high`,`xhigh`]},{models:`^gpt-6`,levels:[`low`,`medium`,`high`,`xhigh`]}]}},{id:`anthropic`,name:`Anthropic Claude`,name_zh:`Anthropic Claude`,protocol:`anthropic`,base_url:`https://api.anthropic.com`,key_url:`https://platform.claude.com/settings/keys`,key_hint:`sk-ant-…`,auth:[`key`,`oauth-claude`],regions:[`global`],capabilities:[`chat`,`vision`],defaults:{chat:`claude-sonnet-5-5`,hands:`claude-sonnet-5-5`},note:`The Messages API, not OpenAI's shape; every current Claude model reads pictures. No image or video models. The phone apps can sign in with a Claude account instead of a key.`,note_zh:`用的是 Messages 接口,不是 OpenAI 格式;现行 Claude 模型都能看图。没有图像和视频模型。手机 App 可以用 Claude 账号登录,不用贴 key。`,verified:`2026-10`,reasoning:{doc:`https://docs.claude.com/en/docs/build-with-claude/effort`,wire:`output_config.effort`,rules:[{models:`^claude-(opus|haiku)-5-5`,levels:[`low`,`medium`,`high`,`xhigh`,`max`],default:`medium`},{models:`^claude-(opus|sonnet)-4-6`,levels:[`low`,`medium`,`high`,`max`],default:`high`},{models:`^claude-(opus-4-[78]|opus-5|sonnet-5|haiku-5|fable-5|mythos-5)`,levels:[`low`,`medium`,`high`,`xhigh`,`max`],default:`high`}]}},{id:`gemini`,name:`Google Gemini`,name_zh:`Google Gemini`,protocol:`gemini`,base_url:`https://generativelanguage.googleapis.com/v1beta/openai`,key_url:`https://aistudio.google.com/apikey`,key_hint:`AIza…`,auth:[`key`],regions:[`global`],capabilities:[`chat`,`vision`,`image`],defaults:{chat:`gemini-3.8-flash`,hands:`gemini-3.8-flash`,image:`gemini-2.5-flash-image`},note:`Google's OpenAI-compatible layer. Gemini models read pictures. Pictures through /images/generations work with gemini-2.5-flash-image and gemini-3-pro-image-preview only; the newer 3.1 image models are not served there. Veo video is not on the compatible layer, so clips are left out.`,note_zh:`Google 的 OpenAI 兼容层。Gemini 模型能看图。走 /images/generations 画图只支持 gemini-2.5-flash-image 和 gemini-3-pro-image-preview,更新的 3.1 出图模型不在兼容层上。Veo 视频不走兼容层,所以不列视频。`,verified:`2026-10`,reasoning:{doc:`https://ai.google.dev/gemini-api/docs/openai`,wire:`reasoning_effort`,rules:[{models:`^gemini-(2\\.5|3)`,levels:[`low`,`medium`,`high`]}]}},{id:`xai`,name:`xAI Grok`,name_zh:`xAI Grok`,protocol:`openai`,base_url:`https://api.x.ai/v1`,key_url:`https://console.x.ai`,key_hint:`xai-…`,auth:[`key`],regions:[`global`],capabilities:[`chat`,`vision`,`image`],defaults:{chat:`grok-4.7`,hands:`grok-4.7`,image:`grok-imagine-image-2.0`},note:`grok-4.7 reads pictures (JPEG and PNG). Pictures through /images/generations with grok-imagine-image-2.0. Grok Imagine video uses xAI's own endpoints, so clips are left out.`,note_zh:`grok-4.7 能看图(JPEG、PNG)。画图走 /images/generations,模型 grok-imagine-image-2.0。Grok Imagine 视频走 xAI 自己的接口,所以不列视频。`,verified:`2026-10`,reasoning:{doc:`https://docs.x.ai/docs/guides/reasoning`,wire:`reasoning_effort`,rules:[{models:`^grok-4\\.5`,levels:[`low`,`medium`,`high`],default:`high`},{models:`^grok-4\\.[6-9]`,levels:[`low`,`medium`,`high`,`xhigh`],default:`high`}]}},{id:`groq`,name:`Groq`,name_zh:`Groq`,protocol:`openai`,base_url:`https://api.groq.com/openai/v1`,key_url:`https://console.groq.com/keys`,key_hint:`gsk_…`,auth:[`key`],regions:[`global`],capabilities:[`chat`,`vision`],defaults:{chat:`openai/gpt-oss-120b`,hands:`qwen/qwen3.8-27b`},note:`Fast hosting of open models. qwen/qwen3.8-27b reads pictures; gpt-oss and Llama do not. No image or video models.`,note_zh:`开源模型的高速托管。qwen/qwen3.8-27b 能看图;gpt-oss 和 Llama 不能。没有图像和视频模型。`,verified:`2026-10`,reasoning:{doc:`https://console.groq.com/docs/reasoning`,wire:`reasoning_effort`,rules:[{models:`^openai/gpt-oss-`,levels:[`low`,`medium`,`high`]},{models:`^qwen/qwen3\\.8`,levels:[`low`,`medium`,`high`],default:`none`}]}},{id:`mistral`,name:`Mistral AI`,name_zh:`Mistral AI`,protocol:`openai`,base_url:`https://api.mistral.ai/v1`,key_url:`https://console.mistral.ai/api-keys`,key_hint:`…`,auth:[`key`],regions:[`global`],capabilities:[`chat`,`vision`],defaults:{chat:`mistral-medium-2508`,hands:`mistral-medium-2508`},note:`mistral-large-2512, mistral-medium-2508, mistral-small-2506 and the Ministral 3 models read pictures. No image or video models.`,note_zh:`mistral-large-2512、mistral-medium-2508、mistral-small-2506 和 Ministral 3 系列能看图。没有图像和视频模型。`,verified:`2026-10`,reasoning:{doc:`https://docs.mistral.ai/capabilities/reasoning/`,wire:`reasoning_effort`,rules:[{models:`^mistral-(small-latest|medium-3-5|large-4-0)`,levels:[`high`],default:`none`},{models:`^zai-glm-5-3`,levels:[`low`,`high`,`max`]}]}},{id:`opencode-zen`,name:`OpenCode Zen`,name_zh:`OpenCode Zen`,protocol:`openai`,base_url:`https://opencode.ai/zen/v1`,key_url:`https://opencode.ai/auth`,auth:[`key`],regions:[`global`],capabilities:[`chat`],defaults:{chat:`deepseek-v4.1-flash`},note:`OpenCode's own gateway: pay per request from a balance, a key made in the OpenCode console, and a few free models beside the paid ones. Chat answers on the OpenAI shape; the GPT, Claude and Gemini ids on the same host speak the Responses, Messages and Google shapes, which this entry does not reach, and the vision model OpenCode lists is deepseek-v4-flash-vision-exp, the id DeepSeek has retired on its own platform, so the hands are not claimed here. OpenCode publishes no plan sign-in, only a key.`,note_zh:`OpenCode 自己的网关:按请求从余额里扣费,key 在 OpenCode 控制台申请,付费模型之外还有几个免费的。对话走 OpenAI 格式;同一域名上的 GPT、Claude、Gemini 走 Responses、Messages 和 Google 格式,本条目到不了;它列的视觉模型是 deepseek-v4-flash-vision-exp,这个 id 在 DeepSeek 自家平台上已经退役,所以「动手」不列入。OpenCode 没有套餐登录,只有 key。`,verified:`2026-10`},{id:`opencode-go`,name:`OpenCode Go`,name_zh:`OpenCode Go`,protocol:`openai`,base_url:`https://opencode.ai/zen/go/v1`,key_url:`https://opencode.ai/auth`,auth:[`key`],regions:[`global`],capabilities:[`chat`],defaults:{chat:`deepseek-v4.1-flash`},session_header:`x-opencode-session`,note:`A subscription for coding agents: Go ($10 a month) or Go Plus ($40) in the OpenCode console, then a key made there; usage is counted per model against monthly, weekly and five hour limits. OpenCode asks every client to name itself and to send one stable id per conversation in x-opencode-session: the runtime sends both, the desktop reaches Go through its model adapter's own OpenCode Go route, which sends the id and speaks each model's shape, and the phone apps send an id per chat (a hash of its first message, the same on every turn). Outside the desktop only the OpenAI shape is reached, which is where the open coding models answer; the GPT, Grok, Claude, MiniMax and Qwen ids speak the Responses and Messages shapes. The one vision model OpenCode lists (deepseek-v4-flash-vision-exp) is an id DeepSeek has retired on its own platform, so the hands are not claimed here. OpenCode publishes no plan sign-in, only a key.`,note_zh:`面向编程智能体的订阅:在 OpenCode 控制台订阅 Go(每月 10 美元)或 Go Plus(每月 40 美元),再在那里申请 key;用量按模型计,分每月、每周和每 5 小时三档上限。OpenCode 要求每个客户端说明自己是谁,并在 x-opencode-session 里为每个对话带上一个固定的 id:运行时两样都发;桌面版通过模型适配器自带的 OpenCode Go 路由访问,这条路由会带上 id,也按每个模型自己的格式说话;手机端为每个聊天带一个 id(由第一条消息算出,每一轮都一样)。桌面版以外只走 OpenAI 格式,开源编程模型都在这个格式上;GPT、Grok、Claude、MiniMax 和 Qwen 走 Responses 和 Messages 格式。它列的那个视觉模型(deepseek-v4-flash-vision-exp)在 DeepSeek 自家平台上已经退役,所以「动手」不列入。OpenCode 没有套餐登录,只有 key。`,verified:`2026-10`},{id:`ollama`,name:`Ollama`,name_zh:`Ollama(本机)`,protocol:`openai`,base_url:`http://127.0.0.1:11434/v1`,key_url:`https://ollama.com/download`,auth:[`none`],regions:[`cn`,`global`],capabilities:[`chat`],defaults:{chat:`qwen3:8b`},note:`Runs on this machine, no key, nothing leaves it. Hands need a model that reads pictures (a vision model such as a Qwen VL build); the model list says which.`,note_zh:`跑在本机,不要 key,什么都不出去。手需要能看图的模型(例如 Qwen 的 VL 版本),模型列表里能看出来。`,verified:`2026-10`,reasoning:{doc:`https://docs.ollama.com/api/openai-compatibility`,wire:`reasoning_effort`,rules:[{models:`gpt-oss`,levels:[`low`,`medium`,`high`]}]}},{id:`lm-studio`,name:`LM Studio`,name_zh:`LM Studio(本机)`,protocol:`openai`,base_url:`http://127.0.0.1:1234/v1`,key_url:`https://lmstudio.ai`,auth:[`none`],regions:[`cn`,`global`],capabilities:[`chat`],defaults:{},note:`LM Studio's local server, OpenAI-compatible, no key. Vision only if the loaded model has it.`,note_zh:`LM Studio 的本地服务,OpenAI 兼容,不要 key。装了能看图的模型才能用手。`,verified:`2026-10`},{id:`vllm`,name:`vLLM`,name_zh:`vLLM(自建)`,protocol:`openai`,base_url:`http://127.0.0.1:8000/v1`,key_url:`https://docs.vllm.ai`,auth:[`none`,`key`],regions:[`cn`,`global`],capabilities:[`chat`],defaults:{},note:`A vLLM server you run yourself; a key only if you started it with one. Vision only if the served model has it.`,note_zh:`自己跑的 vLLM 服务;启动时设了 key 才需要填。服务的模型能看图才能用手。`,verified:`2026-10`,reasoning:{doc:`https://docs.vllm.ai/en/latest/features/reasoning_outputs/`,wire:`reasoning_effort`,rules:[{models:`gpt-oss`,levels:[`low`,`medium`,`high`]}]}},{id:`custom`,name:`Any OpenAI-compatible endpoint`,name_zh:`任何 OpenAI 兼容接口`,protocol:`openai`,base_url:``,key_url:``,auth:[`key`,`none`],regions:[`cn`,`global`],capabilities:[`chat`],user_capabilities:!0,defaults:{},note:`A gateway, a relay, a server of your own: paste the address (usually ending in /v1) and say what it can do; the person sets the capabilities.`,note_zh:`网关、中转、自己的服务:贴地址(一般以 /v1 结尾),再说明它能做什么,能力由你勾选。`,verified:`2026-10`}]};function h(e){return e?.region?e.region===`cn`:e?.signed_in&&e.channel===`sms`?!0:r()===`zh-CN`}function re(e){return/^\s*(\+|00)(?!86\b)\d/.test(e)}var ie=new Map(m.providers.map(e=>[e.id,e]));function g(e,t){let n=ie.get(e);if(!n)throw Error(`providers.json has no ${e}`);return{id:e,preset:t,label:n.name,keyUrl:n.key_url,baseUrl:n.base_url,chatModel:n.defaults.chat??``,guiModel:n.defaults.hands??n.defaults.chat??``,covers:n.capabilities}}var ae=g(`bailian`,`qwen`),oe=g(`openrouter`,`openrouter`);function _(e){return h(e)?ae:oe}function se(e,t){return h(t)?e(`Alibaba Cloud Bailian is a good start: a new account comes with a free quota, set-up takes about two minutes, and one key covers chat, the hands, pictures and clips.`):e(`Alibaba Cloud Bailian only signs up accounts from mainland China. Outside, OpenRouter is the easy way: one account, one key, pay as you go, for chat, the hands and pictures; clips need Bailian.`)}function ce(e){let t=(e||``).toLowerCase().split(`/`).pop()??``;return t?t.startsWith(`deepseek`)?/v4\.1|vision|ocr/.test(t):t.startsWith(`qwen`)&&(t.includes(`-vl`)||t.startsWith(`qwen3.8`))?!0:null:null}function le(e,t,n){let r=_(n).preset;if(!e.includes(r))return e;let i=h(n),a=e.filter(e=>e!==r);if(i)return[r,...a];let o=a.filter(e=>t[e]?.region===`cn`);return[r,...a.filter(e=>!o.includes(e)),...o]}var ue=[`chat`,`vision`,`image`,`video`],v=m.providers,de=[`ollama`,`lm-studio`,`vllm`],fe={cn:[`bailian`],global:[`openrouter`,`openai`]},y={bailian:`qwen`,moonshot:`kimi`,zhipu:`glm`,volcengine:`doubao`};function pe(e){return y[e]??e}function me(e){return Object.entries(y).find(([,t])=>t===e)?.[0]??(e===`openai_responses`?`openai`:e)}function he(e){return h(e)?`cn`:`global`}function b(e,t){return t===`zh-CN`&&e.name_zh||e.name}function ge(e,t){return t===`global`&&e.regions.includes(`global`)&&e.base_url_global?{base_url:e.base_url_global,key_url:e.key_url_global||e.key_url}:{base_url:e.base_url,key_url:e.key_url}}function x(e,t){return e.regions.includes(t)}function S(e,t,n=v){let r=new Map(n.map(e=>[e.id,e])),i=fe[e].map(e=>r.get(e)).filter(t=>!!t&&x(t,e)),a=n.filter(t=>!i.includes(t)&&!de.includes(t.id)&&t.id!==`custom`&&x(t,e)).sort((e,t)=>t.capabilities.length-e.capabilities.length),o=[...i,...a];return t?o.filter(e=>e.capabilities.includes(t)):o}function _e(e=v){let t=[{id:`chatgpt`,provider:`openai`,name:`ChatGPT`,auth:`oauth-chatgpt`,here:!0},{id:`claude`,provider:`anthropic`,name:`Claude`,auth:`oauth-claude`,here:!1},{id:`kimi`,provider:`moonshot`,name:`Kimi`,auth:`device-kimi`,here:!1},{id:`openrouter`,provider:`openrouter`,name:`OpenRouter`,auth:`oauth-openrouter`,here:!1}],n=[];for(let r of t){let t=e.find(e=>e.id===r.provider);t&&t.auth.includes(r.auth)&&n.push({...r,covers:t.auth_capabilities?.[r.auth]??t.capabilities})}return n}function ve(e,t){switch(t){case`chat`:return e(`Chat`);case`vision`:return e(`Hands`);case`image`:return e(`Pictures`);case`video`:return e(`Clips`)}}function ye(e,t){return e(`covers {list}`,{list:ue.filter(e=>t.includes(e)).map(t=>ve(e,t).toLowerCase()).join(e(`, `))})}function be(e,t,n,r,i=v){let a=S(n,t,i).slice(0,4).map(e=>b(e,r)),o=a.pop()??``,s=a.length?`${a.join(e(`, `))}${e(` or `)}${o}`:o;switch(t){case`image`:return e(`Pictures need a provider with image models: {providers}.`,{providers:s});case`video`:return e(`Clips need a provider with video models: {providers}.`,{providers:s});case`vision`:return e(`The hands need a model that sees pictures: {providers}.`,{providers:s});case`chat`:return e(`Chat needs a model: {providers}.`,{providers:s})}}var xe=`https://nanomuse.cn/own-key`,C=null,w=null;async function Se(e=!1){return C&&!e?C:(w&&!e||(w=c.providers().then(e=>({...e,capabilities:e.capabilities??null,source:`runtime`})).catch(()=>({providers:v,region:``,configured:{},capabilities:null,unavailable:{},source:`bundled`})).then(e=>(C=e,w=null,e))),w)}function Ce(){C=null}function we(e=0){let[t,n]=(0,p.useState)(C);return(0,p.useEffect)(()=>{let t=!0;return Se(e>0).then(e=>t&&n(e)),()=>{t=!1}},[e]),t}function Te(e,t){return!e||e.capabilities===null?null:e.capabilities.includes(t)}var T={version:1,star:{enabled:!0,url:`https://github.com/nano-muse/nanoMuse`,moments:{signed_in:!0,tasks:[3,10,30],new_look:!0,exhausted:!0,days_used:[7,30],goal_done:!0},cooldown_days:7,max_asks:4,text:``,text_zh:``}},Ee=864e5;function E(e){if(typeof e!=`string`)return``;let t=e.trim();return t.length<=200?t:``}function De(e,t,n){let{text:r,text_zh:i}=e.star;return t&&i?i:r||n}var D=e=>typeof e==`object`&&!!e&&!Array.isArray(e),O=(e,t)=>typeof e==`boolean`?e:t,k=(e,t,n,r)=>typeof e==`number`&&Number.isFinite(e)&&Math.trunc(e)>=t&&Math.trunc(e)<=n?Math.trunc(e):r;function A(e,t){if(!Array.isArray(e))return t;let n=new Set;for(let r of e){if(typeof r!=`number`||!Number.isFinite(r)||Math.trunc(r)<1)return t;n.add(Math.trunc(r))}return[...n].sort((e,t)=>e-t)}function Oe(e){let t=T.star;if(!D(e))return structuredClone(T);let n=k(e.version,1,1e9,1),r=D(e.star)?e.star:{},i=D(r.moments)?r.moments:{},a=typeof r.url==`string`&&/^https?:\/\//.test(r.url)&&r.url.length<=200?r.url:t.url;return{version:n,star:{enabled:O(r.enabled,t.enabled),url:a,moments:{signed_in:O(i.signed_in,t.moments.signed_in),tasks:A(i.tasks,t.moments.tasks),new_look:O(i.new_look,t.moments.new_look),exhausted:O(i.exhausted,t.moments.exhausted),days_used:A(i.days_used,t.moments.days_used),goal_done:O(i.goal_done,t.moments.goal_done)},cooldown_days:k(r.cooldown_days,0,365,t.cooldown_days),max_asks:k(r.max_asks,0,50,t.max_asks),text:E(r.text),text_zh:E(r.text_zh)}}}var j={starred:`nm.star.starred`,tasks:`nm.star.tasks`,asks:`nm.star.asks`,lastAsk:`nm.star.last_ask`,shown:`nm.star.shown`,days:`nm.star.days`,lastDay:`nm.star.last_day`,migrated:`nm.star.v2`},ke=[`signed_in`,`first_task`,`tenth_task`,`new_look`],M=e=>{let t=Number(e);return Number.isFinite(t)&&t>=0?Math.trunc(t):0};function N(e){let t=[];try{let n=JSON.parse(e.getItem(j.shown)??`[]`);Array.isArray(n)&&(t=n.filter(e=>typeof e==`string`))}catch{t=[]}let n=e.getItem(j.lastAsk);return{starred:e.getItem(j.starred)===`1`,tasks:M(e.getItem(j.tasks)),asks:M(e.getItem(j.asks)),lastAsk:n&&M(n)||null,shown:t,days:M(e.getItem(j.days)),lastDay:e.getItem(j.lastDay)??``}}function P(e,t){e.setItem(j.starred,t.starred?`1`:`0`),e.setItem(j.tasks,String(t.tasks)),e.setItem(j.asks,String(t.asks)),t.lastAsk?e.setItem(j.lastAsk,String(t.lastAsk)):e.removeItem(j.lastAsk),e.setItem(j.shown,JSON.stringify(t.shown)),e.setItem(j.days,String(t.days)),e.setItem(j.lastDay,t.lastDay)}function Ae(e){let t=N(e);if(e.getItem(j.migrated)===`1`)return t;for(let n of ke){let r=`nm.star.${n}`;e.getItem(r)===`1`&&!t.shown.includes(n)&&(t.shown.push(n),t.asks+=1),e.removeItem(r)}return P(e,t),e.setItem(j.migrated,`1`),t}var F=(e,t)=>e===`tasks`||e===`days_used`?`${e}:${t??0}`:e;function je(e,t,n){let r=e.star;return!r.enabled||t.starred||t.asks>=r.max_asks?!1:t.lastAsk===null||n-t.lastAsk>=r.cooldown_days*Ee}function Me(e,t,n,r,i){if(!je(t,n,r))return!1;let a=t.star.moments;return(e===`tasks`||e===`days_used`?i!==void 0&&a[e].includes(i):a[e])&&!n.shown.includes(F(e,i))}function Ne(e,t,n){let r=N(e);return r.shown.includes(t)||(r.shown.push(t),r.asks+=1,r.lastAsk=n,P(e,r)),r}function Pe(e){let t=N(e);t.starred=!0,P(e,t)}function Fe(e){let t=N(e);return t.tasks+=1,P(e,t),t.tasks}var Ie=e=>`${e.getFullYear()}-${String(e.getMonth()+1).padStart(2,`0`)}-${String(e.getDate()).padStart(2,`0`)}`;function Le(e,t){let n=N(e),r=Ie(t);return n.lastDay===r?{days:n.days,fresh:!1}:(n.days+=1,n.lastDay=r,P(e,n),{days:n.days,fresh:!0})}var I=s(),Re=`https://github.com/nano-muse/nanoMuse`,ze=`https://github.com/nano-muse/nanoMuse/issues/new/choose`,L=`https://nanomuse.cn/#open-source`;function Be({compact:t=!1,className:r}){let i=n();return(0,I.jsxs)(`section`,{className:e(`rounded-[22px] border border-accent/25 bg-accent/[0.06] p-4 dark:bg-accent/[0.10]`,r),children:[(0,I.jsxs)(`a`,{href:L,target:`_blank`,rel:`noreferrer`,className:`flex items-start gap-2 text-[13.5px] font-semibold hover:text-accent`,children:[(0,I.jsx)(d,{size:16,className:`mt-0.5 shrink-0 text-accent`}),(0,I.jsx)(`span`,{className:`min-w-0 flex-1 leading-snug`,children:i(`Free, open source, non-profit`)}),(0,I.jsx)(ee,{size:12,className:`mt-1 shrink-0 text-muted`})]}),(0,I.jsx)(`p`,{className:e(`mt-1.5 leading-relaxed text-fg/85`,t?`text-[12.5px]`:`text-[13px]`),children:i(`nanoMuse is a non-profit open-source community project, free forever. Sign in with a phone number or an e-mail and the model comes with a free allowance, paid by the developer; when it is gone, use your own key (Alibaba Cloud Bailian in mainland China, OpenRouter elsewhere). Nothing is sold; what the relay keeps is in the privacy policy, and Settings → Data controls is yours. Delete the account whenever you like.`)}),(0,I.jsx)(`p`,{className:e(`mt-1.5 leading-relaxed text-fg/85`,t?`text-[12.5px]`:`text-[13px]`),children:i(`The people building it use it every day. Report a bug, ask for a feature, send a pull request: that is what moves the project. A star on GitHub helps others find it.`)}),(0,I.jsxs)(`div`,{className:`mt-3 flex flex-wrap gap-2 text-[12.5px] font-medium`,children:[(0,I.jsxs)(`a`,{href:Re,target:`_blank`,rel:`noreferrer`,onClick:K,className:`inline-flex items-center gap-1.5 rounded-full bg-fg px-3 py-1.5 text-bg hover:opacity-90`,children:[(0,I.jsx)(ne,{size:13}),` `,i(`Star on GitHub`)]}),(0,I.jsxs)(`a`,{href:ze,target:`_blank`,rel:`noreferrer`,className:`inline-flex items-center gap-1.5 rounded-full border border-border bg-surface px-3 py-1.5 text-fg hover:bg-surface-2`,children:[(0,I.jsx)(u,{size:13}),` `,i(`Report a bug or ask for a feature`)]})]})]})}var R=new Map,z={getItem:e=>{try{return localStorage.getItem(e)}catch{return R.get(e)??null}},setItem:(e,t)=>{try{localStorage.setItem(e,t)}catch{R.set(e,t)}},removeItem:e=>{try{localStorage.removeItem(e)}catch{R.delete(e)}}},B=!1;function Ve(){return B?N(z):(B=!0,Ae(z))}var V=T,H=!1,U=null,W=new Set;function He(){return U??=c.nudges().then(e=>{V=Oe(e?.policy)}).catch(()=>{V=T}).finally(()=>{H=!0,W.forEach(e=>e())}),U}function G(){let[,e]=(0,p.useState)(0);return(0,p.useEffect)(()=>{let t=()=>e(e=>e+1);return W.add(t),He(),()=>{W.delete(t)}},[]),{policy:V,ready:H}}var Ue=()=>Fe(z),We=()=>Le(z,new Date),Ge=(e,t)=>H&&Me(e,V,Ve(),Date.now(),t),Ke=(e,t)=>{Ne(z,F(e,t),Date.now())},K=()=>Pe(z);function q(e){K(),window.open(e||V.star.url||`https://github.com/nano-muse/nanoMuse`,`_blank`,`noopener,noreferrer`)}function J(e,t,n){switch(t){case`signed_in`:return e(`Welcome. nanoMuse is free, open source and non-profit, a personal agent for anyone who runs it. If that is worth something to you, a star on GitHub is how the next person finds it.`);case`tasks`:return n===3?e(`Three tasks done. If nanoMuse is useful, a star on GitHub helps the next person find it.`):n===10?e(`Ten tasks together. If nanoMuse has become part of your day, a star on GitHub tells others it is worth a try.`):e(`{n} tasks done. If nanoMuse is useful, a star on GitHub helps the next person find it.`,{n:n??0});case`new_look`:return e(`A new face, drawn for you. If you like where nanoMuse is going, a star on GitHub helps more people find it.`);case`exhausted`:return e(`The free allowance is used up. Thank you for coming this far. If nanoMuse has earned it, a star on GitHub keeps the project in view for the next person.`);case`days_used`:return n===7?e(`A week with nanoMuse. If it has earned a place in your day, a star on GitHub helps the next person find it.`):n===30?e(`A month with nanoMuse. If it has become part of your routine, a star on GitHub tells others it is worth a try.`):e(`{n} days with nanoMuse. If it has earned a place in your day, a star on GitHub helps the next person find it.`,{n:n??0});case`goal_done`:return e(`Goal reached. If nanoMuse helped you get there, a star on GitHub tells the people building it that it did.`)}}var Y=null,X=null;function Z(){let[e,t]=(0,p.useState)(Y??{});return(0,p.useEffect)(()=>{if(Y)return;X??=c.cloudConfig().then(e=>Y=e&&typeof e==`object`?e:{}).catch(()=>Y={});let e=!0;return X.then(n=>e&&t(n)),()=>{e=!1}},[]),e}function Q(e){let{policy:t}=G();return De(t,a()===`zh-CN`,e)}function qe({text:t,onDone:r,className:i}){let a=n(),o=Z(),s=Q(t);return(0,I.jsxs)(`section`,{className:e(`rounded-[22px] border border-amber-400/40 bg-amber-50/70 p-4 dark:bg-amber-400/[0.08]`,i),children:[(0,I.jsxs)(`div`,{className:`flex items-start gap-2.5`,children:[(0,I.jsx)(f,{size:18,className:`mt-0.5 shrink-0 text-amber-500`}),(0,I.jsxs)(`div`,{className:`min-w-0 flex-1`,children:[(0,I.jsx)(`div`,{className:`text-[14px] font-semibold leading-snug`,children:a(`A star on GitHub helps`)}),(0,I.jsx)(`p`,{className:`mt-1 text-[13px] leading-relaxed text-fg/85`,children:s})]})]}),(0,I.jsxs)(`div`,{className:`mt-3 flex flex-wrap gap-2 pl-7`,children:[(0,I.jsx)(`button`,{type:`button`,className:e(te,`!w-auto !py-1.5 !px-3.5 text-[13px]`),onClick:()=>{q(o.repo_url),r()},children:a(`Star on GitHub`)}),(0,I.jsx)(`button`,{type:`button`,className:e(l,`!w-auto !py-1.5 !px-3.5 text-[13px]`),onClick:r,children:a(`Not now`)}),(0,I.jsx)(`button`,{type:`button`,className:e(l,`!w-auto !py-1.5 !px-3.5 text-[13px]`),onClick:()=>{K(),r()},children:a(`I already starred`)})]})]})}function Je({moment:e,n:t,text:r,className:i,due:a=!0}){let o=n(),[s,c]=$(e,a,t);return s?(0,I.jsx)(qe,{text:r??J(o,e,t),onDone:()=>c(!1),className:i}):null}function $(e,t=!0,n){let{ready:r}=G(),[i,a]=(0,p.useState)(!1);return(0,p.useEffect)(()=>{t&&r&&!i&&Ge(e,n)&&(Ke(e,n),a(!0))},[t,r,e,n,i]),[i,a]}export{se as A,he as C,re as D,h as E,f as M,d as N,ce as O,u as P,S,we as T,Te as _,q as a,pe as b,$ as c,L as d,v as f,ge as g,ye as h,K as i,_ as j,le as k,Q as l,me as m,We as n,J as o,xe as p,Ue as r,Z as s,Je as t,Be as u,Ce as v,be as w,b as x,_e as y}; \ No newline at end of file diff --git a/nanomuse/server/static/assets/clapperboard-BokpXv9J.js b/nanomuse/server/static/assets/clapperboard-C1_tjTS2.js similarity index 81% rename from nanomuse/server/static/assets/clapperboard-BokpXv9J.js rename to nanomuse/server/static/assets/clapperboard-C1_tjTS2.js index 9dec4809c..a7ab06718 100644 --- a/nanomuse/server/static/assets/clapperboard-BokpXv9J.js +++ b/nanomuse/server/static/assets/clapperboard-C1_tjTS2.js @@ -1 +1 @@ -import{J as e}from"./MuseHeader-Pw-NI98v.js";var t=e(`clapperboard`,[[`path`,{d:`m12.296 3.464 3.02 3.956`,key:`qash78`}],[`path`,{d:`M20.2 6 3 11l-.9-2.4c-.3-1.1.3-2.2 1.3-2.5l13.5-4c1.1-.3 2.2.3 2.5 1.3z`,key:`1h7j8b`}],[`path`,{d:`M3 11h18v8a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z`,key:`4lm6w1`}],[`path`,{d:`m6.18 5.276 3.1 3.899`,key:`zjj9t3`}]]);export{t}; \ No newline at end of file +import{J as e}from"./MuseHeader-BDWXHKHT.js";var t=e(`clapperboard`,[[`path`,{d:`m12.296 3.464 3.02 3.956`,key:`qash78`}],[`path`,{d:`M20.2 6 3 11l-.9-2.4c-.3-1.1.3-2.2 1.3-2.5l13.5-4c1.1-.3 2.2.3 2.5 1.3z`,key:`1h7j8b`}],[`path`,{d:`M3 11h18v8a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z`,key:`4lm6w1`}],[`path`,{d:`m6.18 5.276 3.1 3.899`,key:`zjj9t3`}]]);export{t}; \ No newline at end of file diff --git a/nanomuse/server/static/assets/database-zap-CzaFBl6C.js b/nanomuse/server/static/assets/database-zap-6Cufqig1.js similarity index 80% rename from nanomuse/server/static/assets/database-zap-CzaFBl6C.js rename to nanomuse/server/static/assets/database-zap-6Cufqig1.js index f7962dd30..936264078 100644 --- a/nanomuse/server/static/assets/database-zap-CzaFBl6C.js +++ b/nanomuse/server/static/assets/database-zap-6Cufqig1.js @@ -1 +1 @@ -import{J as e}from"./MuseHeader-Pw-NI98v.js";var t=e(`database-zap`,[[`ellipse`,{cx:`12`,cy:`5`,rx:`9`,ry:`3`,key:`msslwz`}],[`path`,{d:`M3 5V19A9 3 0 0 0 15 21.84`,key:`14ibmq`}],[`path`,{d:`M21 5V8`,key:`1marbg`}],[`path`,{d:`M21 12L18 17H22L19 22`,key:`zafso`}],[`path`,{d:`M3 12A9 3 0 0 0 14.59 14.87`,key:`1y4wr8`}]]);export{t}; \ No newline at end of file +import{J as e}from"./MuseHeader-BDWXHKHT.js";var t=e(`database-zap`,[[`ellipse`,{cx:`12`,cy:`5`,rx:`9`,ry:`3`,key:`msslwz`}],[`path`,{d:`M3 5V19A9 3 0 0 0 15 21.84`,key:`14ibmq`}],[`path`,{d:`M21 5V8`,key:`1marbg`}],[`path`,{d:`M21 12L18 17H22L19 22`,key:`zafso`}],[`path`,{d:`M3 12A9 3 0 0 0 14.59 14.87`,key:`1y4wr8`}]]);export{t}; \ No newline at end of file diff --git a/nanomuse/server/static/assets/external-link-Xj5fjR8v.js b/nanomuse/server/static/assets/external-link-CZH-rQLq.js similarity index 79% rename from nanomuse/server/static/assets/external-link-Xj5fjR8v.js rename to nanomuse/server/static/assets/external-link-CZH-rQLq.js index 462183115..26a24f51d 100644 --- a/nanomuse/server/static/assets/external-link-Xj5fjR8v.js +++ b/nanomuse/server/static/assets/external-link-CZH-rQLq.js @@ -1 +1 @@ -import{J as e}from"./MuseHeader-Pw-NI98v.js";var t=e(`check`,[[`path`,{d:`M20 6 9 17l-5-5`,key:`1gmf2c`}]]),n=e(`external-link`,[[`path`,{d:`M15 3h6v6`,key:`1q9fwt`}],[`path`,{d:`M10 14 21 3`,key:`gplh6r`}],[`path`,{d:`M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6`,key:`a6xqqp`}]]);export{t as n,n as t}; \ No newline at end of file +import{J as e}from"./MuseHeader-BDWXHKHT.js";var t=e(`check`,[[`path`,{d:`M20 6 9 17l-5-5`,key:`1gmf2c`}]]),n=e(`external-link`,[[`path`,{d:`M15 3h6v6`,key:`1q9fwt`}],[`path`,{d:`M10 14 21 3`,key:`gplh6r`}],[`path`,{d:`M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6`,key:`a6xqqp`}]]);export{t as n,n as t}; \ No newline at end of file diff --git a/nanomuse/server/static/assets/image-crWy0a06.js b/nanomuse/server/static/assets/image-kcW5PNCE.js similarity index 75% rename from nanomuse/server/static/assets/image-crWy0a06.js rename to nanomuse/server/static/assets/image-kcW5PNCE.js index 1f5695455..ed89dfd8f 100644 --- a/nanomuse/server/static/assets/image-crWy0a06.js +++ b/nanomuse/server/static/assets/image-kcW5PNCE.js @@ -1 +1 @@ -import{J as e}from"./MuseHeader-Pw-NI98v.js";var t=e(`image`,[[`rect`,{width:`18`,height:`18`,x:`3`,y:`3`,rx:`2`,ry:`2`,key:`1m3agn`}],[`circle`,{cx:`9`,cy:`9`,r:`2`,key:`af1f0g`}],[`path`,{d:`m21 15-3.086-3.086a2 2 0 0 0-2.828 0L6 21`,key:`1xmnt7`}]]);export{t}; \ No newline at end of file +import{J as e}from"./MuseHeader-BDWXHKHT.js";var t=e(`image`,[[`rect`,{width:`18`,height:`18`,x:`3`,y:`3`,rx:`2`,ry:`2`,key:`1m3agn`}],[`circle`,{cx:`9`,cy:`9`,r:`2`,key:`af1f0g`}],[`path`,{d:`m21 15-3.086-3.086a2 2 0 0 0-2.828 0L6 21`,key:`1xmnt7`}]]);export{t}; \ No newline at end of file diff --git a/nanomuse/server/static/assets/index-CwUBXfPC.css b/nanomuse/server/static/assets/index-CwUBXfPC.css deleted file mode 100644 index a3236b7a6..000000000 --- a/nanomuse/server/static/assets/index-CwUBXfPC.css +++ /dev/null @@ -1,2 +0,0 @@ -/*! tailwindcss v4.3.3 | MIT License | https://tailwindcss.com */ -@layer properties{@supports (((-webkit-hyphens:none)) and (not (margin-trim:inline))) or ((-moz-orient:inline) and (not (color:rgb(from red r g b)))){*,:before,:after,::backdrop{--tw-border-spacing-x:0;--tw-border-spacing-y:0;--tw-translate-x:0;--tw-translate-y:0;--tw-translate-z:0;--tw-space-y-reverse:0;--tw-divide-y-reverse:0;--tw-border-style:solid;--tw-gradient-position:initial;--tw-gradient-from:#0000;--tw-gradient-via:#0000;--tw-gradient-to:#0000;--tw-gradient-stops:initial;--tw-gradient-via-stops:initial;--tw-gradient-from-position:0%;--tw-gradient-via-position:50%;--tw-gradient-to-position:100%;--tw-leading:initial;--tw-font-weight:initial;--tw-tracking:initial;--tw-ordinal:initial;--tw-slashed-zero:initial;--tw-numeric-figure:initial;--tw-numeric-spacing:initial;--tw-numeric-fraction:initial;--tw-shadow:0 0 #0000;--tw-shadow-color:initial;--tw-shadow-alpha:100%;--tw-inset-shadow:0 0 #0000;--tw-inset-shadow-color:initial;--tw-inset-shadow-alpha:100%;--tw-ring-color:initial;--tw-ring-shadow:0 0 #0000;--tw-inset-ring-color:initial;--tw-inset-ring-shadow:0 0 #0000;--tw-ring-inset:initial;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-offset-shadow:0 0 #0000;--tw-blur:initial;--tw-brightness:initial;--tw-contrast:initial;--tw-grayscale:initial;--tw-hue-rotate:initial;--tw-invert:initial;--tw-opacity:initial;--tw-saturate:initial;--tw-sepia:initial;--tw-drop-shadow:initial;--tw-drop-shadow-color:initial;--tw-drop-shadow-alpha:100%;--tw-drop-shadow-size:initial;--tw-backdrop-blur:initial;--tw-backdrop-brightness:initial;--tw-backdrop-contrast:initial;--tw-backdrop-grayscale:initial;--tw-backdrop-hue-rotate:initial;--tw-backdrop-invert:initial;--tw-backdrop-opacity:initial;--tw-backdrop-saturate:initial;--tw-backdrop-sepia:initial;--tw-duration:initial;--tw-scale-x:1;--tw-scale-y:1;--tw-scale-z:1}}}@layer theme{:root,:host{--font-sans:"Figtree", ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", "Noto Sans CJK SC", sans-serif;--font-mono:ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;--color-red-400:oklch(70.4% .191 22.216);--color-red-500:oklch(63.7% .237 25.331);--color-red-600:oklch(57.7% .245 27.325);--color-orange-300:oklch(83.7% .128 66.29);--color-orange-400:oklch(75% .183 55.934);--color-orange-500:oklch(70.5% .213 47.604);--color-orange-600:oklch(64.6% .222 41.116);--color-amber-50:oklch(98.7% .022 95.277);--color-amber-200:oklch(92.4% .12 95.746);--color-amber-300:oklch(87.9% .169 91.605);--color-amber-400:oklch(82.8% .189 84.429);--color-amber-500:oklch(76.9% .188 70.08);--color-amber-600:oklch(66.6% .179 58.318);--color-amber-700:oklch(55.5% .163 48.998);--color-amber-800:oklch(47.3% .137 46.201);--color-emerald-300:oklch(84.5% .143 164.978);--color-emerald-400:oklch(76.5% .177 163.223);--color-emerald-500:oklch(69.6% .17 162.48);--color-emerald-600:oklch(59.6% .145 163.225);--color-emerald-700:oklch(50.8% .118 165.612);--color-teal-700:oklch(51.1% .096 186.391);--color-cyan-300:oklch(86.5% .127 207.078);--color-cyan-500:oklch(71.5% .143 215.221);--color-cyan-600:oklch(60.9% .126 221.723);--color-sky-300:oklch(82.8% .111 230.318);--color-sky-400:oklch(74.6% .16 232.661);--color-sky-500:oklch(68.5% .169 237.323);--color-sky-600:oklch(58.8% .158 241.966);--color-violet-300:oklch(81.1% .111 293.571);--color-violet-500:oklch(60.6% .25 292.717);--color-violet-600:oklch(54.1% .281 293.009);--color-fuchsia-300:oklch(83.3% .145 321.434);--color-fuchsia-500:oklch(66.7% .295 322.15);--color-fuchsia-600:oklch(59.1% .293 322.896);--color-pink-300:oklch(82.3% .12 346.018);--color-pink-500:oklch(65.6% .241 354.308);--color-pink-600:oklch(59.2% .249 .584);--color-rose-300:oklch(81% .117 11.638);--color-rose-400:oklch(71.2% .194 13.428);--color-rose-500:oklch(64.5% .246 16.439);--color-rose-600:oklch(58.6% .253 17.585);--color-rose-700:oklch(51.4% .222 16.935);--color-slate-400:oklch(70.4% .04 256.788);--color-slate-600:oklch(44.6% .043 257.281);--color-slate-700:oklch(37.2% .044 257.287);--color-slate-900:oklch(20.8% .042 265.755);--color-black:#000;--color-white:#fff;--spacing:.25rem;--container-sm:24rem;--container-md:28rem;--container-lg:32rem;--font-weight-normal:400;--font-weight-medium:500;--font-weight-semibold:600;--font-weight-bold:700;--tracking-tight:-.025em;--tracking-normal:0em;--tracking-wide:.025em;--leading-tight:1.25;--leading-snug:1.375;--leading-relaxed:1.625;--radius-sm:.25rem;--radius-md:.375rem;--radius-lg:.5rem;--radius-xl:.75rem;--radius-2xl:1rem;--radius-3xl:1.5rem;--drop-shadow-sm:0 1px 2px #00000026;--animate-spin:spin 1s linear infinite;--animate-pulse:pulse 2s cubic-bezier(.4, 0, .6, 1) infinite;--blur-2xl:40px;--blur-3xl:64px;--default-transition-duration:.15s;--default-transition-timing-function:cubic-bezier(.4, 0, .2, 1);--default-font-family:var(--font-sans);--default-mono-font-family:var(--font-mono);--color-bg:var(--om-bg);--color-surface:var(--om-surface);--color-surface-2:var(--om-surface-2);--color-border:var(--om-border);--color-fg:var(--om-fg);--color-muted:var(--om-muted);--color-accent:var(--om-accent);--color-accent-fg:#fff;--color-accent-soft:var(--om-accent-soft);--color-accent-soft-fg:var(--om-accent-soft-fg);--color-bubble-user:var(--om-bubble-user);--color-bubble-user-fg:var(--om-bubble-user-fg)}}@layer base{*,:after,:before,::backdrop{box-sizing:border-box;border:0 solid;margin:0;padding:0}::file-selector-button{box-sizing:border-box;border:0 solid;margin:0;padding:0}html,:host{-webkit-text-size-adjust:100%;tab-size:4;line-height:1.5;font-family:var(--default-font-family,-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", "Noto Sans", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji");font-feature-settings:var(--default-font-feature-settings,normal);font-variation-settings:var(--default-font-variation-settings,normal);-webkit-tap-highlight-color:transparent}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,samp,pre{font-family:var(--default-mono-font-family,ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace);font-feature-settings:var(--default-mono-font-feature-settings,normal);font-variation-settings:var(--default-mono-font-variation-settings,normal);font-size:1em}small{font-size:80%}sub,sup{vertical-align:baseline;font-size:75%;line-height:0;position:relative}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}:-moz-focusring:where(:not(iframe)){outline:auto}progress{vertical-align:baseline}summary{display:list-item}ol,ul,menu{list-style:none}img,svg,video,canvas,audio,iframe,embed,object{vertical-align:middle;display:block}img,video{max-width:100%;height:auto}button,input,select,optgroup,textarea{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}::file-selector-button{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}:where(select:is([multiple],[size])) optgroup{font-weight:bolder}:where(select:is([multiple],[size])) optgroup option{padding-inline-start:20px}::file-selector-button{margin-inline-end:4px}::placeholder{opacity:1}@supports (not ((-webkit-appearance:-apple-pay-button))) or (contain-intrinsic-size:1px){::placeholder{color:currentColor}@supports (color:color-mix(in lab, red, red)){::placeholder{color:color-mix(in oklab, currentcolor 50%, transparent)}}}textarea{resize:vertical}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-date-and-time-value{min-height:1lh;text-align:inherit}::-webkit-datetime-edit{display:inline-flex}::-webkit-datetime-edit-fields-wrapper{padding:0}::-webkit-datetime-edit{padding-block:0}::-webkit-datetime-edit-year-field{padding-block:0}::-webkit-datetime-edit-month-field{padding-block:0}::-webkit-datetime-edit-day-field{padding-block:0}::-webkit-datetime-edit-hour-field{padding-block:0}::-webkit-datetime-edit-minute-field{padding-block:0}::-webkit-datetime-edit-second-field{padding-block:0}::-webkit-datetime-edit-millisecond-field{padding-block:0}::-webkit-datetime-edit-meridiem-field{padding-block:0}::-webkit-calendar-picker-indicator{line-height:1}:-moz-ui-invalid{box-shadow:none}button,input:where([type=button],[type=reset],[type=submit]){appearance:button}::file-selector-button{appearance:button}::-webkit-inner-spin-button{height:auto}::-webkit-outer-spin-button{height:auto}[hidden]:where(:not([hidden=until-found])){display:none!important}}@layer components;@layer utilities{.\@container{container-type:inline-size}.pointer-events-auto{pointer-events:auto}.pointer-events-none{pointer-events:none}.visible{visibility:visible}.sr-only{clip-path:inset(50%);white-space:nowrap;border-width:0;width:1px;height:1px;margin:-1px;padding:0;position:absolute;overflow:hidden}.absolute{position:absolute}.fixed{position:fixed}.relative{position:relative}.static{position:static}.sticky{position:sticky}.inset-0{inset:0}.inset-x-0{inset-inline:0}.inset-y-0{inset-block:0}.-top-1{top:calc(var(--spacing) * -1)}.-top-1\.5{top:calc(var(--spacing) * -1.5)}.-top-20{top:calc(var(--spacing) * -20)}.top-0{top:0}.top-0\.5{top:calc(var(--spacing) * .5)}.top-1{top:var(--spacing)}.top-1\.5{top:calc(var(--spacing) * 1.5)}.top-1\/2{top:50%}.top-2{top:calc(var(--spacing) * 2)}.top-2\.5{top:calc(var(--spacing) * 2.5)}.top-9{top:calc(var(--spacing) * 9)}.top-12{top:calc(var(--spacing) * 12)}.top-\[3px\]{top:3px}.top-full{top:100%}.-right-0\.5{right:calc(var(--spacing) * -.5)}.-right-1{right:calc(var(--spacing) * -1)}.-right-1\.5{right:calc(var(--spacing) * -1.5)}.-right-16{right:calc(var(--spacing) * -16)}.right-0{right:0}.right-1{right:var(--spacing)}.right-1\.5{right:calc(var(--spacing) * 1.5)}.right-2{right:calc(var(--spacing) * 2)}.right-2\.5{right:calc(var(--spacing) * 2.5)}.right-3{right:calc(var(--spacing) * 3)}.right-4{right:calc(var(--spacing) * 4)}.right-\[3px\]{right:3px}.-bottom-0\.5{bottom:calc(var(--spacing) * -.5)}.bottom-0{bottom:0}.bottom-1{bottom:var(--spacing)}.bottom-2{bottom:calc(var(--spacing) * 2)}.bottom-\[calc\(6rem\+env\(safe-area-inset-bottom\)\)\]{bottom:calc(6rem + env(safe-area-inset-bottom))}.tabbar-float{bottom:calc(12px + env(safe-area-inset-bottom))}.left-0{left:0}.left-0\.5{left:calc(var(--spacing) * .5)}.left-1\.5{left:calc(var(--spacing) * 1.5)}.left-1\/2{left:50%}.left-2\.5{left:calc(var(--spacing) * 2.5)}.left-3{left:calc(var(--spacing) * 3)}.left-4{left:calc(var(--spacing) * 4)}.left-\[18px\]{left:18px}.left-\[22px\]{left:22px}.left-\[26px\]{left:26px}.left-\[68px\]{left:68px}.z-10{z-index:10}.z-20{z-index:20}.z-30{z-index:30}.z-50{z-index:50}.z-\[60\]{z-index:60}.z-\[70\]{z-index:70}.container{width:100%}@media (width>=40rem){.container{max-width:40rem}}@media (width>=48rem){.container{max-width:48rem}}@media (width>=64rem){.container{max-width:64rem}}@media (width>=80rem){.container{max-width:80rem}}@media (width>=96rem){.container{max-width:96rem}}.-mx-4{margin-inline:calc(var(--spacing) * -4)}.mx-1{margin-inline:var(--spacing)}.mx-2{margin-inline:calc(var(--spacing) * 2)}.mx-3{margin-inline:calc(var(--spacing) * 3)}.mx-4{margin-inline:calc(var(--spacing) * 4)}.mx-auto{margin-inline:auto}.my-1{margin-block:var(--spacing)}.my-1\.5{margin-block:calc(var(--spacing) * 1.5)}.my-2{margin-block:calc(var(--spacing) * 2)}.my-8{margin-block:calc(var(--spacing) * 8)}.-mt-0\.5{margin-top:calc(var(--spacing) * -.5)}.-mt-1{margin-top:calc(var(--spacing) * -1)}.-mt-2\.5{margin-top:calc(var(--spacing) * -2.5)}.mt-0\.5{margin-top:calc(var(--spacing) * .5)}.mt-1{margin-top:var(--spacing)}.mt-1\.5{margin-top:calc(var(--spacing) * 1.5)}.mt-2{margin-top:calc(var(--spacing) * 2)}.mt-2\.5{margin-top:calc(var(--spacing) * 2.5)}.mt-3{margin-top:calc(var(--spacing) * 3)}.mt-3\.5{margin-top:calc(var(--spacing) * 3.5)}.mt-4{margin-top:calc(var(--spacing) * 4)}.mt-5{margin-top:calc(var(--spacing) * 5)}.mt-6{margin-top:calc(var(--spacing) * 6)}.mt-7{margin-top:calc(var(--spacing) * 7)}.mt-8{margin-top:calc(var(--spacing) * 8)}.mt-\[2px\]{margin-top:2px}.mt-\[3px\]{margin-top:3px}.mt-\[22px\]{margin-top:22px}.mt-auto{margin-top:auto}.-mr-1\.5{margin-right:calc(var(--spacing) * -1.5)}.-mr-2{margin-right:calc(var(--spacing) * -2)}.mr-2{margin-right:calc(var(--spacing) * 2)}.mr-2\.5{margin-right:calc(var(--spacing) * 2.5)}.mr-3{margin-right:calc(var(--spacing) * 3)}.mr-5{margin-right:calc(var(--spacing) * 5)}.-mb-2{margin-bottom:calc(var(--spacing) * -2)}.mb-0\.5{margin-bottom:calc(var(--spacing) * .5)}.mb-1{margin-bottom:var(--spacing)}.mb-1\.5{margin-bottom:calc(var(--spacing) * 1.5)}.mb-2{margin-bottom:calc(var(--spacing) * 2)}.mb-3{margin-bottom:calc(var(--spacing) * 3)}.mb-4{margin-bottom:calc(var(--spacing) * 4)}.mb-5{margin-bottom:calc(var(--spacing) * 5)}.mb-6{margin-bottom:calc(var(--spacing) * 6)}.-ml-1{margin-left:calc(var(--spacing) * -1)}.ml-0\.5{margin-left:calc(var(--spacing) * .5)}.ml-1{margin-left:var(--spacing)}.ml-1\.5{margin-left:calc(var(--spacing) * 1.5)}.ml-2{margin-left:calc(var(--spacing) * 2)}.ml-2\.5{margin-left:calc(var(--spacing) * 2.5)}.ml-4{margin-left:calc(var(--spacing) * 4)}.ml-\[52px\]{margin-left:52px}.ml-\[76px\]{margin-left:76px}.ml-auto{margin-left:auto}.line-clamp-2{-webkit-line-clamp:2;-webkit-box-orient:vertical;display:-webkit-box;overflow:hidden}.line-clamp-3{-webkit-line-clamp:3;-webkit-box-orient:vertical;display:-webkit-box;overflow:hidden}.line-clamp-4{-webkit-line-clamp:4;-webkit-box-orient:vertical;display:-webkit-box;overflow:hidden}.block{display:block}.contents{display:contents}.flex{display:flex}.grid{display:grid}.hidden{display:none}.inline{display:inline}.inline-block{display:inline-block}.inline-flex{display:inline-flex}.table{display:table}.aspect-\[16\/10\]{aspect-ratio:16/10}.aspect-square{aspect-ratio:1}.h-1{height:var(--spacing)}.h-1\.5{height:calc(var(--spacing) * 1.5)}.h-2{height:calc(var(--spacing) * 2)}.h-2\.5{height:calc(var(--spacing) * 2.5)}.h-3\.5{height:calc(var(--spacing) * 3.5)}.h-4{height:calc(var(--spacing) * 4)}.h-5{height:calc(var(--spacing) * 5)}.h-6{height:calc(var(--spacing) * 6)}.h-7{height:calc(var(--spacing) * 7)}.h-8{height:calc(var(--spacing) * 8)}.h-9{height:calc(var(--spacing) * 9)}.h-10{height:calc(var(--spacing) * 10)}.h-11{height:calc(var(--spacing) * 11)}.h-12{height:calc(var(--spacing) * 12)}.h-14{height:calc(var(--spacing) * 14)}.h-16{height:calc(var(--spacing) * 16)}.h-28{height:calc(var(--spacing) * 28)}.h-40{height:calc(var(--spacing) * 40)}.h-44{height:calc(var(--spacing) * 44)}.h-48{height:calc(var(--spacing) * 48)}.h-\[9px\]{height:9px}.h-\[17px\]{height:17px}.h-\[18px\]{height:18px}.h-\[46px\]{height:46px}.h-\[46vh\]{height:46vh}.h-\[50px\]{height:50px}.h-\[72px\]{height:72px}.h-\[100dvh\]{height:100dvh}.h-\[130px\]{height:130px}.h-\[148px\]{height:148px}.h-\[480px\]{height:480px}.h-full{height:100%}.max-h-28{max-height:calc(var(--spacing) * 28)}.max-h-32{max-height:calc(var(--spacing) * 32)}.max-h-40{max-height:calc(var(--spacing) * 40)}.max-h-52{max-height:calc(var(--spacing) * 52)}.max-h-64{max-height:calc(var(--spacing) * 64)}.max-h-72{max-height:calc(var(--spacing) * 72)}.max-h-\[60vh\]{max-height:60vh}.max-h-\[92dvh\]{max-height:92dvh}.max-h-full{max-height:100%}.min-h-0{min-height:0}.min-h-\[40vh\]{min-height:40vh}.min-h-\[44px\]{min-height:44px}.min-h-\[54px\]{min-height:54px}.min-h-\[56px\]{min-height:56px}.\!w-auto{width:auto!important}.w-1{width:var(--spacing)}.w-1\.5{width:calc(var(--spacing) * 1.5)}.w-2{width:calc(var(--spacing) * 2)}.w-2\.5{width:calc(var(--spacing) * 2.5)}.w-5{width:calc(var(--spacing) * 5)}.w-6{width:calc(var(--spacing) * 6)}.w-7{width:calc(var(--spacing) * 7)}.w-8{width:calc(var(--spacing) * 8)}.w-9{width:calc(var(--spacing) * 9)}.w-10{width:calc(var(--spacing) * 10)}.w-11{width:calc(var(--spacing) * 11)}.w-12{width:calc(var(--spacing) * 12)}.w-14{width:calc(var(--spacing) * 14)}.w-16{width:calc(var(--spacing) * 16)}.w-28{width:calc(var(--spacing) * 28)}.w-40{width:calc(var(--spacing) * 40)}.w-44{width:calc(var(--spacing) * 44)}.w-48{width:calc(var(--spacing) * 48)}.w-56{width:calc(var(--spacing) * 56)}.w-\[9px\]{width:9px}.w-\[46px\]{width:46px}.w-\[60px\]{width:60px}.w-\[64px\]{width:64px}.w-\[72px\]{width:72px}.w-\[74px\]{width:74px}.w-\[76px\]{width:76px}.w-\[82vw\]{width:82vw}.w-\[86px\]{width:86px}.w-\[148px\]{width:148px}.w-\[188px\]{width:188px}.w-\[232px\]{width:232px}.w-\[248px\]{width:248px}.w-\[260px\]{width:260px}.w-\[300px\]{width:300px}.w-\[900px\]{width:900px}.w-auto{width:auto}.w-fit{width:fit-content}.w-full{width:100%}.max-w-\[60\%\]{max-width:60%}.max-w-\[68px\]{max-width:68px}.max-w-\[86\%\]{max-width:86%}.max-w-\[240px\]{max-width:240px}.max-w-\[320px\]{max-width:320px}.max-w-\[340px\]{max-width:340px}.max-w-\[360px\]{max-width:360px}.max-w-\[520px\]{max-width:520px}.max-w-\[560px\]{max-width:560px}.max-w-\[600px\]{max-width:600px}.max-w-\[720px\]{max-width:720px}.max-w-\[760px\]{max-width:760px}.max-w-\[calc\(100\%-128px\)\]{max-width:calc(100% - 128px)}.max-w-full{max-width:100%}.max-w-md{max-width:var(--container-md)}.max-w-sm{max-width:var(--container-sm)}.min-w-0{min-width:0}.min-w-\[17px\]{min-width:17px}.min-w-\[18px\]{min-width:18px}.min-w-\[180px\]{min-width:180px}.min-w-full{min-width:100%}.flex-1{flex:1}.shrink-0{flex-shrink:0}.border-separate{border-collapse:separate}.border-spacing-0{--tw-border-spacing-x:0px;--tw-border-spacing-y:0px;border-spacing:var(--tw-border-spacing-x) var(--tw-border-spacing-y)}.origin-top-left{transform-origin:0 0}.-translate-x-1\/2{--tw-translate-x:calc(calc(1 / 2 * 100%) * -1);translate:var(--tw-translate-x) var(--tw-translate-y)}.-translate-y-1\/2{--tw-translate-y:calc(calc(1 / 2 * 100%) * -1);translate:var(--tw-translate-x) var(--tw-translate-y)}.scale-\[0\.3333\]{scale:.3333}.animate-pulse{animation:var(--animate-pulse)}.animate-spin{animation:var(--animate-spin)}.cursor-crosshair{cursor:crosshair}.cursor-pointer{cursor:pointer}.resize-none{resize:none}.resize-y{resize:vertical}.scroll-mt-4{scroll-margin-top:calc(var(--spacing) * 4)}.list-decimal{list-style-type:decimal}.grid-cols-1{grid-template-columns:repeat(1,minmax(0,1fr))}.grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}.grid-cols-4{grid-template-columns:repeat(4,minmax(0,1fr))}.grid-cols-8{grid-template-columns:repeat(8,minmax(0,1fr))}.grid-cols-\[1fr_1fr_auto\]{grid-template-columns:1fr 1fr auto}.grid-cols-\[1fr_84px\]{grid-template-columns:1fr 84px}.grid-cols-\[auto_1fr\]{grid-template-columns:auto 1fr}.flex-col{flex-direction:column}.flex-wrap{flex-wrap:wrap}.items-baseline{align-items:baseline}.items-center{align-items:center}.items-end{align-items:flex-end}.items-start{align-items:flex-start}.justify-between{justify-content:space-between}.justify-center{justify-content:center}.justify-end{justify-content:flex-end}.justify-start{justify-content:flex-start}.gap-0\.5{gap:calc(var(--spacing) * .5)}.gap-1{gap:var(--spacing)}.gap-1\.5{gap:calc(var(--spacing) * 1.5)}.gap-2{gap:calc(var(--spacing) * 2)}.gap-2\.5{gap:calc(var(--spacing) * 2.5)}.gap-3{gap:calc(var(--spacing) * 3)}.gap-3\.5{gap:calc(var(--spacing) * 3.5)}.gap-4{gap:calc(var(--spacing) * 4)}.gap-\[3px\]{gap:3px}:where(.space-y-0\.5>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * .5) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * .5) * calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-1>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(var(--spacing) * var(--tw-space-y-reverse));margin-block-end:calc(var(--spacing) * calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-1\.5>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * 1.5) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * 1.5) * calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-2>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * 2) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * 2) * calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-2\.5>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * 2.5) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * 2.5) * calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-3>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * 3) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * 3) * calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-3\.5>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * 3.5) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * 3.5) * calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-4>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * 4) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * 4) * calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-5>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * 5) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * 5) * calc(1 - var(--tw-space-y-reverse)))}.gap-x-1\.5{column-gap:calc(var(--spacing) * 1.5)}.gap-x-2{column-gap:calc(var(--spacing) * 2)}.gap-x-3{column-gap:calc(var(--spacing) * 3)}.gap-x-4{column-gap:calc(var(--spacing) * 4)}.gap-y-0\.5{row-gap:calc(var(--spacing) * .5)}.gap-y-1{row-gap:var(--spacing)}.gap-y-1\.5{row-gap:calc(var(--spacing) * 1.5)}:where(.divide-y>:not(:last-child)){--tw-divide-y-reverse:0;border-bottom-style:var(--tw-border-style);border-top-style:var(--tw-border-style);border-top-width:calc(1px * var(--tw-divide-y-reverse));border-bottom-width:calc(1px * calc(1 - var(--tw-divide-y-reverse)))}:where(.divide-border>:not(:last-child)),:where(.divide-border\/60>:not(:last-child)){border-color:var(--color-border)}@supports (color:color-mix(in lab, red, red)){:where(.divide-border\/60>:not(:last-child)){border-color:color-mix(in oklab, var(--color-border) 60%, transparent)}}:where(.divide-border\/70>:not(:last-child)){border-color:var(--color-border)}@supports (color:color-mix(in lab, red, red)){:where(.divide-border\/70>:not(:last-child)){border-color:color-mix(in oklab, var(--color-border) 70%, transparent)}}.self-center{align-self:center}.self-start{align-self:flex-start}.truncate{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.overflow-auto{overflow:auto}.overflow-hidden{overflow:hidden}.overflow-x-auto{overflow-x:auto}.overflow-x-hidden{overflow-x:hidden}.overflow-y-auto{overflow-y:auto}.rounded{border-radius:.25rem}.rounded-2xl{border-radius:var(--radius-2xl)}.rounded-3xl{border-radius:var(--radius-3xl)}.rounded-\[10px\]{border-radius:10px}.rounded-\[13px\]{border-radius:13px}.rounded-\[14px\]{border-radius:14px}.rounded-\[18px\]{border-radius:18px}.rounded-\[20px\]{border-radius:20px}.rounded-\[22px\]{border-radius:22px}.rounded-\[26px\]{border-radius:26px}.rounded-\[28px\]{border-radius:28px}.rounded-full{border-radius:2147483647px}.rounded-lg{border-radius:var(--radius-lg)}.rounded-md{border-radius:var(--radius-md)}.rounded-sm{border-radius:var(--radius-sm)}.rounded-xl{border-radius:var(--radius-xl)}.rounded-t-3xl{border-top-left-radius:var(--radius-3xl);border-top-right-radius:var(--radius-3xl)}.rounded-t-\[28px\]{border-top-left-radius:28px;border-top-right-radius:28px}.rounded-tl-lg{border-top-left-radius:var(--radius-lg)}.rounded-br-lg{border-bottom-right-radius:var(--radius-lg)}.rounded-bl-lg{border-bottom-left-radius:var(--radius-lg)}.rounded-bl-md{border-bottom-left-radius:var(--radius-md)}.border{border-style:var(--tw-border-style);border-width:1px}.border-0{border-style:var(--tw-border-style);border-width:0}.border-2{border-style:var(--tw-border-style);border-width:2px}.border-\[1\.5px\]{border-style:var(--tw-border-style);border-width:1.5px}.border-y{border-block-style:var(--tw-border-style);border-block-width:1px}.border-t{border-top-style:var(--tw-border-style);border-top-width:1px}.border-r{border-right-style:var(--tw-border-style);border-right-width:1px}.border-b{border-bottom-style:var(--tw-border-style);border-bottom-width:1px}.border-dashed{--tw-border-style:dashed;border-style:dashed}.border-accent,.border-accent\/15{border-color:var(--color-accent)}@supports (color:color-mix(in lab, red, red)){.border-accent\/15{border-color:color-mix(in oklab, var(--color-accent) 15%, transparent)}}.border-accent\/25{border-color:var(--color-accent)}@supports (color:color-mix(in lab, red, red)){.border-accent\/25{border-color:color-mix(in oklab, var(--color-accent) 25%, transparent)}}.border-accent\/30{border-color:var(--color-accent)}@supports (color:color-mix(in lab, red, red)){.border-accent\/30{border-color:color-mix(in oklab, var(--color-accent) 30%, transparent)}}.border-accent\/40{border-color:var(--color-accent)}@supports (color:color-mix(in lab, red, red)){.border-accent\/40{border-color:color-mix(in oklab, var(--color-accent) 40%, transparent)}}.border-accent\/50{border-color:var(--color-accent)}@supports (color:color-mix(in lab, red, red)){.border-accent\/50{border-color:color-mix(in oklab, var(--color-accent) 50%, transparent)}}.border-amber-400\/40{border-color:#fcbb0066}@supports (color:color-mix(in lab, red, red)){.border-amber-400\/40{border-color:color-mix(in oklab, var(--color-amber-400) 40%, transparent)}}.border-amber-500\/50{border-color:#f99c0080}@supports (color:color-mix(in lab, red, red)){.border-amber-500\/50{border-color:color-mix(in oklab, var(--color-amber-500) 50%, transparent)}}.border-bg{border-color:var(--color-bg)}.border-border,.border-border\/60{border-color:var(--color-border)}@supports (color:color-mix(in lab, red, red)){.border-border\/60{border-color:color-mix(in oklab, var(--color-border) 60%, transparent)}}.border-border\/70{border-color:var(--color-border)}@supports (color:color-mix(in lab, red, red)){.border-border\/70{border-color:color-mix(in oklab, var(--color-border) 70%, transparent)}}.border-border\/80{border-color:var(--color-border)}@supports (color:color-mix(in lab, red, red)){.border-border\/80{border-color:color-mix(in oklab, var(--color-border) 80%, transparent)}}.border-current{border-color:currentColor}.border-fg{border-color:var(--color-fg)}.border-rose-400{border-color:var(--color-rose-400)}.border-rose-400\/60{border-color:#ff667f99}@supports (color:color-mix(in lab, red, red)){.border-rose-400\/60{border-color:color-mix(in oklab, var(--color-rose-400) 60%, transparent)}}.border-rose-500\/25{border-color:#ff235740}@supports (color:color-mix(in lab, red, red)){.border-rose-500\/25{border-color:color-mix(in oklab, var(--color-rose-500) 25%, transparent)}}.border-surface{border-color:var(--color-surface)}.border-transparent{border-color:#0000}.border-t-transparent{border-top-color:#0000}.bg-\[\#2fb344\]{background-color:#2fb344}.bg-\[\#f1efeb\]{background-color:#f1efeb}.bg-accent{background-color:var(--color-accent)}.bg-accent-soft{background-color:var(--color-accent-soft)}.bg-accent\/5{background-color:var(--color-accent)}@supports (color:color-mix(in lab, red, red)){.bg-accent\/5{background-color:color-mix(in oklab, var(--color-accent) 5%, transparent)}}.bg-accent\/8{background-color:var(--color-accent)}@supports (color:color-mix(in lab, red, red)){.bg-accent\/8{background-color:color-mix(in oklab, var(--color-accent) 8%, transparent)}}.bg-accent\/10{background-color:var(--color-accent)}@supports (color:color-mix(in lab, red, red)){.bg-accent\/10{background-color:color-mix(in oklab, var(--color-accent) 10%, transparent)}}.bg-accent\/12{background-color:var(--color-accent)}@supports (color:color-mix(in lab, red, red)){.bg-accent\/12{background-color:color-mix(in oklab, var(--color-accent) 12%, transparent)}}.bg-accent\/15{background-color:var(--color-accent)}@supports (color:color-mix(in lab, red, red)){.bg-accent\/15{background-color:color-mix(in oklab, var(--color-accent) 15%, transparent)}}.bg-accent\/70{background-color:var(--color-accent)}@supports (color:color-mix(in lab, red, red)){.bg-accent\/70{background-color:color-mix(in oklab, var(--color-accent) 70%, transparent)}}.bg-accent\/\[0\.06\]{background-color:var(--color-accent)}@supports (color:color-mix(in lab, red, red)){.bg-accent\/\[0\.06\]{background-color:color-mix(in oklab, var(--color-accent) 6%, transparent)}}.bg-amber-50\/70{background-color:#fffbebb3}@supports (color:color-mix(in lab, red, red)){.bg-amber-50\/70{background-color:color-mix(in oklab, var(--color-amber-50) 70%, transparent)}}.bg-amber-400{background-color:var(--color-amber-400)}.bg-amber-400\/15{background-color:#fcbb0026}@supports (color:color-mix(in lab, red, red)){.bg-amber-400\/15{background-color:color-mix(in oklab, var(--color-amber-400) 15%, transparent)}}.bg-amber-500{background-color:var(--color-amber-500)}.bg-amber-500\/10{background-color:#f99c001a}@supports (color:color-mix(in lab, red, red)){.bg-amber-500\/10{background-color:color-mix(in oklab, var(--color-amber-500) 10%, transparent)}}.bg-amber-500\/12{background-color:#f99c001f}@supports (color:color-mix(in lab, red, red)){.bg-amber-500\/12{background-color:color-mix(in oklab, var(--color-amber-500) 12%, transparent)}}.bg-amber-500\/15{background-color:#f99c0026}@supports (color:color-mix(in lab, red, red)){.bg-amber-500\/15{background-color:color-mix(in oklab, var(--color-amber-500) 15%, transparent)}}.bg-bg,.bg-bg\/50{background-color:var(--color-bg)}@supports (color:color-mix(in lab, red, red)){.bg-bg\/50{background-color:color-mix(in oklab, var(--color-bg) 50%, transparent)}}.bg-bg\/60{background-color:var(--color-bg)}@supports (color:color-mix(in lab, red, red)){.bg-bg\/60{background-color:color-mix(in oklab, var(--color-bg) 60%, transparent)}}.bg-bg\/80{background-color:var(--color-bg)}@supports (color:color-mix(in lab, red, red)){.bg-bg\/80{background-color:color-mix(in oklab, var(--color-bg) 80%, transparent)}}.bg-black\/20{background-color:#0003}@supports (color:color-mix(in lab, red, red)){.bg-black\/20{background-color:color-mix(in oklab, var(--color-black) 20%, transparent)}}.bg-black\/40{background-color:#0006}@supports (color:color-mix(in lab, red, red)){.bg-black\/40{background-color:color-mix(in oklab, var(--color-black) 40%, transparent)}}.bg-black\/45{background-color:#00000073}@supports (color:color-mix(in lab, red, red)){.bg-black\/45{background-color:color-mix(in oklab, var(--color-black) 45%, transparent)}}.bg-black\/60{background-color:#0009}@supports (color:color-mix(in lab, red, red)){.bg-black\/60{background-color:color-mix(in oklab, var(--color-black) 60%, transparent)}}.bg-border{background-color:var(--color-border)}.bg-bubble-user{background-color:var(--color-bubble-user)}.bg-cyan-500\/12{background-color:#00b7d71f}@supports (color:color-mix(in lab, red, red)){.bg-cyan-500\/12{background-color:color-mix(in oklab, var(--color-cyan-500) 12%, transparent)}}.bg-emerald-500{background-color:var(--color-emerald-500)}.bg-emerald-500\/12{background-color:#00bb7f1f}@supports (color:color-mix(in lab, red, red)){.bg-emerald-500\/12{background-color:color-mix(in oklab, var(--color-emerald-500) 12%, transparent)}}.bg-emerald-500\/15{background-color:#00bb7f26}@supports (color:color-mix(in lab, red, red)){.bg-emerald-500\/15{background-color:color-mix(in oklab, var(--color-emerald-500) 15%, transparent)}}.bg-fg,.bg-fg\/40{background-color:var(--color-fg)}@supports (color:color-mix(in lab, red, red)){.bg-fg\/40{background-color:color-mix(in oklab, var(--color-fg) 40%, transparent)}}.bg-fuchsia-500\/12{background-color:#e12afb1f}@supports (color:color-mix(in lab, red, red)){.bg-fuchsia-500\/12{background-color:color-mix(in oklab, var(--color-fuchsia-500) 12%, transparent)}}.bg-muted,.bg-muted\/35{background-color:var(--color-muted)}@supports (color:color-mix(in lab, red, red)){.bg-muted\/35{background-color:color-mix(in oklab, var(--color-muted) 35%, transparent)}}.bg-orange-500\/12{background-color:#fe6e001f}@supports (color:color-mix(in lab, red, red)){.bg-orange-500\/12{background-color:color-mix(in oklab, var(--color-orange-500) 12%, transparent)}}.bg-pink-500{background-color:var(--color-pink-500)}.bg-pink-500\/12{background-color:#f6339a1f}@supports (color:color-mix(in lab, red, red)){.bg-pink-500\/12{background-color:color-mix(in oklab, var(--color-pink-500) 12%, transparent)}}.bg-red-500{background-color:var(--color-red-500)}.bg-rose-400{background-color:var(--color-rose-400)}.bg-rose-500{background-color:var(--color-rose-500)}.bg-rose-500\/12{background-color:#ff23571f}@supports (color:color-mix(in lab, red, red)){.bg-rose-500\/12{background-color:color-mix(in oklab, var(--color-rose-500) 12%, transparent)}}.bg-rose-500\/15{background-color:#ff235726}@supports (color:color-mix(in lab, red, red)){.bg-rose-500\/15{background-color:color-mix(in oklab, var(--color-rose-500) 15%, transparent)}}.bg-rose-500\/\[0\.04\]{background-color:#ff23570a}@supports (color:color-mix(in lab, red, red)){.bg-rose-500\/\[0\.04\]{background-color:color-mix(in oklab, var(--color-rose-500) 4%, transparent)}}.bg-sky-500\/12{background-color:#00a5ef1f}@supports (color:color-mix(in lab, red, red)){.bg-sky-500\/12{background-color:color-mix(in oklab, var(--color-sky-500) 12%, transparent)}}.bg-surface{background-color:var(--color-surface)}.bg-surface-2,.bg-surface-2\/40{background-color:var(--color-surface-2)}@supports (color:color-mix(in lab, red, red)){.bg-surface-2\/40{background-color:color-mix(in oklab, var(--color-surface-2) 40%, transparent)}}.bg-surface-2\/55{background-color:var(--color-surface-2)}@supports (color:color-mix(in lab, red, red)){.bg-surface-2\/55{background-color:color-mix(in oklab, var(--color-surface-2) 55%, transparent)}}.bg-surface-2\/60{background-color:var(--color-surface-2)}@supports (color:color-mix(in lab, red, red)){.bg-surface-2\/60{background-color:color-mix(in oklab, var(--color-surface-2) 60%, transparent)}}.bg-surface-2\/70{background-color:var(--color-surface-2)}@supports (color:color-mix(in lab, red, red)){.bg-surface-2\/70{background-color:color-mix(in oklab, var(--color-surface-2) 70%, transparent)}}.bg-surface-2\/80{background-color:var(--color-surface-2)}@supports (color:color-mix(in lab, red, red)){.bg-surface-2\/80{background-color:color-mix(in oklab, var(--color-surface-2) 80%, transparent)}}.bg-surface\/40{background-color:var(--color-surface)}@supports (color:color-mix(in lab, red, red)){.bg-surface\/40{background-color:color-mix(in oklab, var(--color-surface) 40%, transparent)}}.bg-surface\/70{background-color:var(--color-surface)}@supports (color:color-mix(in lab, red, red)){.bg-surface\/70{background-color:color-mix(in oklab, var(--color-surface) 70%, transparent)}}.bg-surface\/90{background-color:var(--color-surface)}@supports (color:color-mix(in lab, red, red)){.bg-surface\/90{background-color:color-mix(in oklab, var(--color-surface) 90%, transparent)}}.bg-transparent{background-color:#0000}.bg-violet-500{background-color:var(--color-violet-500)}.bg-violet-500\/12{background-color:#8d54ff1f}@supports (color:color-mix(in lab, red, red)){.bg-violet-500\/12{background-color:color-mix(in oklab, var(--color-violet-500) 12%, transparent)}}.bg-white{background-color:var(--color-white)}.bg-white\/80{background-color:#fffc}@supports (color:color-mix(in lab, red, red)){.bg-white\/80{background-color:color-mix(in oklab, var(--color-white) 80%, transparent)}}.bg-gradient-to-b{--tw-gradient-position:to bottom in oklab;background-image:linear-gradient(var(--tw-gradient-stops))}.bg-gradient-to-br{--tw-gradient-position:to bottom right in oklab;background-image:linear-gradient(var(--tw-gradient-stops))}.bg-\[radial-gradient\(ellipse_at_top\,rgba\(0\,100\,212\,0\.14\)\,transparent_65\%\)\]{background-image:radial-gradient(at top,#0064d424,#0000 65%)}.from-\[\#7d6bc7\]{--tw-gradient-from:#7d6bc7;--tw-gradient-stops:var(--tw-gradient-via-stops,var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position))}.from-\[\#b0413e\]{--tw-gradient-from:#b0413e;--tw-gradient-stops:var(--tw-gradient-via-stops,var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position))}.from-accent{--tw-gradient-from:var(--color-accent);--tw-gradient-stops:var(--tw-gradient-via-stops,var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position))}.from-emerald-500{--tw-gradient-from:var(--color-emerald-500);--tw-gradient-stops:var(--tw-gradient-via-stops,var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position))}.from-orange-400{--tw-gradient-from:var(--color-orange-400);--tw-gradient-stops:var(--tw-gradient-via-stops,var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position))}.from-slate-400{--tw-gradient-from:var(--color-slate-400);--tw-gradient-stops:var(--tw-gradient-via-stops,var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position))}.from-slate-700{--tw-gradient-from:var(--color-slate-700);--tw-gradient-stops:var(--tw-gradient-via-stops,var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position))}.to-\[\#7a1f1f\]{--tw-gradient-to:#7a1f1f;--tw-gradient-stops:var(--tw-gradient-via-stops,var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position))}.to-\[\#574494\]{--tw-gradient-to:#574494;--tw-gradient-stops:var(--tw-gradient-via-stops,var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position))}.to-amber-600{--tw-gradient-to:var(--color-amber-600);--tw-gradient-stops:var(--tw-gradient-via-stops,var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position))}.to-sky-400{--tw-gradient-to:var(--color-sky-400);--tw-gradient-stops:var(--tw-gradient-via-stops,var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position))}.to-slate-600{--tw-gradient-to:var(--color-slate-600);--tw-gradient-stops:var(--tw-gradient-via-stops,var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position))}.to-slate-900{--tw-gradient-to:var(--color-slate-900);--tw-gradient-stops:var(--tw-gradient-via-stops,var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position))}.to-teal-700{--tw-gradient-to:var(--color-teal-700);--tw-gradient-stops:var(--tw-gradient-via-stops,var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position))}.object-contain{object-fit:contain}.object-cover{object-fit:cover}.object-top{object-position:top}.p-0\.5{padding:calc(var(--spacing) * .5)}.p-1{padding:var(--spacing)}.p-1\.5{padding:calc(var(--spacing) * 1.5)}.p-2{padding:calc(var(--spacing) * 2)}.p-2\.5{padding:calc(var(--spacing) * 2.5)}.p-3{padding:calc(var(--spacing) * 3)}.p-3\.5{padding:calc(var(--spacing) * 3.5)}.p-4{padding:calc(var(--spacing) * 4)}.p-5{padding:calc(var(--spacing) * 5)}.p-6{padding:calc(var(--spacing) * 6)}.p-8{padding:calc(var(--spacing) * 8)}.\!px-3\.5{padding-inline:calc(var(--spacing) * 3.5)!important}.px-0\.5{padding-inline:calc(var(--spacing) * .5)}.px-1{padding-inline:var(--spacing)}.px-1\.5{padding-inline:calc(var(--spacing) * 1.5)}.px-2{padding-inline:calc(var(--spacing) * 2)}.px-2\.5{padding-inline:calc(var(--spacing) * 2.5)}.px-3{padding-inline:calc(var(--spacing) * 3)}.px-3\.5{padding-inline:calc(var(--spacing) * 3.5)}.px-4{padding-inline:calc(var(--spacing) * 4)}.px-5{padding-inline:calc(var(--spacing) * 5)}.px-6{padding-inline:calc(var(--spacing) * 6)}.px-8{padding-inline:calc(var(--spacing) * 8)}.px-16{padding-inline:calc(var(--spacing) * 16)}.\!py-1\.5{padding-block:calc(var(--spacing) * 1.5)!important}.py-0\.5{padding-block:calc(var(--spacing) * .5)}.py-1{padding-block:var(--spacing)}.py-1\.5{padding-block:calc(var(--spacing) * 1.5)}.py-2{padding-block:calc(var(--spacing) * 2)}.py-2\.5{padding-block:calc(var(--spacing) * 2.5)}.py-3{padding-block:calc(var(--spacing) * 3)}.py-3\.5{padding-block:calc(var(--spacing) * 3.5)}.py-4{padding-block:calc(var(--spacing) * 4)}.py-6{padding-block:calc(var(--spacing) * 6)}.py-8{padding-block:calc(var(--spacing) * 8)}.py-10{padding-block:calc(var(--spacing) * 10)}.pt-0{padding-top:0}.pt-0\.5{padding-top:calc(var(--spacing) * .5)}.pt-1{padding-top:var(--spacing)}.pt-1\.5{padding-top:calc(var(--spacing) * 1.5)}.pt-2{padding-top:calc(var(--spacing) * 2)}.pt-2\.5{padding-top:calc(var(--spacing) * 2.5)}.pt-3{padding-top:calc(var(--spacing) * 3)}.pt-3\.5{padding-top:calc(var(--spacing) * 3.5)}.pt-4{padding-top:calc(var(--spacing) * 4)}.pt-5{padding-top:calc(var(--spacing) * 5)}.pt-6{padding-top:calc(var(--spacing) * 6)}.pt-9{padding-top:calc(var(--spacing) * 9)}.pt-10{padding-top:calc(var(--spacing) * 10)}.pt-14{padding-top:calc(var(--spacing) * 14)}.pt-\[3px\]{padding-top:3px}.pt-\[18px\]{padding-top:18px}.pt-\[22px\]{padding-top:22px}.pr-1{padding-right:var(--spacing)}.pr-2{padding-right:calc(var(--spacing) * 2)}.pr-2\.5{padding-right:calc(var(--spacing) * 2.5)}.pr-3{padding-right:calc(var(--spacing) * 3)}.pr-5{padding-right:calc(var(--spacing) * 5)}.pr-8{padding-right:calc(var(--spacing) * 8)}.pr-10{padding-right:calc(var(--spacing) * 10)}.pb-0\.5{padding-bottom:calc(var(--spacing) * .5)}.pb-1{padding-bottom:var(--spacing)}.pb-1\.5{padding-bottom:calc(var(--spacing) * 1.5)}.pb-2{padding-bottom:calc(var(--spacing) * 2)}.pb-2\.5{padding-bottom:calc(var(--spacing) * 2.5)}.pb-3{padding-bottom:calc(var(--spacing) * 3)}.pb-3\.5{padding-bottom:calc(var(--spacing) * 3.5)}.pb-4{padding-bottom:calc(var(--spacing) * 4)}.pb-5{padding-bottom:calc(var(--spacing) * 5)}.pb-6{padding-bottom:calc(var(--spacing) * 6)}.pb-7{padding-bottom:calc(var(--spacing) * 7)}.pb-8{padding-bottom:calc(var(--spacing) * 8)}.tabbar-room{padding-bottom:calc(74px + env(safe-area-inset-bottom))}.pl-3{padding-left:calc(var(--spacing) * 3)}.pl-3\.5{padding-left:calc(var(--spacing) * 3.5)}.pl-4{padding-left:calc(var(--spacing) * 4)}.pl-5{padding-left:calc(var(--spacing) * 5)}.pl-7{padding-left:calc(var(--spacing) * 7)}.pl-9{padding-left:calc(var(--spacing) * 9)}.pl-12{padding-left:calc(var(--spacing) * 12)}.pl-\[18px\]{padding-left:18px}.text-center{text-align:center}.text-left{text-align:left}.text-right{text-align:right}.align-middle{vertical-align:middle}.font-mono{font-family:var(--font-mono)}.font-sans{font-family:var(--font-sans)}.text-\[10\.5px\]{font-size:10.5px}.text-\[10px\]{font-size:10px}.text-\[11\.5px\]{font-size:11.5px}.text-\[11px\]{font-size:11px}.text-\[12\.5px\]{font-size:12.5px}.text-\[12px\]{font-size:12px}.text-\[13\.5px\]{font-size:13.5px}.text-\[13px\]{font-size:13px}.text-\[14\.5px\]{font-size:14.5px}.text-\[14px\]{font-size:14px}.text-\[15px\]{font-size:15px}.text-\[16px\]{font-size:16px}.text-\[17px\]{font-size:17px}.text-\[18px\]{font-size:18px}.text-\[20px\]{font-size:20px}.text-\[21px\]{font-size:21px}.text-\[22px\]{font-size:22px}.text-\[24px\]{font-size:24px}.text-\[26px\]{font-size:26px}.text-\[28px\]{font-size:28px}.text-\[30px\]{font-size:30px}.text-\[64px\]{font-size:64px}.leading-4{--tw-leading:calc(var(--spacing) * 4);line-height:calc(var(--spacing) * 4)}.leading-6{--tw-leading:calc(var(--spacing) * 6);line-height:calc(var(--spacing) * 6)}.leading-7{--tw-leading:calc(var(--spacing) * 7);line-height:calc(var(--spacing) * 7)}.leading-8{--tw-leading:calc(var(--spacing) * 8);line-height:calc(var(--spacing) * 8)}.leading-\[1\.4\]{--tw-leading:1.4;line-height:1.4}.leading-\[1\.5\]{--tw-leading:1.5;line-height:1.5}.leading-\[1\.45\]{--tw-leading:1.45;line-height:1.45}.leading-\[14px\]{--tw-leading:14px;line-height:14px}.leading-\[17px\]{--tw-leading:17px;line-height:17px}.leading-\[18px\]{--tw-leading:18px;line-height:18px}.leading-\[19px\]{--tw-leading:19px;line-height:19px}.leading-\[20px\]{--tw-leading:20px;line-height:20px}.leading-\[21px\]{--tw-leading:21px;line-height:21px}.leading-\[22px\]{--tw-leading:22px;line-height:22px}.leading-\[26px\]{--tw-leading:26px;line-height:26px}.leading-\[34px\]{--tw-leading:34px;line-height:34px}.leading-none{--tw-leading:1;line-height:1}.leading-relaxed{--tw-leading:var(--leading-relaxed);line-height:var(--leading-relaxed)}.leading-snug{--tw-leading:var(--leading-snug);line-height:var(--leading-snug)}.leading-tight{--tw-leading:var(--leading-tight);line-height:var(--leading-tight)}.font-bold{--tw-font-weight:var(--font-weight-bold);font-weight:var(--font-weight-bold)}.font-medium{--tw-font-weight:var(--font-weight-medium);font-weight:var(--font-weight-medium)}.font-normal{--tw-font-weight:var(--font-weight-normal);font-weight:var(--font-weight-normal)}.font-semibold{--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold)}.tracking-\[0\.2em\]{--tw-tracking:.2em;letter-spacing:.2em}.tracking-\[0\.3em\]{--tw-tracking:.3em;letter-spacing:.3em}.tracking-normal{--tw-tracking:var(--tracking-normal);letter-spacing:var(--tracking-normal)}.tracking-tight{--tw-tracking:var(--tracking-tight);letter-spacing:var(--tracking-tight)}.tracking-wide{--tw-tracking:var(--tracking-wide);letter-spacing:var(--tracking-wide)}.break-words{overflow-wrap:break-word}.break-all{word-break:break-all}.whitespace-nowrap{white-space:nowrap}.whitespace-pre-wrap{white-space:pre-wrap}.text-accent{color:var(--color-accent)}.text-accent-fg{color:var(--color-accent-fg)}.text-accent-soft-fg{color:var(--color-accent-soft-fg)}.text-accent\/80{color:var(--color-accent)}@supports (color:color-mix(in lab, red, red)){.text-accent\/80{color:color-mix(in oklab, var(--color-accent) 80%, transparent)}}.text-amber-500{color:var(--color-amber-500)}.text-amber-600{color:var(--color-amber-600)}.text-amber-700{color:var(--color-amber-700)}.text-amber-800{color:var(--color-amber-800)}.text-bg{color:var(--color-bg)}.text-bubble-user-fg{color:var(--color-bubble-user-fg)}.text-cyan-600{color:var(--color-cyan-600)}.text-emerald-500{color:var(--color-emerald-500)}.text-emerald-600{color:var(--color-emerald-600)}.text-emerald-700{color:var(--color-emerald-700)}.text-fg,.text-fg\/45{color:var(--color-fg)}@supports (color:color-mix(in lab, red, red)){.text-fg\/45{color:color-mix(in oklab, var(--color-fg) 45%, transparent)}}.text-fg\/60{color:var(--color-fg)}@supports (color:color-mix(in lab, red, red)){.text-fg\/60{color:color-mix(in oklab, var(--color-fg) 60%, transparent)}}.text-fg\/65{color:var(--color-fg)}@supports (color:color-mix(in lab, red, red)){.text-fg\/65{color:color-mix(in oklab, var(--color-fg) 65%, transparent)}}.text-fg\/70{color:var(--color-fg)}@supports (color:color-mix(in lab, red, red)){.text-fg\/70{color:color-mix(in oklab, var(--color-fg) 70%, transparent)}}.text-fg\/75{color:var(--color-fg)}@supports (color:color-mix(in lab, red, red)){.text-fg\/75{color:color-mix(in oklab, var(--color-fg) 75%, transparent)}}.text-fg\/80{color:var(--color-fg)}@supports (color:color-mix(in lab, red, red)){.text-fg\/80{color:color-mix(in oklab, var(--color-fg) 80%, transparent)}}.text-fg\/85{color:var(--color-fg)}@supports (color:color-mix(in lab, red, red)){.text-fg\/85{color:color-mix(in oklab, var(--color-fg) 85%, transparent)}}.text-fg\/90{color:var(--color-fg)}@supports (color:color-mix(in lab, red, red)){.text-fg\/90{color:color-mix(in oklab, var(--color-fg) 90%, transparent)}}.text-fuchsia-600{color:var(--color-fuchsia-600)}.text-muted,.text-muted\/70{color:var(--color-muted)}@supports (color:color-mix(in lab, red, red)){.text-muted\/70{color:color-mix(in oklab, var(--color-muted) 70%, transparent)}}.text-muted\/80{color:var(--color-muted)}@supports (color:color-mix(in lab, red, red)){.text-muted\/80{color:color-mix(in oklab, var(--color-muted) 80%, transparent)}}.text-orange-600{color:var(--color-orange-600)}.text-pink-600{color:var(--color-pink-600)}.text-red-600{color:var(--color-red-600)}.text-rose-500{color:var(--color-rose-500)}.text-rose-600{color:var(--color-rose-600)}.text-rose-700{color:var(--color-rose-700)}.text-sky-600{color:var(--color-sky-600)}.text-violet-600{color:var(--color-violet-600)}.text-white{color:var(--color-white)}.text-white\/85{color:#ffffffd9}@supports (color:color-mix(in lab, red, red)){.text-white\/85{color:color-mix(in oklab, var(--color-white) 85%, transparent)}}.text-white\/90{color:#ffffffe6}@supports (color:color-mix(in lab, red, red)){.text-white\/90{color:color-mix(in oklab, var(--color-white) 90%, transparent)}}.capitalize{text-transform:capitalize}.normal-case{text-transform:none}.uppercase{text-transform:uppercase}.ordinal{--tw-ordinal:ordinal;font-variant-numeric:var(--tw-ordinal,) var(--tw-slashed-zero,) var(--tw-numeric-figure,) var(--tw-numeric-spacing,) var(--tw-numeric-fraction,)}.tabular-nums{--tw-numeric-spacing:tabular-nums;font-variant-numeric:var(--tw-ordinal,) var(--tw-slashed-zero,) var(--tw-numeric-figure,) var(--tw-numeric-spacing,) var(--tw-numeric-fraction,)}.line-through{text-decoration-line:line-through}.underline{text-decoration-line:underline}.decoration-border{-webkit-text-decoration-color:var(--color-border);-webkit-text-decoration-color:var(--color-border);-webkit-text-decoration-color:var(--color-border);text-decoration-color:var(--color-border)}.decoration-dotted{text-decoration-style:dotted}.underline-offset-2{text-underline-offset:2px}.accent-\[var\(--om-accent\)\]{accent-color:var(--om-accent)}.accent-accent{accent-color:var(--color-accent)}.opacity-0{opacity:0}.opacity-45{opacity:.45}.opacity-50{opacity:.5}.opacity-60{opacity:.6}.opacity-70{opacity:.7}.opacity-80{opacity:.8}.opacity-90{opacity:.9}.shadow{--tw-shadow:0 1px 3px 0 var(--tw-shadow-color,#0000001a), 0 1px 2px -1px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.shadow-2xl{--tw-shadow:0 25px 50px -12px var(--tw-shadow-color,#00000040);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.shadow-\[0_1px_4px_rgba\(0\,0\,0\,0\.14\)\]{--tw-shadow:0 1px 4px var(--tw-shadow-color,#00000024);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.shadow-\[0_1px_4px_rgba\(0\,0\,0\,0\.16\)\]{--tw-shadow:0 1px 4px var(--tw-shadow-color,#00000029);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.shadow-\[0_1px_4px_rgba\(0\,0\,0\,0\.18\)\]{--tw-shadow:0 1px 4px var(--tw-shadow-color,#0000002e);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.shadow-\[0_2px_12px_-6px_rgba\(0\,0\,0\,0\.12\)\]{--tw-shadow:0 2px 12px -6px var(--tw-shadow-color,#0000001f);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.shadow-\[0_2px_12px_rgba\(0\,0\,0\,0\.12\)\]{--tw-shadow:0 2px 12px var(--tw-shadow-color,#0000001f);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.shadow-\[0_4px_20px_-12px_rgba\(0\,0\,0\,0\.2\)\]{--tw-shadow:0 4px 20px -12px var(--tw-shadow-color,#0003);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.shadow-\[0_12px_40px_-12px_rgba\(0\,0\,0\,0\.3\)\]{--tw-shadow:0 12px 40px -12px var(--tw-shadow-color,#0000004d);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.shadow-lg{--tw-shadow:0 10px 15px -3px var(--tw-shadow-color,#0000001a), 0 4px 6px -4px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.shadow-md{--tw-shadow:0 4px 6px -1px var(--tw-shadow-color,#0000001a), 0 2px 4px -2px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.shadow-sm{--tw-shadow:0 1px 3px 0 var(--tw-shadow-color,#0000001a), 0 1px 2px -1px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.shadow-xl{--tw-shadow:0 20px 25px -5px var(--tw-shadow-color,#0000001a), 0 8px 10px -6px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.ring,.ring-1{--tw-ring-shadow:var(--tw-ring-inset,) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.ring-2{--tw-ring-shadow:var(--tw-ring-inset,) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.ring-\[2\.5px\]{--tw-ring-shadow:var(--tw-ring-inset,) 0 0 0 calc(2.5px + var(--tw-ring-offset-width)) var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.ring-\[3px\]{--tw-ring-shadow:var(--tw-ring-inset,) 0 0 0 calc(3px + var(--tw-ring-offset-width)) var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.ring-accent,.ring-accent\/40{--tw-ring-color:var(--color-accent)}@supports (color:color-mix(in lab, red, red)){.ring-accent\/40{--tw-ring-color:color-mix(in oklab, var(--color-accent) 40%, transparent)}}.ring-border\/50{--tw-ring-color:var(--color-border)}@supports (color:color-mix(in lab, red, red)){.ring-border\/50{--tw-ring-color:color-mix(in oklab, var(--color-border) 50%, transparent)}}.ring-offset-2{--tw-ring-offset-width:2px;--tw-ring-offset-shadow:var(--tw-ring-inset,) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color)}.ring-offset-bg{--tw-ring-offset-color:var(--color-bg)}.blur-3xl{--tw-blur:blur(var(--blur-3xl));filter:var(--tw-blur,) var(--tw-brightness,) var(--tw-contrast,) var(--tw-grayscale,) var(--tw-hue-rotate,) var(--tw-invert,) var(--tw-saturate,) var(--tw-sepia,) var(--tw-drop-shadow,)}.drop-shadow-\[0_20px_40px_rgba\(0\,100\,212\,0\.28\)\]{--tw-drop-shadow-size:drop-shadow(0 20px 40px var(--tw-drop-shadow-color,#0064d447));--tw-drop-shadow:var(--tw-drop-shadow-size);filter:var(--tw-blur,) var(--tw-brightness,) var(--tw-contrast,) var(--tw-grayscale,) var(--tw-hue-rotate,) var(--tw-invert,) var(--tw-saturate,) var(--tw-sepia,) var(--tw-drop-shadow,)}.drop-shadow-sm{--tw-drop-shadow-size:drop-shadow(0 1px 2px var(--tw-drop-shadow-color,#00000026));--tw-drop-shadow:drop-shadow(var(--drop-shadow-sm));filter:var(--tw-blur,) var(--tw-brightness,) var(--tw-contrast,) var(--tw-grayscale,) var(--tw-hue-rotate,) var(--tw-invert,) var(--tw-saturate,) var(--tw-sepia,) var(--tw-drop-shadow,)}.filter{filter:var(--tw-blur,) var(--tw-brightness,) var(--tw-contrast,) var(--tw-grayscale,) var(--tw-hue-rotate,) var(--tw-invert,) var(--tw-saturate,) var(--tw-sepia,) var(--tw-drop-shadow,)}.backdrop-blur{--tw-backdrop-blur:blur(8px);-webkit-backdrop-filter:var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,);backdrop-filter:var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,)}.backdrop-blur-2xl{--tw-backdrop-blur:blur(var(--blur-2xl));-webkit-backdrop-filter:var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,);backdrop-filter:var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,)}.backdrop-blur-\[2px\]{--tw-backdrop-blur:blur(2px);-webkit-backdrop-filter:var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,);backdrop-filter:var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,)}.transition{transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to,opacity,box-shadow,transform,translate,scale,rotate,filter,-webkit-backdrop-filter,backdrop-filter,display,content-visibility,overlay,pointer-events;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-all{transition-property:all;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-colors{transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.duration-300{--tw-duration:.3s;transition-duration:.3s}.will-change-transform{will-change:transform}.outline-none{--tw-outline-style:none;outline-style:none}.select-all{-webkit-user-select:all;user-select:all}.select-none{-webkit-user-select:none;user-select:none}@media (hover:hover){.group-hover\:opacity-100:is(:where(.group):hover *){opacity:1}}.placeholder\:text-muted::placeholder{color:var(--color-muted)}.odd\:bg-surface:nth-child(odd){background-color:var(--color-surface)}.focus-within\:border-fg\/20:focus-within{border-color:var(--color-fg)}@supports (color:color-mix(in lab, red, red)){.focus-within\:border-fg\/20:focus-within{border-color:color-mix(in oklab, var(--color-fg) 20%, transparent)}}.focus-within\:ring-2:focus-within{--tw-ring-shadow:var(--tw-ring-inset,) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.focus-within\:ring-accent\/40:focus-within{--tw-ring-color:var(--color-accent)}@supports (color:color-mix(in lab, red, red)){.focus-within\:ring-accent\/40:focus-within{--tw-ring-color:color-mix(in oklab, var(--color-accent) 40%, transparent)}}@media (hover:hover){.hover\:scale-\[1\.04\]:hover{scale:1.04}.hover\:bg-accent\/15:hover{background-color:var(--color-accent)}@supports (color:color-mix(in lab, red, red)){.hover\:bg-accent\/15:hover{background-color:color-mix(in oklab, var(--color-accent) 15%, transparent)}}.hover\:bg-border\/60:hover{background-color:var(--color-border)}@supports (color:color-mix(in lab, red, red)){.hover\:bg-border\/60:hover{background-color:color-mix(in oklab, var(--color-border) 60%, transparent)}}.hover\:bg-rose-500\/10:hover{background-color:#ff23571a}@supports (color:color-mix(in lab, red, red)){.hover\:bg-rose-500\/10:hover{background-color:color-mix(in oklab, var(--color-rose-500) 10%, transparent)}}.hover\:bg-surface:hover{background-color:var(--color-surface)}.hover\:bg-surface-2:hover,.hover\:bg-surface-2\/60:hover{background-color:var(--color-surface-2)}@supports (color:color-mix(in lab, red, red)){.hover\:bg-surface-2\/60:hover{background-color:color-mix(in oklab, var(--color-surface-2) 60%, transparent)}}.hover\:bg-surface-2\/70:hover{background-color:var(--color-surface-2)}@supports (color:color-mix(in lab, red, red)){.hover\:bg-surface-2\/70:hover{background-color:color-mix(in oklab, var(--color-surface-2) 70%, transparent)}}.hover\:text-accent:hover{color:var(--color-accent)}.hover\:text-fg:hover{color:var(--color-fg)}.hover\:text-rose-500:hover{color:var(--color-rose-500)}.hover\:underline:hover{text-decoration-line:underline}.hover\:opacity-90:hover{opacity:.9}.hover\:opacity-100:hover{opacity:1}.hover\:ring-2:hover{--tw-ring-shadow:var(--tw-ring-inset,) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.hover\:ring-accent:hover,.hover\:ring-accent\/60:hover{--tw-ring-color:var(--color-accent)}@supports (color:color-mix(in lab, red, red)){.hover\:ring-accent\/60:hover{--tw-ring-color:color-mix(in oklab, var(--color-accent) 60%, transparent)}}}.focus\:border-accent:focus{border-color:var(--color-accent)}.focus\:bg-surface-2:focus{background-color:var(--color-surface-2)}.focus\:opacity-100:focus{opacity:1}.focus\:ring-2:focus{--tw-ring-shadow:var(--tw-ring-inset,) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.focus\:ring-accent\/40:focus{--tw-ring-color:var(--color-accent)}@supports (color:color-mix(in lab, red, red)){.focus\:ring-accent\/40:focus{--tw-ring-color:color-mix(in oklab, var(--color-accent) 40%, transparent)}}.focus\:outline-none:focus{--tw-outline-style:none;outline-style:none}.active\:scale-95:active{--tw-scale-x:95%;--tw-scale-y:95%;--tw-scale-z:95%;scale:var(--tw-scale-x) var(--tw-scale-y)}.active\:scale-\[0\.98\]:active{scale:.98}.active\:scale-\[0\.99\]:active{scale:.99}.active\:bg-surface-2:active,.active\:bg-surface-2\/70:active{background-color:var(--color-surface-2)}@supports (color:color-mix(in lab, red, red)){.active\:bg-surface-2\/70:active{background-color:color-mix(in oklab, var(--color-surface-2) 70%, transparent)}}.disabled\:opacity-40:disabled{opacity:.4}.disabled\:opacity-50:disabled{opacity:.5}.disabled\:opacity-60:disabled{opacity:.6}.disabled\:opacity-70:disabled{opacity:.7}@media (width>=40rem){.sm\:hidden{display:none}.sm\:max-w-lg{max-width:var(--container-lg)}.sm\:grid-cols-5{grid-template-columns:repeat(5,minmax(0,1fr))}.sm\:items-center{align-items:center}.sm\:justify-center{justify-content:center}.sm\:rounded-3xl{border-radius:var(--radius-3xl)}.sm\:rounded-\[28px\]{border-radius:28px}.sm\:border-x{border-inline-style:var(--tw-border-style);border-inline-width:1px}.sm\:border-border{border-color:var(--color-border)}}@container (width>=42rem){.\@2xl\:grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}}.dark\:border:where([data-theme=dark],[data-theme=dark] *){border-style:var(--tw-border-style);border-width:1px}.dark\:border-border:where([data-theme=dark],[data-theme=dark] *){border-color:var(--color-border)}.dark\:bg-accent\/\[0\.10\]:where([data-theme=dark],[data-theme=dark] *){background-color:var(--color-accent)}@supports (color:color-mix(in lab, red, red)){.dark\:bg-accent\/\[0\.10\]:where([data-theme=dark],[data-theme=dark] *){background-color:color-mix(in oklab, var(--color-accent) 10%, transparent)}}.dark\:bg-amber-400\/\[0\.08\]:where([data-theme=dark],[data-theme=dark] *){background-color:#fcbb0014}@supports (color:color-mix(in lab, red, red)){.dark\:bg-amber-400\/\[0\.08\]:where([data-theme=dark],[data-theme=dark] *){background-color:color-mix(in oklab, var(--color-amber-400) 8%, transparent)}}.dark\:bg-\[radial-gradient\(ellipse_at_top\,rgba\(23\,147\,255\,0\.2\)\,transparent_65\%\)\]:where([data-theme=dark],[data-theme=dark] *){background-image:radial-gradient(at top,#1793ff33,#0000 65%)}.dark\:text-amber-200:where([data-theme=dark],[data-theme=dark] *){color:var(--color-amber-200)}.dark\:text-amber-300:where([data-theme=dark],[data-theme=dark] *){color:var(--color-amber-300)}.dark\:text-cyan-300:where([data-theme=dark],[data-theme=dark] *){color:var(--color-cyan-300)}.dark\:text-emerald-300:where([data-theme=dark],[data-theme=dark] *){color:var(--color-emerald-300)}.dark\:text-emerald-400:where([data-theme=dark],[data-theme=dark] *){color:var(--color-emerald-400)}.dark\:text-fuchsia-300:where([data-theme=dark],[data-theme=dark] *){color:var(--color-fuchsia-300)}.dark\:text-orange-300:where([data-theme=dark],[data-theme=dark] *){color:var(--color-orange-300)}.dark\:text-pink-300:where([data-theme=dark],[data-theme=dark] *){color:var(--color-pink-300)}.dark\:text-red-400:where([data-theme=dark],[data-theme=dark] *){color:var(--color-red-400)}.dark\:text-rose-300:where([data-theme=dark],[data-theme=dark] *){color:var(--color-rose-300)}.dark\:text-rose-400:where([data-theme=dark],[data-theme=dark] *){color:var(--color-rose-400)}.dark\:text-sky-300:where([data-theme=dark],[data-theme=dark] *){color:var(--color-sky-300)}.dark\:text-violet-300:where([data-theme=dark],[data-theme=dark] *){color:var(--color-violet-300)}.dark\:shadow-none:where([data-theme=dark],[data-theme=dark] *){--tw-shadow:0 0 #0000;box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}@media (width>=64rem){.wide\:invisible{visibility:hidden}}:where(html.desktop) .wide\:invisible{visibility:hidden}@media (width>=64rem){.wide\:inset-y-0{inset-block:0}}:where(html.desktop) .wide\:inset-y-0{inset-block:0}@media (width>=64rem){.wide\:mt-0{margin-top:0}}:where(html.desktop) .wide\:mt-0{margin-top:0}@media (width>=64rem){.wide\:mt-5{margin-top:calc(var(--spacing) * 5)}}:where(html.desktop) .wide\:mt-5{margin-top:calc(var(--spacing) * 5)}@media (width>=64rem){.wide\:block{display:block}}:where(html.desktop) .wide\:block{display:block}@media (width>=64rem){.wide\:flex{display:flex}}:where(html.desktop) .wide\:flex{display:flex}@media (width>=64rem){.wide\:grid{display:grid}}:where(html.desktop) .wide\:grid{display:grid}@media (width>=64rem){.wide\:hidden{display:none}}:where(html.desktop) .wide\:hidden{display:none}@media (width>=64rem){.wide\:h-auto{height:auto}}:where(html.desktop) .wide\:h-auto{height:auto}@media (width>=64rem){.wide\:h-full{height:100%}}:where(html.desktop) .wide\:h-full{height:100%}@media (width>=64rem){.wide\:max-w-\[600px\]{max-width:600px}}:where(html.desktop) .wide\:max-w-\[600px\]{max-width:600px}@media (width>=64rem){.wide\:max-w-\[900px\]{max-width:900px}}:where(html.desktop) .wide\:max-w-\[900px\]{max-width:900px}@media (width>=64rem){.wide\:max-w-\[980px\]{max-width:980px}}:where(html.desktop) .wide\:max-w-\[980px\]{max-width:980px}@media (width>=64rem){.wide\:max-w-md{max-width:var(--container-md)}}:where(html.desktop) .wide\:max-w-md{max-width:var(--container-md)}@media (width>=64rem){.wide\:max-w-none{max-width:none}}:where(html.desktop) .wide\:max-w-none{max-width:none}@media (width>=64rem){.wide\:grid-cols-1{grid-template-columns:repeat(1,minmax(0,1fr))}}:where(html.desktop) .wide\:grid-cols-1{grid-template-columns:repeat(1,minmax(0,1fr))}@media (width>=64rem){.wide\:grid-cols-4{grid-template-columns:repeat(4,minmax(0,1fr))}}:where(html.desktop) .wide\:grid-cols-4{grid-template-columns:repeat(4,minmax(0,1fr))}@media (width>=64rem){.wide\:grid-cols-\[1\.1fr_1fr\]{grid-template-columns:1.1fr 1fr}}:where(html.desktop) .wide\:grid-cols-\[1\.1fr_1fr\]{grid-template-columns:1.1fr 1fr}@media (width>=64rem){.wide\:flex-row{flex-direction:row}}:where(html.desktop) .wide\:flex-row{flex-direction:row}@media (width>=64rem){.wide\:items-center{align-items:center}}:where(html.desktop) .wide\:items-center{align-items:center}@media (width>=64rem){.wide\:items-start{align-items:flex-start}}:where(html.desktop) .wide\:items-start{align-items:flex-start}@media (width>=64rem){.wide\:gap-1\.5{gap:calc(var(--spacing) * 1.5)}}:where(html.desktop) .wide\:gap-1\.5{gap:calc(var(--spacing) * 1.5)}@media (width>=64rem){.wide\:gap-16{gap:calc(var(--spacing) * 16)}}:where(html.desktop) .wide\:gap-16{gap:calc(var(--spacing) * 16)}@media (width>=64rem){.wide\:border-0{border-style:var(--tw-border-style);border-width:0}}:where(html.desktop) .wide\:border-0{border-style:var(--tw-border-style);border-width:0}@media (width>=64rem){.wide\:border-x-0{border-inline-style:var(--tw-border-style);border-inline-width:0}}:where(html.desktop) .wide\:border-x-0{border-inline-style:var(--tw-border-style);border-inline-width:0}@media (width>=64rem){.wide\:bg-transparent{background-color:#0000}}:where(html.desktop) .wide\:bg-transparent{background-color:#0000}@media (width>=64rem){.wide\:bg-\[radial-gradient\(ellipse_at_left\,rgba\(0\,100\,212\,0\.12\)\,transparent_60\%\)\]{background-image:radial-gradient(at 0,#0064d41f,#0000 60%)}}:where(html.desktop) .wide\:bg-\[radial-gradient\(ellipse_at_left\,rgba\(0\,100\,212\,0\.12\)\,transparent_60\%\)\]{background-image:radial-gradient(at 0,#0064d41f,#0000 60%)}@media (width>=64rem){.wide\:p-7{padding:calc(var(--spacing) * 7)}}:where(html.desktop) .wide\:p-7{padding:calc(var(--spacing) * 7)}@media (width>=64rem){.wide\:px-0{padding-inline:0}}:where(html.desktop) .wide\:px-0{padding-inline:0}@media (width>=64rem){.wide\:px-12{padding-inline:calc(var(--spacing) * 12)}}:where(html.desktop) .wide\:px-12{padding-inline:calc(var(--spacing) * 12)}@media (width>=64rem){.wide\:py-1{padding-block:var(--spacing)}}:where(html.desktop) .wide\:py-1{padding-block:var(--spacing)}@media (width>=64rem){.wide\:pt-0{padding-top:0}}:where(html.desktop) .wide\:pt-0{padding-top:0}@media (width>=64rem){.wide\:pb-0{padding-bottom:0}}:where(html.desktop) .wide\:pb-0{padding-bottom:0}@media (width>=64rem){.wide\:text-left{text-align:left}}:where(html.desktop) .wide\:text-left{text-align:left}@media (width>=64rem){.wide\:text-\[13\.5px\]{font-size:13.5px}}:where(html.desktop) .wide\:text-\[13\.5px\]{font-size:13.5px}@media (width>=64rem){.wide\:text-\[15\.5px\]{font-size:15.5px}}:where(html.desktop) .wide\:text-\[15\.5px\]{font-size:15.5px}@media (width>=64rem){.wide\:text-\[34px\]{font-size:34px}}:where(html.desktop) .wide\:text-\[34px\]{font-size:34px}@media (width>=64rem){.wide\:dark\:bg-\[radial-gradient\(ellipse_at_left\,rgba\(23\,147\,255\,0\.16\)\,transparent_60\%\)\]:where([data-theme=dark],[data-theme=dark] *){background-image:radial-gradient(at 0,#1793ff29,#0000 60%)}}:where(html.desktop) .wide\:dark\:bg-\[radial-gradient\(ellipse_at_left\,rgba\(23\,147\,255\,0\.16\)\,transparent_60\%\)\]:where([data-theme=dark],[data-theme=dark] *){background-image:radial-gradient(at 0,#1793ff29,#0000 60%)}.\[\&\+\&\]\:mt-1\.5+.\[\&\+\&\]\:mt-1\.5{margin-top:calc(var(--spacing) * 1.5)}}@font-face{font-family:Figtree;font-style:normal;font-weight:300 900;font-display:swap;src:url(/fonts/figtree-latin.woff2)format("woff2");unicode-range:U+??,U+131,U+152-153,U+2BB-2BC,U+2C6,U+2DA,U+2DC,U+304,U+308,U+329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}@font-face{font-family:Figtree;font-style:normal;font-weight:300 900;font-display:swap;src:url(/fonts/figtree-latin-ext.woff2)format("woff2");unicode-range:U+100-2BA,U+2BD-2C5,U+2C7-2CC,U+2CE-2D7,U+2DD-2FF,U+304,U+308,U+329,U+1D00-1DBF,U+1E00-1E9F,U+1EF2-1EFF,U+2020,U+20A0-20AB,U+20AD-20C0,U+2113,U+2C60-2C7F,U+A720-A7FF}:root{--om-bg:#fcfcfc;--om-surface:#fff;--om-surface-2:#f2f2f4;--om-border:#e7e7ea;--om-fg:#111112;--om-muted:#6b6b71;--om-accent:#0064d4;--om-accent-soft:#e5f0ff;--om-accent-soft-fg:#012f80;--om-bubble-user:#d8e9ff;--om-bubble-user-fg:#111112;--lightningcss-light:initial;--lightningcss-dark: ;color-scheme:light}html[data-theme=dark]{--om-bg:#181819;--om-surface:#202022;--om-surface-2:#2a2a2d;--om-border:#333337;--om-fg:#fff;--om-muted:#9d9da4;--om-accent:#1793ff;--om-accent-soft:#1a2b4a;--om-accent-soft-fg:#e5f0ff;--om-bubble-user:#1c3d66;--om-bubble-user-fg:#fff;--lightningcss-light: ;--lightningcss-dark:initial;color-scheme:dark}html,body,#root{height:100%}body{background:var(--om-bg);color:var(--om-fg);font-family:var(--font-sans);-webkit-font-smoothing:antialiased;-webkit-tap-highlight-color:transparent;overscroll-behavior-y:none;margin:0}.safe-top{padding-top:env(safe-area-inset-top)}.titlebar-room{display:none}html.desktop[data-platform=darwin] .titlebar-room{-webkit-app-region:drag;flex-shrink:0;height:28px;display:block}.safe-bottom{padding-bottom:env(safe-area-inset-bottom)}*{scrollbar-width:thin;scrollbar-color:var(--om-border) transparent}::-webkit-scrollbar{width:6px;height:6px}::-webkit-scrollbar-thumb{background:var(--om-border);border-radius:999px}::-webkit-scrollbar-track{background:0 0}@media (pointer:coarse),(width<=480px){*{scrollbar-width:none}::-webkit-scrollbar{display:none}}.no-scrollbar::-webkit-scrollbar{display:none}.no-scrollbar{scrollbar-width:none}.md>:first-child{margin-top:0}.md>:last-child{margin-bottom:0}.md p{margin:.35em 0}.md ul,.md ol{margin:.35em 0;padding-left:1.3em}.md ul{list-style:outside}.md ol{list-style:decimal}.md li{margin:.15em 0}.md h1,.md h2,.md h3,.md h4{margin:.7em 0 .3em;font-weight:650;line-height:1.3}.md h1{font-size:1.15em}.md h2{font-size:1.08em}.md h3,.md h4{font-size:1em}.md a{color:var(--om-accent);text-underline-offset:2px;word-break:break-all;text-decoration:underline}.bubble-user .md a{color:var(--om-accent)}.md code{background:#7f7fa029;border-radius:6px;padding:.1em .35em;font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;font-size:.86em}.md pre{color:#eaeaf5;background:#0f0f19e6;border-radius:12px;margin:.5em 0;padding:.7em .85em;font-size:.82em;line-height:1.45;overflow-x:auto}.md pre code{font-size:inherit;background:0 0;padding:0}.md .md-file{color:var(--om-accent);background:var(--om-accent);font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;font-size:.86em}@supports (color:color-mix(in lab, red, red)){.md .md-file{background:color-mix(in srgb, var(--om-accent) 12%, transparent)}}.md .md-file{text-underline-offset:2px;word-break:break-all;border-radius:6px;padding:.1em .4em;-webkit-text-decoration:underline dotted;text-decoration:underline dotted}.md blockquote{border-left:3px solid var(--om-border);color:var(--om-muted);margin:.5em 0;padding-left:.8em}.md table{border-collapse:collapse;max-width:100%;margin:.5em 0;font-size:.9em;display:block;overflow-x:auto}.md th,.md td{border:1px solid var(--om-border);text-align:left;padding:.3em .55em}.md hr{border:0;border-top:1px solid var(--om-border);margin:.7em 0}.md img{border-radius:10px;max-width:100%}@keyframes om-breathe{0%,to{transform:translateY(0)scale(1)}50%{transform:translateY(-1.5%)scale(1.025)}}@keyframes om-sway{0%,to{transform:rotate(-4deg)translateY(0)}25%{transform:rotate(0)translateY(-2%)}50%{transform:rotate(4deg)translateY(0)}75%{transform:rotate(0)translateY(-2%)}}@keyframes om-hop{0%,70%,to{transform:translateY(0)scale(1)}78%{transform:translateY(-9%)scale(1.04,.97)}86%{transform:translateY(0)scale(.98,1.03)}92%{transform:translateY(-3%)scale(1)}}@keyframes om-wiggle{0%,to{transform:rotate(0)}20%{transform:rotate(-10deg)scale(1.06)}45%{transform:rotate(9deg)scale(1.06)}70%{transform:rotate(-5deg)}}.avatar-idle{animation:4.5s ease-in-out infinite om-breathe}.avatar-working{animation:2.6s ease-in-out infinite om-sway}.avatar-waiting{animation:3.2s ease-in-out infinite om-hop}.avatar-wiggle{animation:.6s ease-in-out om-wiggle}@keyframes om-pop{0%{transform:scale(.6)}70%{transform:scale(1.06)}to{transform:scale(1)}}.avatar-pop{animation:.55s cubic-bezier(.34,1.56,.64,1) om-pop}@media (prefers-reduced-motion:reduce){.avatar-idle,.avatar-working,.avatar-waiting,.avatar-wiggle,.avatar-pop{animation:none}}@keyframes om-blink{50%{opacity:.25}}.typing-dot{animation:1.1s infinite om-blink}.typing-dot:nth-child(2){animation-delay:.18s}.typing-dot:nth-child(3){animation-delay:.36s}@keyframes om-rise{0%{opacity:0;transform:translateY(6px)}to{opacity:1;transform:none}}.rise{animation:.18s ease-out om-rise}@keyframes om-sheet{0%{transform:translateY(100%)}to{transform:none}}.sheet-in{animation:.22s cubic-bezier(.2,.8,.2,1) om-sheet}@keyframes om-drawer-in{0%{transform:translate(-100%)}to{transform:none}}.drawer-in{animation:.2s ease-out om-drawer-in}@property --tw-border-spacing-x{syntax:"";inherits:false;initial-value:0}@property --tw-border-spacing-y{syntax:"";inherits:false;initial-value:0}@property --tw-translate-x{syntax:"*";inherits:false;initial-value:0}@property --tw-translate-y{syntax:"*";inherits:false;initial-value:0}@property --tw-translate-z{syntax:"*";inherits:false;initial-value:0}@property --tw-space-y-reverse{syntax:"*";inherits:false;initial-value:0}@property --tw-divide-y-reverse{syntax:"*";inherits:false;initial-value:0}@property --tw-border-style{syntax:"*";inherits:false;initial-value:solid}@property --tw-gradient-position{syntax:"*";inherits:false}@property --tw-gradient-from{syntax:"";inherits:false;initial-value:#0000}@property --tw-gradient-via{syntax:"";inherits:false;initial-value:#0000}@property --tw-gradient-to{syntax:"";inherits:false;initial-value:#0000}@property --tw-gradient-stops{syntax:"*";inherits:false}@property --tw-gradient-via-stops{syntax:"*";inherits:false}@property --tw-gradient-from-position{syntax:"";inherits:false;initial-value:0%}@property --tw-gradient-via-position{syntax:"";inherits:false;initial-value:50%}@property --tw-gradient-to-position{syntax:"";inherits:false;initial-value:100%}@property --tw-leading{syntax:"*";inherits:false}@property --tw-font-weight{syntax:"*";inherits:false}@property --tw-tracking{syntax:"*";inherits:false}@property --tw-ordinal{syntax:"*";inherits:false}@property --tw-slashed-zero{syntax:"*";inherits:false}@property --tw-numeric-figure{syntax:"*";inherits:false}@property --tw-numeric-spacing{syntax:"*";inherits:false}@property --tw-numeric-fraction{syntax:"*";inherits:false}@property --tw-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-shadow-color{syntax:"*";inherits:false}@property --tw-shadow-alpha{syntax:"";inherits:false;initial-value:100%}@property --tw-inset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-shadow-color{syntax:"*";inherits:false}@property --tw-inset-shadow-alpha{syntax:"";inherits:false;initial-value:100%}@property --tw-ring-color{syntax:"*";inherits:false}@property --tw-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-ring-color{syntax:"*";inherits:false}@property --tw-inset-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-ring-inset{syntax:"*";inherits:false}@property --tw-ring-offset-width{syntax:"";inherits:false;initial-value:0}@property --tw-ring-offset-color{syntax:"*";inherits:false;initial-value:#fff}@property --tw-ring-offset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-blur{syntax:"*";inherits:false}@property --tw-brightness{syntax:"*";inherits:false}@property --tw-contrast{syntax:"*";inherits:false}@property --tw-grayscale{syntax:"*";inherits:false}@property --tw-hue-rotate{syntax:"*";inherits:false}@property --tw-invert{syntax:"*";inherits:false}@property --tw-opacity{syntax:"*";inherits:false}@property --tw-saturate{syntax:"*";inherits:false}@property --tw-sepia{syntax:"*";inherits:false}@property --tw-drop-shadow{syntax:"*";inherits:false}@property --tw-drop-shadow-color{syntax:"*";inherits:false}@property --tw-drop-shadow-alpha{syntax:"";inherits:false;initial-value:100%}@property --tw-drop-shadow-size{syntax:"*";inherits:false}@property --tw-backdrop-blur{syntax:"*";inherits:false}@property --tw-backdrop-brightness{syntax:"*";inherits:false}@property --tw-backdrop-contrast{syntax:"*";inherits:false}@property --tw-backdrop-grayscale{syntax:"*";inherits:false}@property --tw-backdrop-hue-rotate{syntax:"*";inherits:false}@property --tw-backdrop-invert{syntax:"*";inherits:false}@property --tw-backdrop-opacity{syntax:"*";inherits:false}@property --tw-backdrop-saturate{syntax:"*";inherits:false}@property --tw-backdrop-sepia{syntax:"*";inherits:false}@property --tw-duration{syntax:"*";inherits:false}@property --tw-scale-x{syntax:"*";inherits:false;initial-value:1}@property --tw-scale-y{syntax:"*";inherits:false;initial-value:1}@property --tw-scale-z{syntax:"*";inherits:false;initial-value:1}@keyframes spin{to{transform:rotate(360deg)}}@keyframes pulse{50%{opacity:.5}} diff --git a/nanomuse/server/static/assets/index-CIdGZ5PB.js b/nanomuse/server/static/assets/index-DKrXW2Qj.js similarity index 99% rename from nanomuse/server/static/assets/index-CIdGZ5PB.js rename to nanomuse/server/static/assets/index-DKrXW2Qj.js index 0ba4f0f94..2b525b1a8 100644 --- a/nanomuse/server/static/assets/index-CIdGZ5PB.js +++ b/nanomuse/server/static/assets/index-DKrXW2Qj.js @@ -1,5 +1,5 @@ -const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["assets/AccountScreen-bHMDrVr5.js","assets/MuseHeader-Pw-NI98v.js","assets/StarNudge-DjXecvWj.js","assets/external-link-Xj5fjR8v.js","assets/Form-DwKuBk1V.js","assets/clapperboard-BokpXv9J.js","assets/database-zap-CzaFBl6C.js","assets/image-crWy0a06.js","assets/BackBar-Dl56jHZM.js","assets/AvatarStudioScreen-DD2X0R8P.js","assets/refresh-cw-BKgIzslL.js","assets/AvatarPicker-gR2knlot.js","assets/ChannelsScreen-mBzj7BLf.js","assets/CodingScreen-C_tutsx0.js","assets/ConnectionsScreen-CMt7GOff.js","assets/plug-Bj_5EEV3.js","assets/CloudCard-CtVHK0qc.js","assets/DevicesScreen-g6FUY327.js","assets/GoalsScreen-Dp2fRaLA.js","assets/IdeasScreen-CGfvq5H-.js","assets/LibraryScreen-B8JlrC_n.js","assets/MemoryScreen-M8j03G3u.js","assets/Onboarding-CtVO6gdK.js","assets/IdentityForm-BTGczGT_.js","assets/SettingsScreen-CHVg61To.js","assets/SkillsScreen-Dr-d7iS7.js"])))=>i.map(i=>d[i]); -import{A as e,B as t,C as n,D as r,E as i,I as a,J as o,K as s,L as c,M as l,N as u,O as d,P as f,Q as p,R as m,S as h,T as g,U as _,V as v,W as y,X as b,Y as x,Z as S,b as C,c as w,d as T,f as E,i as D,j as O,n as k,p as ee,q as A,r as te,s as j,t as ne,u as re,x as M,y as N,z as P}from"./MuseHeader-Pw-NI98v.js";import{A as ie,C as ae,D as oe,E as se,M as ce,N as le,P as ue,S as de,a as fe,b as pe,c as me,h as he,i as ge,j as _e,l as ve,n as ye,o as be,p as xe,r as Se,s as Ce,t as we,u as Te,v as Ee,x as De,y as Oe}from"./StarNudge-DjXecvWj.js";import{n as ke,t as Ae}from"./external-link-Xj5fjR8v.js";import{a as je,c as Me,i as Ne,n as Pe,o as Fe,r as Ie,s as Le}from"./Form-DwKuBk1V.js";import{t as Re}from"./refresh-cw-BKgIzslL.js";(function(){let e=document.createElement(`link`).relList;if(e&&e.supports&&e.supports(`modulepreload`))return;for(let e of document.querySelectorAll(`link[rel="modulepreload"]`))n(e);new MutationObserver(e=>{for(let t of e)if(t.type===`childList`)for(let e of t.addedNodes)e.tagName===`LINK`&&e.rel===`modulepreload`&&n(e)}).observe(document,{childList:!0,subtree:!0});function t(e){let t={};return e.integrity&&(t.integrity=e.integrity),e.referrerPolicy&&(t.referrerPolicy=e.referrerPolicy),t.credentials=e.crossOrigin===`use-credentials`?`include`:e.crossOrigin===`anonymous`?`omit`:`same-origin`,t}function n(e){if(e.ep)return;e.ep=!0;let n=t(e);fetch(e.href,n)}})();var ze=b((e=>{function t(e,t){var n=e.length;e.push(t);a:for(;0>>1,a=e[r];if(0>>1;ri(c,n))li(u,c)?(e[r]=u,e[l]=n,r=l):(e[r]=c,e[s]=n,r=s);else if(li(u,n))e[r]=u,e[l]=n,r=l;else break a}}return t}function i(e,t){var n=e.sortIndex-t.sortIndex;return n===0?e.id-t.id:n}if(typeof performance==`object`&&typeof performance.now==`function`){var a=performance;e.unstable_now=function(){return a.now()}}else{var o=Date,s=o.now();e.unstable_now=function(){return o.now()-s}}var c=[],l=[],u=1,d=null,f=3,p=!1,m=!1,h=!1,g=typeof setTimeout==`function`?setTimeout:null,_=typeof clearTimeout==`function`?clearTimeout:null,v=typeof setImmediate<`u`?setImmediate:null;typeof navigator<`u`&&navigator.scheduling!==void 0&&navigator.scheduling.isInputPending!==void 0&&navigator.scheduling.isInputPending.bind(navigator.scheduling);function y(e){for(var i=n(l);i!==null;){if(i.callback===null)r(l);else if(i.startTime<=e)r(l),i.sortIndex=i.expirationTime,t(c,i);else break;i=n(l)}}function b(e){if(h=!1,y(e),!m){if(n(c)!==null)m=!0,te(x);else{var t=n(l);t!==null&&j(b,t.startTime-e)}}}function x(t,i){m=!1,h&&(h=!1,_(w),w=-1),p=!0;var a=f;try{for(y(i),d=n(c);d!==null&&(!(d.expirationTime>i)||t&&!D());){var o=d.callback;if(typeof o==`function`){d.callback=null,f=d.priorityLevel;var s=o(d.expirationTime<=i);i=e.unstable_now(),typeof s==`function`?d.callback=s:d===n(c)&&r(c),y(i)}else r(c);d=n(c)}if(d!==null)var u=!0;else{var g=n(l);g!==null&&j(b,g.startTime-i),u=!1}return u}finally{d=null,f=a,p=!1}}var S=!1,C=null,w=-1,T=5,E=-1;function D(){return!(e.unstable_now()-Ee||125o?(r.sortIndex=a,t(l,r),n(c)===null&&r===n(l)&&(h?(_(w),w=-1):h=!0,j(b,a-o))):(r.sortIndex=s,t(c,r),m||p||(m=!0,te(x))),r},e.unstable_shouldYield=D,e.unstable_wrapCallback=function(e){var t=f;return function(){var n=f;f=t;try{return e.apply(this,arguments)}finally{f=n}}}})),Be=b(((e,t)=>{t.exports=ze()})),Ve=b((e=>{var t=x(),n=Be();function r(e){for(var t=`https://reactjs.org/docs/error-decoder.html?invariant=`+e,n=1;nt}return!1}function g(e,t,n,r,i,a,o){this.acceptsBooleans=t===2||t===3||t===4,this.attributeName=r,this.attributeNamespace=i,this.mustUseProperty=n,this.propertyName=e,this.type=t,this.sanitizeURL=a,this.removeEmptyString=o}var _={};`children dangerouslySetInnerHTML defaultValue defaultChecked innerHTML suppressContentEditableWarning suppressHydrationWarning style`.split(` `).forEach(function(e){_[e]=new g(e,0,!1,e,null,!1,!1)}),[[`acceptCharset`,`accept-charset`],[`className`,`class`],[`htmlFor`,`for`],[`httpEquiv`,`http-equiv`]].forEach(function(e){var t=e[0];_[t]=new g(t,1,!1,e[1],null,!1,!1)}),[`contentEditable`,`draggable`,`spellCheck`,`value`].forEach(function(e){_[e]=new g(e,2,!1,e.toLowerCase(),null,!1,!1)}),[`autoReverse`,`externalResourcesRequired`,`focusable`,`preserveAlpha`].forEach(function(e){_[e]=new g(e,2,!1,e,null,!1,!1)}),`allowFullScreen async autoFocus autoPlay controls default defer disabled disablePictureInPicture disableRemotePlayback formNoValidate hidden loop noModule noValidate open playsInline readOnly required reversed scoped seamless itemScope`.split(` `).forEach(function(e){_[e]=new g(e,3,!1,e.toLowerCase(),null,!1,!1)}),[`checked`,`multiple`,`muted`,`selected`].forEach(function(e){_[e]=new g(e,3,!0,e,null,!1,!1)}),[`capture`,`download`].forEach(function(e){_[e]=new g(e,4,!1,e,null,!1,!1)}),[`cols`,`rows`,`size`,`span`].forEach(function(e){_[e]=new g(e,6,!1,e,null,!1,!1)}),[`rowSpan`,`start`].forEach(function(e){_[e]=new g(e,5,!1,e.toLowerCase(),null,!1,!1)});var v=/[\-:]([a-z])/g;function y(e){return e[1].toUpperCase()}`accent-height alignment-baseline arabic-form baseline-shift cap-height clip-path clip-rule color-interpolation color-interpolation-filters color-profile color-rendering dominant-baseline enable-background fill-opacity fill-rule flood-color flood-opacity font-family font-size font-size-adjust font-stretch font-style font-variant font-weight glyph-name glyph-orientation-horizontal glyph-orientation-vertical horiz-adv-x horiz-origin-x image-rendering letter-spacing lighting-color marker-end marker-mid marker-start overline-position overline-thickness paint-order panose-1 pointer-events rendering-intent shape-rendering stop-color stop-opacity strikethrough-position strikethrough-thickness stroke-dasharray stroke-dashoffset stroke-linecap stroke-linejoin stroke-miterlimit stroke-opacity stroke-width text-anchor text-decoration text-rendering underline-position underline-thickness unicode-bidi unicode-range units-per-em v-alphabetic v-hanging v-ideographic v-mathematical vector-effect vert-adv-y vert-origin-x vert-origin-y word-spacing writing-mode xmlns:xlink x-height`.split(` `).forEach(function(e){var t=e.replace(v,y);_[t]=new g(t,1,!1,e,null,!1,!1)}),`xlink:actuate xlink:arcrole xlink:role xlink:show xlink:title xlink:type`.split(` `).forEach(function(e){var t=e.replace(v,y);_[t]=new g(t,1,!1,e,`http://www.w3.org/1999/xlink`,!1,!1)}),[`xml:base`,`xml:lang`,`xml:space`].forEach(function(e){var t=e.replace(v,y);_[t]=new g(t,1,!1,e,`http://www.w3.org/XML/1998/namespace`,!1,!1)}),[`tabIndex`,`crossOrigin`].forEach(function(e){_[e]=new g(e,1,!1,e.toLowerCase(),null,!1,!1)}),_.xlinkHref=new g(`xlinkHref`,1,!1,`xlink:href`,`http://www.w3.org/1999/xlink`,!0,!1),[`src`,`href`,`action`,`formAction`].forEach(function(e){_[e]=new g(e,1,!1,e.toLowerCase(),null,!0,!0)});function b(e,t,n,r){var i=_.hasOwnProperty(t)?_[t]:null;(i===null?r||!(2i.map(i=>d[i]); +import{A as e,B as t,C as n,D as r,E as i,I as a,J as o,K as s,L as c,M as l,N as u,O as d,P as f,Q as p,R as m,S as h,T as g,U as _,V as v,W as y,X as b,Y as x,Z as S,b as C,c as w,d as T,f as E,i as D,j as O,n as k,p as ee,q as A,r as te,s as j,t as ne,u as re,x as M,y as N,z as P}from"./MuseHeader-BDWXHKHT.js";import{A as ie,C as ae,D as oe,E as se,M as ce,N as le,P as ue,S as de,a as fe,b as pe,c as me,h as he,i as ge,j as _e,l as ve,n as ye,o as be,p as xe,r as Se,s as Ce,t as we,u as Te,v as Ee,x as De,y as Oe}from"./StarNudge-B8P2bPEz.js";import{n as ke,t as Ae}from"./external-link-CZH-rQLq.js";import{a as je,c as Me,i as Ne,n as Pe,o as Fe,r as Ie,s as Le}from"./Form-B3Ejw5aI.js";import{t as Re}from"./refresh-cw-qw351CFk.js";(function(){let e=document.createElement(`link`).relList;if(e&&e.supports&&e.supports(`modulepreload`))return;for(let e of document.querySelectorAll(`link[rel="modulepreload"]`))n(e);new MutationObserver(e=>{for(let t of e)if(t.type===`childList`)for(let e of t.addedNodes)e.tagName===`LINK`&&e.rel===`modulepreload`&&n(e)}).observe(document,{childList:!0,subtree:!0});function t(e){let t={};return e.integrity&&(t.integrity=e.integrity),e.referrerPolicy&&(t.referrerPolicy=e.referrerPolicy),t.credentials=e.crossOrigin===`use-credentials`?`include`:e.crossOrigin===`anonymous`?`omit`:`same-origin`,t}function n(e){if(e.ep)return;e.ep=!0;let n=t(e);fetch(e.href,n)}})();var ze=b((e=>{function t(e,t){var n=e.length;e.push(t);a:for(;0>>1,a=e[r];if(0>>1;ri(c,n))li(u,c)?(e[r]=u,e[l]=n,r=l):(e[r]=c,e[s]=n,r=s);else if(li(u,n))e[r]=u,e[l]=n,r=l;else break a}}return t}function i(e,t){var n=e.sortIndex-t.sortIndex;return n===0?e.id-t.id:n}if(typeof performance==`object`&&typeof performance.now==`function`){var a=performance;e.unstable_now=function(){return a.now()}}else{var o=Date,s=o.now();e.unstable_now=function(){return o.now()-s}}var c=[],l=[],u=1,d=null,f=3,p=!1,m=!1,h=!1,g=typeof setTimeout==`function`?setTimeout:null,_=typeof clearTimeout==`function`?clearTimeout:null,v=typeof setImmediate<`u`?setImmediate:null;typeof navigator<`u`&&navigator.scheduling!==void 0&&navigator.scheduling.isInputPending!==void 0&&navigator.scheduling.isInputPending.bind(navigator.scheduling);function y(e){for(var i=n(l);i!==null;){if(i.callback===null)r(l);else if(i.startTime<=e)r(l),i.sortIndex=i.expirationTime,t(c,i);else break;i=n(l)}}function b(e){if(h=!1,y(e),!m){if(n(c)!==null)m=!0,te(x);else{var t=n(l);t!==null&&j(b,t.startTime-e)}}}function x(t,i){m=!1,h&&(h=!1,_(w),w=-1),p=!0;var a=f;try{for(y(i),d=n(c);d!==null&&(!(d.expirationTime>i)||t&&!D());){var o=d.callback;if(typeof o==`function`){d.callback=null,f=d.priorityLevel;var s=o(d.expirationTime<=i);i=e.unstable_now(),typeof s==`function`?d.callback=s:d===n(c)&&r(c),y(i)}else r(c);d=n(c)}if(d!==null)var u=!0;else{var g=n(l);g!==null&&j(b,g.startTime-i),u=!1}return u}finally{d=null,f=a,p=!1}}var S=!1,C=null,w=-1,T=5,E=-1;function D(){return!(e.unstable_now()-Ee||125o?(r.sortIndex=a,t(l,r),n(c)===null&&r===n(l)&&(h?(_(w),w=-1):h=!0,j(b,a-o))):(r.sortIndex=s,t(c,r),m||p||(m=!0,te(x))),r},e.unstable_shouldYield=D,e.unstable_wrapCallback=function(e){var t=f;return function(){var n=f;f=t;try{return e.apply(this,arguments)}finally{f=n}}}})),Be=b(((e,t)=>{t.exports=ze()})),Ve=b((e=>{var t=x(),n=Be();function r(e){for(var t=`https://reactjs.org/docs/error-decoder.html?invariant=`+e,n=1;nt}return!1}function g(e,t,n,r,i,a,o){this.acceptsBooleans=t===2||t===3||t===4,this.attributeName=r,this.attributeNamespace=i,this.mustUseProperty=n,this.propertyName=e,this.type=t,this.sanitizeURL=a,this.removeEmptyString=o}var _={};`children dangerouslySetInnerHTML defaultValue defaultChecked innerHTML suppressContentEditableWarning suppressHydrationWarning style`.split(` `).forEach(function(e){_[e]=new g(e,0,!1,e,null,!1,!1)}),[[`acceptCharset`,`accept-charset`],[`className`,`class`],[`htmlFor`,`for`],[`httpEquiv`,`http-equiv`]].forEach(function(e){var t=e[0];_[t]=new g(t,1,!1,e[1],null,!1,!1)}),[`contentEditable`,`draggable`,`spellCheck`,`value`].forEach(function(e){_[e]=new g(e,2,!1,e.toLowerCase(),null,!1,!1)}),[`autoReverse`,`externalResourcesRequired`,`focusable`,`preserveAlpha`].forEach(function(e){_[e]=new g(e,2,!1,e,null,!1,!1)}),`allowFullScreen async autoFocus autoPlay controls default defer disabled disablePictureInPicture disableRemotePlayback formNoValidate hidden loop noModule noValidate open playsInline readOnly required reversed scoped seamless itemScope`.split(` `).forEach(function(e){_[e]=new g(e,3,!1,e.toLowerCase(),null,!1,!1)}),[`checked`,`multiple`,`muted`,`selected`].forEach(function(e){_[e]=new g(e,3,!0,e,null,!1,!1)}),[`capture`,`download`].forEach(function(e){_[e]=new g(e,4,!1,e,null,!1,!1)}),[`cols`,`rows`,`size`,`span`].forEach(function(e){_[e]=new g(e,6,!1,e,null,!1,!1)}),[`rowSpan`,`start`].forEach(function(e){_[e]=new g(e,5,!1,e.toLowerCase(),null,!1,!1)});var v=/[\-:]([a-z])/g;function y(e){return e[1].toUpperCase()}`accent-height alignment-baseline arabic-form baseline-shift cap-height clip-path clip-rule color-interpolation color-interpolation-filters color-profile color-rendering dominant-baseline enable-background fill-opacity fill-rule flood-color flood-opacity font-family font-size font-size-adjust font-stretch font-style font-variant font-weight glyph-name glyph-orientation-horizontal glyph-orientation-vertical horiz-adv-x horiz-origin-x image-rendering letter-spacing lighting-color marker-end marker-mid marker-start overline-position overline-thickness paint-order panose-1 pointer-events rendering-intent shape-rendering stop-color stop-opacity strikethrough-position strikethrough-thickness stroke-dasharray stroke-dashoffset stroke-linecap stroke-linejoin stroke-miterlimit stroke-opacity stroke-width text-anchor text-decoration text-rendering underline-position underline-thickness unicode-bidi unicode-range units-per-em v-alphabetic v-hanging v-ideographic v-mathematical vector-effect vert-adv-y vert-origin-x vert-origin-y word-spacing writing-mode xmlns:xlink x-height`.split(` `).forEach(function(e){var t=e.replace(v,y);_[t]=new g(t,1,!1,e,null,!1,!1)}),`xlink:actuate xlink:arcrole xlink:role xlink:show xlink:title xlink:type`.split(` `).forEach(function(e){var t=e.replace(v,y);_[t]=new g(t,1,!1,e,`http://www.w3.org/1999/xlink`,!1,!1)}),[`xml:base`,`xml:lang`,`xml:space`].forEach(function(e){var t=e.replace(v,y);_[t]=new g(t,1,!1,e,`http://www.w3.org/XML/1998/namespace`,!1,!1)}),[`tabIndex`,`crossOrigin`].forEach(function(e){_[e]=new g(e,1,!1,e.toLowerCase(),null,!1,!1)}),_.xlinkHref=new g(`xlinkHref`,1,!1,`xlink:href`,`http://www.w3.org/1999/xlink`,!0,!1),[`src`,`href`,`action`,`formAction`].forEach(function(e){_[e]=new g(e,1,!1,e.toLowerCase(),null,!0,!0)});function b(e,t,n,r){var i=_.hasOwnProperty(t)?_[t]:null;(i===null?r||!(2s||i[o]!==a[s]){var c=` @@ -41,4 +41,4 @@ Error generating stack: `+e.message+` `)){let e=/^\s*(```|~~~)/.exec(t);if(r){n.push(t),e&&e[1]===r&&(r=null);continue}if(e){n.length&&i(),r=e[1],n.push(t);continue}if(t.trim()===``){i();continue}n.push(t)}return i(),t}function hf({text:e,files:t=[],onOpenFile:n}){let r=e=>n&&e&&t.length>0?uf(e,t):null,i=e=>n?.(e),a=n&&t.length>0?ff(e,t):e;return(0,R.jsx)(`div`,{className:`md text-[15px] leading-[1.5] break-words`,children:(0,R.jsx)(il,{remarkPlugins:[lf],components:{a:({href:e,children:t,...n})=>{let a=e&&!/^[a-z]+:/i.test(e)?r(O(e)):null;return a?(0,R.jsx)(`button`,{type:`button`,className:`md-file`,onClick:()=>i(a),children:t}):(0,R.jsx)(`a`,{href:e,...n,target:`_blank`,rel:`noreferrer noopener`,children:t})},code:({children:e,...t})=>{let n=pf({children:e,...t})&&typeof e==`string`?r(e):null;return n?(0,R.jsx)(`button`,{type:`button`,className:`md-file`,onClick:()=>i(n),title:n,children:e}):(0,R.jsx)(`code`,{...t,children:e})}},children:a})})}function gf({path:e,onClose:t}){let n=s(),i=(0,L.useRef)(null);if(On(i,!!e),(0,L.useEffect)(()=>{if(!e)return;let n=e=>e.key===`Escape`&&t();return window.addEventListener(`keydown`,n),()=>window.removeEventListener(`keydown`,n)},[e,t]),!e)return null;let a=e.split(`/`).pop()??e,o=r(a);return(0,R.jsxs)(`div`,{ref:i,role:`dialog`,"aria-modal":`true`,"aria-label":a,className:`fixed inset-0 z-[60] flex flex-col bg-bg`,children:[(0,R.jsxs)(`header`,{className:`safe-top shrink-0 flex items-center gap-2 border-b border-border bg-surface/90 px-3 py-2 backdrop-blur`,children:[(0,R.jsx)(`button`,{type:`button`,onClick:t,"aria-label":n(`Close`),className:`p-2 rounded-full text-muted hover:bg-surface-2`,children:(0,R.jsx)(Fe,{size:20})}),(0,R.jsxs)(`div`,{className:`flex-1 min-w-0`,children:[(0,R.jsx)(`div`,{className:`font-semibold text-[15px] truncate`,children:a}),(0,R.jsx)(`div`,{className:`text-[12px] text-muted truncate`,children:e})]}),o!==`html`&&(0,R.jsx)(`a`,{href:h(e),target:`_blank`,rel:`noreferrer noopener`,"aria-label":n(`Open in a new tab`),className:`p-2 rounded-full text-muted hover:bg-surface-2`,children:(0,R.jsx)(Ae,{size:19})}),(0,R.jsx)(`a`,{href:h(e,!0),"aria-label":n(`Download`),className:`p-2 rounded-full text-muted hover:bg-surface-2`,children:(0,R.jsx)(ft,{size:19})})]}),(0,R.jsx)(`div`,{className:`min-h-0 flex-1 overflow-auto`,children:(0,R.jsx)(_f,{path:e,kind:o})})]})}function _f({path:e,kind:t}){let n=s();return t===`image`?(0,R.jsx)(`div`,{className:`flex h-full items-center justify-center p-3`,children:(0,R.jsx)(`img`,{src:h(e),alt:e,className:`max-h-full max-w-full rounded-2xl object-contain`})}):t===`pdf`?(0,R.jsx)(`iframe`,{title:e,src:h(e),className:`h-full w-full bg-white`}):t===`html`?(0,R.jsx)(yf,{path:e}):t===`event`?(0,R.jsx)(bf,{path:e}):t===`text`||t===`code`||t===`data`?(0,R.jsx)(Cf,{path:e,kind:t}):(0,R.jsxs)(`div`,{className:`p-8 text-center text-muted text-[14px]`,children:[n(`No preview for this file type.`),` `,(0,R.jsx)(`a`,{href:h(e,!0),className:`text-accent font-medium`,children:n(`Download it`)})]})}function vf(e){let[t,n]=(0,L.useState)(null),[r,i]=(0,L.useState)(null);return(0,L.useEffect)(()=>{let t=!0;return n(null),i(null),M.fileText(e).then(e=>t&&n(e)).catch(e=>t&&i(e.message)),()=>{t=!1}},[e]),{text:t,error:r}}function yf({path:e}){let{text:t,error:n}=vf(e);return n?(0,R.jsx)(Ef,{error:n}):t===null?(0,R.jsx)(Tf,{}):(0,R.jsx)(`iframe`,{title:e,srcDoc:t,sandbox:`allow-scripts allow-popups allow-forms allow-modals`,referrerPolicy:`no-referrer`,className:`h-full w-full bg-white`})}function bf({path:e}){let t=s(),{text:n,error:r}=vf(e);if(r)return(0,R.jsx)(Ef,{error:r});if(n===null)return(0,R.jsx)(Tf,{});let i=xf(n);return(0,R.jsxs)(`div`,{className:`mx-auto max-w-[560px] px-5 py-6 space-y-4`,children:[i.length===0&&(0,R.jsx)(`div`,{className:`text-center text-muted text-[14px]`,children:t(`No event in this file.`)}),i.map((e,n)=>(0,R.jsxs)(`div`,{className:`rounded-3xl border border-border/70 bg-surface shadow-sm p-5`,children:[(0,R.jsxs)(`div`,{className:`flex items-start gap-3`,children:[(0,R.jsx)(`div`,{className:`rounded-2xl bg-accent/12 text-accent p-2.5`,children:(0,R.jsx)(tt,{size:22})}),(0,R.jsxs)(`div`,{className:`min-w-0 flex-1`,children:[(0,R.jsx)(`div`,{className:`text-[18px] font-semibold leading-snug`,children:e.summary||t(`Untitled event`)}),(0,R.jsx)(`div`,{className:`mt-1 text-[14px] text-muted`,children:Sf(e)}),e.location&&(0,R.jsxs)(`div`,{className:`mt-1 flex items-center gap-1 text-[14px] text-muted`,children:[(0,R.jsx)(Dt,{size:14}),` `,e.location]})]})]}),e.description&&(0,R.jsx)(`div`,{className:`mt-4 whitespace-pre-wrap text-[14px] leading-relaxed`,children:e.description})]},n)),(0,R.jsxs)(`a`,{href:h(e,!0),download:!0,className:`flex items-center justify-center gap-2 rounded-2xl bg-accent text-accent-fg px-4 py-3 text-[15px] font-medium`,children:[(0,R.jsx)(nt,{size:18}),` `,t(`Add to calendar`)]}),(0,R.jsx)(`p`,{className:`text-center text-[12.5px] text-muted`,children:t(`Opens in your calendar app, which asks before it saves anything.`)})]})}function xf(e){let t=e.replace(/\r\n/g,` `).replace(/\n[ \t]/g,``).split(` `),n=[],r=null,i=e=>e.replace(/\\n/gi,` -`).replace(/\\([,;\\])/g,`$1`),a=(e,t)=>{if(/VALUE=DATE(?![-])/i.test(t)||/^\d{8}$/.test(e)){let t=/^(\d{4})(\d{2})(\d{2})/.exec(e);return{at:t?new Date(+t[1],t[2]-1,+t[3]):null,allDay:!0}}let n=/^(\d{4})(\d{2})(\d{2})T(\d{2})(\d{2})(\d{2})?(Z?)$/.exec(e);if(!n)return{at:null,allDay:!1};let r=[+n[1],n[2]-1,+n[3],+n[4],+n[5],+(n[6]??0)];return{at:n[7]?new Date(Date.UTC(...r)):new Date(...r),allDay:!1}};for(let e of t)if(e===`BEGIN:VEVENT`)r={summary:``,location:``,description:``,start:null,end:null,allDay:!1};else if(e===`END:VEVENT`&&r)n.push(r),r=null;else if(r){let t=e.indexOf(`:`);if(t<0)continue;let[n,...o]=e.slice(0,t).split(`;`),s=e.slice(t+1),c=o.join(`;`);if(n===`SUMMARY`)r.summary=i(s);else if(n===`LOCATION`)r.location=i(s);else if(n===`DESCRIPTION`)r.description=i(s);else if(n===`DTSTART`){let e=a(s,c);r.start=e.at,r.allDay=e.allDay}else n===`DTEND`&&(r.end=a(s,c).at)}return n}function Sf(e){if(!e.start)return``;let t=m(),n=e=>e.toLocaleDateString(t,{weekday:`short`,year:`numeric`,month:`short`,day:`numeric`}),r=e=>e.toLocaleTimeString(t,{hour:`numeric`,minute:`2-digit`});if(e.allDay){let t=e.end?new Date(e.end.getTime()-864e5):e.start;return t>e.start?`${n(e.start)} – ${n(t)}`:`${n(e.start)} · ${_(`all day`)}`}return e.end?e.start.toDateString()===e.end.toDateString()?`${n(e.start)} ${r(e.start)}–${r(e.end)}`:`${n(e.start)} ${r(e.start)} – ${n(e.end)} ${r(e.end)}`:`${n(e.start)} ${r(e.start)}`}function Cf({path:e,kind:t}){let{text:n,error:r}=vf(e);return r?(0,R.jsx)(Ef,{error:r}):n===null?(0,R.jsx)(Tf,{}):t===`text`&&/\.md$/i.test(e)?(0,R.jsx)(`div`,{className:`mx-auto max-w-[720px] px-5 py-4`,children:(0,R.jsx)(hf,{text:n})}):t===`data`&&/\.csv$/i.test(e)?(0,R.jsx)(wf,{text:n}):(0,R.jsx)(`pre`,{className:`whitespace-pre-wrap break-words px-4 py-3 font-mono text-[12.5px] leading-relaxed`,children:n})}function wf({text:e}){let t=s(),n=e.split(/\r?\n/).filter(e=>e.trim()).slice(0,500).map(e=>e.split(`,`));if(!n.length)return(0,R.jsx)(`div`,{className:`p-6 text-muted text-center`,children:t(`Empty file.`)});let[r,...i]=n;return(0,R.jsx)(`div`,{className:`overflow-auto p-3`,children:(0,R.jsxs)(`table`,{className:`min-w-full text-[13px] border-separate border-spacing-0`,children:[(0,R.jsx)(`thead`,{children:(0,R.jsx)(`tr`,{children:r.map((e,t)=>(0,R.jsx)(`th`,{className:`sticky top-0 bg-surface-2 text-left font-semibold px-3 py-2 border-b border-border whitespace-nowrap`,children:e},t))})}),(0,R.jsx)(`tbody`,{children:i.map((e,t)=>(0,R.jsx)(`tr`,{className:`odd:bg-surface`,children:e.map((e,t)=>(0,R.jsx)(`td`,{className:`px-3 py-1.5 border-b border-border/60 whitespace-nowrap`,children:e},t))},t))})]})})}function Tf(){return(0,R.jsx)(`div`,{className:`flex h-full items-center justify-center text-muted`,children:(0,R.jsx)(A,{className:`animate-spin`,size:22})})}function Ef({error:e}){let t=s();return(0,R.jsx)(`div`,{className:`p-8 text-center text-rose-600 dark:text-rose-300 text-[14px]`,children:t(`Could not load the file: {error}`,{error:e})})}var Df=`OpenAI's terms cover using a ChatGPT plan inside OpenAI's own Codex; other apps have had this access cut off before (OpenCode, January 2026). If it stops working, an API key does.`,Of=2e3,kf=6e5;function Af({compact:e,onChanged:t}){let n=s(),{toast:r}=E(),[a,o]=(0,L.useState)(null),[c,l]=(0,L.useState)(`unknown`),[u,d]=(0,L.useState)(null),[f,p]=(0,L.useState)(null),[m,h]=(0,L.useState)(!0),[g,_]=(0,L.useState)(``),[v,y]=(0,L.useState)(null),b=(0,L.useRef)(0),x=(0,L.useCallback)(async()=>{try{let e=await M.chatgptStatus();return o(e),l(`yes`),e}catch(e){return/not found/i.test(e.message)?l(`no`):y(e.message),null}},[]);(0,L.useEffect)(()=>{x().then(e=>{e?.pending&&e.url&&(b.current=Date.now(),h(e.port_bound!==!1),p(e.url))})},[x]),(0,L.useEffect)(()=>{if(!f)return;let e=setInterval(()=>{x().then(e=>{e?.signed_in?(p(null),Ee(),r(n(`Signed in with {label}.`,{label:e.label||`ChatGPT`})),t?.()):e&&e.pending===!1&&e.error?(p(null),y(n(e.error))):Date.now()-b.current>kf&&(p(null),y(n(`The sign-in did not finish in ten minutes. Try again.`)))})},Of);return()=>clearInterval(e)},[f,x,t,r,n]);let S=async()=>{d(`login`),y(null);try{let e=await M.chatgptLogin();b.current=Date.now(),h(e.port_bound!==!1),_(``),p(e.url),window.open(e.url,`_blank`,`noopener`)}catch(e){/not found/i.test(e.message)?l(`no`):y(e.message)}finally{d(null)}},C=async()=>{let e=g.trim();if(e){d(`paste`),y(null);try{await M.chatgptCallback(e),_(``)}catch(e){let t=e.message;/state/i.test(t)?y(n(`That address belongs to another sign-in attempt. Open the page again and paste the address it ends on.`)):/no sign-in|409/i.test(t)?(p(null),y(n(`The sign-in did not finish in ten minutes. Try again.`))):y(t)}finally{d(null)}}},w=async()=>{d(`use`),y(null);try{await M.setLLM({provider:`chatgpt`,model:a?.models?.[0]??``,base_url:``,api_key:``}),Ee(),r(n(`ChatGPT answers the chat now.`)),t?.()}catch(e){y(e.message)}finally{d(null)}},T=async()=>{d(`logout`),y(null);try{await M.chatgptLogout(),Ee(),await x(),t?.()}catch(e){y(e.message)}finally{d(null)}},D=n(`Covers chat and the hands. Pictures and clips are not part of it; those need a provider with image or video models.`);return(0,R.jsxs)(`div`,{className:i(`space-y-2`,!e&&`rounded-2xl bg-surface-2/60 p-3`),children:[!e&&(0,R.jsxs)(`div`,{className:`flex items-center gap-2 text-[13px] font-medium`,children:[(0,R.jsx)(Mt,{size:15,className:`text-accent`}),` `,n(`Sign in with ChatGPT`)]}),c===`no`?(0,R.jsxs)(`p`,{className:`text-[12.5px] text-muted`,children:[n(`This nanoMuse has no sign-in route yet. In a terminal on this computer, run`),` `,(0,R.jsx)(`code`,{className:`rounded bg-surface-2 px-1 py-0.5 text-[12px]`,children:`nanomuse chatgpt login`}),` `,n(`and reload this page.`)]}):a?.signed_in?(0,R.jsxs)(`div`,{className:`space-y-2`,children:[(0,R.jsxs)(`p`,{className:`text-[12.5px]`,children:[(0,R.jsx)(`span`,{className:`font-medium`,children:n(`Signed in with {label}.`,{label:a.label||`ChatGPT`})}),` `,(0,R.jsx)(`span`,{className:`text-muted`,children:D})]}),(0,R.jsxs)(`div`,{className:`flex flex-wrap gap-2`,children:[(0,R.jsxs)(`button`,{type:`button`,disabled:u!==null,onClick:()=>void w(),className:i(Ne,`inline-flex items-center gap-1.5 py-2`),children:[u===`use`?(0,R.jsx)(A,{size:14,className:`animate-spin`}):(0,R.jsx)(Mt,{size:14}),` `,n(`Use it for the chat`)]}),(0,R.jsxs)(`button`,{type:`button`,disabled:u!==null,onClick:()=>void T(),className:i(je,`inline-flex items-center gap-1.5`),children:[u===`logout`?(0,R.jsx)(A,{size:14,className:`animate-spin`}):(0,R.jsx)(Tt,{size:14}),` `,n(`Sign out of ChatGPT`)]})]})]}):f?(0,R.jsxs)(`div`,{className:`space-y-2`,children:[(0,R.jsxs)(`p`,{className:`flex items-start gap-2 text-[12.5px] text-muted`,children:[(0,R.jsx)(A,{size:14,className:`mt-0.5 shrink-0 animate-spin`}),(0,R.jsx)(`span`,{children:n(m?`A page from OpenAI opened in a new tab. Sign in there; this card follows on its own.`:`A page from OpenAI opened in a new tab. Sign in there; when the browser ends on an address that will not load, paste that address below.`)})]}),(0,R.jsxs)(`div`,{className:`flex flex-wrap gap-2`,children:[(0,R.jsxs)(`a`,{href:f,target:`_blank`,rel:`noopener noreferrer`,className:i(je,`inline-flex items-center gap-1.5`),children:[(0,R.jsx)(Ae,{size:14}),` `,n(`Open the page again`)]}),(0,R.jsx)(`button`,{type:`button`,onClick:()=>p(null),className:je,children:n(`Cancel`)})]}),(0,R.jsxs)(`form`,{className:`flex flex-wrap items-center gap-2`,onSubmit:e=>{e.preventDefault(),C()},children:[(0,R.jsx)(`input`,{type:`url`,value:g,onChange:e=>_(e.target.value),placeholder:`http://localhost:1455/auth/callback?code=…`,"aria-label":n(`The address the browser ended on`),className:`min-w-0 flex-1 rounded-lg border border-border bg-surface px-2 py-1.5 text-[12.5px]`}),(0,R.jsxs)(`button`,{type:`submit`,disabled:u!==null||!g.trim(),className:i(je,`inline-flex items-center gap-1.5`),children:[u===`paste`?(0,R.jsx)(A,{size:14,className:`animate-spin`}):null,` `,n(`Use this address`)]})]}),!m&&(0,R.jsx)(`p`,{className:`text-[11.5px] text-muted`,children:n(`This nanoMuse runs where the browser cannot reach port 1455, so it cannot pick the sign-in up by itself.`)})]}):(0,R.jsxs)(`div`,{className:`space-y-2`,children:[(0,R.jsx)(`p`,{className:`text-[12.5px] text-muted`,children:D}),(0,R.jsxs)(`button`,{type:`button`,disabled:u!==null||c===`unknown`,onClick:()=>void S(),className:i(Ne,`inline-flex items-center gap-1.5 py-2`),children:[u===`login`?(0,R.jsx)(A,{size:14,className:`animate-spin`}):(0,R.jsx)(wt,{size:14}),` `,n(`Sign in with ChatGPT`)]})]}),(0,R.jsx)(`p`,{className:`text-[11.5px] leading-snug text-muted`,children:n(Df)}),v&&(0,R.jsx)(`p`,{className:`text-[12px] text-rose-600 dark:text-rose-300`,children:v})]})}var jf=xe,Mf=`nm.connections.preset`;function Nf(e,t=_e().preset){try{sessionStorage.setItem(Mf,t)}catch{}e(`connections`)}function Pf(){try{let e=sessionStorage.getItem(Mf);return e&&sessionStorage.removeItem(Mf),e}catch{return null}}function Ff({info:e,exhausted:t,compact:n}){let r=s(),{toast:a,setTab:o,state:l}=E(),u=l.hub?.account,d=_e(u),f=ae(u),p=c(),m=e.invite_bonus_cny??5,h=e.own_key_docs||e.guidance?.docs||jf,g=e.invite_url||``,[_,v]=(0,L.useState)(!1),[y,b]=(0,L.useState)(!1),x=(e.guidance?.providers??de(f)).filter(e=>e.id!==d.id).map(e=>({id:e.id,name:De(e,p),keyUrl:e.key_url,covers:`covers`in e?e.covers:e.capabilities})),S=Oe().map(e=>e.name),C=async e=>{try{await navigator.clipboard.writeText(e),a(r(`Copied`))}catch{a(e)}},w=async()=>{let e=r(`Try nanoMuse with me, a fully open-source personal agent, free to use. Sign up with my link: {link}`,{link:g}),t=navigator;if(t.share)try{await t.share({text:e});return}catch{}await C(e)},T=Ce(),[D,O]=me(`exhausted`,t),k=ve(be(r,`exhausted`)),ee=t?r(`The free allowance is used up.`):r(`Nearly used up: ¥{left} of ¥{grant} left.`,{left:(e.left??0).toFixed(2),grant:(e.grant??0).toFixed(0)});return(0,R.jsxs)(`div`,{className:i(`space-y-2.5`,!n&&`pt-1`),children:[(0,R.jsxs)(`div`,{children:[(0,R.jsx)(`div`,{className:i(`font-semibold`,n?`text-[13.5px]`:`text-[15px]`),children:ee}),(0,R.jsx)(`div`,{className:`mt-0.5 text-[12.5px] text-muted`,children:r(`Three ways on; your sign-in and your devices keep working whichever you pick.`)})]}),(0,R.jsxs)(If,{icon:(0,R.jsx)(xt,{size:16}),tone:`bg-accent/12 text-accent`,title:r(`Use your own model key`),children:[(0,R.jsx)(`p`,{className:`text-[12.5px] text-muted`,children:ie(r,u)}),(0,R.jsxs)(`div`,{className:`flex flex-wrap gap-2`,children:[(0,R.jsxs)(`button`,{type:`button`,onClick:()=>Nf(o,d.preset),className:i(Ne,`inline-flex items-center gap-1.5 py-2`),children:[(0,R.jsx)(xt,{size:14}),` `,r(`Set it up`)]}),(0,R.jsxs)(`a`,{href:d.keyUrl,target:`_blank`,rel:`noopener noreferrer`,className:i(je,`inline-flex items-center gap-1.5`),children:[(0,R.jsx)(Ae,{size:14}),` `,r(`Get a key from {vendor}`,{vendor:d.label})]}),(0,R.jsxs)(`a`,{href:h,target:`_blank`,rel:`noopener noreferrer`,className:i(je,`inline-flex items-center gap-1.5`),children:[(0,R.jsx)(Ae,{size:14}),` `,r(`Step-by-step guide`)]})]}),x.length>0&&(0,R.jsxs)(`div`,{children:[(0,R.jsxs)(`button`,{type:`button`,onClick:()=>v(!_),className:`inline-flex items-center gap-1 text-[12px] text-muted`,children:[_?(0,R.jsx)(Le,{size:13}):(0,R.jsx)(Me,{size:13}),` `,r(`Other providers and what each key covers`)]}),_&&(0,R.jsx)(`ul`,{className:`mt-1.5 space-y-1 text-[12.5px]`,children:x.map(e=>(0,R.jsxs)(`li`,{className:`flex flex-wrap items-baseline justify-between gap-x-3`,children:[(0,R.jsxs)(`span`,{children:[(0,R.jsx)(`span`,{className:`font-medium`,children:e.name}),` `,(0,R.jsxs)(`span`,{className:`text-muted`,children:[`· `,he(r,e.covers)]})]}),(0,R.jsxs)(`span`,{className:`flex gap-2`,children:[(0,R.jsx)(`button`,{type:`button`,onClick:()=>Nf(o,pe(e.id)),className:`text-accent`,children:r(`Set it up`)}),(0,R.jsxs)(`a`,{href:e.keyUrl,target:`_blank`,rel:`noopener noreferrer`,className:`inline-flex items-center gap-0.5 text-accent`,children:[r(`Get a key`),` `,(0,R.jsx)(Ae,{size:11})]})]})]},e.id))})]})]}),(0,R.jsxs)(If,{icon:(0,R.jsx)(wt,{size:16}),tone:`bg-emerald-500/12 text-emerald-600 dark:text-emerald-300`,title:r(`Sign in with a plan you already pay for`),children:[(0,R.jsx)(`p`,{className:`text-[12.5px] text-muted`,children:r(`{plans}: the plan's models answer here, no key to make. ChatGPT works on every device, the others on the phones. A ChatGPT sign-in covers chat and the hands; pictures and clips still want a key.`,{plans:S.join(r(`, `))})}),y?(0,R.jsx)(Af,{compact:!0,onChanged:()=>b(!1)}):(0,R.jsxs)(`button`,{type:`button`,onClick:()=>b(!0),className:i(je,`inline-flex items-center gap-1.5`),children:[(0,R.jsx)(wt,{size:14}),` `,r(`Sign in with ChatGPT`)]})]}),(0,R.jsx)(If,{icon:(0,R.jsx)(hn,{size:16}),tone:`bg-violet-500/12 text-violet-600 dark:text-violet-300`,title:r(`Invite a friend: +¥{bonus} for you and +¥{bonus} for them, for each new person who signs up with your link.`,{bonus:m.toFixed(0)}),children:g?(0,R.jsxs)(`div`,{className:`flex flex-wrap gap-2`,children:[(0,R.jsxs)(`button`,{type:`button`,onClick:()=>void w(),className:i(je,`inline-flex items-center gap-1.5`),children:[(0,R.jsx)(Xt,{size:14}),` `,r(`Share the link`)]}),(0,R.jsxs)(`button`,{type:`button`,onClick:()=>void C(g),className:i(je,`inline-flex items-center gap-1.5`),children:[(0,R.jsx)(ut,{size:14}),` `,r(`Copy the link`)]})]}):(0,R.jsxs)(`button`,{type:`button`,onClick:()=>o(`account`),className:i(je,`inline-flex items-center gap-1.5`),children:[(0,R.jsx)(Xt,{size:14}),` `,r(`Your invite link is under Account`)]})}),t&&D&&(0,R.jsxs)(If,{icon:(0,R.jsx)(ce,{size:16}),tone:`bg-amber-400/15 text-amber-600 dark:text-amber-300`,title:k,children:[(0,R.jsxs)(`button`,{type:`button`,onClick:()=>fe(T.repo_url),className:i(`flex items-center justify-center gap-1.5 rounded-2xl border border-border px-4 py-2.5 text-[14px] font-medium text-muted disabled:opacity-40`,`inline-flex items-center gap-1.5`),children:[(0,R.jsx)(ce,{size:14}),` `,r(`Star on GitHub`)]}),(0,R.jsx)(`button`,{type:`button`,onClick:()=>{ge(),O(!1)},className:i(`flex items-center justify-center gap-1.5 rounded-2xl border border-border px-4 py-2.5 text-[14px] font-medium text-muted disabled:opacity-40`,`inline-flex items-center gap-1.5`),children:r(`I already starred`)})]})]})}function If({icon:e,tone:t,title:n,children:r}){return(0,R.jsxs)(`div`,{className:`flex gap-3 rounded-2xl bg-surface-2/60 p-3`,children:[(0,R.jsx)(`span`,{className:i(`flex h-8 w-8 shrink-0 items-center justify-center rounded-xl`,t),children:e}),(0,R.jsxs)(`div`,{className:`min-w-0 flex-1 space-y-2`,children:[(0,R.jsx)(`div`,{className:`text-[13px] font-medium leading-snug`,children:n}),r]})]})}var Lf=`nm.cloud.warned_grant`;function Rf(){let e=s(),{state:t,setTab:n}=E(),[r,i]=(0,L.useState)(null),a=(0,L.useRef)(0),o=t.hub?.account,c=!!o?.signed_in&&!!o.is_model,l=t.finishedAt;if((0,L.useEffect)(()=>{if(!c||!l||r||Date.now()-a.current<6e4)return;a.current=Date.now();let e=!1;return M.cloudMe().then(t=>{if(e)return;let n=t.spend,r=n.grant??n.allowance_cny??0,a=n.left??null;if(n.unlimited||!n.warn||a===null||a<=0)return;let o=null;try{o=localStorage.getItem(Lf)}catch{}o!==String(r)&&i({left:a,grant:r,invite_url:t.invite?.url,invite_bonus_cny:n.invite_bonus_cny,invitee_bonus_cny:n.invitee_bonus_cny,own_key_docs:n.own_key_docs,guidance:n.guidance})}).catch(()=>{}),()=>{e=!0}},[c,l,r]),!r)return null;let u=()=>{try{localStorage.setItem(Lf,String(r.grant??0))}catch{}i(null)};return(0,R.jsxs)(`div`,{className:`rise mx-3 mb-1.5 flex items-start gap-2 rounded-2xl bg-amber-500/12 px-3 py-2 text-[12.5px] leading-snug text-amber-800 dark:text-amber-200`,children:[(0,R.jsx)(nn,{size:14,className:`mt-0.5 shrink-0`}),(0,R.jsxs)(`div`,{className:`min-w-0 flex-1`,children:[e(`Nearly used up: ¥{left} of ¥{grant} left.`,{left:(r.left??0).toFixed(2),grant:(r.grant??0).toFixed(0)}),` `,e(`Invite a friend (+¥{invite} for each of you) or bring your own key; your sign-in keeps working either way.`,{invite:(r.invite_bonus_cny??5).toFixed(0)}),` `,(0,R.jsx)(`button`,{type:`button`,onClick:()=>{u(),n(`account`)},className:`font-semibold underline decoration-dotted underline-offset-2`,children:e(`See the ways`)})]}),(0,R.jsx)(`button`,{type:`button`,onClick:u,"aria-label":e(`Dismiss`),className:`shrink-0 rounded-full p-0.5 opacity-70 hover:opacity-100`,children:(0,R.jsx)(Fe,{size:14})})]})}var zf=`nm.cloud.first_sign_in`,Bf=`nm:first-sign-in`;function Vf(){try{sessionStorage.setItem(zf,`1`)}catch{}window.dispatchEvent(new Event(Bf))}function Hf(){try{sessionStorage.removeItem(zf)}catch{}window.dispatchEvent(new Event(Bf))}function Uf(){try{return sessionStorage.getItem(zf)===`1`}catch{return!1}}function Wf(){let[e,t]=(0,L.useState)(Uf);return(0,L.useEffect)(()=>{let e=()=>t(Uf());return window.addEventListener(Bf,e),()=>window.removeEventListener(Bf,e)},[]),e}function Gf(){let e=s(),{toast:t,refreshHub:n,setTab:r,state:a}=E(),o=_e(a.hub?.account),[c,l]=(0,L.useState)(`password`),[u,d]=(0,L.useState)(``),[f,p]=(0,L.useState)(``),[m,h]=(0,L.useState)(!1),[g,_]=(0,L.useState)(null),v=async()=>{Hf(),await n().catch(()=>void 0)},y=async()=>{if(!(u.length<8||u!==f)){h(!0),_(null);try{await M.cloudPassword(u),t(e(`Password set.`)),d(``),p(``),l(`source`)}catch(t){_(e(t.message))}finally{h(!1)}}},b=async()=>{await v(),Nf(r,o.preset)},x=(0,L.useRef)(null);On(x,!0);let S=f.length>0&&f!==u;return(0,R.jsx)(`div`,{className:`fixed inset-0 z-50 flex items-end justify-center bg-black/40 backdrop-blur-[2px] sm:items-center`,role:`dialog`,"aria-modal":`true`,children:(0,R.jsxs)(`div`,{ref:x,className:`safe-bottom w-full max-w-[520px] rounded-t-[28px] bg-bg p-6 shadow-2xl sm:rounded-[28px]`,children:[(0,R.jsxs)(`div`,{className:`mb-4 flex gap-1`,children:[(0,R.jsx)(`span`,{className:i(`h-1.5 w-5 rounded-full bg-accent`)}),(0,R.jsx)(`span`,{className:i(`h-1.5 rounded-full transition-all`,c===`source`?`w-5 bg-accent`:`w-1.5 bg-border`)})]}),c===`password`?(0,R.jsxs)(`form`,{className:`space-y-4`,onSubmit:e=>{e.preventDefault(),y()},children:[(0,R.jsxs)(`div`,{className:`flex items-start gap-3`,children:[(0,R.jsx)(`span`,{className:`flex h-11 w-11 shrink-0 items-center justify-center rounded-2xl bg-accent/12 text-accent`,children:(0,R.jsx)(xt,{size:20})}),(0,R.jsxs)(`div`,{children:[(0,R.jsx)(`h2`,{className:`text-[20px] font-bold tracking-tight`,children:e(`Set a password`)}),(0,R.jsx)(`p`,{className:`mt-1 text-[13.5px] leading-relaxed text-muted`,children:e(`Your account is in. With a password, your phone and your other computers sign in at once, without waiting for a code. Optional; you can set one later under Account.`)})]})]}),(0,R.jsxs)(`div`,{className:`space-y-2`,children:[(0,R.jsx)(`input`,{type:`password`,value:u,onChange:e=>d(e.target.value),autoComplete:`new-password`,autoFocus:!0,placeholder:e(`At least 8 characters`),className:Ie}),(0,R.jsx)(`input`,{type:`password`,value:f,onChange:e=>p(e.target.value),autoComplete:`new-password`,placeholder:e(`Once more`),className:i(Ie,S&&`border-rose-400`)}),S&&(0,R.jsx)(`p`,{className:`text-[12px] text-rose-600 dark:text-rose-300`,children:e(`The two do not match.`)})]}),g&&(0,R.jsx)(`div`,{className:`rounded-2xl bg-rose-500/12 px-3 py-2 text-[12.5px] text-rose-700 dark:text-rose-300`,children:g}),(0,R.jsxs)(`div`,{className:`flex gap-2`,children:[(0,R.jsx)(`button`,{type:`button`,disabled:m,onClick:()=>l(`source`),className:je,children:e(`Skip`)}),(0,R.jsxs)(`button`,{type:`submit`,disabled:m||u.length<8||u!==f,className:i(Ne,`flex-1 py-3`),children:[m?(0,R.jsx)(A,{size:15,className:`animate-spin`}):null,` `,e(`Set the password`),` `,(0,R.jsx)(qe,{size:16})]})]})]}):(0,R.jsxs)(`div`,{className:`space-y-4`,children:[(0,R.jsxs)(`div`,{className:`flex items-start gap-3`,children:[(0,R.jsx)(`span`,{className:`flex h-11 w-11 shrink-0 items-center justify-center rounded-2xl bg-accent/12 text-accent`,children:(0,R.jsx)(ot,{size:20})}),(0,R.jsxs)(`div`,{children:[(0,R.jsx)(`h2`,{className:`text-[20px] font-bold tracking-tight`,children:e(`Which model answers?`)}),(0,R.jsx)(`p`,{className:`mt-1 text-[13.5px] leading-relaxed text-muted`,children:e(`Your account already brings one. You can add your own API key as well and switch at any time.`)})]})]}),(0,R.jsxs)(`ul`,{className:`space-y-2 text-[13px] leading-snug`,children:[(0,R.jsxs)(`li`,{className:`flex items-start gap-2.5 rounded-2xl bg-surface-2 px-3 py-2.5`,children:[(0,R.jsx)(ot,{size:16,className:`mt-0.5 shrink-0 text-accent`}),(0,R.jsxs)(`span`,{children:[(0,R.jsx)(`span`,{className:`font-medium`,children:e(`Use the nanoMuse Cloud model`)}),(0,R.jsx)(`span`,{className:`block text-muted`,children:e(`DeepSeek for the chat and Qwen for the hands, with a free allowance per account paid by the developer. Nothing to configure.`)})]})]}),(0,R.jsxs)(`li`,{className:`flex items-start gap-2.5 rounded-2xl bg-surface-2 px-3 py-2.5`,children:[(0,R.jsx)(xt,{size:16,className:`mt-0.5 shrink-0 text-accent`}),(0,R.jsxs)(`span`,{children:[(0,R.jsx)(`span`,{className:`font-medium`,children:e(`I have my own API key`)}),(0,R.jsx)(`span`,{className:`block text-muted`,children:o.preset===`qwen`?e(`Alibaba Cloud Bailian first (one key covers chat, the hands, pictures and clips), then DeepSeek, Kimi, Zhipu, OpenAI, OpenRouter and any OpenAI-compatible endpoint. The key stays on this device.`):e(`OpenRouter first (one account, one key, pay as you go), then OpenAI, Anthropic, Gemini, DeepSeek and any OpenAI-compatible endpoint. The key stays on this device.`)})]})]}),(0,R.jsxs)(`li`,{className:`flex items-start gap-2.5 rounded-2xl bg-surface-2 px-3 py-2.5`,children:[(0,R.jsx)(wt,{size:16,className:`mt-0.5 shrink-0 text-accent`}),(0,R.jsxs)(`span`,{children:[(0,R.jsx)(`span`,{className:`font-medium`,children:e(`Sign in with a plan you already pay for`)}),(0,R.jsx)(`span`,{className:`block text-muted`,children:e(`A ChatGPT plan signs in from Connections and answers the chat and the hands. Pictures and clips still want a key.`)})]})]})]}),(0,R.jsxs)(`div`,{className:`flex gap-2`,children:[(0,R.jsx)(`button`,{type:`button`,disabled:m,onClick:()=>void b(),className:je,children:e(`I have my own API key`)}),(0,R.jsxs)(`button`,{type:`button`,disabled:m,onClick:()=>void v(),className:i(Ne,`flex-1 py-3`),children:[e(`Use the nanoMuse Cloud model`),` `,(0,R.jsx)(qe,{size:16})]})]})]})]})})}var Kf=`nanomuse_devtools`;function qf(){try{return localStorage.getItem(Kf)===`1`}catch{return!1}}var Jf=qf(),Yf=new Set;function Xf(){return Jf}function Zf(e){Jf=e;try{localStorage.setItem(Kf,e?`1`:`0`)}catch{}Yf.forEach(e=>e())}function Qf(e){return Yf.add(e),()=>Yf.delete(e)}function $f(){return(0,L.useSyncExternalStore)(Qf,Xf,Xf)}function ep(e,t,n){if(!n.signedIn||n.chatOnCloud||n.deviceChat)return;let r=e[t];if(r?.type===`notice`&&r.level===`error`&&r.code&&r.code!==`allowance`&&!r.model_used)for(let n=t-1;n>=0;n--){let t=e[n];if(t?.type===`user`){let e=(t.files??[]).map(e=>e.path);return t.text||e.length>0?{text:t.text,files:e}:void 0}}}var tp=[`idle`,`working`,`waiting`,`happy`,`error`];function np({event:e,name:t=`nanoMuse`}){let n=s(),{toast:r}=E(),[a,o]=(0,L.useState)(null),c=e.cost??{},l=e.candidates??[null,null,null,null],u=e.moods??{},d=e.clips??{},f=async(e,t)=>{o(e);try{await t()}catch(e){r(e.message)}finally{o(null)}},p=e.stage===`estimate`||e.stage===`drawing`||e.stage===`choose`||e.stage===`posing`||e.stage===`animating`,m=c.clips?n(`{n} pictures and {c} clips`,{n:c.pictures??8,c:c.clips}):n(`{n} pictures`,{n:c.pictures??8}),g=(()=>{if(c.cloud===!1)return n(`{what}, made with your own key at your provider's prices.`,{what:m});if(c.error)return n(`The cost could not be checked: {error}`,{error:c.error});if(typeof c.cny!=`number`)return n(`Checking the cost…`);if(c.unlimited)return n(`About ¥{cny} for {what}; your account has no limit.`,{cny:c.cny.toFixed(2),what:m});let e=typeof c.left_cny==`number`?c.left_cny.toFixed(2):`?`;return c.affordable===!1?n(`About ¥{cny} for {what}, more than the ¥{left} left in your allowance.`,{cny:c.cny.toFixed(2),what:m,left:e}):n(`About ¥{cny} for {what}; ¥{left} left in your allowance.`,{cny:c.cny.toFixed(2),what:m,left:e})})();return(0,R.jsx)(`div`,{className:`rise flex justify-start pr-8`,children:(0,R.jsxs)(`div`,{className:i(`w-full max-w-[360px] overflow-hidden rounded-3xl rounded-tl-lg border bg-surface shadow-sm`,p?`border-accent/50`:`border-border/70`),children:[(0,R.jsxs)(`div`,{className:`flex items-start gap-3 px-4 pt-3.5 pb-2`,children:[(0,R.jsx)(`div`,{className:i(`mt-0.5 rounded-full p-2`,p?`bg-accent/12 text-accent`:`bg-surface-2 text-fg/80`),children:(0,R.jsx)(nn,{size:18})}),(0,R.jsxs)(`div`,{className:`min-w-0 flex-1`,children:[(0,R.jsxs)(`div`,{className:`text-[12.5px] font-medium text-muted`,children:[e.stage===`estimate`&&n(`A new look for {name}`,{name:t}),e.stage===`drawing`&&n(`Drawing four to choose from…`),e.stage===`choose`&&n(`Pick one: tap it, or say which`),e.stage===`posing`&&n(`Drawing the poses…`),e.stage===`animating`&&n(`The new look is on; making the clips…`),e.stage===`done`&&n(`The new look is on`),e.stage===`cancelled`&&n(`Not this time`),e.stage===`failed`&&n(`That did not work`)]}),(0,R.jsx)(`div`,{className:`mt-0.5 text-[14px] leading-snug`,children:e.description}),e.reference&&(0,R.jsxs)(`div`,{className:`mt-1.5 flex items-center gap-2 text-[12px] text-muted`,children:[(0,R.jsx)(`img`,{src:h(e.reference),alt:``,draggable:!1,className:`h-9 w-9 rounded-lg object-cover`}),n(`drawn from the picture you attached`)]})]})]}),e.stage===`estimate`&&(0,R.jsxs)(`div`,{className:`px-4 pb-3.5 space-y-2.5`,children:[(0,R.jsx)(`p`,{className:`text-[12.5px] text-muted`,children:g}),(0,R.jsxs)(`div`,{className:`flex gap-2`,children:[(0,R.jsxs)(`button`,{type:`button`,disabled:a!==null||c.cloud!==!1&&typeof c.cny!=`number`&&!c.error,onClick:()=>f(`start`,()=>M.avatarStart(e.session)),className:i(`flex items-center justify-center gap-1.5 rounded-2xl bg-accent text-accent-fg px-4 py-2.5 text-[14px] font-medium disabled:opacity-40`,`inline-flex items-center gap-1.5 py-2`),children:[a===`start`?(0,R.jsx)(A,{size:14,className:`animate-spin`}):(0,R.jsx)(nn,{size:14}),` `,n(`Draw`)]}),(0,R.jsxs)(`button`,{type:`button`,disabled:a!==null,onClick:()=>f(`cancel`,()=>M.avatarCancel(e.session)),className:i(`flex items-center justify-center gap-1.5 rounded-2xl border border-border px-4 py-2.5 text-[14px] font-medium text-muted disabled:opacity-40`,`inline-flex items-center gap-1.5`),children:[(0,R.jsx)(Fe,{size:14}),` `,n(`Not now`)]})]})]}),(e.stage===`drawing`||e.stage===`choose`)&&(0,R.jsxs)(`div`,{className:`px-4 pb-3.5 space-y-2.5`,children:[(0,R.jsx)(`div`,{className:`grid grid-cols-2 gap-2`,children:l.map((t,r)=>(0,R.jsxs)(`button`,{type:`button`,disabled:!t||e.stage!==`choose`||a!==null,onClick:()=>f(`pick${r}`,()=>M.avatarChoose(e.session,r)),"aria-label":n(`Candidate {n}`,{n:r+1}),className:i(`relative aspect-square overflow-hidden rounded-2xl bg-[#f1efeb] transition`,t&&e.stage===`choose`?`hover:ring-2 hover:ring-accent`:``),children:[t?(0,R.jsx)(`img`,{src:h(t),alt:``,draggable:!1,className:`h-full w-full object-cover`}):(0,R.jsx)(`span`,{className:`absolute inset-0 flex items-center justify-center text-muted`,children:e.stage===`drawing`?(0,R.jsx)(A,{size:20,className:`animate-spin`}):(0,R.jsx)(Fe,{size:18,className:`opacity-50`})}),a===`pick${r}`&&(0,R.jsx)(`span`,{className:`absolute inset-0 flex items-center justify-center bg-bg/60`,children:(0,R.jsx)(A,{size:20,className:`animate-spin`})}),(0,R.jsx)(`span`,{className:`absolute left-1.5 top-1.5 rounded-full bg-bg/80 px-1.5 text-[10.5px] font-semibold text-fg/80`,children:r+1})]},r))}),e.errors&&e.errors.length>0&&(0,R.jsx)(`p`,{className:`text-[12px] text-rose-600 dark:text-rose-300`,children:n(e.errors[0])}),e.stage===`choose`&&(0,R.jsxs)(`div`,{className:`flex gap-2`,children:[(0,R.jsxs)(`button`,{type:`button`,disabled:a!==null,onClick:()=>f(`redraw`,()=>M.avatarStart(e.session)),className:i(`flex items-center justify-center gap-1.5 rounded-2xl border border-border px-4 py-2.5 text-[14px] font-medium text-muted disabled:opacity-40`,`inline-flex items-center gap-1.5`),children:[a===`redraw`?(0,R.jsx)(A,{size:14,className:`animate-spin`}):(0,R.jsx)(Re,{size:14}),` `,n(`Redraw`)]}),(0,R.jsxs)(`button`,{type:`button`,disabled:a!==null,onClick:()=>f(`cancel`,()=>M.avatarCancel(e.session)),className:i(`flex items-center justify-center gap-1.5 rounded-2xl border border-border px-4 py-2.5 text-[14px] font-medium text-muted disabled:opacity-40`,`inline-flex items-center gap-1.5`),children:[(0,R.jsx)(Fe,{size:14}),` `,n(`Not now`)]})]})]}),(e.stage===`posing`||e.stage===`animating`||e.stage===`done`)&&(0,R.jsxs)(`div`,{className:`px-4 pb-3.5 space-y-2`,children:[(0,R.jsx)(`div`,{className:`flex gap-1.5`,children:tp.map(t=>(0,R.jsxs)(`div`,{className:`relative aspect-square flex-1 overflow-hidden rounded-xl bg-[#f1efeb]`,children:[d[t]?(0,R.jsx)(`video`,{src:h(d[t]),poster:u[t]?h(u[t]):void 0,autoPlay:!0,loop:!0,muted:!0,playsInline:!0,disablePictureInPicture:!0,className:`h-full w-full object-cover`},d[t]):u[t]?(0,R.jsx)(`img`,{src:h(u[t]),alt:``,draggable:!1,className:`h-full w-full object-cover`}):(0,R.jsx)(`span`,{className:`absolute inset-0 flex items-center justify-center text-muted`,children:(0,R.jsx)(A,{size:14,className:`animate-spin`})}),e.stage===`animating`&&u[t]&&!d[t]&&t!==`error`&&(0,R.jsx)(`span`,{className:`absolute bottom-1 right-1 rounded-full bg-white/80 p-0.5 text-muted`,children:(0,R.jsx)(A,{size:10,className:`animate-spin`})})]},t))}),e.stage===`done`?(0,R.jsxs)(`p`,{className:`flex items-center gap-1.5 text-[12.5px] text-muted`,children:[(0,R.jsx)(ke,{size:14,className:`text-emerald-600`}),` `,n(`Idle, working, waiting, happy, sorry: the face follows what {name} is doing.`,{name:t})]}):e.stage===`animating`?(0,R.jsx)(`p`,{className:`text-[12.5px] text-muted`,children:n(`The face is already on; four short clips are being made from the poses, a few minutes.`)}):(0,R.jsx)(`p`,{className:`text-[12.5px] text-muted`,children:n(`Four more pictures from the one you picked; this takes a minute or two.`)}),e.errors&&e.errors.length>0&&e.stage===`done`&&(0,R.jsxs)(`p`,{className:`text-[12px] text-muted`,children:[e.errors.some(e=>!e.includes(` clip:`))&&n(`Some poses could not be drawn and show the idle picture instead.`),` `,e.errors.some(e=>e.includes(` clip:`))&&n(`Some clips could not be made; those moods stay still.`)]})]}),(e.stage===`failed`||e.stage===`cancelled`)&&e.message&&(0,R.jsx)(`p`,{className:`px-4 pb-3.5 text-[12.5px] text-muted`,children:n(e.message)})]})})}function rp(){let e=ip();if(!e||typeof e.keepRunning!=`function`)return null;try{return JSON.parse(e.keepRunning())}catch{return null}}function ip(){return window.NanoMuseAndroid??null}function ap(){let e=ip();return!!e&&typeof e.takeOverBrowser==`function`&&(typeof e.hasBrowser!=`function`||e.hasBrowser())}function op(){let e=ip();if(!e||typeof e.accessibilityState!=`function`)return null;let t=e.accessibilityState();return t===`on`||t===`off`||t===`unsupported`?t:null}function sp(e,t=15){switch(e){case`web_search`:return(0,R.jsx)(qt,{size:t});case`web_fetch`:case`browser`:return(0,R.jsx)(gt,{size:t});case`files`:return(0,R.jsx)(mt,{size:t});case`shell`:return(0,R.jsx)(dn,{size:t});case`python_execute`:return(0,R.jsx)(ct,{size:t});case`read_emails`:case`send_email`:return(0,R.jsx)(Et,{size:t});case`goals`:return(0,R.jsx)(un,{size:t});case`remember`:case`recall`:case`forget`:return(0,R.jsx)(Qe,{size:t});case`ask_user`:return(0,R.jsx)(kt,{size:t});case`devices`:return(0,R.jsx)(It,{size:t});case`device_shell`:return(0,R.jsx)(dn,{size:t});case`device_files`:case`device_get`:case`device_put`:return(0,R.jsx)(mt,{size:t});case`device_open`:return(0,R.jsx)(Ae,{size:t});case`device_screen`:return(0,R.jsx)(Lt,{size:t});case`device_notify`:return(0,R.jsx)(Xe,{size:t});case`delegate`:return(0,R.jsx)(Jt,{size:t});case`computer_screen`:return(0,R.jsx)(Lt,{size:t});case`computer_act`:return(0,R.jsx)(zt,{size:t});case`computer_task`:case`computer_app`:return(0,R.jsx)(vt,{size:t});case`phone_screen`:case`phone_act`:case`phone_task`:return(0,R.jsx)(tn,{size:t});default:return(0,R.jsx)(Ze,{size:t})}}function cp({device:e,className:t}){let n=s();return(0,R.jsxs)(`span`,{className:i(`inline-flex max-w-full items-center gap-1 rounded-full bg-accent/12 px-2 py-0.5 text-[11px] font-medium text-accent`,t),children:[(0,R.jsx)(It,{size:11,className:`shrink-0`}),` `,(0,R.jsx)(`span`,{className:`truncate`,children:n(`on {device}`,{device:e})})]})}var lp={safe:`bg-emerald-500/15 text-emerald-700 dark:text-emerald-300`,moderate:`bg-amber-500/15 text-amber-700 dark:text-amber-300`,sensitive:`bg-rose-500/15 text-rose-700 dark:text-rose-300`};function up({risk:e}){return(0,R.jsx)(`span`,{className:i(`px-2 py-0.5 rounded-full text-[11px] font-semibold uppercase tracking-wide`,lp[e]),children:_(e)})}function dp({args:e}){let t=Object.entries(e??{}).filter(([,e])=>e!=null&&e!==``);return t.length?(0,R.jsx)(`dl`,{className:`mt-2 grid grid-cols-[auto_1fr] gap-x-3 gap-y-1 text-[13px]`,children:t.map(([e,t])=>(0,R.jsxs)(`div`,{className:`contents`,children:[(0,R.jsx)(`dt`,{className:`text-muted`,children:e}),(0,R.jsx)(`dd`,{className:`break-words whitespace-pre-wrap font-mono text-[12.5px] leading-snug`,children:String(t)})]},e))}):null}function fp({event:e}){let[t,n]=(0,L.useState)(!1),r=e.status===`running`?(0,R.jsx)(A,{size:14,className:`animate-spin text-accent`}):e.status===`ok`?(0,R.jsx)(ke,{size:14,className:`text-emerald-500`}):e.status===`blocked`?(0,R.jsx)(Ye,{size:14,className:`text-rose-500`}):(0,R.jsx)(Fe,{size:14,className:`text-rose-500`});return(0,R.jsx)(`div`,{className:`rise flex justify-start pr-8`,children:(0,R.jsxs)(`button`,{type:`button`,onClick:()=>n(e=>!e),className:`max-w-full text-left rounded-2xl bg-surface-2/80 border border-border/60 px-3 py-1.5 text-[13px] text-muted hover:text-fg transition`,children:[(0,R.jsxs)(`span`,{className:`flex items-center gap-2`,children:[(0,R.jsx)(`span`,{className:`text-muted`,children:sp(e.tool)}),(0,R.jsx)(`span`,{className:`truncate flex-1`,children:e.title||e.summary||e.tool}),e.device&&(0,R.jsx)(cp,{device:e.device}),r,e.output?t?(0,R.jsx)(Me,{size:13}):(0,R.jsx)(rt,{size:13}):null]}),t&&(0,R.jsxs)(`div`,{className:`mt-2 text-fg`,children:[(0,R.jsx)(dp,{args:e.args}),e.output&&(0,R.jsx)(`pre`,{className:`mt-2 max-h-52 overflow-auto whitespace-pre-wrap break-words rounded-xl bg-bg p-2 text-[12px] leading-snug`,children:e.output})]})]})})}function pp(e,t,n){if(!t)return e.replace(/_/g,` `);switch(e){case`shell`:return _(`{what} commands`,{what:t.split(`,`).join(`, `)});case`send_email`:return _(`email to {who}`,{who:t.split(`,`).join(`, `)});case`remote_control`:return _(`the device {name}`,{name:typeof n?.device==`string`&&n.device?n.device:t});case`computer_app`:return _(`the hands in {app}`,{app:typeof n?.name==`string`&&n.name?n.name:t});default:return t}}function mp(e,t,n,r){switch(e){case`once`:return _(`Once`);case`conversation`:return _(`For this conversation`);case`session`:return _(`Until restart`);case`24h`:return _(`For 24 hours`);case`always`:return _(`Always for {subject}`,{subject:pp(t,n,r)});default:return e}}function hp({event:e,name:t=`nanoMuse`,onDecide:n}){let[r,a]=(0,L.useState)(!1),[o,c]=(0,L.useState)(!1),[l,d]=(0,L.useState)(!1),[f,p]=(0,L.useState)(!1),m=(e,t)=>{f||(p(!0),Promise.resolve(n(e,t)).finally(()=>p(!1)))},h=(0,L.useRef)(null),g=(0,L.useRef)(null),_=s(),y=e.status===`pending`,b=e.risk===`sensitive`,x=(e.grant_options??[`once`]).filter(e=>e!==`once`),S=e.egress_target||([`web_fetch`,`browser`,`web_search`].includes(e.tool)?e.target:null),C=e.tool===`send_email`?e.target:null,w=Object.values(e.args??{}).some(e=>e!=null&&e!==``);return(0,L.useEffect)(()=>{let e=g.current;e&&!r&&d(e.scrollHeight>e.clientHeight+2)},[e.args,r]),(0,L.useEffect)(()=>{(r||o)&&h.current?.scrollIntoView({block:`end`,behavior:`smooth`})},[r,o]),(0,R.jsx)(`div`,{className:`rise flex justify-start`,ref:h,children:(0,R.jsxs)(`div`,{className:i(`w-full max-w-[600px] overflow-hidden rounded-[22px] bg-surface shadow-[0_2px_12px_rgba(0,0,0,0.12)] dark:border dark:border-border dark:shadow-none`,y&&b&&`border border-rose-400/60`),children:[(0,R.jsxs)(`div`,{className:`flex items-start gap-3 px-4 pt-4 pb-2`,children:[(0,R.jsx)(`div`,{className:i(`flex h-10 w-10 shrink-0 items-center justify-center rounded-full`,b?`bg-rose-500/12 text-rose-500`:`bg-surface-2 text-fg`),children:b?(0,R.jsx)(Zt,{size:22}):sp(e.tool,22)}),(0,R.jsxs)(`div`,{className:`min-w-0 flex-1`,children:[(0,R.jsxs)(`div`,{className:`flex flex-wrap items-center gap-1.5 text-[12.5px] font-medium text-muted`,children:[(0,R.jsx)(`span`,{children:e.remote?_(`{name} on {device} wants to`,{name:t,device:e.remote.name}):_(`{name} wants to`,{name:t})}),e.remote&&(0,R.jsx)(cp,{device:e.remote.name})]}),(0,R.jsx)(`div`,{className:`mt-0.5 break-words text-[17px] font-semibold leading-[22px]`,children:e.summary}),S?(0,R.jsxs)(`div`,{className:`mt-1 flex items-center gap-1 text-[13px] text-muted`,children:[(0,R.jsx)(gt,{size:12}),` `,(0,R.jsx)(`span`,{className:`truncate`,children:_(`at {host}`,{host:S})})]}):C?(0,R.jsxs)(`div`,{className:`mt-1 flex items-center gap-1 text-[13px] text-muted`,children:[(0,R.jsx)(Et,{size:12}),` `,(0,R.jsx)(`span`,{className:`truncate`,children:_(`to {recipient}`,{recipient:C})})]}):null,e.purpose&&(0,R.jsx)(`div`,{className:`mt-1.5 break-words text-[13px] leading-snug text-muted line-clamp-2`,children:e.purpose}),b&&(0,R.jsx)(`div`,{className:`mt-1.5`,children:(0,R.jsx)(up,{risk:e.risk})})]})]}),e.warnings?.length>0&&(0,R.jsx)(`div`,{className:`space-y-1 px-4 pb-2`,children:e.warnings.map(e=>(0,R.jsxs)(`div`,{className:`flex items-start gap-1.5 text-[12.5px] text-rose-600 dark:text-rose-300`,children:[(0,R.jsx)(pn,{size:13,className:`mt-0.5 shrink-0`}),` `,(0,R.jsx)(`span`,{children:_(e)})]},e))}),(w||e.reasons?.length>0)&&(0,R.jsx)(`div`,{className:`px-4 pb-2`,children:(0,R.jsxs)(`div`,{className:`rounded-xl bg-surface-2 px-3 py-2.5`,children:[(0,R.jsx)(`div`,{className:`text-[11px] font-medium text-muted`,children:_(`Exactly what will run`)}),(0,R.jsxs)(`div`,{ref:g,className:i(`-mt-1`,!r&&`max-h-40 overflow-hidden`),children:[(0,R.jsx)(dp,{args:e.args}),e.reasons?.length>0&&(0,R.jsx)(`div`,{className:`mt-1.5 text-[12px] text-muted`,children:_(`Why it asks: {reasons}`,{reasons:e.reasons.map(v).join(` · `)})})]}),(l||r)&&(0,R.jsxs)(`button`,{type:`button`,className:`mt-1 flex items-center gap-1 text-[12.5px] text-accent`,onClick:()=>a(e=>!e),children:[r?(0,R.jsx)(Me,{size:13}):(0,R.jsx)(rt,{size:13}),` `,_(r?`Fewer options`:`Show all`)]})]})}),y?(0,R.jsxs)(`div`,{className:`flex flex-col gap-2 px-4 pb-4 pt-2`,children:[(0,R.jsx)(`button`,{type:`button`,onClick:()=>m(!0,`once`),disabled:f,className:`h-[46px] w-full rounded-full bg-accent text-[15px] font-semibold text-accent-fg transition active:scale-[0.98] disabled:opacity-60`,children:_(`Allow once`)}),x.filter(e=>o||e===`conversation`||e===`always`).map(t=>(0,R.jsx)(`button`,{type:`button`,onClick:()=>m(!0,t),disabled:f,className:`h-11 w-full truncate rounded-full bg-surface-2 px-4 text-[15px] font-medium transition active:scale-[0.98] disabled:opacity-60`,children:mp(t,e.tool,e.target,e.args)},t)),(0,R.jsx)(`button`,{type:`button`,onClick:()=>m(!1,`once`),disabled:f,className:`h-11 w-full rounded-full bg-surface-2 text-[15px] font-medium transition active:scale-[0.98] disabled:opacity-60`,children:_(`Deny`)}),x.length===0?(0,R.jsx)(`div`,{className:`text-center text-[12px] text-muted`,children:_(`This kind of action is approved one at a time.`)}):!o&&x.some(e=>e!==`conversation`&&e!==`always`)&&(0,R.jsx)(`button`,{type:`button`,className:`self-center text-[12.5px] text-muted`,onClick:()=>c(!0),children:_(`Allow {subject} for longer…`,{subject:pp(e.tool,e.target,e.args)})})]}):(0,R.jsxs)(`div`,{className:i(`flex items-center gap-1.5 border-t border-border px-4 py-2.5 text-[13px] font-medium`,e.status===`approved`?`text-emerald-600 dark:text-emerald-300`:`text-muted`),children:[e.status===`approved`?(0,R.jsx)(ke,{size:15}):(0,R.jsx)(Fe,{size:15}),e.status===`approved`?`${_(`Approved`)}${e.scope&&e.scope!==`once`?` · ${mp(e.scope,e.tool,e.target).toLowerCase()}`:``}`:e.status===`denied`?_(`Denied`):_(`Expired without an answer`),(0,R.jsx)(`span`,{className:`ml-auto font-normal`,children:u(e.updated_ts??e.ts)})]})]})})}function gp({event:e,name:t}){let n=s();return(0,R.jsx)(`div`,{className:`rise flex justify-start pr-8`,children:(0,R.jsxs)(`div`,{className:`max-w-full rounded-[20px] rounded-bl-md border border-accent/30 bg-surface px-4 py-3`,children:[(0,R.jsxs)(`div`,{className:`flex items-center gap-1.5 text-[12.5px] font-medium text-accent`,children:[(0,R.jsx)(kt,{size:14}),` `,n(`{name} asks`,{name:t})]}),(0,R.jsx)(`div`,{className:`mt-1 text-[15px] leading-snug whitespace-pre-wrap break-words`,children:e.text}),e.status===`pending`&&(0,R.jsx)(`div`,{className:`mt-1.5 text-[12.5px] text-muted`,children:n(`Reply below to continue.`)}),e.status===`answered`&&e.answer&&(0,R.jsxs)(`div`,{className:`mt-2 text-[13px] text-muted border-t border-border pt-2`,children:[n(`You:`),` `,(0,R.jsx)(`span`,{className:`text-fg`,children:e.answer})]})]})})}function _p(e){return e.source===`reminder`||e.source===`memory`?t(e.text):_(e.text,e.vars)}function vp({event:e,onCloudRetry:t}){let n=s(),[r,a]=(0,L.useState)(!1),[o,c]=(0,L.useState)(!1),[l,u]=(0,L.useState)(null),d=e.detail&&e.detail!==e.text?e.detail:null;return e.code===`allowance`&&e.allowance?(0,R.jsxs)(`div`,{className:`rise flex flex-col items-center gap-2 px-6`,children:[(0,R.jsx)(`div`,{className:`max-w-full rounded-2xl bg-amber-500/12 px-3 py-1.5 text-center text-[12.5px] leading-snug text-amber-700 dark:text-amber-300`,children:n(e.text)}),(0,R.jsx)(`div`,{className:`w-full max-w-[520px]`,children:(0,R.jsx)(Ff,{info:e.allowance,exhausted:!0,compact:!0})})]}):(0,R.jsx)(`div`,{className:`rise flex justify-center px-6`,children:(0,R.jsxs)(`div`,{className:i(`max-w-full rounded-2xl px-3 py-1.5 text-center text-[12.5px] leading-snug`,e.level===`info`&&`bg-surface-2/70 text-muted`,e.level===`warn`&&`bg-amber-500/12 text-amber-700 dark:text-amber-300`,e.level===`error`&&`bg-rose-500/12 text-rose-700 dark:text-rose-300`),children:[_p(e),d&&(0,R.jsxs)(R.Fragment,{children:[` `,(0,R.jsx)(`button`,{type:`button`,onClick:()=>a(e=>!e),className:`underline decoration-dotted underline-offset-2 opacity-70 hover:opacity-100`,children:n(r?`Hide details`:`Details`)}),r&&(0,R.jsx)(`div`,{className:`mt-1.5 break-all text-left font-mono text-[11px] opacity-80`,children:d})]}),t&&(0,R.jsxs)(`div`,{className:`mt-1.5 flex flex-col items-center gap-1`,children:[(0,R.jsx)(`button`,{type:`button`,disabled:o,onClick:()=>{t&&(c(!0),u(null),t().catch(e=>u(n(e.message||`Could not send`))).finally(()=>c(!1)))},className:`rounded-full bg-accent/12 px-3 py-1 text-[12px] font-medium text-accent disabled:opacity-50`,children:n(`Use nanoMuse Cloud this time`)}),l&&(0,R.jsx)(`div`,{className:`text-[12px] text-rose-700 dark:text-rose-300`,children:l})]})]})})}function yp({event:e,onOpen:t}){let[r,i]=(0,L.useState)(!1),a=s(),o=e.status===`live`,c=e.url;try{c=new URL(e.url).host}catch{}return(0,R.jsx)(`div`,{className:`rise flex justify-start pr-8`,children:(0,R.jsxs)(`button`,{type:`button`,onClick:()=>t(e.id),"aria-label":a(`Browser: {title}`,{title:e.title||c}),className:`w-full max-w-[340px] overflow-hidden rounded-3xl rounded-tl-lg border border-border bg-surface shadow-sm hover:bg-surface-2 transition text-left`,children:[(0,R.jsxs)(`div`,{className:`relative aspect-[16/10] bg-surface-2`,children:[r?(0,R.jsxs)(`div`,{className:`absolute inset-0 flex flex-col items-center justify-center gap-1 text-muted`,children:[(0,R.jsx)(gt,{size:22}),(0,R.jsx)(`span`,{className:`text-[12px]`,children:a(`Frame no longer available`)})]}):(0,R.jsx)(`img`,{src:n(e.thread,e.frame),alt:e.title||c,onError:()=>i(!0),className:`absolute inset-0 h-full w-full object-cover object-top`},e.frame),(0,R.jsx)(`div`,{className:`absolute left-2.5 top-2.5 flex items-center gap-1.5 rounded-full bg-black/60 px-2 py-0.5 text-[10.5px] font-semibold text-white`,children:o?(0,R.jsxs)(R.Fragment,{children:[(0,R.jsx)(`span`,{className:`h-1.5 w-1.5 rounded-full bg-rose-400 animate-pulse`}),` `,a(`LIVE`)]}):(0,R.jsxs)(R.Fragment,{children:[(0,R.jsx)(gt,{size:11}),` `,a(`BROWSER`)]})})]}),(0,R.jsxs)(`div`,{className:`flex items-center gap-2 px-3.5 py-2.5`,children:[(0,R.jsxs)(`div`,{className:`min-w-0 flex-1`,children:[(0,R.jsx)(`div`,{className:`text-[13.5px] font-medium truncate`,children:e.title||c}),(0,R.jsxs)(`div`,{className:`text-[12px] text-muted truncate`,children:[e.by_user&&e.action.startsWith(`You`)?a(`You`)+e.action.slice(3):e.action,` · `,c]})]}),(0,R.jsx)(rt,{size:16,className:`text-muted shrink-0`})]})]})})}function bp({event:e,name:t=`nanoMuse`}){let n=s(),{state:r,toast:a}=E(),[o,c]=(0,L.useState)(!1),[l,d]=(0,L.useState)(!1),f=e.status===`live`,p=e.last,m=[e.app,e.title].filter(Boolean).join(` · `),h=r.holds.find(t=>t.thread===e.thread&&t.tool===`computer`),g=async()=>{c(!0);try{await M.stopHands()}catch{}finally{c(!1)}},_=async()=>{d(!0);try{await M.openHold(e.thread,`computer`)}catch(e){a(e.message)}finally{d(!1)}};return(0,R.jsx)(`div`,{className:`rise flex justify-start pr-8`,children:(0,R.jsxs)(`div`,{className:i(`w-full max-w-[360px] overflow-hidden rounded-3xl rounded-tl-lg border bg-surface shadow-sm`,f?`border-accent/50`:`border-border/70`),children:[(0,R.jsxs)(`div`,{className:`flex items-start gap-3 px-4 pt-3.5 pb-2`,children:[(0,R.jsx)(`div`,{className:i(`mt-0.5 rounded-full p-2`,f?`bg-accent/12 text-accent`:`bg-surface-2 text-fg/80`),children:(0,R.jsx)(vt,{size:18})}),(0,R.jsxs)(`div`,{className:`min-w-0 flex-1`,children:[(0,R.jsxs)(`div`,{className:`flex items-center gap-2 text-[12.5px] font-medium text-muted`,children:[(0,R.jsx)(`span`,{children:f?n(`{name} is using this computer`,{name:t}):e.status===`stopped`?n(`Hands stopped`):n(`Hands done`)}),f&&(0,R.jsxs)(`span`,{className:`flex items-center gap-1 rounded-full bg-accent/12 px-2 py-0.5 text-[10.5px] font-semibold text-accent`,children:[(0,R.jsx)(`span`,{className:`h-1.5 w-1.5 animate-pulse rounded-full bg-accent`}),` `,n(`LIVE`)]})]}),e.text&&(0,R.jsx)(`div`,{className:`mt-0.5 break-words text-[15px] font-semibold leading-snug`,children:e.text}),p?.action&&(0,R.jsxs)(`div`,{className:`mt-1.5 flex items-center gap-1.5 text-[13px] text-fg/90`,children:[(0,R.jsx)(zt,{size:13,className:`shrink-0 text-muted`}),(0,R.jsx)(`span`,{className:`truncate`,children:Tp(p,n)})]}),m&&(0,R.jsx)(`div`,{className:`mt-1 truncate text-[12px] text-muted`,children:m}),e.notice&&(0,R.jsx)(`div`,{className:`mt-1.5 rounded-2xl bg-amber-500/12 px-3 py-1.5 text-[12.5px] text-amber-700 dark:text-amber-300`,children:e.notice}),f&&h&&(0,R.jsx)(xp,{hold:h})]})]}),(0,R.jsxs)(`div`,{className:`flex items-center gap-2 border-t border-border/70 px-4 py-2 text-[12px] text-muted`,children:[(0,R.jsx)(`span`,{children:n(`{n} steps`,{n:e.steps})}),(0,R.jsx)(`span`,{className:`ml-auto`,children:u(e.updated_ts??e.ts)}),f&&!h&&(0,R.jsxs)(`button`,{type:`button`,onClick:()=>void _(),disabled:l,className:`ml-1 inline-flex items-center gap-1.5 rounded-full bg-accent/12 px-3 py-1 text-[12.5px] font-semibold text-accent transition active:scale-95 disabled:opacity-60`,children:[(0,R.jsx)(vt,{size:11}),` `,n(`Take over`)]}),f&&(0,R.jsxs)(`button`,{type:`button`,onClick:()=>void g(),disabled:o,className:`ml-1 inline-flex items-center gap-1.5 rounded-full bg-fg px-3 py-1 text-[12.5px] font-semibold text-bg transition active:scale-95 disabled:opacity-60`,children:[(0,R.jsx)(sn,{size:10,fill:`currentColor`}),` `,n(`Stop`)]})]})]})})}function xp({hold:e,compact:t}){let n=s(),[r,a]=(0,L.useState)(!1),o=async()=>{a(!0);try{await M.doneHold(e.id)}catch{}finally{a(!1)}};return(0,R.jsxs)(`div`,{className:i(`flex items-center gap-2 rounded-2xl bg-amber-500/12 px-3 text-amber-800 dark:text-amber-200`,t?`py-1.5 text-[12.5px]`:`mt-1.5 py-2 text-[13px]`),children:[(0,R.jsx)(vt,{size:14,className:`shrink-0`}),(0,R.jsx)(`span`,{className:`min-w-0 flex-1 leading-snug`,children:Cp(e,n)}),(0,R.jsx)(`button`,{type:`button`,onClick:()=>void o(),disabled:r,className:`shrink-0 rounded-full bg-fg px-3 py-1 text-[12.5px] font-semibold text-bg transition active:scale-95 disabled:opacity-60`,children:r?(0,R.jsx)(A,{size:13,className:`animate-spin`}):n(`Done`)})]})}function Sp(e,t){return t(e===`browser`?`the browser`:e===`phone`?`the phone`:`this computer`)}function Cp(e,t){return e.by===`agent`?e.reason?t(`Your turn: {reason}`,{reason:e.reason}):t(`Your turn`):t(`You took over {thing}`,{thing:Sp(e.tool,t)})}function wp({event:e,name:t=`nanoMuse`}){let n=s(),[r,a]=(0,L.useState)(!1),o=e.status===`on`,c=Sp(e.tool,n),l=async()=>{a(!0);try{await M.doneHold(e.id)}catch{}finally{a(!1)}},d=e.timed_out?n(`{name} waited ten minutes and went on without you.`,{name:t}):e.stale?n(`Ended when the runtime restarted.`):e.by===`agent`?n(`You did it; {name} carried on.`,{name:t}):n(`Handed back; {name} carried on.`,{name:t});return(0,R.jsx)(`div`,{className:`rise flex justify-start pr-8`,children:(0,R.jsxs)(`div`,{className:i(`w-full max-w-[360px] overflow-hidden rounded-3xl rounded-tl-lg border bg-surface shadow-sm`,o?`border-amber-500/50`:`border-border/70 opacity-70`),children:[(0,R.jsxs)(`div`,{className:`flex items-start gap-3 px-4 pt-3.5 pb-3`,children:[(0,R.jsx)(`div`,{className:i(`mt-0.5 rounded-full p-2`,o?`bg-amber-500/15 text-amber-700 dark:text-amber-300`:`bg-surface-2 text-fg/70`),children:(0,R.jsx)(vt,{size:18})}),(0,R.jsxs)(`div`,{className:`min-w-0 flex-1`,children:[(0,R.jsx)(`div`,{className:`text-[12.5px] font-medium text-muted`,children:e.tool===`browser`?n(`The browser`):e.tool===`phone`?n(`The phone`):n(`This computer`)}),(0,R.jsx)(`div`,{className:`mt-0.5 break-words text-[15px] font-semibold leading-snug`,children:e.by===`agent`?n(`Your turn`):n(`You took over {thing}`,{thing:c})}),e.by===`agent`&&e.reason&&(0,R.jsx)(`div`,{className:`mt-1 break-words text-[13.5px] leading-snug text-fg/90`,children:e.reason}),(0,R.jsx)(`div`,{className:`mt-1.5 text-[12.5px] leading-snug text-muted`,children:o?e.by===`agent`?n(`Do this part yourself, then press Done. {name} looks again and carries on from there.`,{name:t}):n(`{name} waits. Press Done when you are finished and it looks again.`,{name:t}):d})]})]}),(0,R.jsxs)(`div`,{className:`flex items-center gap-2 border-t border-border/70 px-4 py-2 text-[12px] text-muted`,children:[(0,R.jsx)(`span`,{children:u(e.ts)}),o&&(0,R.jsxs)(`button`,{type:`button`,onClick:()=>void l(),disabled:r,className:`ml-auto inline-flex items-center gap-1.5 rounded-full bg-fg px-3.5 py-1 text-[12.5px] font-semibold text-bg transition active:scale-95 disabled:opacity-60`,children:[r?(0,R.jsx)(A,{size:13,className:`animate-spin`}):(0,R.jsx)(ke,{size:12}),` `,n(`Done`)]})]})]})})}function Tp(e,t){let n=e.label?`“${e.label}”`:``;switch(e.action){case`click`:return n?t(`Clicked {label}`,{label:n}):t(`Clicked`);case`double_click`:return n?t(`Double-clicked {label}`,{label:n}):t(`Double-clicked`);case`right_click`:case`middle_click`:return n?t(`Right-clicked {label}`,{label:n}):t(`Right-clicked`);case`move`:return n?t(`Pointed at {label}`,{label:n}):t(`Moved the mouse`);case`type`:return t(`Typed {n} characters`,{n:(e.text??``).length});case`key`:return t(`Pressed {keys}`,{keys:(e.keys??[]).join(`+`)});case`scroll`:return t(`Scrolled`);case`drag`:return t(`Dragged`);case`open_app`:return n?t(`Opened {label}`,{label:n}):t(`Opened an application`);case`wait`:return t(`Waited`);default:return e.action??``}}function Ep({event:e,onOpen:t}){let n=s(),a=r(e.name),o=n(a===`html`?`Page`:a===`image`?`Image`:a===`data`?`Data`:a===`code`?`Code`:a===`event`?`Event`:`Document`),c=e.action===`update`?`${o} · ${n(`updated`)}`:o,l=a===`html`||a===`image`;return(0,R.jsx)(`div`,{className:`rise flex justify-start pr-8`,children:(0,R.jsxs)(`button`,{type:`button`,onClick:()=>t(e.path),className:i(`max-w-full overflow-hidden rounded-[20px] border border-border bg-surface text-left shadow-[0_4px_20px_-12px_rgba(0,0,0,0.2)] transition hover:bg-surface-2`,l?`w-[300px]`:``),children:[l&&(0,R.jsx)(Dp,{path:e.path,kind:a}),(0,R.jsxs)(`div`,{className:`flex items-center gap-3 px-4 py-3`,children:[!l&&(0,R.jsx)(`div`,{className:`rounded-2xl bg-accent/12 p-2.5 text-accent`,children:a===`code`?(0,R.jsx)(ct,{size:20}):a===`event`?(0,R.jsx)(tt,{size:20}):(0,R.jsx)(mt,{size:20})}),(0,R.jsxs)(`div`,{className:`min-w-0 flex-1`,children:[(0,R.jsx)(`div`,{className:`text-[11px] font-semibold uppercase tracking-wide text-muted`,children:c}),(0,R.jsx)(`div`,{className:`truncate text-[14.5px] font-medium`,children:e.name}),(0,R.jsx)(`div`,{className:`truncate text-[12px] text-muted`,children:e.path})]}),(0,R.jsx)(rt,{size:16,className:`ml-1 shrink-0 text-muted`})]})]})})}function Dp({path:e,kind:t}){return t===`image`?(0,R.jsx)(`img`,{src:h(e),alt:``,loading:`lazy`,className:`h-40 w-full object-cover`}):(0,R.jsx)(`div`,{className:`pointer-events-none relative h-40 w-full overflow-hidden bg-white`,children:(0,R.jsx)(`iframe`,{title:e,src:h(e),sandbox:``,tabIndex:-1,loading:`lazy`,scrolling:`no`,className:`absolute left-0 top-0 h-[480px] w-[900px] origin-top-left scale-[0.3333] border-0`})})}function Op({open:e,onClose:t,title:n,children:r,footer:i}){let a=s(),o=(0,L.useRef)(null);return On(o,e),(0,L.useEffect)(()=>{if(!e)return;let n=e=>e.key===`Escape`&&t();return window.addEventListener(`keydown`,n),()=>window.removeEventListener(`keydown`,n)},[e,t]),e?(0,R.jsxs)(`div`,{className:`fixed inset-0 z-50 flex items-end sm:items-center sm:justify-center`,children:[(0,R.jsx)(`div`,{className:`absolute inset-0 bg-black/45 backdrop-blur-[2px]`,onClick:t}),(0,R.jsxs)(`div`,{ref:o,role:`dialog`,"aria-modal":`true`,className:`sheet-in relative w-full sm:max-w-lg max-h-[92dvh] flex flex-col bg-surface rounded-t-3xl sm:rounded-3xl shadow-2xl border border-border`,children:[(0,R.jsxs)(`div`,{className:`flex items-center gap-3 px-5 pt-4 pb-2`,children:[(0,R.jsx)(`div`,{className:`sm:hidden absolute left-1/2 -translate-x-1/2 top-2 h-1 w-10 rounded-full bg-border`}),(0,R.jsx)(`div`,{className:`flex-1 font-semibold text-[17px] mt-1`,children:n}),(0,R.jsx)(`button`,{type:`button`,onClick:t,"aria-label":a(`Close`),className:`p-2 -mr-2 rounded-full text-muted hover:bg-surface-2`,children:(0,R.jsx)(Fe,{size:20})})]}),(0,R.jsx)(`div`,{className:`flex-1 overflow-y-auto px-5 pb-4`,children:r}),i&&(0,R.jsx)(`div`,{className:`px-5 pt-2 pb-4 safe-bottom border-t border-border`,children:i})]})]}):null}var kp=1e3;function Ap({thread:e,eventId:t,onClose:r}){let{state:a,toast:o}=E(),c=s(),l=(a.events[e]??[]).find(e=>e.id===t),u=a.holds.find(t=>t.thread===e&&t.tool===`browser`),[d,f]=(0,L.useState)(null),[p,m]=(0,L.useState)(null),[h,g]=(0,L.useState)(``),[_,v]=(0,L.useState)(``),[y,b]=(0,L.useState)(!1),x=(0,L.useRef)(null),S=d?d===`on`:!!u;(0,L.useEffect)(()=>b(!1),[l?.frame]),(0,L.useEffect)(()=>f(null),[u?.id,u?.status]);let C=l?.backend===`device`&&ap();(0,L.useEffect)(()=>{if(!C)return;let t=t=>{let n=t.detail;n?.thread&&n.thread!==e||M.browserControl(e,{action:`handed_back`}).catch(e=>o(e.message))};return window.addEventListener(`nanomuse:browser-handed-back`,t),()=>window.removeEventListener(`nanomuse:browser-handed-back`,t)},[C,e,o]);let w=(0,L.useCallback)(async t=>{m(t.action);try{await M.browserControl(e,t)}catch(e){o(e.message)}finally{m(null)}},[e,o]),T=()=>{if(C){ip()?.takeOverBrowser?.(e),M.browserControl(e,{action:`take_over`}).catch(()=>void 0);return}f(`on`),w({action:`take_over`})},D=()=>{f(`off`),w({action:`handed_back`})};(0,L.useEffect)(()=>{if(!S||C||!l||l.status!==`live`)return;let t=window.setInterval(()=>{document.hidden||M.browserControl(e,{action:`look`}).catch(()=>void 0)},kp);return()=>window.clearInterval(t)},[S,C,e,l]);let O=e=>{if(!S||p)return;let t=e.currentTarget.getBoundingClientRect(),n=(e.clientX-t.left)/t.width,r=(e.clientY-t.top)/t.height;w({action:`click`,x:Math.min(Math.max(n,0),1),y:Math.min(Math.max(r,0),1)})},k=e=>{!S||p||Math.abs(e.deltaY)<8||w({action:`scroll`,dy:Math.max(-2e3,Math.min(2e3,Math.round(e.deltaY*2)))})};if(!l)return null;let ee=l.url;try{ee=new URL(l.url).host}catch{}let te=l.status===`live`,j=a.profile?.name??`nanoMuse`,ne=u?c(`{name} is waiting for you`,{name:j}):a.status.state!==`idle`&&a.status.thread===e?c(`{name} is working`,{name:j}):l.action;return(0,R.jsxs)(Op,{open:!0,onClose:r,title:(0,R.jsxs)(`div`,{className:`flex items-center gap-2 min-w-0`,children:[(0,R.jsx)(gt,{size:17,className:`text-accent shrink-0`}),(0,R.jsx)(`span`,{className:`truncate`,children:l.title||ee}),te&&(0,R.jsxs)(`span`,{className:`ml-1 flex items-center gap-1 rounded-full bg-rose-500/12 px-2 py-0.5 text-[10.5px] font-semibold text-rose-500`,children:[(0,R.jsx)(`span`,{className:`h-1.5 w-1.5 rounded-full bg-rose-500 animate-pulse`}),` `,c(`LIVE`)]})]}),footer:S?(0,R.jsxs)(`div`,{className:`space-y-2`,children:[(0,R.jsxs)(`form`,{className:`flex items-center gap-2`,onSubmit:e=>{e.preventDefault(),h&&w({action:`type`,text:h}).then(()=>g(``))},children:[(0,R.jsx)(`input`,{value:h,onChange:e=>g(e.target.value),placeholder:c(`Type into the focused field…`),className:`flex-1 rounded-2xl bg-surface-2 px-3.5 py-2.5 text-[14px] outline-none`,autoComplete:`off`,autoCapitalize:`off`}),(0,R.jsx)(`button`,{type:`submit`,disabled:!h||!!p,"aria-label":c(`Type`),className:`rounded-full bg-accent p-2.5 text-white disabled:opacity-40`,children:p===`type`?(0,R.jsx)(A,{size:16,className:`animate-spin`}):(0,R.jsx)(qe,{size:16})}),(0,R.jsx)(`button`,{type:`button`,onClick:()=>void w({action:`key`,key:`Enter`}),disabled:!!p,"aria-label":c(`Press Enter`),className:`rounded-full bg-surface-2 p-2.5 text-fg disabled:opacity-40`,children:(0,R.jsx)(dt,{size:16})})]}),(0,R.jsxs)(`form`,{className:`flex items-center gap-2`,onSubmit:e=>{e.preventDefault(),_&&w({action:`navigate`,url:_}).then(()=>v(``))},children:[(0,R.jsx)(`button`,{type:`button`,onClick:()=>void w({action:`back`}),disabled:!!p,"aria-label":c(`Back`),className:`rounded-full bg-surface-2 p-2 text-fg disabled:opacity-40`,children:(0,R.jsx)(Ke,{size:15})}),(0,R.jsx)(`input`,{value:_,onChange:e=>v(e.target.value),placeholder:c(`Open a URL…`),inputMode:`url`,autoCapitalize:`off`,className:`flex-1 min-w-0 rounded-2xl bg-surface-2 px-3.5 py-2 text-[13px] outline-none`}),(0,R.jsx)(`button`,{type:`submit`,disabled:!_||!!p,className:`rounded-2xl bg-surface-2 px-3 py-2 text-[13px] font-medium disabled:opacity-40`,children:c(`Go`)}),(0,R.jsx)(`button`,{type:`button`,onClick:()=>void w({action:`scroll`,dy:-600}),disabled:!!p,"aria-label":c(`Scroll up`),className:`rounded-full bg-surface-2 p-2 text-fg disabled:opacity-40`,children:(0,R.jsx)(Je,{size:15})}),(0,R.jsx)(`button`,{type:`button`,onClick:()=>void w({action:`scroll`,dy:600}),disabled:!!p,"aria-label":c(`Scroll down`),className:`rounded-full bg-surface-2 p-2 text-fg disabled:opacity-40`,children:(0,R.jsx)(Ge,{size:15})})]}),(0,R.jsxs)(`div`,{className:`flex items-center justify-between gap-2`,children:[(0,R.jsx)(`span`,{className:`min-w-0 truncate text-[12px] text-muted`,children:c(`Tap the page to click. If the browser was closed, open a URL first.`)}),(0,R.jsxs)(`button`,{type:`button`,onClick:D,disabled:p===`handed_back`,className:`flex shrink-0 items-center gap-1.5 whitespace-nowrap rounded-full bg-fg px-3.5 py-1.5 text-[13px] font-semibold text-bg disabled:opacity-60`,children:[p===`handed_back`?(0,R.jsx)(A,{size:14,className:`animate-spin`}):(0,R.jsx)(ke,{size:14}),` `,c(`Done`)]})]})]}):(0,R.jsxs)(`div`,{className:`flex items-center justify-between gap-2`,children:[(0,R.jsxs)(`div`,{className:`min-w-0 text-[12.5px] text-muted truncate`,children:[ne,` · `,ee]}),(0,R.jsxs)(`div`,{className:`flex items-center gap-2 shrink-0`,children:[(0,R.jsx)(`button`,{type:`button`,onClick:()=>void w({action:`look`}),disabled:!!p,"aria-label":c(`Refresh`),className:`rounded-full bg-surface-2 p-2 text-muted disabled:opacity-40`,children:p===`look`?(0,R.jsx)(A,{size:15,className:`animate-spin`}):(0,R.jsx)(Re,{size:15})}),(0,R.jsxs)(`button`,{type:`button`,onClick:T,disabled:d===`on`,className:`flex items-center gap-1.5 rounded-full bg-accent px-3.5 py-2 text-[13px] font-semibold text-white disabled:opacity-60`,children:[(0,R.jsx)(vt,{size:14}),` `,c(`Take over`)]})]})]}),children:[u&&u.by===`agent`&&(0,R.jsx)(`div`,{className:`mb-2`,children:(0,R.jsx)(xp,{hold:u,compact:!0})}),(0,R.jsxs)(`div`,{className:i(`relative overflow-hidden rounded-2xl border border-border bg-surface-2`,S&&`ring-2 ring-accent`),children:[y?(0,R.jsxs)(`div`,{className:`flex aspect-[16/10] flex-col items-center justify-center gap-1 text-muted`,children:[(0,R.jsx)(gt,{size:24}),(0,R.jsx)(`span`,{className:`text-[12.5px]`,children:c(`This frame is no longer available.`)}),(0,R.jsx)(`button`,{type:`button`,onClick:()=>void w({action:`look`}),className:`text-accent text-[13px] font-medium`,children:c(`Look again`)})]}):(0,R.jsx)(`img`,{ref:x,src:n(e,l.frame),alt:l.title||ee,onError:()=>b(!0),onClick:O,onWheel:k,draggable:!1,className:i(`block w-full select-none`,S?`cursor-crosshair`:``)},l.frame),p&&p!==`look`&&(0,R.jsx)(`div`,{className:`absolute inset-0 flex items-center justify-center bg-black/20`,children:(0,R.jsx)(A,{size:26,className:`animate-spin text-white`})})]}),(0,R.jsxs)(`div`,{className:`mt-2 flex items-center justify-between text-[12px] text-muted`,children:[(0,R.jsx)(`span`,{className:`truncate`,children:l.url}),(0,R.jsx)(`span`,{className:`shrink-0 ml-2`,children:l.frames===1?c(`1 frame`):c(`{n} frames`,{n:l.frames})})]}),S&&(0,R.jsxs)(`div`,{className:`mt-3 rounded-2xl bg-accent/8 px-3.5 py-2.5 text-[13px] leading-snug`,children:[(0,R.jsx)(`div`,{className:`font-medium`,children:u&&u.by===`agent`?Cp(u,c):c(`You have the page. Press Done when you are finished.`)}),(0,R.jsx)(`div`,{className:`mt-1 text-muted`,children:c(`{name} waits meanwhile, then looks at the page as you left it and carries on. Passwords you type here go to the website, never to the model.`,{name:j})})]})]})}function jp(){if(typeof window>`u`)return null;let e=window;return e.SpeechRecognition??e.webkitSpeechRecognition??null}function Mp(){return jp()!==null}function Np(e,t){let[n,r]=(0,L.useState)(!1),i=(0,L.useRef)(null),a=(0,L.useRef)(``),o=s(),c=(0,L.useCallback)(()=>{i.current?.stop()},[]),l=(0,L.useCallback)(()=>{let n=jp();if(!n)return;let s=new n;s.lang=navigator.language||`en-US`,s.continuous=!0,s.interimResults=!0,a.current=``,s.onresult=t=>{let n=``;for(let e=t.resultIndex;e{let n=e.error||``;n!==`aborted`&&n!==`no-speech`&&t?.(n===`not-allowed`||n===`service-not-allowed`?o(`The microphone is not allowed. Allow it in the browser and try again.`):o(`Voice input stopped ({code}).`,{code:n}))},s.onend=()=>{i.current=null,r(!1)},i.current=s;try{s.start(),r(!0)}catch{i.current=null,r(!1)}},[e,t,o]),u=(0,L.useCallback)(()=>{i.current?c():l()},[l,c]);return(0,L.useEffect)(()=>()=>i.current?.abort(),[]),{supported:Mp(),listening:n,toggle:u,stop:c}}function Pp({listening:e,onClick:t,className:n}){let r=s();return(0,R.jsx)(`button`,{type:`button`,onClick:t,"aria-label":r(e?`Stop voice input`:`Voice input`),"aria-pressed":e,className:i(`flex h-9 w-9 shrink-0 items-center justify-center rounded-full transition active:scale-95`,e?`bg-accent/15 text-accent animate-pulse`:`text-fg/70 hover:bg-surface-2`,n),children:e?(0,R.jsx)(Pt,{size:19}):(0,R.jsx)(Ft,{size:19})})}function Fp({lines:e}){return(0,R.jsx)(`div`,{className:`flex items-end gap-2 pr-10`,children:(0,R.jsx)(`div`,{className:`min-w-0 max-w-full`,children:e.map((e,t)=>(0,R.jsx)(`div`,{className:`my-1 max-w-[340px] rounded-[20px] bg-surface-2 px-3.5 py-2.5 text-[14.5px] leading-snug whitespace-pre-wrap break-words wide:max-w-[600px]`,children:e},t))})})}function Ip({chips:e,chosen:t,busy:n,onPick:r,onElse:a}){let o=s();return e.length===0&&!t?null:(0,R.jsxs)(`section`,{className:`rise mx-1 my-2 rounded-[22px] border border-border/70 bg-surface p-3.5`,children:[(0,R.jsxs)(`div`,{className:`flex items-center gap-2 text-[13px] font-medium text-fg`,children:[(0,R.jsx)(nn,{size:14,className:`text-accent`}),` `,o(`Pick a name for me, or type one`)]}),(0,R.jsxs)(`div`,{className:`mt-2.5 flex flex-wrap gap-2`,children:[e.map(e=>{let a=t===e;return(0,R.jsxs)(`button`,{type:`button`,disabled:n||!!t,onClick:()=>r(e),className:i(`inline-flex items-center gap-1.5 rounded-full px-3.5 py-1.5 text-[13.5px] font-medium transition-colors disabled:opacity-60`,a?`bg-accent text-accent-fg`:`bg-surface-2 hover:bg-border/60`),children:[a&&(0,R.jsx)(ke,{size:13,strokeWidth:3}),e]},e)}),!t&&(0,R.jsx)(`button`,{type:`button`,disabled:n,onClick:a,className:`rounded-full border border-border px-3.5 py-1.5 text-[13.5px] text-muted hover:bg-surface-2 disabled:opacity-60`,children:o(`Something else`)})]})]})}var Lp=[{id:`pink`,background:`#F9D9E3`,accent:`#B5476A`,mood:`idle`},{id:`blue`,background:`#D6E6FA`,accent:`#2F5FA8`,mood:`working`},{id:`yellow`,background:`#FBEFC7`,accent:`#9A6B12`,mood:`waiting`},{id:`purple`,background:`#E4DDF7`,accent:`#5D44A6`,mood:`happy`},{id:`green`,background:`#D9F0DF`,accent:`#2E7D4F`,mood:`error`}],Rp=`github.com/nano-muse/nanoMuse`,zp=540,Bp=720;function Vp(e,t){return!e||w(e.avatar)?j(t):e.avatar?re(e.avatar,t):null}function Hp(e){return new Promise(t=>{let n=new Image;n.crossOrigin=`anonymous`,n.onload=()=>t(n),n.onerror=()=>t(null),n.src=e})}function Up(e,t,n){let r=t.includes(` `)?t.split(` `):Array.from(t),i=t.includes(` `)?` `:``,a=[],o=``;for(let t of r){let r=o?o+i+t:t;e.measureText(r).width>n&&o?(a.push(o),o=t):o=r}return o&&a.push(o),a}function Wp(e,t,n,r,i,a){e.beginPath(),e.moveTo(t+a,n),e.arcTo(t+r,n,t+r,n+i,a),e.arcTo(t+r,n+i,t,n+i,a),e.arcTo(t,n+i,t,n,a),e.arcTo(t,n,t+r,n,a),e.closePath()}async function Gp(e,t,n,r,i,a=2){let o=document.createElement(`canvas`);o.width=zp*a,o.height=Bp*a;let s=o.getContext(`2d`);if(!s)return o;s.scale(a,a),s.fillStyle=e.background,Wp(s,0,0,zp,Bp,36),s.fill(),s.font=`600 22px system-ui, -apple-system, 'Segoe UI', sans-serif`;let c=Up(s,r,400),l=Math.max(...c.map(e=>s.measureText(e).width))+48,u=c.length*30+36,d=(zp-l)/2;s.fillStyle=`#ffffff`,Wp(s,d,56,l,u,24),s.fill(),s.beginPath(),s.moveTo(zp/2-14,56+u-1),s.lineTo(zp/2,56+u+18),s.lineTo(284,56+u-1),s.closePath(),s.fill(),s.fillStyle=e.accent,s.textAlign=`center`,s.textBaseline=`top`,c.forEach((e,t)=>s.fillText(e,zp/2,74+t*30+3));let f=56+u+54;s.fillStyle=`#ffffff`,s.beginPath(),s.arc(zp/2,f+150,158,0,Math.PI*2),s.fill();let p=Vp(t,e.mood),m=p?await Hp(p):null;return s.save(),s.beginPath(),s.arc(zp/2,f+150,150,0,Math.PI*2),s.clip(),m?(s.fillStyle=`#f1efeb`,s.fillRect(120,f,300,300),s.drawImage(m,120,f,300,300)):(s.fillStyle=t?.color??`#0064d4`,s.fillRect(120,f,300,300),s.font=`150px system-ui, 'Apple Color Emoji', 'Segoe UI Emoji', sans-serif`,s.textAlign=`center`,s.textBaseline=`middle`,s.fillStyle=`#ffffff`,s.fillText(t?.emoji??`✨`,zp/2,f+150+6)),s.restore(),s.fillStyle=e.accent,s.textAlign=`center`,s.textBaseline=`top`,s.font=`700 30px system-ui, -apple-system, 'Segoe UI', sans-serif`,s.fillText(n,zp/2,f+300+34),s.font=`500 15px system-ui, -apple-system, 'Segoe UI', sans-serif`,s.globalAlpha=.8,Up(s,i,460).forEach((e,t)=>s.fillText(e,zp/2,644+t*22)),s.globalAlpha=1,o}function Kp(e){return new Promise(t=>e.toBlob(t,`image/png`))}function qp({open:e,onClose:t}){let{state:n,toast:r}=E(),a=s(),o=n.profile,c=o?.name??`nanoMuse`,[l,u]=(0,L.useState)(0),[d,f]=(0,L.useState)([]),[p,m]=(0,L.useState)(!1),h=(0,L.useRef)(!0),g=a(`Hi, I'm {name}, a personal AI agent. Meet nanoMuse: open source, runs on your phone.`,{name:c}),_=a(`Your personal AI agent, open source · {repo}`,{repo:Rp});(0,L.useEffect)(()=>{if(h.current=!0,e)return u(0),(async()=>{let e=[];for(let t of Lp){let n=await Gp(t,o,c,g,_,1);e.push(n.toDataURL(`image/png`))}h.current&&f(e)})(),()=>{h.current=!1}},[e,o?.avatar,o?.emoji,o?.color,c]);let v=async()=>{m(!0);try{let e=await Kp(await Gp(Lp[l]??Lp[0],o,c,g,_,2));if(!e)throw Error(a(`The card could not be drawn.`));let n=new File([e],`${c}-nanomuse.png`,{type:`image/png`}),i=`${g}\nhttps://${Rp}`,s=navigator;if(typeof s.share==`function`&&(!s.canShare||s.canShare({files:[n]})))try{await s.share({files:[n],text:i,title:c}),t();return}catch(e){if(e.name===`AbortError`)return}let u=document.createElement(`a`);u.href=URL.createObjectURL(e),u.download=n.name,u.click(),window.setTimeout(()=>URL.revokeObjectURL(u.href),2e3),r(a(`Saved the card as a picture.`))}catch(e){r(e.message)}finally{m(!1)}};return(0,R.jsxs)(Op,{open:e,onClose:t,title:a(`Share my avatar`),children:[(0,R.jsx)(`p`,{className:`mb-3 text-[13px] text-muted`,children:a(`Pick a card. It goes out through the system share sheet, or saves as a picture where there is none.`)}),(0,R.jsx)(`div`,{className:`grid grid-cols-3 gap-2.5 sm:grid-cols-5`,children:Lp.map((e,t)=>(0,R.jsx)(`button`,{type:`button`,"aria-label":e.id,"aria-pressed":l===t,onClick:()=>u(t),className:i(`overflow-hidden rounded-2xl border-2 transition`,l===t?`border-accent`:`border-transparent`),style:{background:e.background,aspectRatio:`${zp} / ${Bp}`},children:d[t]?(0,R.jsx)(`img`,{src:d[t],alt:``,className:`h-full w-full object-cover`}):(0,R.jsx)(A,{size:18,className:`mx-auto my-8 animate-spin text-muted`})},e.id))}),d[l]&&(0,R.jsx)(`img`,{src:d[l],alt:``,className:`mx-auto mt-4 w-[260px] rounded-[20px] shadow-md`}),(0,R.jsxs)(`div`,{className:`mt-4 flex justify-end gap-2`,children:[(0,R.jsx)(`button`,{type:`button`,onClick:t,className:je,children:a(`Later`)}),(0,R.jsxs)(`button`,{type:`button`,disabled:p||!d.length,onClick:()=>void v(),className:Ne,children:[p?(0,R.jsx)(A,{size:15,className:`animate-spin`}):typeof navigator.share==`function`?(0,R.jsx)(Xt,{size:15}):(0,R.jsx)(ft,{size:15}),` `,typeof navigator.share==`function`?a(`Share`):a(`Save picture`)]})]})]})}function Jp({message:e,onRetry:t}){let n=s();return(0,R.jsxs)(`div`,{className:`flex flex-col items-center gap-3 px-8 py-10 text-center`,children:[(0,R.jsx)(`p`,{className:`text-[14px] text-rose-600 dark:text-rose-300`,children:n(e)||n(`Could not load.`)}),(0,R.jsxs)(`button`,{type:`button`,onClick:t,className:`flex h-10 items-center gap-1.5 rounded-full bg-surface px-4 text-[13.5px] font-medium shadow-[0_1px_4px_rgba(0,0,0,0.14)] dark:border dark:border-border dark:shadow-none`,children:[(0,R.jsx)(Re,{size:14}),` `,n(`Try again`)]})]})}var Yp=[{id:`health`,label:`Health`,icon:e=>(0,R.jsx)(yt,{...e}),tone:`bg-rose-500/12 text-rose-600 dark:text-rose-300`},{id:`finance`,label:`Finance`,icon:e=>(0,R.jsx)(Wt,{...e}),tone:`bg-emerald-500/12 text-emerald-600 dark:text-emerald-300`},{id:`career`,label:`Career`,icon:e=>(0,R.jsx)($e,{...e}),tone:`bg-sky-500/12 text-sky-600 dark:text-sky-300`},{id:`learning`,label:`Learning`,icon:e=>(0,R.jsx)(_t,{...e}),tone:`bg-violet-500/12 text-violet-600 dark:text-violet-300`},{id:`relationships`,label:`Relationships`,icon:e=>(0,R.jsx)(le,{...e}),tone:`bg-pink-500/12 text-pink-600 dark:text-pink-300`},{id:`family`,label:`Family`,icon:e=>(0,R.jsx)(hn,{...e}),tone:`bg-amber-500/12 text-amber-600 dark:text-amber-300`},{id:`home`,label:`Home`,icon:e=>(0,R.jsx)(bt,{...e}),tone:`bg-orange-500/12 text-orange-600 dark:text-orange-300`},{id:`travel`,label:`Travel`,icon:e=>(0,R.jsx)(lt,{...e}),tone:`bg-cyan-500/12 text-cyan-600 dark:text-cyan-300`},{id:`creative`,label:`Creative`,icon:e=>(0,R.jsx)(Vt,{...e}),tone:`bg-fuchsia-500/12 text-fuchsia-600 dark:text-fuchsia-300`},{id:`other`,label:`Other`,icon:e=>(0,R.jsx)(ln,{...e}),tone:`bg-surface-2 text-muted`}];function Xp(e){return Yp.find(t=>t.id===e)??null}var Zp=[{id:``,label:`No reminders`},{id:`daily`,label:`Every day`},{id:`weekdays`,label:`Weekdays`},{id:`weekly`,label:`Once a week`},{id:`monthly`,label:`Once a month`}],Qp=[`mon`,`tue`,`wed`,`thu`,`fri`,`sat`,`sun`];function $p(e){let t=/^(daily|weekdays|weekly|monthly)(?:\s+(\S+?))?(?:\s+(\d{1,2}:\d{2}))?$/.exec(e.trim());if(!t)return{cadence:``,anchor:``,time:`09:00`};let n=t[2]??``,r=t[3]??`09:00`;return n&&/^\d{1,2}:\d{2}$/.test(n)&&(r=n,n=``),{cadence:t[1],anchor:n,time:r.padStart(5,`0`)}}function em(e,t,n){return e?[e,t,n].filter(Boolean).join(` `):``}function tm(e){let t=Qp.indexOf(e);return t<0?e:new Date(2024,0,1+t).toLocaleDateString(m(),{weekday:`long`})}function nm(e){let{cadence:t,anchor:n,time:r}=$p(e);switch(t){case`daily`:return _(`Daily at {time}`,{time:r});case`weekdays`:return _(`Weekdays at {time}`,{time:r});case`weekly`:return n&&Qp.includes(n)?_(`{day}s at {time}`,{day:tm(n),time:r}):_(`Weekly at {time}`,{time:r});case`monthly`:return _(`Monthly on the {day} at {time}`,{day:rm(Number(n||1)),time:r});default:return``}}function rm(e){if(c()!==`en`)return String(e);let t=[`th`,`st`,`nd`,`rd`],n=e%100;return`${e}${t[(n-20)%10]??t[n]??t[0]}`}function im(e,t){if(!e)return``;let n=new Date(`${e}T00:00:00`),r=n.toLocaleDateString(m(),{month:`short`,day:`numeric`,year:n.getFullYear()===new Date().getFullYear()?void 0:`numeric`});if(t)return _(`Was due {date}`,{date:r});let i=Math.ceil((n.getTime()-Date.now())/864e5);return i<=0?_(`Due today`):i===1?_(`Due tomorrow`):i<=14?_(`Due in {n} days`,{n:i}):_(`By {date}`,{date:r})}function am({open:e,onClose:t}){let{state:n,setTab:r,draft:a,toast:o}=E(),[c,l]=(0,L.useState)(0),[u,d]=(0,L.useState)(!1),[f,p]=(0,L.useState)(!1),[m,h]=(0,L.useState)(!1),g=n.profile?.name??`nanoMuse`,_=n.pendingApprovals.length,v=s();(0,L.useEffect)(()=>{e&&(l(+(_>0)),d(!1),p(!1))},[e]);let y=(e,n)=>{t(),n&&history.replaceState(null,``,`${window.location.pathname}${window.location.search}#${n}`),r(e)},b=n.status.state===`working`,x=_>0?_>1?v(`{n} approvals waiting for you`,{n:_}):v(`1 approval waiting for you`):b?n.status.detail||v(`On it`):n.status.state===`waiting`?v(`Waiting for you`):v(`online`),S=async()=>{h(!0);try{(await M.stopThread(n.status.thread||`main`)).ok||o(v(`Nothing to stop`))}catch(e){o(e.message)}finally{h(!1)}},C=[{icon:(0,R.jsx)(it,{size:22}),label:v(`Activity`)},{icon:(0,R.jsx)(Qt,{size:22}),label:v(`Approvals`),badge:_},{icon:(0,R.jsx)(at,{size:22}),label:v(`Daily`)},{icon:(0,R.jsx)(ht,{size:22}),label:v(`Soul & memory`)}];return(0,R.jsxs)(Op,{open:e,onClose:t,children:[(0,R.jsxs)(`div`,{className:`relative flex flex-col items-center px-1 pb-3 text-center`,children:[(0,R.jsx)(`button`,{type:`button`,"aria-label":v(`Share avatar`),title:v(`Share avatar`),onClick:()=>p(!0),className:`absolute right-0 top-0 flex h-9 w-9 items-center justify-center rounded-full bg-surface-2/70 text-fg hover:bg-surface-2`,children:(0,R.jsx)(Xt,{size:16})}),(0,R.jsxs)(`div`,{className:`relative`,children:[(0,R.jsx)(D,{profile:n.profile,status:n.status,size:72}),(0,R.jsx)(`button`,{type:`button`,"aria-label":v(`Edit`),"aria-expanded":u,onClick:()=>d(e=>!e),className:`absolute -bottom-0.5 -right-0.5 flex h-6 w-6 items-center justify-center rounded-full bg-surface text-fg shadow-[0_1px_4px_rgba(0,0,0,0.18)] hover:bg-surface-2 dark:border dark:border-border`,children:(0,R.jsx)(Ht,{size:13})}),u&&(0,R.jsxs)(`div`,{className:`absolute left-1/2 top-full z-20 mt-2 w-56 -translate-x-1/2 overflow-hidden rounded-2xl border border-border/70 bg-surface py-1 text-left text-[14px] shadow-lg`,children:[(0,R.jsx)(`button`,{type:`button`,onClick:()=>{a(v(`Change your avatar to `)),t(),r(`chat`)},className:`block w-full px-4 py-2.5 text-left hover:bg-surface-2`,children:v(`Change avatar`)}),(0,R.jsx)(`button`,{type:`button`,onClick:()=>y(`you`,`who`),className:`block w-full px-4 py-2.5 text-left hover:bg-surface-2`,children:v(`Edit name`)}),(0,R.jsx)(`button`,{type:`button`,onClick:()=>y(`avatar`),className:`block w-full px-4 py-2.5 text-left text-muted hover:bg-surface-2`,children:v(`Avatar studio…`)})]})]}),(0,R.jsx)(`div`,{className:`mt-2.5 text-[21px] font-semibold leading-[26px]`,children:g}),(0,R.jsxs)(`div`,{className:i(`mt-0.5 flex items-center gap-1.5 text-[14px]`,b||_>0?`text-fg`:`text-muted`),children:[b&&(0,R.jsx)(A,{size:13,className:`animate-spin text-accent`}),(0,R.jsx)(`span`,{className:`line-clamp-2`,children:x})]}),(b||n.status.state===`waiting`)&&(0,R.jsxs)(`button`,{type:`button`,onClick:()=>void S(),disabled:m,className:`mt-2.5 inline-flex items-center gap-1.5 rounded-full bg-fg px-4 py-1.5 text-[13.5px] font-semibold text-bg transition active:scale-95 disabled:opacity-60`,children:[(0,R.jsx)(sn,{size:12,fill:`currentColor`}),` `,v(`Stop`)]})]}),(0,R.jsx)(`div`,{role:`tablist`,className:`mb-5 flex rounded-2xl bg-surface-2/60 p-1`,children:C.map((e,t)=>(0,R.jsxs)(`button`,{type:`button`,role:`tab`,"aria-selected":c===t,"aria-label":e.label,title:e.label,onClick:()=>l(t),className:i(`relative flex h-11 flex-1 items-center justify-center rounded-[13px] text-fg transition`,c===t&&`bg-surface shadow-sm`),children:[e.icon,e.badge?(0,R.jsx)(`span`,{className:`absolute right-1.5 top-1 flex h-[17px] min-w-[17px] items-center justify-center rounded-full bg-rose-500 px-1 text-[10px] font-bold text-white`,children:e.badge}):null]},e.label))}),c===0&&(0,R.jsx)(ym,{open:e}),c===1&&(0,R.jsxs)(R.Fragment,{children:[_>0&&(0,R.jsx)(cm,{onDone:()=>void 0}),(0,R.jsx)(bm,{open:e})]}),c===2&&(0,R.jsx)(lm,{onSettings:()=>y(`you`,`proactivity`)}),c===3&&(0,R.jsx)(om,{name:g,onEdit:()=>y(`you`,`who`),onMemory:()=>y(`memory`)}),(0,R.jsx)(qp,{open:f,onClose:()=>p(!1)})]})}function om({name:e,onEdit:t,onMemory:n}){let{state:r}=E(),i=s(),a=r.profile?.tagline?.trim()??``;return(0,R.jsxs)(`div`,{className:`pb-2`,children:[(0,R.jsx)(`div`,{className:`px-1 text-[15px]`,children:e}),(0,R.jsxs)(`button`,{type:`button`,onClick:t,className:`mt-2 flex h-[50px] w-full items-center justify-center gap-2 rounded-2xl bg-surface-2/70 text-[15px] font-medium hover:bg-surface-2`,children:[(0,R.jsx)(Ht,{size:18}),` `,i(`Edit`)]}),(0,R.jsxs)(`div`,{className:`mt-4 grid grid-cols-2 gap-3`,children:[(0,R.jsx)(sm,{title:`SOUL`,caption:i(`Handle with care`),foot:a,colors:`from-[#7d6bc7] to-[#574494]`,onClick:t}),(0,R.jsx)(sm,{title:i(`Memory`),caption:i(`Handle with care`),foot:r.settings?.memory_enabled===!1?i(`Off`):``,colors:`from-[#b0413e] to-[#7a1f1f]`,onClick:n})]})]})}function sm({title:e,caption:t,foot:n,colors:r,onClick:a}){return(0,R.jsxs)(`button`,{type:`button`,onClick:a,className:i(`flex h-[130px] flex-col items-start rounded-[18px] bg-gradient-to-b p-3.5 text-left text-white transition active:scale-[0.98]`,r),children:[(0,R.jsx)(`span`,{className:`text-[17px] font-semibold`,children:e}),(0,R.jsx)(`span`,{className:`mt-0.5 text-[11px] text-white/85`,children:t}),(0,R.jsx)(`span`,{className:`mt-auto text-[12px] text-white/90`,children:n})]})}function cm({onDone:e}){let{state:t,decide:n,openThread:r,toast:i}=E(),a=t.profile?.name??`nanoMuse`,o=s(),c=[...t.pendingApprovals].sort((e,t)=>e.ts.localeCompare(t.ts)),l=e=>{let n=t.threads.find(t=>t.id===e);return n?n.id===`main`?o(n.title):n.title:e};return(0,L.useEffect)(()=>{if(c.length===0){let t=window.setTimeout(e,600);return()=>window.clearTimeout(t)}},[c.length,e]),c.length===0?(0,R.jsxs)(`div`,{className:`py-10 text-center text-muted text-[14px]`,children:[(0,R.jsx)(ke,{size:26,className:`mx-auto mb-2 text-emerald-500`}),o(`Nothing is waiting for you.`)]}):(0,R.jsxs)(`div`,{className:`space-y-4 pb-2`,children:[(0,R.jsx)(`p`,{className:`text-[12.5px] text-muted`,children:o(`Actions {name} wants to take but cannot without you. Each one shows what will run and why; a permission you grant is bound to that exact tool and target.`,{name:a})}),c.map(e=>(0,R.jsxs)(`div`,{children:[(0,R.jsxs)(`button`,{type:`button`,onClick:()=>r(e.thread),className:`mb-1 px-1 text-[12px] font-semibold uppercase tracking-wide text-muted hover:text-accent`,children:[l(e.thread),` · `,u(e.ts)]}),(0,R.jsx)(`div`,{className:`rounded-[22px] border border-border/70`,children:(0,R.jsx)(hp,{event:e,onDecide:(t,r)=>n(e.id,t,r).catch(e=>i(e.message))})})]},e.id))]})}function lm({onSettings:t}){let{state:n,refreshSettings:r,toast:a}=E(),[o,c]=(0,L.useState)(null),[l,d]=(0,L.useState)(null),[f,p]=(0,L.useState)(null),m=n.profile?.name??`nanoMuse`,h=s(),g=()=>M.upcoming().then(e=>{c(e),d(null)}).catch(e=>o===null?d(e.message):a(e.message));(0,L.useEffect)(()=>{g()},[n.goalsVersion,n.remindersVersion,n.profile?.proactive,n.profile?.goal_interval_minutes]);let _=async()=>{try{await M.updateSettings({profile:{proactive:!n.profile?.proactive}}),await r()}catch(e){a(e.message)}},v=async e=>{p(e);try{await M.advanceGoal(e),a(h(`{name} is working on it in the main chat`,{name:m}))}catch(e){a(e.message)}finally{p(null)}};return o?(0,R.jsxs)(`div`,{className:`space-y-4 pb-2`,children:[(0,R.jsxs)(`div`,{className:`rounded-2xl border border-border p-3.5`,children:[(0,R.jsxs)(`div`,{className:`flex items-center justify-between gap-3`,children:[(0,R.jsxs)(`div`,{children:[(0,R.jsx)(`div`,{className:`font-medium`,children:h(`Background work`)}),(0,R.jsx)(`div`,{className:`text-[12.5px] text-muted`,children:o.proactive?`${h(o.proactivity[0].toUpperCase()+o.proactivity.slice(1))} · ${h(`every {n} min {name} picks one active goal and works on its next step.`,{n:o.effective_interval_minutes,name:m})}${o.quiet_until?` ${h(`Quiet hours until {time}.`,{time:u(o.quiet_until)})}`:o.next_pass_at?` ${h(`Next around {time}.`,{time:u(o.next_pass_at)})}`:``}`:h(`Off. {name} only works when you ask.`,{name:m})})]}),(0,R.jsx)(`button`,{type:`button`,role:`switch`,"aria-checked":o.proactive,onClick:()=>void _(),className:i(`relative h-7 w-12 shrink-0 rounded-full transition`,o.proactive?`bg-accent`:`bg-border`),children:(0,R.jsx)(`span`,{className:i(`absolute top-0.5 h-6 w-6 rounded-full bg-white shadow transition`,o.proactive?`left-[26px]`:`left-0.5`)})})]}),(0,R.jsx)(`button`,{type:`button`,onClick:t,className:`mt-2 text-[12.5px] text-accent font-medium`,children:h(`Level, interval and quiet hours in Settings`)})]}),(0,R.jsxs)(`div`,{children:[(0,R.jsx)(`div`,{className:`text-[12px] uppercase tracking-wide text-muted font-semibold mb-1.5`,children:h(`In line`)}),o.queue.length===0?(0,R.jsx)(`div`,{className:`text-[13px] text-muted`,children:h(`No active goal has a next step. Add one in Goals and {name} will pick it up.`,{name:m})}):(0,R.jsx)(`ul`,{className:`space-y-1.5`,children:o.queue.map((e,t)=>(0,R.jsxs)(`li`,{className:`flex items-center gap-2.5 rounded-2xl bg-surface-2/60 px-3 py-2`,children:[(0,R.jsx)(`span`,{className:`w-5 text-center text-[12px] font-semibold text-muted`,children:t+1}),(0,R.jsxs)(`div`,{className:`min-w-0 flex-1`,children:[(0,R.jsx)(`div`,{className:`text-[13.5px] font-medium truncate`,children:e.title}),(0,R.jsxs)(`div`,{className:`text-[11.5px] text-muted truncate`,children:[e.next_step??`—`,` · `,h(`{done}/{total} done`,{done:e.progress.done,total:e.progress.total})]})]}),(0,R.jsx)(`button`,{type:`button`,onClick:()=>void v(e.goal_id),disabled:f!==null||o.busy,"aria-label":h(`Work on {title} now`,{title:e.title}),className:`rounded-full bg-accent/12 p-2 text-accent disabled:opacity-50`,children:f===e.goal_id?(0,R.jsx)(A,{size:15,className:`animate-spin`}):(0,R.jsx)(Gt,{size:15})})]},e.goal_id))})]}),o.check_ins.length>0&&(0,R.jsxs)(`div`,{children:[(0,R.jsx)(`div`,{className:`text-[12px] uppercase tracking-wide text-muted font-semibold mb-1.5`,children:h(`Check-ins`)}),(0,R.jsx)(`ul`,{className:`space-y-1.5`,children:o.check_ins.map(t=>(0,R.jsxs)(`li`,{className:`flex items-center gap-2.5 rounded-2xl bg-surface-2/60 px-3 py-2`,children:[(0,R.jsx)(Xe,{size:15,className:`text-muted shrink-0`}),(0,R.jsxs)(`div`,{className:`min-w-0 flex-1`,children:[(0,R.jsx)(`div`,{className:`text-[13.5px] font-medium truncate`,children:t.title}),(0,R.jsxs)(`div`,{className:`text-[11.5px] text-muted truncate`,children:[e(t.at),` · `,u(t.at),` · `,nm(t.cadence).toLowerCase()]})]})]},t.goal_id))}),(0,R.jsx)(`div`,{className:`mt-1.5 text-[12px] text-muted`,children:h(`Goal nudges you asked for; they arrive whatever the proactivity level, but wait out quiet hours.`)})]}),(0,R.jsx)(um,{items:o.reminders,name:m,onChange:()=>void g()}),(0,R.jsx)(mm,{data:o.triggers,name:m,onChange:()=>void g()})]}):l?(0,R.jsx)(Jp,{message:l,onRetry:()=>void g()}):(0,R.jsx)(`div`,{className:`py-10 flex justify-center text-muted`,children:(0,R.jsx)(A,{className:`animate-spin`,size:20})})}function um({items:t,name:n,onChange:r}){let{toast:i}=E(),a=s(),[o,c]=(0,L.useState)(null),[l,d]=(0,L.useState)(!1),f=t.filter(e=>e.status===`active`),p=t.filter(e=>e.status!==`active`),m=async e=>{c(e.id);try{await M.cancelReminder(e.id),r()}catch(e){i(e.message)}finally{c(null)}},h=async e=>{c(e.id);try{await M.fireReminder(e.id),i(e.kind===`task`?a(`{name} is on it`,{name:n}):a(`{name} will say it now`,{name:n})),r()}catch(e){i(e.message)}finally{c(null)}};return(0,R.jsxs)(`div`,{children:[(0,R.jsxs)(`div`,{className:`flex items-center justify-between mb-1.5`,children:[(0,R.jsx)(`div`,{className:`text-[12px] uppercase tracking-wide text-muted font-semibold`,children:a(`Reminders & routines`)}),!l&&(0,R.jsx)(`button`,{type:`button`,onClick:()=>d(!0),className:`text-[12.5px] text-accent font-medium`,children:a(`+ Add`)})]}),l&&(0,R.jsx)(dm,{onDone:()=>{d(!1),r()},onCancel:()=>d(!1)}),f.length===0&&!l?(0,R.jsx)(`div`,{className:`text-[13px] text-muted`,children:a(`Nothing scheduled. Tell {name} “remind me at six to call mum” or “every weekday morning, summarise my unread email”.`,{name:n})}):(0,R.jsx)(`ul`,{className:`space-y-1.5`,children:f.map(t=>(0,R.jsxs)(`li`,{className:`flex items-center gap-2.5 rounded-2xl bg-surface-2/60 px-3 py-2`,children:[t.kind===`task`?(0,R.jsx)(Kt,{size:15,className:`text-muted shrink-0`}):(0,R.jsx)(We,{size:15,className:`text-muted shrink-0`}),(0,R.jsxs)(`div`,{className:`min-w-0 flex-1`,children:[(0,R.jsx)(`div`,{className:`text-[13.5px] font-medium truncate`,children:t.text}),(0,R.jsxs)(`div`,{className:`text-[11.5px] text-muted truncate`,children:[t.next_at?`${e(t.next_at)} · ${u(t.next_at)}`:`—`,t.repeat&&` · ${nm(t.repeat).toLowerCase()}`,t.kind===`task`&&` · ${a(`does the work`)}`]})]}),(0,R.jsx)(`button`,{type:`button`,onClick:()=>void h(t),disabled:o!==null,"aria-label":t.kind===`task`?a(`Do “{text}” now`,{text:t.text}):a(`Remind me now: {text}`,{text:t.text}),className:`rounded-full bg-accent/12 p-2 text-accent disabled:opacity-50`,children:o===t.id?(0,R.jsx)(A,{size:15,className:`animate-spin`}):(0,R.jsx)(Gt,{size:15})}),(0,R.jsx)(`button`,{type:`button`,onClick:()=>void m(t),disabled:o!==null,"aria-label":a(`Cancel: {text}`,{text:t.text}),className:`rounded-full p-2 text-muted hover:text-fg disabled:opacity-50`,children:(0,R.jsx)(Fe,{size:15})})]},t.id))}),p.length>0&&(0,R.jsxs)(`details`,{className:`mt-2`,children:[(0,R.jsx)(`summary`,{className:`text-[12px] text-muted cursor-pointer select-none`,children:a(`{n} finished recently`,{n:p.length})}),(0,R.jsx)(`ul`,{className:`mt-1.5 space-y-1`,children:p.map(t=>(0,R.jsxs)(`li`,{className:`flex items-center gap-2 px-3 text-[12.5px] text-muted`,children:[(0,R.jsx)(`span`,{className:`min-w-0 flex-1 truncate line-through decoration-border`,children:t.text}),(0,R.jsx)(`span`,{className:`shrink-0`,children:t.status===`done`?t.last_fired_at?e(t.last_fired_at):a(`done`):a(`cancelled`)})]},t.id))})]}),(0,R.jsx)(`div`,{className:`mt-1.5 text-[12px] text-muted`,children:a(`A time you named is kept whatever the level or the quiet hours. Reminders just say it; routines do the work and report.`)})]})}function dm({onDone:e,onCancel:t}){let{toast:n}=E(),r=s(),[a,o]=(0,L.useState)(``),[c,l]=(0,L.useState)(`remind`),[u,d]=(0,L.useState)(`once`),[f,p]=(0,L.useState)(()=>_m()),[h,g]=(0,L.useState)(`daily`),[_,v]=(0,L.useState)(`09:00`),[y,b]=(0,L.useState)(`mon`),[x,S]=(0,L.useState)(`1`),[C,w]=(0,L.useState)(!1),T=h===`weekly`?`weekly ${y} ${_}`:h===`monthly`?`monthly ${x} ${_}`:`${h} ${_}`,D=async()=>{if(a.trim()){w(!0);try{await M.createReminder(u===`once`?{text:a.trim(),kind:c,at:f.replace(`T`,` `)}:{text:a.trim(),kind:c,repeat:T}),e()}catch(e){n(e.message)}finally{w(!1)}}},O=`h-9 rounded-xl bg-surface border border-border px-3 text-[13px] outline-none focus:border-accent`;return(0,R.jsxs)(`div`,{className:`mb-2 rounded-2xl border border-border p-3 space-y-2`,children:[(0,R.jsx)(`input`,{autoFocus:!0,value:a,onChange:e=>o(e.target.value),placeholder:r(c===`task`?`What should be done…`:`What to remind you of…`),className:i(O,`w-full h-10 text-[14px]`)}),(0,R.jsxs)(`div`,{className:`flex gap-1.5 text-[12.5px]`,children:[(0,R.jsx)(gm,{options:[[`remind`,r(`Remind me`)],[`task`,r(`Do it for me`)]],value:c,onChange:e=>l(e)}),(0,R.jsx)(gm,{options:[[`once`,r(`Once`)],[`repeat`,r(`Repeat`)]],value:u,onChange:e=>d(e)})]}),u===`once`?(0,R.jsx)(`input`,{type:`datetime-local`,value:f,onChange:e=>p(e.target.value),className:i(O,`w-full`)}):(0,R.jsxs)(`div`,{className:`flex flex-wrap gap-1.5`,children:[(0,R.jsxs)(`select`,{value:h,onChange:e=>g(e.target.value),className:O,children:[(0,R.jsx)(`option`,{value:`daily`,children:r(`Every day`)}),(0,R.jsx)(`option`,{value:`weekdays`,children:r(`Weekdays`)}),(0,R.jsx)(`option`,{value:`weekly`,children:r(`Weekly`)}),(0,R.jsx)(`option`,{value:`monthly`,children:r(`Monthly`)})]}),h===`weekly`&&(0,R.jsx)(`select`,{value:y,onChange:e=>b(e.target.value),className:O,children:[`mon`,`tue`,`wed`,`thu`,`fri`,`sat`,`sun`].map((e,t)=>(0,R.jsx)(`option`,{value:e,children:new Date(2024,0,1+t).toLocaleDateString(m(),{weekday:`long`})},e))}),h===`monthly`&&(0,R.jsx)(`select`,{value:x,onChange:e=>S(e.target.value),className:O,children:Array.from({length:28},(e,t)=>String(t+1)).map(e=>(0,R.jsx)(`option`,{value:e,children:r(`Day {d}`,{d:e})},e))}),(0,R.jsx)(`input`,{type:`time`,value:_,onChange:e=>v(e.target.value),className:O})]}),(0,R.jsxs)(`div`,{className:`flex justify-end gap-2 pt-0.5`,children:[(0,R.jsx)(`button`,{type:`button`,onClick:t,className:`rounded-full px-3 py-1.5 text-[13px] text-muted`,children:r(`Cancel`)}),(0,R.jsx)(`button`,{type:`button`,onClick:()=>void D(),disabled:C||!a.trim(),className:`rounded-full bg-accent px-3.5 py-1.5 text-[13px] font-medium text-accent-fg disabled:opacity-50`,children:r(C?`Saving…`:u===`once`?`Set reminder`:`Set routine`)})]})]})}var fm={mail:Et,event:et,hook:_n};function pm(e,t){if(e.kind===`mail`)return e.match?t(`mail matching “{match}”`,{match:e.match}):t(`any new mail`);if(e.kind===`event`){let n=e.match?t(`events matching “{match}”`,{match:e.match}):t(`any event`);return t(`{n} min before {what}`,{n:e.lead_minutes,what:n})}return e.match?t(`webhook “{match}”`,{match:e.match}):t(`webhook`)}function mm({data:t,name:n,onChange:r}){let{toast:a}=E(),o=s(),[c,l]=(0,L.useState)(null),[u,d]=(0,L.useState)(!1),f=t.items.filter(e=>e.status===`active`),p=f.some(e=>e.kind===`mail`),m=async e=>{l(e.id);try{await M.cancelTrigger(e.id),r()}catch(e){a(e.message)}finally{l(null)}},h=async e=>{l(e.id);try{await M.fireTrigger(e.id),a(o(`{name} is on it`,{name:n})),r()}catch(e){a(e.message)}finally{l(null)}},g=async e=>{if(e.url)try{await navigator.clipboard.writeText(e.url),a(o(`Webhook URL copied`))}catch{a(e.url)}};return(0,R.jsxs)(`div`,{children:[(0,R.jsxs)(`div`,{className:`flex items-center justify-between mb-1.5`,children:[(0,R.jsx)(`div`,{className:`text-[12px] uppercase tracking-wide text-muted font-semibold`,children:o(`When something happens`)}),!u&&(0,R.jsx)(`button`,{type:`button`,onClick:()=>d(!0),className:`text-[12.5px] text-accent font-medium`,children:o(`+ Add`)})]}),u&&(0,R.jsx)(hm,{available:t.available,onDone:()=>{d(!1),r()},onCancel:()=>d(!1)}),f.length===0&&!u?(0,R.jsx)(`div`,{className:`text-[13px] text-muted`,children:o(`Nothing yet. Tell {name} “when the landlord writes back, summarise it and draft a reply” or “half an hour before any review, brief me”.`,{name:n})}):(0,R.jsx)(`ul`,{className:`space-y-1.5`,children:f.map(t=>{let n=fm[t.kind];return(0,R.jsxs)(`li`,{className:`flex items-start gap-2.5 rounded-2xl bg-surface-2/60 px-3 py-2`,children:[(0,R.jsx)(n,{size:15,className:`text-muted shrink-0 mt-[3px]`}),(0,R.jsxs)(`div`,{className:`min-w-0 flex-1`,children:[(0,R.jsx)(`div`,{className:`text-[13.5px] font-medium`,children:pm(t,o)}),(0,R.jsx)(`div`,{className:`text-[12px] leading-snug text-fg/80 line-clamp-2`,children:t.text}),(0,R.jsxs)(`div`,{className:`text-[11.5px] text-muted flex flex-wrap items-center gap-x-1.5`,children:[t.fired>0?(0,R.jsxs)(`span`,{children:[o(`fired {n}×`,{n:t.fired}),t.last_fired_at&&` · ${e(t.last_fired_at)}`]}):(0,R.jsx)(`span`,{children:o(`not fired yet`)}),t.kind===`hook`&&t.url&&(0,R.jsxs)(`button`,{type:`button`,onClick:()=>void g(t),className:`inline-flex items-center gap-1 text-accent font-medium`,children:[(0,R.jsx)(ut,{size:11}),` `,o(`Copy URL`)]})]})]}),(0,R.jsx)(`button`,{type:`button`,onClick:()=>void h(t),disabled:c!==null,"aria-label":o(`Run now: {text}`,{text:t.text}),className:`rounded-full bg-accent/12 p-2 text-accent disabled:opacity-50`,children:c===t.id?(0,R.jsx)(A,{size:15,className:`animate-spin`}):(0,R.jsx)(Gt,{size:15})}),(0,R.jsx)(`button`,{type:`button`,onClick:()=>void m(t),disabled:c!==null,"aria-label":o(`Cancel: {text}`,{text:t.text}),className:`rounded-full p-2 text-muted hover:text-fg disabled:opacity-50`,children:(0,R.jsx)(Fe,{size:15})})]},t.id)})}),p&&(0,R.jsx)(`div`,{className:i(`mt-1.5 text-[12px]`,t.mail_error?`text-rose-500`:`text-muted`),children:t.mail_error?o(`The inbox could not be read: {error}`,{error:t.mail_error}):t.mail_checked_at?o(`Inbox checked {when}; {name} looks every {n} min.`,{when:e(t.mail_checked_at),name:n,n:t.mail_poll_minutes}):o(`{name} will look at the inbox shortly, then every {n} min.`,{name:n,n:t.mail_poll_minutes})}),(0,R.jsx)(`div`,{className:`mt-1.5 text-[12px] text-muted`,children:o(`Each time it happens {name} does the work in the chat it was set from and reports in the Feed. A mail or a request is treated as data, never as instructions.`,{name:n})})]})}function hm({available:e,onDone:t,onCancel:n}){let{toast:r}=E(),a=s(),o=[`mail`,`event`,`hook`].find(t=>e[t])??`hook`,[c,l]=(0,L.useState)(o),[u,d]=(0,L.useState)(``),[f,p]=(0,L.useState)(`30`),[m,h]=(0,L.useState)(``),[g,_]=(0,L.useState)(!1),[v,y]=(0,L.useState)(null),b=async()=>{if(m.trim()){_(!0);try{let e=await M.createTrigger({kind:c,text:m.trim(),match:u.trim(),lead_minutes:Number(f)||30});e.kind===`hook`&&e.url?y(e):t()}catch(e){r(e.message)}finally{_(!1)}}},x=`h-9 rounded-xl bg-surface border border-border px-3 text-[13px] outline-none focus:border-accent`;if(v)return(0,R.jsxs)(`div`,{className:`mb-2 rounded-2xl border border-border p-3 space-y-2`,children:[(0,R.jsx)(`div`,{className:`text-[13.5px] font-medium`,children:a(`Webhook ready`)}),(0,R.jsx)(`div`,{className:`text-[12.5px] text-muted`,children:a(`POST anything to this URL and the work starts. The key is in the URL; share it only with the program that will call it.`)}),(0,R.jsx)(`code`,{className:`block break-all rounded-xl bg-surface-2 px-3 py-2 text-[12px]`,children:v.url}),(0,R.jsxs)(`div`,{className:`flex justify-end gap-2 pt-0.5`,children:[(0,R.jsx)(`button`,{type:`button`,onClick:()=>void navigator.clipboard.writeText(v.url??``).then(()=>r(a(`Webhook URL copied`)),()=>r(v.url??``)),className:`rounded-full px-3 py-1.5 text-[13px] text-accent font-medium`,children:a(`Copy`)}),(0,R.jsx)(`button`,{type:`button`,onClick:t,className:`rounded-full bg-accent px-3.5 py-1.5 text-[13px] font-medium text-accent-fg`,children:a(`Done`)})]})]});let S=[[`mail`,a(`New mail`)],[`event`,a(`Before an event`)],[`hook`,a(`Webhook`)]];return(0,R.jsxs)(`div`,{className:`mb-2 rounded-2xl border border-border p-3 space-y-2`,children:[(0,R.jsx)(gm,{options:S,value:c,onChange:e=>l(e)}),!e[c]&&(0,R.jsx)(`div`,{className:`text-[12.5px] text-rose-500`,children:a(c===`mail`?`Connect a mailbox under Connections first.`:`Add a calendar under Connections first.`)}),(0,R.jsxs)(`div`,{className:`flex gap-1.5`,children:[(0,R.jsx)(`input`,{value:u,onChange:e=>d(e.target.value),placeholder:a(c===`mail`?`Words in the sender or subject (empty: any mail)`:c===`event`?`Words in the title or place (empty: any event)`:`A name for this hook`),className:i(x,`min-w-0 flex-1`)}),c===`event`&&(0,R.jsxs)(`label`,{className:`flex items-center gap-1 text-[12.5px] text-muted`,children:[(0,R.jsx)(`input`,{type:`number`,min:0,max:1440,value:f,onChange:e=>p(e.target.value),className:i(x,`w-[64px] px-2`),"aria-label":a(`Minutes before`)}),a(`min before`)]})]}),(0,R.jsx)(`input`,{value:m,onChange:e=>h(e.target.value),placeholder:a(`What should be done each time…`),className:i(x,`w-full h-10 text-[14px]`)}),(0,R.jsx)(`div`,{className:`text-[12px] text-muted`,children:a(`When {condition}`,{condition:pm({kind:c,match:u.trim(),lead_minutes:Number(f)||30},a)})}),(0,R.jsxs)(`div`,{className:`flex justify-end gap-2 pt-0.5`,children:[(0,R.jsx)(`button`,{type:`button`,onClick:n,className:`rounded-full px-3 py-1.5 text-[13px] text-muted`,children:a(`Cancel`)}),(0,R.jsx)(`button`,{type:`button`,onClick:()=>void b(),disabled:g||!m.trim()||!e[c],className:`rounded-full bg-accent px-3.5 py-1.5 text-[13px] font-medium text-accent-fg disabled:opacity-50`,children:a(g?`Saving…`:`Set trigger`)})]})]})}function gm({options:e,value:t,onChange:n}){return(0,R.jsx)(`div`,{className:`flex rounded-full bg-surface-2 p-0.5`,children:e.map(([e,r])=>(0,R.jsx)(`button`,{type:`button`,onClick:()=>n(e),className:i(`rounded-full px-2.5 py-1 transition`,t===e?`bg-surface shadow-sm font-medium`:`text-muted`),children:r},e))})}function _m(){let e=new Date(Date.now()+36e5);e.setMinutes(0,0,0);let t=e=>String(e).padStart(2,`0`);return`${e.getFullYear()}-${t(e.getMonth()+1)}-${t(e.getDate())}T${t(e.getHours())}:${t(e.getMinutes())}`}function vm(e){let[t,n]=(0,L.useState)(null),[r,i]=(0,L.useState)(null),a=async()=>{try{n(await M.activity(150)),i(null)}catch(e){i(e.message||`Could not load.`)}};return(0,L.useEffect)(()=>{if(!e)return;a();let t=window.setInterval(()=>void a(),4e3);return()=>window.clearInterval(t)},[e]),[t,a,r]}function ym({open:e}){let[t,n,r]=vm(e),{state:i}=E(),a=s(),o=i.profile?.name??`nanoMuse`,c=(t?.audit??[]).filter(e=>e.event===`tool_call`).reverse(),l=c.filter(e=>e.channel===`gui`).length;return(0,R.jsxs)(`div`,{className:`pb-2`,children:[(0,R.jsx)(`p`,{className:`text-[12.5px] text-muted mb-2`,children:a(`Every tool call goes through the Sentinel and is written to the audit log, including the ones it refused.`)}),l>0&&(0,R.jsx)(`p`,{className:`text-[12.5px] text-muted mb-2`,children:a(`On the phone's screen: {gui} of {total} steps ({pct}%). The screen is the last resort; a skill, a fetch or the browser comes first.`,{gui:String(l),total:String(c.length),pct:String(Math.round(l/c.length*100))})}),!t&&r&&(0,R.jsx)(Jp,{message:r,onRetry:()=>void n()}),!t&&!r&&(0,R.jsx)(`div`,{className:`py-10 flex justify-center text-muted`,children:(0,R.jsx)(A,{className:`animate-spin`,size:20})}),t&&c.length===0&&(0,R.jsx)(`div`,{className:`py-8 text-center text-muted text-[14px]`,children:a(`Nothing yet today. What you ask for and what {name} does about it shows up here.`,{name:o})}),(0,R.jsx)(`ul`,{className:`space-y-1.5`,children:c.map((e,t)=>(0,R.jsx)(Tm,{entry:e},`${e.ts}-${t}`))})]})}function bm({open:e}){let{state:t,toast:n}=E(),r=s(),[i,a]=vm(e),o=async()=>{if(window.confirm(r(`Forget every permission you granted? {name} will ask again next time.`,{name:t.profile?.name??`nanoMuse`})))try{await M.resetApprovals(),await a(),n(r(`Permissions reset`))}catch(e){n(e.message)}},c=async e=>{try{await M.revokeGrant(e.key),await a(),n(r(`Revoked: {subject}`,{subject:pp(e.tool,e.target)}))}catch(e){n(e.message)}},l=t.settings?.sentinel.mode;return(0,R.jsxs)(`div`,{className:`space-y-4 pb-2`,children:[(0,R.jsxs)(`div`,{className:`rounded-2xl border border-border p-3.5`,children:[(0,R.jsxs)(`div`,{className:`flex items-center gap-2 font-medium`,children:[(0,R.jsx)(Qt,{size:18,className:`text-accent`}),` `,r(`Sentinel mode:`),` `,(0,R.jsx)(`span`,{className:`capitalize`,children:l===`ask`?r(`balanced`):l===`strict`?r(`cautious`):l===`auto`?r(`hands-off`):l})]}),(0,R.jsxs)(`p`,{className:`mt-1 text-[12.5px] text-muted`,children:[l===`ask`&&r(`Safe and moderate actions run freely; anything sensitive (email, shell, purchases) waits for you.`),l===`strict`&&r(`Moderate and sensitive actions both wait for your approval.`),l===`auto`&&r(`Everything is approved automatically except explicit deny rules. Use with care.`)]}),i?.tainted&&(0,R.jsxs)(`p`,{className:`mt-2 text-[12.5px] text-amber-600 dark:text-amber-300 flex items-center gap-1.5`,children:[(0,R.jsx)($t,{size:14}),` `,r(`Private data was read this session: network calls to new destinations need approval.`)]})]}),(0,R.jsx)(Cm,{grants:i?.grants??[],onRevoke:c}),(0,R.jsx)(wm,{title:r(`Always ask (from config)`),tools:t.settings?.sentinel.always_ask_tools??[],muted:!0}),(i?.grants.length??0)>0&&(0,R.jsx)(`button`,{type:`button`,onClick:()=>void o(),className:`w-full rounded-2xl border border-border py-2.5 text-[14px] font-medium`,children:r(`Reset all granted permissions`)})]})}function xm(e,t){switch(e.scope){case`conversation`:return t(`for this conversation`);case`session`:return t(`until restart`);case`24h`:return e.expires_at?t(`until {time}`,{time:u(e.expires_at)}):t(`for 24 hours`);case`always`:return t(`always`);default:return e.scope}}var Sm=[`sensitive`,`moderate`,`low`,`safe`];function Cm({grants:e,onRevoke:t}){let n=s(),{state:r}=E(),i=e=>r.settings?.tools.find(t=>t.name===e)?.risk??`moderate`,a=Sm.map(t=>({risk:t,rows:e.filter(e=>i(e.tool)===t)})).filter(e=>e.rows.length>0);return(0,R.jsx)(`div`,{className:`space-y-3`,children:e.length===0?(0,R.jsxs)(`div`,{children:[(0,R.jsx)(`div`,{className:`text-[12px] uppercase tracking-wide text-muted font-semibold mb-1.5`,children:n(`Permissions you granted`)}),(0,R.jsx)(`div`,{className:`text-[13px] text-muted`,children:n(`No standing approvals. When you answer “always allow” to a risky step, it is listed here and can be revoked; approvals you give once are not kept.`)})]}):a.map((e,r)=>(0,R.jsxs)(`div`,{children:[(0,R.jsxs)(`div`,{className:`text-[12px] uppercase tracking-wide text-muted font-semibold mb-1.5`,children:[r===0?`${n(`Permissions you granted`)} · `:``,n(e.risk)]}),(0,R.jsx)(`ul`,{className:`space-y-1.5`,children:e.rows.map(e=>(0,R.jsxs)(`li`,{className:`flex items-center gap-2.5 rounded-2xl bg-surface-2/60 px-3 py-2`,children:[(0,R.jsx)(`span`,{className:`text-accent`,children:sp(e.tool,15)}),(0,R.jsxs)(`div`,{className:`min-w-0 flex-1`,children:[(0,R.jsx)(`div`,{className:`text-[13.5px] font-medium truncate`,children:pp(e.tool,e.target)}),(0,R.jsxs)(`div`,{className:`text-[11.5px] text-muted`,children:[e.tool,` · `,xm(e,n),` · `,n(`granted {time}`,{time:u(e.granted_at)})]})]}),(0,R.jsx)(`button`,{type:`button`,"aria-label":n(`Revoke {what}`,{what:mp(e.scope,e.tool,e.target)}),onClick:()=>t(e),className:`rounded-full p-1.5 text-muted hover:bg-surface active:scale-95`,children:(0,R.jsx)(Fe,{size:15})})]},e.key))})]},e.risk))})}function wm({title:e,tools:t,muted:n}){let r=s();return(0,R.jsxs)(`div`,{children:[(0,R.jsx)(`div`,{className:`text-[12px] uppercase tracking-wide text-muted font-semibold mb-1.5`,children:e}),t.length===0?(0,R.jsx)(`div`,{className:`text-[13px] text-muted`,children:r(`None`)}):(0,R.jsx)(`div`,{className:`flex flex-wrap gap-1.5`,children:t.map(e=>(0,R.jsxs)(`span`,{className:i(`rounded-full px-2.5 py-1 text-[12.5px] flex items-center gap-1`,n?`bg-surface-2 text-muted`:`bg-accent/12 text-accent`),children:[sp(e,12),` `,e]},e))})]})}function Tm({entry:e}){let t=s(),n=e.decision===`deny`,r=e.ok===!1&&!n;return(0,R.jsxs)(`li`,{className:`flex items-start gap-2.5 rounded-2xl bg-surface-2/60 px-3 py-2`,children:[(0,R.jsx)(`div`,{className:i(`mt-0.5`,n?`text-rose-500`:r?`text-amber-500`:`text-muted`),children:n||r?(0,R.jsx)(Ye,{size:15}):(0,R.jsx)(ke,{size:15})}),(0,R.jsxs)(`div`,{className:`min-w-0 flex-1`,children:[(0,R.jsxs)(`div`,{className:`flex items-center gap-2 text-[13.5px]`,children:[(0,R.jsx)(`span`,{className:`text-muted`,children:sp(e.tool??``,13)}),(0,R.jsx)(`span`,{className:`font-medium truncate`,children:e.summary||e.tool})]}),(0,R.jsxs)(`div`,{className:`mt-0.5 flex flex-wrap items-center gap-x-2 gap-y-0.5 text-[11.5px] text-muted`,children:[(0,R.jsx)(`span`,{children:u(e.ts)}),e.risk&&(0,R.jsx)(up,{risk:e.risk}),e.approved===!0&&(0,R.jsxs)(`span`,{className:`text-emerald-600 dark:text-emerald-300`,children:[t(`approved by you`),e.approval_scope&&e.approval_scope!==`once`?` (${e.approval_scope})`:``]}),e.approved==null&&e.approval_scope&&e.approval_scope!==`once`&&(0,R.jsx)(`span`,{className:`text-emerald-600 dark:text-emerald-300`,children:t(`covered by your {scope} permission`,{scope:e.approval_scope})}),n&&(0,R.jsx)(`span`,{className:`text-rose-500`,children:t(`blocked`)}),r&&(0,R.jsx)(`span`,{className:`text-amber-600`,children:t(`failed`)}),typeof e.duration_ms==`number`&&(0,R.jsxs)(`span`,{children:[(e.duration_ms/1e3).toFixed(1),`s`]})]}),n&&e.reasons&&e.reasons.length>0&&(0,R.jsx)(`div`,{className:`mt-0.5 text-[12px] text-muted`,children:e.reasons.map(v).join(` · `)})]})]})}function Em({title:e,actions:t=[],trailing:n,children:r}){let{state:i,setDrawer:a}=E(),o=s(),[c,l]=(0,L.useState)(!1),u=i.profile?.name||`nanoMuse`,d=i.pendingApprovals.length,f=d>0?d>1?o(`{n} approvals waiting for you`,{n:d}):o(`1 approval waiting for you`):i.status.state===`working`?i.status.detail||o(`On it`):i.status.state===`waiting`?o(`Waiting for you`):null;return(0,R.jsxs)(R.Fragment,{children:[(0,R.jsx)(ne,{profile:i.profile,status:i.status,name:u,statusLine:f,statusTone:f?`accent`:`muted`,spinning:i.status.state===`working`&&d===0,badge:d,onAvatar:()=>l(!0),leading:(0,R.jsx)(te,{onClick:()=>a(!0),label:o(`Chats`),className:`wide:invisible`,children:(0,R.jsx)(Ot,{size:22})}),trailing:n??(0,R.jsx)(Dm,{actions:t})}),(e||r)&&(0,R.jsxs)(`div`,{className:`flex shrink-0 items-center gap-3 pr-5`,children:[(0,R.jsx)(k,{className:`flex-1`,children:e}),r]}),(0,R.jsx)(am,{open:c,onClose:()=>l(!1)})]})}function Dm({actions:e=[]}){let{setTab:t}=E(),n=s(),[r,i]=(0,L.useState)(!1),a=(0,L.useRef)(null);(0,L.useEffect)(()=>{if(!r)return;let e=e=>{a.current?.contains(e.target)||i(!1)},t=e=>{e.key===`Escape`&&i(!1)};return window.addEventListener(`pointerdown`,e),window.addEventListener(`keydown`,t),()=>{window.removeEventListener(`pointerdown`,e),window.removeEventListener(`keydown`,t)}},[r]);let o=e=>{i(!1),t(e)},c=[...e.map(e=>({label:e.label,onClick:()=>{i(!1),e.onClick()}})),{label:n(`Memory`),onClick:()=>o(`memory`)},{label:n(`Settings`),onClick:()=>o(`you`)}];return(0,R.jsxs)(`div`,{ref:a,className:`relative`,children:[(0,R.jsx)(te,{onClick:()=>i(e=>!e),label:n(`More`),expanded:r,children:(0,R.jsx)(pt,{size:22})}),r&&(0,R.jsx)(`ul`,{role:`menu`,className:`absolute right-0 top-12 z-30 min-w-[180px] overflow-hidden rounded-2xl border border-border bg-surface py-1 shadow-xl`,children:c.map(e=>(0,R.jsx)(`li`,{children:(0,R.jsx)(`button`,{type:`button`,role:`menuitem`,onClick:e.onClick,className:`w-full px-4 py-2.5 text-left text-[14.5px] hover:bg-surface-2`,children:e.label})},e.label))})]})}var Om=`nanomuse-naming`;function km(e){return e.replace(/[.*+?^${}()|[\]\\]/g,`\\$&`)}function Am(e,t,n=!1){let r="```"+t,i=e;if(i.includes(r)){let e=RegExp("```"+km(t)+"[ \\t]*\\r?\\n[\\s\\S]*?```",`g`);i=i.replace(e,``);let n=i.lastIndexOf(r);n>=0&&(i=i.slice(0,n))}if(n){let e=i.lastIndexOf("```");e>=0&&r.startsWith(i.slice(e))&&(i=i.slice(0,e))}return i===e?e:i.replace(/\s+$/,``)}function jm(e,t=!1){return Am(e,Om,t)}function Mm(e){return e.filter(e=>!e.this&&e.kind!==`web`&&e.name.trim()!==``)}function Nm(e){let t=/^@([^\s,:;,:;]*)$/.exec(e);return t?t[1]:null}function Pm(e,t,n=6){let r=Nm(e);if(r===null)return[];let i=r.toLowerCase();return Mm(t).filter(e=>e.name.toLowerCase().startsWith(i)).sort((e,t)=>Number(t.online)-Number(e.online)||e.name.localeCompare(t.name)).slice(0,n)}function Fm(e,t){let n=e.trimStart();if(!n.startsWith(`@`))return null;let r=n.slice(1),i=r.toLowerCase(),a=Mm(t),o=a.filter(e=>{let t=e.name.trim().toLowerCase();if(!i.startsWith(t))return!1;let n=r.charAt(t.length);return n===``||/[\s,:;,:;]/.test(n)}).sort((e,t)=>t.name.length-e.name.length);if(o[0])return o[0];let s=/^[^\s,:;,:;]+/.exec(r)?.[0]?.toLowerCase()??``;if(!s)return null;let c=a.filter(e=>e.name.trim().toLowerCase().startsWith(s));if(c.length===1)return c[0];let l=c.filter(e=>e.online);return l.length===1?l[0]:null}var Im=`nm.show_steps`;function Lm(){try{return localStorage.getItem(Im)!==`0`}catch{return!0}}var Rm=Lm(),zm=new Set;function Bm(){return Rm}function Vm(e){Rm=e;try{localStorage.setItem(Im,e?`1`:`0`)}catch{}zm.forEach(e=>e())}function Hm(e){return zm.add(e),()=>zm.delete(e)}function Um(){return(0,L.useSyncExternalStore)(Hm,Bm,Bm)}function Wm(){let{state:e,send:t,sendViaCloud:n,decide:r,loadEvents:i,openFile:a,toast:o,setDrawer:c,setTab:l}=E(),u=s(),{profile:d,status:f,activeThread:p,threads:m}=e,h=e.events[p],g=(0,L.useMemo)(()=>h??[],[h]),_=h!==void 0,v=e.streams[p],b=m.find(e=>e.id===p),[x,S]=(0,L.useState)(!1),[C,w]=(0,L.useState)(null),T=d?.name??`nanoMuse`,D=b?.device?e.hub?.devices.find(e=>e.id===b.device)?.online??null:null,O=nh(e.working[p]),k=(0,L.useRef)(null),ee=(0,L.useRef)(null),A=(0,L.useRef)(!0),[j,re]=(0,L.useState)(!1),N=e.firstrun,P=!!N&&N.phase!==`none`&&N.session_id===p,ie=P&&N.running,ae=y()===`zh-CN`?`zh`:`en`,[oe,se]=(0,L.useState)(null);(0,L.useEffect)(()=>{if(!P||oe?.lang===ae)return;let e=!0;return M.firstrun(ae).then(t=>e&&t.intro&&se({lang:ae,lines:t.intro})).catch(()=>void 0),()=>{e=!1}},[P,ae,oe?.lang]);let ce=e=>{M.firstrunPick(e).then(()=>t(p,e)).catch(e=>o(e.message||u(`Could not send`)))},le=()=>window.dispatchEvent(new Event(`nanomuse:quick-chat`)),[ue,de]=(0,L.useState)(null),fe=e.settings?.onboarded===!0,pe=(0,L.useRef)(!1),me=(0,L.useRef)(!1);(0,L.useEffect)(()=>{if(b?.busy){pe.current||(me.current=ie),pe.current=!0;return}pe.current&&(pe.current=!1,fe&&!me.current&&!ie&&ch(g)&&de(Se()))},[b?.busy,g,fe,ie]);let[he,ge]=(0,L.useState)(null);(0,L.useEffect)(()=>{let{days:e,fresh:t}=ye();t&&ge(e)},[]);let _e=(0,L.useCallback)(()=>{let e=k.current;e&&(e.scrollTop=e.scrollHeight,re(!1))},[]),ve=(0,L.useCallback)(()=>{let e=k.current;if(!e)return;let t=e.scrollHeight-e.scrollTop-e.clientHeight;A.current=t<120,re(t>400)},[]),be=(0,L.useRef)(null);(0,L.useLayoutEffect)(()=>{be.current!==p&&(be.current=p,A.current=!0),A.current&&_e()},[g,v?.text,p,_e]),(0,L.useEffect)(()=>{let e=k.current,t=ee.current;if(!e||!t||typeof ResizeObserver>`u`)return;let n=new ResizeObserver(()=>{A.current?_e():ve()});return n.observe(e),n.observe(t),()=>n.disconnect()},[_e,ve]);let xe=()=>{let e=k.current;e&&e.scrollTo({top:e.scrollHeight,behavior:`smooth`})},Ce=e.pendingApprovals.length,Te=e.pendingApprovals.filter(e=>e.thread===p).length,Ee=(0,L.useMemo)(()=>{let e=!f.thread||f.thread===p;if(Te>0&&!(e&&f.state===`working`))return Te>1?u(`{n} approvals waiting for you`,{n:Te}):u(`1 approval waiting for you`);if(!e)return b?.busy?u(`On it`):void 0;if(f.state===`idle`&&!b?.busy)return;if(f.detail)return f.detail;if(f.state===`waiting`)return u(`Waiting for you`);let t=sh(g);return t?u(`On it: {request}`,{request:t}):u(`On it`)},[f,b,p,Te,g,u]),De=g.filter(e=>e.type===`approval`&&e.status===`pending`).length,Oe=Um(),ke=(0,L.useMemo)(()=>Oe?g:g.filter(e=>e.type!==`tool`),[g,Oe]),Ae={signedIn:!!e.hub?.account.signed_in,chatOnCloud:!!e.settings?.llm.cloud,deviceChat:!!b?.device},je=e=>{let t=ep(ke,e,Ae);return t?()=>n(p,t.text,t.files):void 0},Ne=(0,L.useMemo)(()=>Array.from(new Set(g.flatMap(e=>e.type===`artifact`?[e.path]:[]))),[g]);return(0,R.jsxs)(`div`,{className:`flex h-full flex-col`,children:[(0,R.jsx)(ne,{profile:d,status:f,name:T,statusLine:Ee,statusTone:f.state===`idle`&&!b?.busy?`muted`:`accent`,spinning:(f.state===`working`&&f.thread===p||!!b?.busy)&&Te===0,badge:Ce,onAvatar:()=>S(!0),leading:(0,R.jsx)(te,{onClick:()=>c(!0),label:u(`Chats`),dot:m.length>1&&p!==`main`,className:`wide:invisible`,children:(0,R.jsx)(Ot,{size:22})}),trailing:(0,R.jsx)(Dm,{actions:[{label:u(`Coding agents`),onClick:()=>l(`coding`)}]}),under:b&&b.id!==`main`?b.device?(0,R.jsxs)(`span`,{className:`flex max-w-full items-center gap-1 rounded-full bg-accent/12 px-2.5 py-0.5 text-[11.5px] font-medium text-accent`,children:[D===!1?(0,R.jsx)(`span`,{className:`h-1.5 w-1.5 rounded-full bg-border`}):(0,R.jsx)(`span`,{className:`h-1.5 w-1.5 rounded-full bg-emerald-500`}),(0,R.jsx)(`span`,{className:`truncate`,children:u(`on {device}`,{device:b.device_name||b.device})})]}):b.remote_from?(0,R.jsxs)(`span`,{className:`flex max-w-full items-center gap-1 rounded-full bg-surface-2 px-2.5 py-0.5 text-[11.5px] font-medium text-fg/80`,children:[(0,R.jsx)(It,{size:11}),` `,(0,R.jsx)(`span`,{className:`truncate`,children:u(`from {device}`,{device:b.remote_from.name})})]}):(0,R.jsx)(`span`,{className:`truncate rounded-full bg-surface-2 px-2.5 py-0.5 text-[11.5px] font-medium text-fg/80`,children:b.title}):void 0}),(0,R.jsxs)(`div`,{ref:k,onScroll:ve,className:`relative flex-1 overflow-y-auto px-3 py-3`,children:[(0,R.jsxs)(`div`,{ref:ee,className:`space-y-2.5`,children:[e.hasMore[p]&&g.length>0&&(0,R.jsx)(`div`,{className:`flex justify-center`,children:(0,R.jsx)(`button`,{type:`button`,className:`text-[12.5px] text-accent px-3 py-1 rounded-full bg-surface-2`,onClick:()=>void i(p,g[0]?.id),children:u(`Load earlier messages`)})}),P&&_&&!e.hasMore[p]&&oe&&(0,R.jsx)(Fp,{lines:oe.lines}),_&&g.length===0&&!v&&!P&&(0,R.jsx)(ih,{name:T,device:b?.device?b.device_name||b.device:void 0,onSend:e=>t(p,e).catch(e=>o(e.message||u(`Could not send`)))}),ke.map((e,t)=>(0,R.jsx)(Gm,{event:e,prev:ke[t-1],name:T,onDecide:(t,n)=>r(e.id,t,n).catch(e=>o(e.message||u(`Could not send decision`))),onOpenFile:a,onOpenBrowser:w,files:Ne,onCloudRetry:je(t)},e.id)),v&&v.text&&(0,R.jsx)($m,{text:v.text,streaming:!0,files:Ne,onOpenFile:a}),(b?.busy||f.state!==`idle`)&&!v?.text&&f.state!==`waiting`&&(0,R.jsx)(th,{label:b?.queued?u(`{n} queued`,{n:b.queued}):void 0}),P&&N.phase===`ask_agent_name`&&!b?.busy&&(0,R.jsx)(Ip,{chips:N.chips,chosen:N.chosen,onPick:ce,onElse:le}),O&&!b?.busy&&(0,R.jsx)(rh,{who:O}),!b?.busy&&f.state===`idle`&&ue!==null&&(0,R.jsx)(we,{moment:`tasks`,n:ue,className:`mx-1 my-2`}),!b?.busy&&f.state===`idle`&&he!==null&&(0,R.jsx)(we,{moment:`days_used`,n:he,className:`mx-1 my-2`})]}),j&&(0,R.jsxs)(`button`,{type:`button`,onClick:xe,className:`sticky bottom-2 left-1/2 -translate-x-1/2 rounded-full bg-surface border border-border shadow px-3 py-1.5 text-[12.5px] flex items-center gap-1`,children:[(0,R.jsx)(Me,{size:14}),` `,u(`Latest`),De?` · ${u(`{n} approval`,{n:De})}`:``]})]}),(0,R.jsx)(Rf,{}),(0,R.jsx)(ah,{name:T,busy:!!b?.busy&&De===0,waiting:g.some(e=>e.type===`question`&&e.status===`pending`),onSend:(e,n)=>t(p,e,n).catch(e=>{throw o(e.message||u(`Could not send`)),e})}),(0,R.jsx)(am,{open:x,onClose:()=>S(!1)}),C&&(0,R.jsx)(Ap,{thread:p,eventId:C,onClose:()=>w(null)})]})}function Gm({event:e,prev:t,name:n,onDecide:r,onOpenFile:i,onOpenBrowser:a,files:o,onCloudRetry:s}){let c=qm(t,e)?(0,R.jsx)(Jm,{ts:e.ts}):null,l=(()=>{switch(e.type){case`user`:return(0,R.jsx)(Ym,{event:e,onOpenFile:i});case`assistant`:return e.quiet?(0,R.jsx)(eh,{text:e.text,about:e.about,ts:e.ts}):(0,R.jsx)($m,{text:e.text,reasoning:e.reasoning,continued:t?.type===`assistant`,files:o,onOpenFile:i,spoken:e.via===`call`,modelUsed:e.model_used});case`tool`:return(0,R.jsx)(fp,{event:e});case`approval`:return(0,R.jsx)(hp,{event:e,name:n,onDecide:r});case`question`:return(0,R.jsx)(gp,{event:e,name:n});case`notice`:return(0,R.jsx)(vp,{event:e,onCloudRetry:s});case`artifact`:return(0,R.jsx)(Ep,{event:e,onOpen:i});case`browser`:return(0,R.jsx)(yp,{event:e,onOpen:a});case`hands`:return(0,R.jsx)(bp,{event:e,name:n});case`hold`:return(0,R.jsx)(wp,{event:e,name:n});case`avatar`:return(0,R.jsx)(np,{event:e,name:n});default:return null}})();return l?(0,R.jsxs)(R.Fragment,{children:[c,l]}):null}var Km=6e5;function qm(e,t){return t.ts?!e?.ts||new Date(t.ts).getTime()-new Date(e.ts).getTime()>=Km:!1}function Jm({ts:e}){let t=l(e);return t?(0,R.jsx)(`div`,{className:`pt-2 pb-0.5 text-center text-[11.5px] font-medium text-muted`,children:t}):null}function Ym({event:e,onOpenFile:t}){let n=s(),r=e.files??[],a=r.filter(e=>e.kind===`image`),o=r.filter(e=>e.kind!==`image`);return(0,R.jsxs)(`div`,{className:`rise flex flex-col items-end pl-12`,children:[e.via===`call`?(0,R.jsxs)(`span`,{className:`mb-1 flex items-center gap-1 text-[11.5px] font-medium text-muted`,children:[(0,R.jsx)(Ut,{size:11}),` `,n(`said on a call`)]}):e.via?(0,R.jsx)(`span`,{className:`mb-1 text-[11.5px] font-medium text-muted`,children:n(`asked from {device}`,{device:e.via})}):e.to_device_name||e.to_device?(0,R.jsxs)(`span`,{className:`mb-1 flex items-center gap-1 text-[11.5px] font-medium text-accent`,children:[(0,R.jsx)(It,{size:11}),` `,n(`to {device}`,{device:e.to_device_name||e.to_device||``})]}):(e.via_device_name||e.via_device)&&(0,R.jsx)(`span`,{className:`mb-1 text-[11.5px] font-medium text-muted`,children:n(`From {device}`,{device:e.via_device_name||e.via_device||``})}),a.length>0&&(0,R.jsx)(`div`,{className:`mb-1 flex max-w-full flex-wrap justify-end gap-1.5`,children:a.map(e=>(0,R.jsx)(`button`,{type:`button`,onClick:()=>t(e.path),"aria-label":e.name,className:i(`overflow-hidden rounded-2xl border border-border/60 bg-surface-2 shadow-sm active:scale-[0.98] transition`,a.length===1?`max-h-64 max-w-[240px]`:`h-28 w-28`),children:(0,R.jsx)(`img`,{src:h(e.path),alt:e.name,loading:`lazy`,className:i(`object-cover`,a.length===1?`max-h-64 w-auto max-w-full`:`h-full w-full`)})},e.path))}),o.map(e=>(0,R.jsxs)(`button`,{type:`button`,onClick:()=>t(e.path),className:`mb-1 flex max-w-full items-center gap-2.5 rounded-2xl border border-border bg-surface px-3 py-2 text-left shadow-sm hover:bg-surface-2 active:scale-[0.98] transition`,children:[(0,R.jsx)(`span`,{className:`rounded-xl bg-accent/12 p-2 text-accent`,children:e.kind===`data`?(0,R.jsx)(cn,{size:17}):(0,R.jsx)(mt,{size:17})}),(0,R.jsxs)(`span`,{className:`min-w-0`,children:[(0,R.jsx)(`span`,{className:`block truncate text-[14px] font-medium`,children:e.name}),(0,R.jsx)(`span`,{className:`block text-[11.5px] text-muted`,children:Xm(e.size)})]})]},e.path)),e.text&&(0,R.jsx)(`div`,{className:`bubble-user max-w-full rounded-[20px] bg-bubble-user px-4 py-2.5 text-bubble-user-fg`,children:(0,R.jsx)(`div`,{className:`md text-[15px] leading-[1.45] whitespace-pre-wrap break-words`,children:e.text})})]})}function Xm(e){return e<1024?`${e} B`:e<1048576?`${Math.round(e/1024)} KB`:`${(e/1048576).toFixed(1)} MB`}function Zm(e){let t=e.toLowerCase().split(`.`).pop()??``;return[`csv`,`tsv`,`json`,`xlsx`,`xls`].includes(t)?`data`:`other`}var Qm=`image/*,.pdf,.txt,.md,.csv,.tsv,.json,.log,.html,.xml,.yaml,.yml,.toml,.ics,.vcf,.xlsx,.xls,.docx`;function $m({text:e,reasoning:t,streaming:n,continued:r,files:a,onOpenFile:o,spoken:c,modelUsed:l}){let[u,d]=(0,L.useState)(!1),f=s(),p=(0,L.useMemo)(()=>mf(jm(e,!!n)),[e,n]);return p.length===0&&!n&&!t?null:(0,R.jsx)(`div`,{className:i(`rise flex items-end gap-2 pr-10`,r&&`-mt-1`),children:(0,R.jsxs)(`div`,{className:`min-w-0 max-w-full`,children:[t&&(0,R.jsx)(`button`,{type:`button`,className:`mb-1 ml-1 text-[12px] text-muted`,onClick:()=>d(e=>!e),children:f(u?`Hide thinking`:`Show thinking`)}),t&&u&&(0,R.jsx)(`div`,{className:`mb-1.5 rounded-2xl bg-surface-2/70 px-3 py-2 text-[13px] text-muted whitespace-pre-wrap break-words`,children:t}),p.map((e,t)=>e.bare?(0,R.jsx)(`div`,{className:`my-1 max-w-full`,children:(0,R.jsx)(hf,{text:e.text,files:a,onOpenFile:o})},t):(0,R.jsxs)(`div`,{className:i(`my-1 max-w-[340px] rounded-[20px] bg-surface-2 px-3.5 py-2.5 wide:max-w-[600px]`,c&&`border border-accent/15`),children:[c&&t===0&&(0,R.jsxs)(`div`,{className:`mb-0.5 flex items-center gap-1 text-[11px] font-medium text-accent/80`,children:[(0,R.jsx)(Ut,{size:10}),` `,f(`said on a call`)]}),(0,R.jsx)(hf,{text:e.text,files:a,onOpenFile:o}),n&&t===p.length-1&&(0,R.jsx)(`span`,{className:`inline-block w-1.5 h-4 ml-0.5 align-middle bg-accent/70 animate-pulse rounded-sm`})]},t)),p.length===0&&n&&(0,R.jsx)(`div`,{className:`my-1 rounded-[20px] bg-surface-2 px-3.5 py-2.5`,children:(0,R.jsx)(`span`,{className:`inline-block w-1.5 h-4 align-middle bg-accent/70 animate-pulse rounded-sm`})}),l&&!n&&(0,R.jsx)(`div`,{className:`ml-1 text-[11px] text-muted`,children:f(`Answered by nanoMuse Cloud this time ({model})`,{model:l})})]})})}function eh({text:e,about:n,ts:r}){let[i,a]=(0,L.useState)(!1),o=s(),c=n?t(n.replace(/^Working on your goal: /,``)):o(`background check`);return(0,R.jsx)(`div`,{className:`rise flex justify-center px-6`,children:(0,R.jsxs)(`button`,{type:`button`,onClick:()=>a(e=>!e),className:`max-w-full rounded-2xl px-3 py-1.5 text-[12px] text-muted text-center leading-snug`,children:[(0,R.jsxs)(`span`,{className:`inline-flex items-center gap-1.5`,children:[(0,R.jsx)(Rt,{size:12}),` `,o(`Checked on {label}: nothing new`,{label:c}),r?` · ${u(r)}`:``]}),i&&(0,R.jsx)(`span`,{className:`block mt-1 text-left whitespace-pre-wrap text-[12.5px]`,children:e})]})})}function th({label:e}){return(0,R.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,R.jsxs)(`div`,{className:`rounded-[20px] rounded-bl-md bg-surface-2 px-3.5 py-2.5 flex items-center gap-1`,children:[(0,R.jsx)(`span`,{className:`typing-dot h-2 w-2 rounded-full bg-muted`}),(0,R.jsx)(`span`,{className:`typing-dot h-2 w-2 rounded-full bg-muted`}),(0,R.jsx)(`span`,{className:`typing-dot h-2 w-2 rounded-full bg-muted`})]}),e&&(0,R.jsx)(`span`,{className:`text-[12px] text-muted`,children:e})]})}function nh(e){let t=e?e.at*1e3+N:0,[n,r]=(0,L.useState)(0);return(0,L.useEffect)(()=>{if(!t)return;let e=t-Date.now();if(e<=0){r(t);return}let n=window.setTimeout(()=>r(t),e+50);return()=>window.clearTimeout(n)},[t]),!e||n===t?null:e}function rh({who:e}){let t=s();return(0,R.jsxs)(`div`,{className:`flex items-center gap-1.5 px-1 text-[12px] text-muted`,children:[(0,R.jsx)(A,{size:12,className:`animate-spin`}),(0,R.jsx)(`span`,{children:t(`{device} is working…`,{device:e.device_name||e.device})})]})}function ih({name:e,device:t,onSend:n}){let r=s(),i=t?[r(`What is on your screen right now?`),r(`Which folder are you in, and what is in it?`),r(`Check for updates and tell me what needs a restart`)]:[r(`What can you do for me?`),r(`Plan my week: ask me what's on my plate`),r(`Research and compare two options for me`),r(`Set up a long-term goal and track it`)];return(0,R.jsxs)(`div`,{className:`flex flex-col items-center text-center px-6 pt-10 pb-6 gap-3`,children:[(0,R.jsx)(`div`,{className:`text-[20px] font-semibold`,children:t?r(`This chat goes to {device}.`,{device:t}):r(`Hi, I'm {name}.`,{name:e})}),(0,R.jsx)(`p`,{className:`text-muted text-[14.5px] leading-snug max-w-sm`,children:t?r(`Whatever you ask here, the {name} on {device} does where it is: its shell, its files, its screen. Every step shows up here, and anything that needs an approval asks you here.`,{name:e,device:t}):r(`I don't just answer; I get things done: research, plans, files, code, email, long-running goals. Everything I do shows up here, and anything hard to undo waits for your approval.`)}),(0,R.jsx)(`div`,{className:`mt-2 flex flex-wrap justify-center gap-2`,children:i.map(e=>(0,R.jsx)(`button`,{type:`button`,onClick:()=>n(e),className:`rounded-full bg-surface-2 px-3.5 py-1.5 text-[13.5px] hover:bg-border/60`,children:e},e))})]})}function ah({name:e,busy:t,waiting:n,onSend:r}){let{state:a,draft:o,draftFiles:c,toast:l}=E(),[u,d]=(0,L.useState)(``),[f,p]=(0,L.useState)(!1),m=(0,L.useRef)(``),g=Np((0,L.useCallback)((e,t)=>{let n=m.current,r=n&&!/\s$/.test(n)?` `:``;d(n+r+e+t)},[]),(0,L.useCallback)(e=>l(e),[l])),_=()=>{g.listening||(m.current=u),g.toggle()},[v,y]=(0,L.useState)([]),[b,x]=(0,L.useState)([]);(0,L.useEffect)(()=>{if(!a.draftFiles)return;let e=a.draftFiles.map(e=>({key:`shared-${e.path}`,file:new File([],e.name),preview:e.kind===`image`?h(e.path):null,info:e,error:null}));x(t=>[...t.filter(t=>!e.some(e=>e.key===t.key)),...e].slice(0,10)),c(null)},[a.draftFiles]);let S=(0,L.useRef)(null),C=(0,L.useRef)(null),w=s();(0,L.useEffect)(()=>()=>b.forEach(e=>e.preview?.startsWith(`blob:`)&&URL.revokeObjectURL(e.preview)),[b]),(0,L.useEffect)(()=>{let e=()=>S.current?.focus();return window.addEventListener(`nanomuse:quick-chat`,e),()=>window.removeEventListener(`nanomuse:quick-chat`,e)},[]);let T=e=>{let t=Array.from(e).slice(0,Math.max(0,10-b.length));if(t.length===0)return;let n=t.map(e=>({key:`${e.name}-${e.size}-${e.lastModified}-${Math.random().toString(36).slice(2,7)}`,file:e,preview:e.type.startsWith(`image/`)?URL.createObjectURL(e):null,info:null,error:null}));x(e=>[...e,...n]);for(let e of n)M.upload(e.file).then(t=>x(n=>n.map(n=>n.key===e.key?{...n,info:t}:n))).catch(t=>{let n=t.message?P(t.message):w(`Upload failed`);x(t=>t.map(t=>t.key===e.key?{...t,error:n}:t)),l(n)})},D=e=>x(t=>t.filter(t=>t.key!==e)),O=b.some(e=>!e.info&&!e.error),k=b.flatMap(e=>e.info?[e.info.path]:[]);(0,L.useEffect)(()=>{let e=S.current;e&&(e.style.height=`0px`,e.style.height=`${Math.min(e.scrollHeight,160)}px`)},[u]),(0,L.useEffect)(()=>{if(a.draft===null)return;d(a.draft),o(null);let e=S.current;e&&(e.focus(),e.setSelectionRange(e.value.length,e.value.length))},[a.draft]);let ee=a.settings?.skills?.enabled!==!1;(0,L.useEffect)(()=>{ee&&M.skills().then(e=>y(e.skills.filter(e=>e.enabled))).catch(()=>y([]))},[ee,a.skillsVersion]);let te=/^\/([a-z0-9-]*)$/i.exec(u),j=te?v.filter(e=>e.name.startsWith(te[1].toLowerCase())).slice(0,6):[],ne=e=>{d(`/${e.name} `),S.current?.focus()},re=a.hub?.devices??[],N=Pm(u,re),ie=N.length===0?Fm(u,re):null,ae=e=>{d(`@${e.name} `),S.current?.focus()},oe=e=>{e?.preventDefault();let t=u.trim();if(!t&&k.length===0||O||f)return;g.listening&&g.stop();let n=b;p(!0),d(``),x([]),S.current?.focus(),r(t,k).catch(()=>{d(e=>e||t),x(e=>e.length?e:n)}).finally(()=>p(!1))};return(0,R.jsxs)(`form`,{onSubmit:oe,className:`shrink-0 bg-bg px-3 pt-1.5 pb-1`,children:[t&&!n&&(0,R.jsx)(`div`,{className:`px-2 pb-1 text-[12px] text-muted`,children:w(`{name} is working; anything you send now is picked up right away.`,{name:e})}),j.length>0&&(0,R.jsx)(`ul`,{className:`mb-2 max-h-72 overflow-y-auto rounded-3xl border border-border/70 bg-surface shadow-lg divide-y divide-border/70`,role:`listbox`,"aria-label":w(`Skills`),children:j.map(e=>(0,R.jsx)(`li`,{children:(0,R.jsxs)(`button`,{type:`button`,onClick:()=>ne(e),className:`flex w-full items-center gap-3 px-4 py-2.5 text-left hover:bg-surface-2/70 active:bg-surface-2`,children:[(0,R.jsx)(gn,{size:16,className:`shrink-0 text-accent`}),(0,R.jsxs)(`span`,{className:`min-w-0 flex-1`,children:[(0,R.jsxs)(`span`,{className:`block text-[14px] font-medium`,children:[`/`,e.name]}),(0,R.jsx)(`span`,{className:`block truncate text-[12.5px] text-muted`,children:e.description})]})]})},e.name))}),N.length>0&&(0,R.jsx)(`ul`,{className:`mb-2 max-h-72 overflow-y-auto rounded-3xl border border-border/70 bg-surface shadow-lg divide-y divide-border/70`,role:`listbox`,"aria-label":w(`Devices`),children:N.map(e=>(0,R.jsx)(`li`,{children:(0,R.jsxs)(`button`,{type:`button`,onClick:()=>ae(e),className:`flex w-full items-center gap-3 px-4 py-2.5 text-left hover:bg-surface-2/70 active:bg-surface-2`,children:[(0,R.jsx)(`span`,{className:`shrink-0 text-accent`,children:e.kind===`computer`?(0,R.jsx)(Lt,{size:16}):(0,R.jsx)(tn,{size:16})}),(0,R.jsxs)(`span`,{className:`min-w-0 flex-1`,children:[(0,R.jsxs)(`span`,{className:`block text-[14px] font-medium`,children:[`@`,e.name]}),(0,R.jsx)(`span`,{className:`block truncate text-[12.5px] text-muted`,children:e.online?w(`Runs this there and reports back`):w(`Offline`)})]})]})},e.id))}),ie&&(0,R.jsxs)(`div`,{className:`flex items-center gap-1.5 px-2 pb-1 text-[12px] text-muted`,children:[(0,R.jsx)(It,{size:12}),` `,w(`This goes to {device}.`,{device:ie.name})]}),b.length>0&&(0,R.jsx)(`div`,{className:`mb-1 flex gap-2.5 overflow-x-auto px-1 pt-2.5 pb-1 pr-3`,role:`list`,"aria-label":w(`Attachments`),children:b.map(e=>(0,R.jsxs)(`div`,{role:`listitem`,className:i(`relative shrink-0 rounded-2xl border bg-surface-2`,e.error?`border-danger/60`:`border-border/70`),children:[e.preview?(0,R.jsx)(`img`,{src:e.preview,alt:e.file.name,className:`h-16 w-16 rounded-2xl object-cover`}):(0,R.jsxs)(`div`,{className:`flex h-16 w-40 items-center gap-2 px-2.5`,children:[(0,R.jsx)(`span`,{className:`rounded-xl bg-accent/12 p-1.5 text-accent`,children:Zm(e.file.name)===`data`?(0,R.jsx)(cn,{size:16}):(0,R.jsx)(mt,{size:16})}),(0,R.jsxs)(`span`,{className:`min-w-0`,children:[(0,R.jsx)(`span`,{className:`block truncate text-[12.5px] font-medium`,children:e.file.name}),(0,R.jsx)(`span`,{className:`block text-[11px] text-muted`,children:e.error?w(`Upload failed`):Xm(e.info?.size??e.file.size)})]})]}),!e.info&&!e.error&&(0,R.jsx)(`div`,{className:`absolute inset-0 flex items-center justify-center rounded-2xl bg-bg/50`,children:(0,R.jsx)(A,{size:18,className:`animate-spin text-accent`})}),(0,R.jsx)(`button`,{type:`button`,onClick:()=>D(e.key),"aria-label":w(`Remove`),className:`absolute -right-1.5 -top-1.5 flex h-6 w-6 items-center justify-center rounded-full border border-border bg-surface text-muted shadow-sm`,children:(0,R.jsx)(Fe,{size:13})})]},e.key))}),(0,R.jsxs)(`div`,{className:`flex items-end gap-2 rounded-[26px] border border-border bg-surface px-1.5 py-1.5 shadow-[0_2px_12px_-6px_rgba(0,0,0,0.12)] focus-within:border-fg/20`,children:[(0,R.jsx)(`input`,{ref:C,type:`file`,multiple:!0,accept:Qm,className:`hidden`,onChange:e=>{e.target.files&&T(e.target.files),e.target.value=``}}),(0,R.jsx)(`button`,{type:`button`,onClick:()=>C.current?.click(),"aria-label":w(`Attach a file`),className:`flex h-9 w-9 shrink-0 items-center justify-center rounded-full text-fg/70 transition hover:bg-surface-2 active:scale-95`,children:(0,R.jsx)(I,{size:22})}),(0,R.jsx)(`textarea`,{ref:S,value:u,onChange:e=>d(e.target.value),onPaste:e=>{let t=Array.from(e.clipboardData?.files??[]);t.length>0&&(e.preventDefault(),T(t))},onKeyDown:e=>{if(e.key===`Tab`&&j.length>0&&j[0]){e.preventDefault(),ne(j[0]);return}if(e.key===`Tab`&&N.length>0&&N[0]){e.preventDefault(),ae(N[0]);return}e.key===`Enter`&&!e.shiftKey&&!e.nativeEvent.isComposing&&(e.preventDefault(),oe())},rows:1,placeholder:n?w(`Answer {name}…`,{name:e}):b.length>0?w(`Say what to do with it…`):w(`Message`),className:`flex-1 resize-none bg-transparent px-1 py-2 text-[15px] leading-[1.4] outline-none placeholder:text-muted`}),g.supported&&(0,R.jsx)(Pp,{listening:g.listening,onClick:_}),(0,R.jsx)(`button`,{type:`submit`,disabled:!u.trim()&&k.length===0||O,"aria-label":w(`Send`),className:i(`flex h-9 w-9 shrink-0 items-center justify-center rounded-full transition active:scale-95`,u.trim()||k.length>0?`bg-accent text-accent-fg`:`bg-surface-2 text-muted`,`disabled:opacity-60`),children:(0,R.jsx)(Je,{size:19,strokeWidth:2.5})})]})]})}function oh({threads:e,active:t,onPick:n,onCleared:r,compact:a=!1,grouped:o=!1}){let{state:c,toast:l,dispatch:d}=E(),f=s(),[p,m]=(0,L.useState)(``),[h,g]=(0,L.useState)(!1),_=(0,L.useRef)(null),v=(c.hub?.devices??[]).filter(e=>!e.this&&e.kind!==`web`&&e.online),y=e=>c.hub?.devices.find(t=>t.id===e)?.kind??`phone`,b=async e=>{try{let t=await M.askDevice(e.id);d({type:`ws`,msg:{kind:`thread`,thread:t.thread}}),n(t.thread.id)}catch(e){l(e.message)}},x=async()=>{g(!0);try{let e=await M.createThread(p.trim()||f(`Side chat`));d({type:`ws`,msg:{kind:`thread`,thread:e}}),m(``),n(e.id)}catch(e){l(e.message)}finally{g(!1)}},S=async e=>{if(window.confirm(f(`Delete this side chat and its history?`)))try{await M.deleteThread(e),d({type:`ws`,msg:{kind:`thread_deleted`,thread:e}})}catch(e){l(e.message)}},C=async e=>{if(window.confirm(f(`Clear this conversation? Memory and goals are kept.`)))try{await M.clearThread(e),d({type:`ws`,msg:{kind:`thread_cleared`,thread:e}}),r?.()}catch(e){l(e.message)}},w=e=>(0,R.jsxs)(`li`,{className:i(`group flex items-center gap-2 px-3`,a?`py-2 rounded-xl hover:bg-surface-2/60`:`py-2.5`,e.id===t&&`bg-surface-2/60`),children:[(0,R.jsxs)(`button`,{type:`button`,onClick:()=>n(e.id),className:`flex-1 text-left min-w-0`,children:[(0,R.jsxs)(`div`,{className:i(`font-medium truncate flex items-center gap-2`,a?`text-[13.5px]`:`text-[15px]`),children:[e.device?(0,R.jsx)(`span`,{className:`text-accent`,children:y(e.device)===`computer`?(0,R.jsx)(Lt,{size:14}):(0,R.jsx)(tn,{size:14})}):e.remote_from?(0,R.jsx)(It,{size:14,className:`text-muted`}):null,(0,R.jsx)(`span`,{className:`truncate`,children:e.id===`main`?f(e.title):e.title}),e.busy&&(0,R.jsx)(`span`,{className:`h-1.5 w-1.5 shrink-0 rounded-full bg-amber-400 animate-pulse`})]}),(0,R.jsxs)(`div`,{className:i(`text-muted`,a?`text-[11.5px]`:`text-[12px]`),children:[f(`{n} events`,{n:e.events}),e.queued?` · ${f(`{n} queued`,{n:e.queued})}`:``,` · `,u(e.updated_at)]})]}),(0,R.jsx)(`button`,{type:`button`,"aria-label":f(`Clear`),onClick:()=>void C(e.id),className:i(`p-2 text-muted hover:text-fg`,a&&`opacity-0 group-hover:opacity-100 focus:opacity-100`),children:(0,R.jsx)(Fe,{size:16})}),e.id!==`main`&&(0,R.jsx)(`button`,{type:`button`,"aria-label":f(`Delete`),onClick:()=>void S(e.id),className:i(`p-2 text-muted hover:text-rose-500`,a&&`opacity-0 group-hover:opacity-100 focus:opacity-100`),children:(0,R.jsx)(fn,{size:16})})]},e.id),T=i(`divide-y divide-border overflow-hidden`,a?`rounded-xl`:`rounded-2xl border border-border`),D=`px-3 pb-1 pt-3 text-[11.5px] font-semibold uppercase tracking-wide text-muted`;return(0,R.jsxs)(`div`,{children:[o?(0,R.jsxs)(R.Fragment,{children:[(0,R.jsx)(`div`,{className:D,children:f(`Main chat`)}),(0,R.jsx)(`ul`,{className:T,children:e.filter(e=>e.id===`main`).map(w)}),(0,R.jsxs)(`div`,{className:i(D,`flex items-center justify-between pr-1`),children:[(0,R.jsx)(`span`,{children:f(`Side chats`)}),(0,R.jsx)(`button`,{type:`button`,"aria-label":f(`New side chat`),onClick:()=>_.current?.focus(),className:`flex h-6 w-6 items-center justify-center rounded-full text-muted hover:bg-surface-2 hover:text-fg`,children:(0,R.jsx)(I,{size:15})})]}),(0,R.jsx)(`ul`,{className:T,children:e.filter(e=>e.id!==`main`).map(w)}),e.every(e=>e.id===`main`)&&(0,R.jsx)(`p`,{className:`px-3 py-2 text-[12px] text-muted`,children:f(`A side chat keeps one topic apart from the rest.`)})]}):(0,R.jsx)(`ul`,{className:T,children:e.map(w)}),v.length>0&&(0,R.jsxs)(`div`,{className:`mt-4`,children:[(0,R.jsx)(`div`,{className:`mb-1.5 text-[12px] font-medium text-muted`,children:f(`Ask one of your devices`)}),(0,R.jsx)(`div`,{className:`flex flex-wrap gap-2`,children:v.map(e=>(0,R.jsxs)(`button`,{type:`button`,onClick:()=>void b(e),className:`flex items-center gap-1.5 rounded-full border border-border bg-surface px-3 py-1.5 text-[13px] font-medium hover:bg-surface-2`,children:[e.kind===`phone`?(0,R.jsx)(tn,{size:14,className:`text-accent`}):(0,R.jsx)(Lt,{size:14,className:`text-accent`}),e.name]},e.id))})]}),(0,R.jsxs)(`div`,{className:i(`flex gap-2`,a?`mt-3`:`mt-4`),children:[(0,R.jsx)(`input`,{ref:_,value:p,onChange:e=>m(e.target.value),onKeyDown:e=>{e.key===`Enter`&&!h&&x()},placeholder:f(a?`New side chat`:`New side chat, e.g. “Trip to Kyoto”`),className:i(`min-w-0 flex-1 bg-surface-2 outline-none focus:ring-2 focus:ring-accent/40`,a?`rounded-xl px-3 py-2 text-[13px]`:`rounded-2xl px-3.5 py-2.5 text-[14px]`)}),(0,R.jsxs)(`button`,{type:`button`,disabled:h,onClick:()=>void x(),"aria-label":f(`New`),className:i(`flex items-center gap-1.5 bg-accent text-accent-fg font-medium disabled:opacity-50`,a?`rounded-xl px-2.5`:`rounded-2xl px-3.5 py-2.5`),children:[(0,R.jsx)(jt,{size:18}),` `,!a&&f(`New`)]})]})]})}function sh(e){let t=[...e].reverse().find(e=>e.type===`user`),n=(((t?.type===`user`?t.text:``)||``).split(/\r?\n/).map(e=>e.trim()).find(e=>e.length>0)??``).replace(/\s+/g,` `);if(n.length<=36)return n;let r=n.slice(0,36),i=r.lastIndexOf(` `);return(i>16?r.slice(0,i):r).trimEnd()+`…`}function ch(e){let t=!1;for(let n=e.length-1;n>=0;n--){let r=e[n];if(r.type===`assistant`){if(!r.text||r.quiet)return!1;t=!0;continue}if(r.type===`user`)return t&&!r.via;if(r.type===`notice`)return!1}return!1}function lh(e){let t=Sn(),n=t?`Desktop app (${t.platform}, shell ${t.version})`:`Web app (${navigator.userAgent})`;return`https://github.com/nano-muse/nanoMuse/issues/new?${new URLSearchParams({template:`bug_report.yml`,version:e||``,os:n}).toString()}`}function uh(){let{state:e,setTab:t,openThread:n}=E(),r=s(),[a,o]=(0,L.useState)(!1),[c,l]=(0,L.useState)(!1),[u,d]=(0,L.useState)(``),f=(0,L.useRef)(null),p=$f(),{profile:m,status:h}=e,g=m?.name??`nanoMuse`,_=e.pendingApprovals.length,v=e.goals.filter(e=>e.proposal&&e.status!==`cancelled`).length,y=e.pendingApprovals.filter(t=>t.ts>e.feedSeenAt).length,b=(e.hub?.devices??[]).filter(e=>!e.this&&e.kind!==`web`&&e.online).length,x=_>0?_>1?r(`{n} approvals waiting for you`,{n:_}):r(`1 approval waiting for you`):h.state===`idle`?r(`Idle`):h.detail||(h.state===`waiting`?r(`Waiting for you`):r(`Working…`));(0,L.useEffect)(()=>{if(!c)return;let e=e=>{f.current?.contains(e.target)||l(!1)},t=e=>{e.key===`Escape`&&l(!1)};return document.addEventListener(`mousedown`,e),document.addEventListener(`keydown`,t),()=>{document.removeEventListener(`mousedown`,e),document.removeEventListener(`keydown`,t)}},[c]);let S=[{id:`chat`,label:`Chat`,icon:(0,R.jsx)(At,{size:21}),badge:_},{id:`feed`,label:`Feed`,icon:(0,R.jsx)(Bt,{size:21}),badge:y},{id:`ideas`,label:`Ideas`,icon:(0,R.jsx)(Ct,{size:21})},{id:`goals`,label:`Goals`,icon:(0,R.jsx)(rn,{size:21}),badge:v},{id:`library`,label:`Library`,icon:(0,R.jsx)(St,{size:21})},{id:`devices`,label:`Devices`,icon:(0,R.jsx)(It,{size:21}),dot:b>0},...p?[{id:`coding`,label:`Coding`,icon:(0,R.jsx)(on,{size:21})}]:[]],C=u.trim().toLowerCase(),w=C?e.threads.filter(e=>e.id===`main`||(e.id===`main`?r(e.title):e.title).toLowerCase().includes(C)||(e.device_name??``).toLowerCase().includes(C)):e.threads,T=e=>i(`relative flex w-[60px] flex-col items-center gap-[3px] rounded-xl py-1.5 text-[10.5px] font-medium leading-none transition`,e?`bg-surface-2 text-fg`:`text-fg/65 hover:bg-surface-2/60 hover:text-fg`);return(0,R.jsxs)(`div`,{className:`flex h-full shrink-0`,children:[(0,R.jsxs)(`aside`,{className:`relative flex h-full w-[76px] shrink-0 flex-col items-center border-r border-border bg-surface/70`,children:[(0,R.jsx)(`div`,{className:`titlebar-room`}),(0,R.jsxs)(`button`,{type:`button`,onClick:()=>o(!0),className:`relative mt-3 rounded-full transition hover:scale-[1.04]`,"aria-label":r(`Activity`),title:`${g} · ${x}`,children:[(0,R.jsx)(D,{profile:m,status:h,size:44}),_>0&&(0,R.jsx)(`span`,{className:`pointer-events-none absolute -right-1 -top-1 flex h-[18px] min-w-[18px] items-center justify-center rounded-full border-2 border-surface bg-rose-500 px-1 text-[10.5px] font-bold text-white`,children:_})]}),(0,R.jsx)(`span`,{className:`mt-1.5 max-w-[68px] truncate px-1 text-[11px] font-semibold leading-tight`,children:g}),(0,R.jsx)(`nav`,{className:`mt-3 flex w-full flex-1 flex-col items-center gap-0.5 overflow-y-auto overflow-x-hidden px-2`,children:S.map(n=>{let a=e.tab===n.id;return(0,R.jsxs)(`button`,{type:`button`,onClick:()=>t(n.id),"aria-current":a?`page`:void 0,className:T(a),children:[(0,R.jsx)(`span`,{className:i(a?`text-accent`:`text-fg/60`),children:n.icon}),(0,R.jsx)(`span`,{className:`max-w-full truncate`,children:r(n.label)}),n.badge?(0,R.jsx)(`span`,{className:`absolute right-1.5 top-1 flex h-[17px] min-w-[17px] items-center justify-center rounded-full bg-rose-500 px-1 text-[10px] font-bold text-white`,children:n.badge}):n.dot?(0,R.jsxs)(R.Fragment,{children:[(0,R.jsx)(`span`,{"aria-hidden":`true`,className:`absolute right-3 top-2 h-2 w-2 rounded-full border-2 border-surface bg-emerald-500`}),(0,R.jsx)(`span`,{className:`sr-only`,children:r(`{n} online`,{n:b})})]}):null]},n.id)})}),(0,R.jsxs)(`div`,{className:`flex w-full flex-col items-center gap-0.5 px-2 pb-3 pt-2`,children:[(0,R.jsxs)(`button`,{type:`button`,onClick:()=>t(`account`),"aria-current":e.tab===`account`?`page`:void 0,className:T(e.tab===`account`),title:e.hub?.account.signed_in?e.hub.account.hint:r(`Account`),children:[(0,R.jsx)(mn,{size:21,className:e.tab===`account`?`text-accent`:`text-fg/60`}),(0,R.jsx)(`span`,{className:`max-w-full truncate`,children:r(`Account`)})]}),(0,R.jsxs)(`button`,{type:`button`,onClick:()=>t(`you`),"aria-current":e.tab===`you`?`page`:void 0,className:T(e.tab===`you`),children:[(0,R.jsx)(en,{size:21,className:e.tab===`you`?`text-accent`:`text-fg/60`}),(0,R.jsx)(`span`,{className:`max-w-full truncate`,children:r(`Settings`)})]}),(0,R.jsxs)(`div`,{ref:f,className:`relative w-full`,children:[(0,R.jsxs)(`button`,{type:`button`,onClick:()=>l(e=>!e),"aria-expanded":c,"aria-haspopup":`menu`,className:i(T(c),`mx-auto`),children:[(0,R.jsx)(Ot,{size:21,className:`text-fg/60`}),(0,R.jsx)(`span`,{children:r(`More`)})]}),c&&(0,R.jsxs)(`div`,{role:`menu`,className:`absolute bottom-0 left-[68px] z-30 w-[232px] rounded-2xl border border-border bg-surface p-1.5 shadow-[0_12px_40px_-12px_rgba(0,0,0,0.3)]`,children:[(0,R.jsxs)(`a`,{role:`menuitem`,href:lh(e.version),target:`_blank`,rel:`noreferrer`,onClick:()=>l(!1),className:`flex items-center gap-2.5 rounded-xl px-2.5 py-2 text-[13px] font-medium hover:bg-surface-2`,children:[(0,R.jsx)(ue,{size:16,className:`text-fg/60`}),` `,r(`Report a bug`)]}),(0,R.jsxs)(`button`,{type:`button`,role:`menuitem`,onClick:()=>{l(!1),t(`you`),window.location.hash=`developer`},className:`flex w-full items-center gap-2.5 rounded-xl px-2.5 py-2 text-left text-[13px] font-medium hover:bg-surface-2`,children:[(0,R.jsx)(yn,{size:16,className:`text-fg/60`}),(0,R.jsx)(`span`,{className:`flex-1`,children:r(`Developer tools`)}),(0,R.jsx)(`span`,{className:`text-[11.5px] font-normal text-muted`,children:r(p?`On`:`Off`)})]}),e.version&&(0,R.jsxs)(`div`,{className:`px-2.5 pb-1 pt-1.5 text-[11.5px] text-muted`,children:[`nanoMuse `,e.version]})]})]})]}),(0,R.jsx)(am,{open:a,onClose:()=>o(!1)})]}),e.tab===`chat`&&(0,R.jsxs)(`section`,{className:`flex h-full w-[248px] shrink-0 flex-col border-r border-border bg-surface/40`,"aria-label":r(`Chats`),children:[(0,R.jsx)(`div`,{className:`titlebar-room`}),(0,R.jsxs)(`div`,{className:`px-3 pb-2 pt-4`,children:[(0,R.jsx)(`h2`,{className:`px-1 text-[15px] font-semibold tracking-tight`,children:r(`Chats`)}),(0,R.jsxs)(`label`,{className:`mt-2 flex items-center gap-2 rounded-xl bg-surface-2 px-2.5 py-1.5 text-muted focus-within:ring-2 focus-within:ring-accent/40`,children:[(0,R.jsx)(qt,{size:14,className:`shrink-0`}),(0,R.jsx)(`input`,{value:u,onChange:e=>d(e.target.value),placeholder:r(`Search`),"aria-label":r(`Search chats`),className:`min-w-0 flex-1 bg-transparent text-[13px] text-fg outline-none placeholder:text-muted`}),u&&(0,R.jsx)(`button`,{type:`button`,onClick:()=>d(``),"aria-label":r(`Clear`),className:`shrink-0 hover:text-fg`,children:(0,R.jsx)(Fe,{size:14})})]})]}),(0,R.jsx)(`div`,{className:`min-h-0 flex-1 overflow-y-auto px-2 pb-3`,children:(0,R.jsx)(oh,{threads:w,active:e.activeThread,onPick:e=>n(e),compact:!0,grouped:!0})})]})]})}function dh(){let{state:e,send:t,openThread:n,openFile:r,markFeedSeen:i,setTab:a,toast:o}=E(),[c,l]=(0,L.useState)(null),[u,p]=(0,L.useState)(null),[h,g]=(0,L.useState)(null),[_,v]=(0,L.useState)(null),b=e.profile?.name??`nanoMuse`,x=s(),S=y();(0,L.useEffect)(()=>{let e=!0;return M.feed(80).then(t=>e&&l(t)).catch(e=>o(e.message)),M.upcoming().then(t=>e&&g(t)).catch(()=>void 0),M.feedPosts().then(t=>e&&p(t)).catch(()=>void 0),()=>{e=!1}},[e.feedVersion,e.remindersVersion]),(0,L.useEffect)(()=>{let e=!0;return M.calendar().then(t=>e&&v(t)).catch(()=>void 0),()=>{e=!1}},[e.calendarVersion,e.connectionsVersion]),(0,L.useEffect)(()=>{c&&c.length&&c[0].ts>e.feedSeenAt&&i(c[0].ts)},[c,e.feedSeenAt,i]);let C=(0,L.useMemo)(()=>kh(c??[]),[c,S]),[w,T]=(0,L.useState)(!1),[D,O]=(0,L.useState)(null),[k,ee]=(0,L.useState)(()=>d(fh)===`1`),[j,ne]=(0,L.useState)(!1),re=()=>{f(fh,`1`),ee(!0)},N=async()=>{ne(!0);try{let e=await M.refreshFeedPosts();p(e),e.error&&o(x(`Could not write posts: {error}`,{error:e.error}))}catch(e){o(e.message)}finally{ne(!1)}},P=e=>{t(`main`,e.prompt||`${x(`About this post from my feed:`)}\n\n**${e.title}**\n\n${e.body.slice(0,1200)}`).catch(e=>o(e.message||x(`Could not send`))),n(`main`)},ie=(0,L.useMemo)(()=>mh(u?.posts??[]),[u]),ae=u!==null&&u.posts.length===0;return(0,R.jsxs)(`div`,{className:`flex h-full flex-col`,children:[(0,R.jsx)(Em,{title:``,trailing:(0,R.jsx)(te,{onClick:()=>T(!0),label:x(`Feed settings`),children:(0,R.jsx)(en,{size:22})})}),(0,R.jsxs)(`div`,{className:`flex-1 overflow-y-auto px-3.5 pb-7`,children:[ie.length===0&&(0,R.jsxs)(R.Fragment,{children:[(0,R.jsx)(gh,{text:hh(ph(),new Date)}),!k&&(0,R.jsx)(xh,{instructions:u?.instructions??``,onEdit:()=>T(!0),onAck:re}),ae&&(0,R.jsxs)(R.Fragment,{children:[(0,R.jsx)(Sh,{emoji:`🖼️`,title:x(`Nothing in the feed yet`),body:x(`As we get to know each other, new posts will show up here. Every day at {time} I read what I remember about you (your memory files, the last week of diary, your goals) and write a few short posts.`,{time:u?.time??`08:00`})}),(0,R.jsx)(Sh,{emoji:`📝`,title:x(`Steer it with one sentence`),body:x(`Tap the sliders at the top right to tell me what you want more of, switch the daily routine off, or have me write the first day now.`)}),e.settings&&!e.settings.llm_ready&&(0,R.jsx)(_h,{children:(0,R.jsxs)(`button`,{type:`button`,onClick:()=>a(`you`),className:`flex w-full items-center gap-2 p-4 text-left text-[14px] text-muted`,children:[(0,R.jsx)(F,{size:16,className:`shrink-0 text-accent`}),` `,x(`Add a model first; the feed is written by your agent.`)]})}),(0,R.jsx)(_h,{children:(0,R.jsx)(`div`,{className:`p-4`,children:j?(0,R.jsxs)(`div`,{className:`flex items-center justify-center gap-2.5 text-[15px]`,children:[(0,R.jsx)(A,{size:18,className:`animate-spin text-accent`}),` `,x(`Writing…`)]}):(0,R.jsx)(`button`,{type:`button`,onClick:()=>void N(),className:`h-[46px] w-full rounded-full bg-accent text-[15px] font-semibold text-accent-fg`,children:x(`Write it now`)})})})]})]}),ie.map(([e,t],n)=>(0,R.jsxs)(`section`,{children:[(0,R.jsx)(gh,{text:hh(e,new Date(t[0].ts))}),n===0&&!k&&(0,R.jsx)(xh,{instructions:u?.instructions??``,onEdit:()=>T(!0),onAck:re}),n===0&&j&&(0,R.jsx)(_h,{children:(0,R.jsxs)(`div`,{className:`flex items-center gap-2.5 p-4 text-[15px]`,children:[(0,R.jsx)(A,{size:18,className:`animate-spin text-accent`}),` `,x(`Writing…`)]})}),t.map(e=>(0,R.jsx)(bh,{post:e,onDiscuss:()=>P(e),onInfo:()=>O(e)},e.id))]},e)),(0,R.jsxs)(`div`,{className:`space-y-4 px-0.5 pt-3`,children:[h&&(0,R.jsx)(Th,{data:h,name:b,onSettings:()=>a(`you`),onGoals:()=>a(`goals`)}),_?.configured&&(0,R.jsx)(Eh,{data:_,onAsk:()=>n(`main`)}),c&&c.length===0&&(!u||u.posts.length===0)&&(0,R.jsxs)(`div`,{className:`py-10 text-center text-muted text-[14px] px-6`,children:[(0,R.jsx)(Rt,{size:28,className:`mx-auto mb-2 opacity-60`}),x(`Nothing yet. Once {name} works on a goal in the background or needs your approval, it shows up here.`,{name:b})]}),c&&c.length>0&&(0,R.jsx)(`div`,{className:`px-1 pt-1 text-[12px] font-semibold uppercase tracking-wide text-muted`,children:x(`While you were away`)}),C.map(([t,i])=>(0,R.jsxs)(`section`,{children:[(0,R.jsx)(`div`,{className:`px-1 mb-1.5 text-[12px] uppercase tracking-wide text-muted font-semibold`,children:t}),(0,R.jsx)(`ul`,{className:`space-y-2`,children:i.map(t=>(0,R.jsx)(`li`,{children:(0,R.jsx)(Oh,{item:t,unseen:t.ts>e.feedSeenAt,onOpen:()=>{t.kind===`artifact`&&t.path?r(t.path):n(t.thread)}})},t.id))})]},t))]})]}),(0,R.jsx)(wh,{open:w,onClose:()=>T(!1),data:u,writing:j,onChange:p,onWriteNow:()=>void N()}),(0,R.jsx)(Op,{open:D!==null,onClose:()=>O(null),title:D?.title,children:D&&(0,R.jsxs)(`div`,{className:`space-y-3 px-1 pb-2`,children:[(0,R.jsx)(Ch,{label:x(`Post type`),value:yh(D.area)}),(0,R.jsx)(Ch,{label:x(`Written`),value:new Date(D.ts).toLocaleString(m(),{dateStyle:`medium`,timeStyle:`short`})}),(0,R.jsx)(`button`,{type:`button`,onClick:async()=>{let e=D.id;O(null);try{await M.deleteFeedPost(e),p(t=>t&&{...t,posts:t.posts.filter(t=>t.id!==e)})}catch(e){o(e.message)}},className:`w-full rounded-full bg-surface-2 py-2.5 text-[15px] font-medium text-rose-500`,children:x(`Delete this post`)})]})})]})}var fh=`nanomuse.feed.introAck`;function ph(){let e=new Date;return`${e.getFullYear()}-${String(e.getMonth()+1).padStart(2,`0`)}-${String(e.getDate()).padStart(2,`0`)}`}function mh(e){let t=new Map;for(let n of e){let e=new Date(n.ts),r=`${e.getFullYear()}-${String(e.getMonth()+1).padStart(2,`0`)}-${String(e.getDate()).padStart(2,`0`)}`,i=t.get(r);i?i.push(n):t.set(r,[n])}return[...t.entries()]}function hh(e,t){let n=ph(),r=new Date;r.setDate(r.getDate()-1);let i=`${r.getFullYear()}-${String(r.getMonth()+1).padStart(2,`0`)}-${String(r.getDate()).padStart(2,`0`)}`,a=t.toLocaleDateString(m(),{weekday:`long`});if(e===n){let e=new Date().getHours(),t=_(e<12?`morning`:e<18?`afternoon`:`evening`);return _(`{weekday} {part}`,{weekday:a,part:t})}return e===i?_(`Yesterday`):`${a} · ${t.toLocaleDateString(m(),{month:`short`,day:`numeric`})}`}function gh({text:e}){return(0,R.jsx)(`h2`,{className:`px-1.5 pt-3.5 pb-2 text-[22px] font-bold leading-7`,children:e})}function _h({children:e,className:t}){return(0,R.jsx)(`div`,{className:i(`my-1.5 overflow-hidden rounded-[18px] bg-surface dark:border dark:border-border`,t),children:e})}var vh={planning:`🗓️`,research:`🔍`,goals:`🎯`,money:`💰`,health:`🌿`,home:`🏠`,learning:`📚`,people:`👥`,files:`📄`,fun:`🎈`};function yh(e){switch(e){case`planning`:return _(`Planning`);case`research`:return _(`Research`);case`goals`:return _(`Goals`);case`money`:return _(`Money`);case`health`:return _(`Health`);case`home`:return _(`Home`);case`learning`:return _(`Learning`);case`people`:return _(`People`);case`files`:return _(`Files`);case`fun`:return _(`Fun`);default:return _(`Note`)}}function bh({post:e,onDiscuss:t,onInfo:n}){let r=s();return(0,R.jsx)(_h,{children:(0,R.jsxs)(`article`,{className:`pl-3.5 pr-2.5 pt-3.5 pb-1.5`,children:[(0,R.jsxs)(`div`,{className:`flex items-start gap-3`,children:[(0,R.jsx)(`div`,{className:`flex h-11 w-11 shrink-0 items-center justify-center rounded-xl bg-surface-2 text-[22px] leading-none`,children:vh[e.area]??`📝`}),(0,R.jsxs)(`div`,{className:`min-w-0 flex-1`,children:[(0,R.jsx)(`h3`,{className:`text-[16px] font-semibold leading-[22px]`,children:e.title}),(0,R.jsx)(`div`,{className:`md mt-1 text-[15px] leading-[22px] text-fg/85`,children:(0,R.jsx)(hf,{text:e.body})})]})]}),(0,R.jsxs)(`div`,{className:`mt-1.5 flex items-center`,children:[(0,R.jsxs)(`button`,{type:`button`,onClick:t,className:`flex items-center gap-1.5 rounded-full px-2 py-2 text-[14px] hover:bg-surface-2`,children:[(0,R.jsx)(At,{size:22,strokeWidth:1.8}),` `,r(`Discuss`)]}),(0,R.jsx)(`button`,{type:`button`,onClick:n,"aria-label":r(`About this post`),className:`ml-auto rounded-full p-2 hover:bg-surface-2`,children:(0,R.jsx)(F,{size:22,strokeWidth:1.8})})]})]})})}function xh({instructions:e,onEdit:t,onAck:n}){let r=s();return(0,R.jsxs)(_h,{children:[(0,R.jsxs)(`div`,{className:`px-4 py-3.5`,children:[(0,R.jsx)(`div`,{className:`text-[17px] font-semibold`,children:r(`About the feed`)}),(0,R.jsx)(`p`,{className:`mt-1 text-[13px] leading-[18px] text-muted`,children:r(`Short posts your agent writes for you from what it remembers: your memory files, the last week of diary, your goals. The sentence below steers every post from now on; edit it any time.`)})]}),(0,R.jsxs)(`div`,{className:`border-t border-border/70 px-4 py-3.5`,children:[(0,R.jsx)(`p`,{className:`text-[15px] leading-[22px]`,children:e||r(`Build me a feed about what I care about. Keep it short and direct, easy to skim, no clickbait.`)}),(0,R.jsxs)(`div`,{className:`mt-3.5 flex justify-end gap-2.5`,children:[(0,R.jsx)(`button`,{type:`button`,onClick:t,className:`rounded-full bg-surface-2 px-6 py-2.5 text-[15px] font-medium`,children:r(`Edit`)}),(0,R.jsx)(`button`,{type:`button`,onClick:n,className:`rounded-full bg-accent px-6 py-2.5 text-[15px] font-semibold text-accent-fg`,children:r(`Got it`)})]})]})]})}function Sh({emoji:e,title:t,body:n}){return(0,R.jsx)(_h,{children:(0,R.jsxs)(`div`,{className:`flex items-start gap-3 p-3.5`,children:[(0,R.jsx)(`div`,{className:`flex h-11 w-11 shrink-0 items-center justify-center rounded-xl bg-surface-2 text-[22px] leading-none`,children:e}),(0,R.jsxs)(`div`,{className:`min-w-0 flex-1`,children:[(0,R.jsx)(`div`,{className:`text-[16px] font-semibold leading-[22px]`,children:t}),(0,R.jsx)(`p`,{className:`mt-1 text-[15px] leading-[22px] text-fg/85`,children:n})]})]})})}function Ch({label:e,value:t}){return(0,R.jsxs)(`div`,{className:`flex items-start gap-3 text-[14.5px]`,children:[(0,R.jsx)(`span`,{className:`w-14 shrink-0 text-muted`,children:e}),(0,R.jsx)(`span`,{className:`min-w-0 flex-1 break-words`,children:t})]})}function wh({open:e,onClose:t,data:n,writing:r,onChange:i,onWriteNow:a}){let{toast:o,state:c}=E(),l=s(),[u,d]=(0,L.useState)(``),[f,p]=(0,L.useState)(!1);(0,L.useEffect)(()=>{e&&d(n?.instructions??``)},[e,n]);let m=async()=>{p(!0);try{i(await M.setFeedInstructions({instructions:u})),t()}catch(e){o(e.message)}finally{p(!1)}},h=async e=>{try{i(await M.setFeedInstructions(e))}catch(e){o(e.message)}},g=c.settings?.llm_ready!==!1;return(0,R.jsx)(Op,{open:e,onClose:t,title:l(`Feed`),children:(0,R.jsxs)(`div`,{className:`space-y-3 px-1 pb-2`,children:[(0,R.jsx)(`p`,{className:`text-[13px] leading-[18px] text-muted`,children:l(`Your feed is driven by the instruction below. Any edit you make here applies to every post from now on.`)}),(0,R.jsx)(`textarea`,{value:u,onChange:e=>d(e.target.value),rows:4,maxLength:2e3,placeholder:l(`Build me a feed about what I care about. Keep it short and direct, easy to skim, no clickbait.`),className:`w-full resize-none rounded-2xl bg-surface-2 px-3.5 py-2.5 text-[15px] leading-snug outline-none focus:ring-2 focus:ring-accent/40`}),(0,R.jsxs)(`div`,{className:`space-y-2 rounded-2xl bg-surface-2 px-3.5 py-2.5`,children:[(0,R.jsx)(Pe,{label:l(`Write it every day`),hint:n?.daily===!1?void 0:l(`Daily at {time}`,{time:n?.time??`08:00`}),checked:n?.daily!==!1,onChange:e=>void h({daily:e}),disabled:!n}),n?.daily!==!1&&(0,R.jsxs)(`label`,{className:`flex items-center justify-between gap-3 text-[13px] text-muted`,children:[(0,R.jsx)(`span`,{children:l(`Time of day`)}),(0,R.jsx)(`input`,{type:`time`,value:n?.time??`08:00`,onChange:e=>e.target.value&&void h({time:e.target.value}),className:`rounded-lg bg-surface px-2 py-1 text-[13px] text-fg outline-none focus:ring-2 focus:ring-accent/40`})]}),!g&&(0,R.jsx)(`div`,{className:`text-[12.5px] text-muted`,children:l(`Add a model first; the feed is written by your agent.`)})]}),(0,R.jsxs)(`button`,{type:`button`,onClick:a,disabled:r||!n||!g,className:`flex w-full items-center justify-center gap-2 rounded-full bg-surface-2 py-2.5 text-[15px] font-medium disabled:opacity-60`,children:[r?(0,R.jsx)(A,{size:16,className:`animate-spin`}):(0,R.jsx)(nn,{size:16,className:`text-accent`}),l(r?`Writing…`:`Write it now`)]}),(0,R.jsx)(`button`,{type:`button`,onClick:()=>void m(),disabled:f,className:`h-[46px] w-full rounded-full bg-accent text-[15px] font-semibold text-accent-fg disabled:opacity-60`,children:l(`Save`)})]})})}function Th({data:t,name:n,onSettings:r,onGoals:i}){let a=s(),o=t.queue[0],c=t.reminders.filter(e=>e.status===`active`&&!!e.next_at),l=c[0],d=c.length;return(0,R.jsxs)(`div`,{className:`rounded-3xl border border-border/70 bg-surface shadow-sm px-4 py-3.5`,children:[(0,R.jsxs)(`div`,{className:`flex items-center gap-2 text-[12px] uppercase tracking-wide text-muted font-semibold`,children:[(0,R.jsx)(Xe,{size:13}),` `,a(`Next up`)]}),t.proactive?o?(0,R.jsxs)(`div`,{className:`mt-1.5 text-[14px] leading-snug`,children:[t.busy?a(`Working now`):t.quiet_until?a(`Quiet hours after {time}`,{time:u(t.quiet_until)}):t.next_pass_at?a(`Around {time}`,{time:u(t.next_pass_at)}):a(`Soon`),`: `,(0,R.jsx)(`span`,{className:`font-medium`,children:o.title}),o.next_step&&(0,R.jsxs)(`span`,{className:`text-muted`,children:[` · `,o.next_step]}),o.overdue&&(0,R.jsxs)(`span`,{className:`text-rose-500 font-medium`,children:[` · `,a(`overdue`)]}),t.queue.length>1&&(0,R.jsxs)(`span`,{className:`text-muted`,children:[` · `,a(`{n} more in line`,{n:t.queue.length-1})]})]}):(0,R.jsxs)(`div`,{className:`mt-1.5 text-[14px] leading-snug`,children:[a(`No goal has a next step to work on.`),` `,(0,R.jsx)(`button`,{type:`button`,onClick:i,className:`text-accent font-medium`,children:a(`Add one`)})]}):(0,R.jsxs)(`div`,{className:`mt-1.5 text-[14px] leading-snug`,children:[a(`Background work is off. {name} only acts when you ask.`,{name:n}),` `,(0,R.jsx)(`button`,{type:`button`,onClick:r,className:`text-accent font-medium`,children:a(`Turn it on`)})]}),t.check_ins[0]&&(0,R.jsxs)(`div`,{className:`mt-1.5 text-[12.5px] text-muted`,children:[a(`Check-in on`),` `,(0,R.jsx)(`span`,{className:`font-medium text-fg`,children:t.check_ins[0].title}),` `,e(t.check_ins[0].at),t.check_ins.length>1&&` · ${a(`{n} more`,{n:t.check_ins.length-1})}`]}),l&&(0,R.jsxs)(`div`,{className:`mt-1.5 text-[12.5px] text-muted`,children:[l.kind===`task`?a(`Routine`):a(`Reminder`),` `,(0,R.jsx)(`span`,{className:`font-medium text-fg`,children:l.text}),` `,e(l.next_at),d>1&&` · ${a(`{n} more`,{n:d-1})}`]})]})}function Eh({data:e,onAsk:t}){let n=s(),r=t=>t.start.slice(0,10)<=e.today,a=e.events.filter(r),o=e.events.filter(e=>!r(e)),c=new Date,l=e=>!e.all_day&&new Date(e.end)e.error),d=a.every(l)&&o.length>0,f=d?o:a;return(0,R.jsxs)(`div`,{className:`rounded-3xl border border-border/70 bg-surface shadow-sm px-4 py-3.5`,children:[(0,R.jsxs)(`div`,{className:`flex items-center gap-2 text-[12px] uppercase tracking-wide text-muted font-semibold`,children:[(0,R.jsx)(tt,{size:13}),` `,n(d?`Tomorrow`:`Today`),f.length>0&&(0,R.jsx)(`span`,{className:`ml-auto normal-case tracking-normal font-normal`,children:n(`{n} scheduled`,{n:f.length})})]}),f.length===0?(0,R.jsx)(`div`,{className:`mt-1.5 text-[14px] leading-snug text-muted`,children:n(`Nothing on the calendar today.`)}):(0,R.jsx)(`ul`,{className:`mt-1.5 space-y-1`,children:f.map(e=>(0,R.jsxs)(`li`,{className:i(`flex items-baseline gap-2.5 text-[14px] leading-snug`,!d&&l(e)&&`opacity-50`),children:[(0,R.jsx)(`span`,{className:`w-[86px] shrink-0 tabular-nums text-[12.5px] text-muted`,children:e.all_day?n(`all day`):`${e.start.slice(11,16)}–${e.end.slice(11,16)}`}),(0,R.jsxs)(`span`,{className:`min-w-0 flex-1`,children:[(0,R.jsx)(`span`,{className:`font-medium`,children:e.summary}),e.location&&(0,R.jsxs)(`span`,{className:`text-muted text-[12.5px]`,children:[` `,(0,R.jsx)(Dt,{size:11,className:`inline -mt-0.5`}),` `,e.location]})]})]},`${e.uid}-${e.start}`))}),u.length>0&&(0,R.jsx)(`div`,{className:`mt-1.5 text-[12px] text-rose-500`,children:n(`{name} could not be read`,{name:u.map(e=>e.name).join(`, `)})}),(0,R.jsx)(`button`,{type:`button`,onClick:t,className:`mt-2 text-[12.5px] text-accent font-medium`,children:n(`Ask about your week`)})]})}function Dh(e){return e.replace(/```[\s\S]*?```/g,` `).replace(/^#{1,6}\s+/gm,``).replace(/(\*\*|__|`)/g,``).replace(/^\s*[-*+]\s+/gm,`• `).replace(/\[([^\]]+)\]\([^)]*\)/g,`$1`).trim()}function Oh({item:n,unseen:r,onOpen:a}){let o=s(),c=n.kind===`approval`?(0,R.jsx)(Zt,{size:18}):n.kind===`question`?(0,R.jsx)(kt,{size:18}):n.kind===`artifact`?(0,R.jsx)(mt,{size:18}):n.quiet?(0,R.jsx)(Rt,{size:18}):n.title.startsWith(`New mail: `)?(0,R.jsx)(Et,{size:18}):n.title.startsWith(`Coming up: `)?(0,R.jsx)(et,{size:18}):n.title.startsWith(`Webhook: `)?(0,R.jsx)(_n,{size:18}):(0,R.jsx)(nn,{size:18}),l=n.kind===`approval`?`bg-amber-500/12 text-amber-600 dark:text-amber-300`:n.kind===`question`?`bg-accent/12 text-accent`:`bg-surface-2 text-muted`;return n.quiet?(0,R.jsxs)(`button`,{type:`button`,onClick:a,className:`w-full text-left px-2 py-1.5 flex items-center gap-2 text-[12.5px] text-muted`,children:[(0,R.jsx)(Rt,{size:13,className:`shrink-0`}),(0,R.jsxs)(`span`,{className:`truncate`,children:[o(`{label}: nothing new`,{label:t(n.title.replace(/^Working on your goal: /,``))}),n.text?`: ${n.text}`:``]}),(0,R.jsx)(`span`,{className:`ml-auto shrink-0`,children:e(n.ts)})]}):(0,R.jsx)(`button`,{type:`button`,onClick:a,className:i(`w-full text-left rounded-3xl border bg-surface shadow-sm px-4 py-3 active:scale-[0.99] transition`,r?`border-accent/40`:`border-border/70`),children:(0,R.jsxs)(`div`,{className:`flex items-start gap-3`,children:[(0,R.jsx)(`div`,{className:i(`rounded-2xl p-2 mt-0.5`,l),children:c}),(0,R.jsxs)(`div`,{className:`flex-1 min-w-0`,children:[(0,R.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,R.jsx)(`div`,{className:`font-semibold text-[14.5px] leading-snug truncate`,children:t(n.title)}),r&&(0,R.jsx)(`span`,{className:`h-2 w-2 rounded-full bg-accent shrink-0`})]}),n.text&&(0,R.jsx)(`div`,{className:`mt-0.5 text-[13.5px] text-muted leading-snug line-clamp-3 whitespace-pre-wrap`,children:Dh(n.text)}),(0,R.jsxs)(`div`,{className:`mt-1.5 flex items-center gap-2 text-[12px] text-muted`,children:[(0,R.jsx)(`span`,{children:e(n.ts)}),(0,R.jsx)(`span`,{children:`·`}),(0,R.jsx)(`span`,{className:`truncate`,children:n.thread===`main`?o(n.thread_title):n.thread_title}),(0,R.jsxs)(`span`,{className:`ml-auto flex items-center gap-1 text-accent font-medium`,children:[n.kind===`artifact`?o(`Open`):n.kind===`approval`||n.kind===`question`?o(`Answer`):o(`Open chat`),(0,R.jsx)(qe,{size:13})]})]})]})]})})}function kh(e){let t=new Date,n=new Date(t);n.setDate(t.getDate()-1);let r=e=>{let r=new Date(e);return r.toDateString()===t.toDateString()?_(`Today`):r.toDateString()===n.toDateString()?_(`Yesterday`):r.toLocaleDateString(m(),{weekday:`long`,month:`short`,day:`numeric`})},i=new Map;for(let t of e){let e=r(t.ts);i.set(e,[...i.get(e)??[],t])}return[...i.entries()]}function Ah({children:e,className:t}){return(0,R.jsx)(`div`,{className:i(`mx-4 overflow-hidden rounded-2xl bg-surface dark:border dark:border-border`,t),children:e})}function jh({inset:e=52}){return(0,R.jsx)(`div`,{className:i(`border-t border-border/60`,e===52?`ml-[52px]`:`ml-4`)})}function Mh({icon:e,label:t,value:n,onClick:r,external:a=!1,trailing:o,chevron:s=!0}){let c=(0,R.jsxs)(R.Fragment,{children:[e&&(0,R.jsx)(`span`,{className:`shrink-0 text-fg`,children:e}),(0,R.jsx)(`span`,{className:i(`min-w-0 truncate text-[16px] leading-[21px]`,n?`max-w-[60%] shrink-0`:`flex-1`),children:t}),n&&(0,R.jsx)(`span`,{className:`min-w-0 flex-1 truncate pl-3 text-right text-[14px] leading-[18px] text-muted`,children:n}),o??(s?a?(0,R.jsx)(Ae,{size:16,className:`shrink-0 text-muted/70`}):(0,R.jsx)(rt,{size:18,className:`shrink-0 text-muted/70`}):null)]}),l=`flex min-h-[54px] w-full items-center gap-3.5 px-4 py-2 text-left`;return r?(0,R.jsx)(`button`,{type:`button`,onClick:r,className:i(l,`hover:bg-surface-2/60`),children:c}):(0,R.jsx)(`div`,{className:l,children:c})}function Nh({icon:e,label:t,value:n,checked:r,disabled:a=!1,onChange:o}){return(0,R.jsxs)(`button`,{type:`button`,role:`switch`,"aria-checked":r,disabled:a,onClick:()=>o(!r),className:i(`flex min-h-[54px] w-full items-center gap-3.5 px-4 py-2 text-left`,a?`opacity-60`:`hover:bg-surface-2/60`),children:[e&&(0,R.jsx)(`span`,{className:`shrink-0 text-fg`,children:e}),(0,R.jsx)(`span`,{className:i(`min-w-0 truncate text-[16px] leading-[21px]`,n?`max-w-[60%] shrink-0`:`flex-1`),children:t}),n&&(0,R.jsx)(`span`,{className:`min-w-0 flex-1 truncate pl-3 text-right text-[14px] leading-[18px] text-muted`,children:n}),(0,R.jsx)(Ph,{checked:r})]})}function Ph({checked:e}){return(0,R.jsx)(`span`,{"aria-hidden":!0,className:i(`relative h-7 w-12 shrink-0 rounded-full transition`,e?`bg-accent`:`bg-surface-2 border border-border`),children:(0,R.jsx)(`span`,{className:i(`absolute top-0.5 h-6 w-6 rounded-full bg-white shadow transition`,e?`left-[22px]`:`left-0.5`)})})}function Fh({children:e,className:t}){return(0,R.jsx)(`p`,{className:i(`px-8 py-2 text-[13px] leading-[18px] text-muted`,t),children:e})}function Ih({children:e}){return(0,R.jsx)(`p`,{className:`px-8 pb-2 pt-[18px] text-[13px] leading-[18px] text-muted`,children:e})}var Lh=`https://nanomuse.cn/privacy/`;function Rh({me:e,onChanged:t,flush:n=!1}){let r=s(),{state:a,toast:o}=E(),c=!!a.hub?.account.signed_in,[l,u]=(0,L.useState)(null),[d,f]=(0,L.useState)(!1),p=e??l,m=async()=>{if(c&&!e)try{u(await M.cloudMe())}catch{}};(0,L.useEffect)(()=>{m()},[c,e]);let h=p?.contribute??{on:!1,samples:0},g=h.samples??0,_=h.privacy_url||`https://nanomuse.cn/privacy/`,v=async n=>{f(!0);try{await M.cloudContribute(n),o(r(n?`On. Turn it off here at any time.`:`Off. Nothing more is kept.`)),e?t?.():await m()}catch(e){o(e.message)}finally{f(!1)}},y=async()=>{if(window.confirm(r(`The kept conversations are removed from the server. This cannot be undone.`))){f(!0);try{let n=await M.cloudDeleteSamples();o(r(`{n} turns deleted`,{n:String(n.deleted)})),e?t?.():await m()}catch(e){o(e.message)}finally{f(!1)}}};return(0,R.jsxs)(`div`,{className:i(n&&`-mx-4`),children:[(0,R.jsx)(zh,{signedIn:c}),(0,R.jsx)(Ah,{children:(0,R.jsx)(Nh,{label:r(`Help improve nanoMuse's AI models`),checked:c&&h.on,disabled:d||!c||!p,onChange:e=>void v(e)})}),(0,R.jsxs)(Fh,{children:[r(`While this is on, the text of your chats with the nanoMuse Cloud models (what you wrote, what it answered and the tools it chose to call) is kept on the relay to train the community's own open model. Not your memory or SOUL (the system prompt), not what tools returned, not pictures, and never next to who you are. Your own API key never passes through the relay.`),` `,c?h.default_on!==void 0&&(h.default_on?r(`New accounts start with it on.`):r(`New accounts start with it off.`)):r(`Sign in to nanoMuse Cloud to use it.`),` `,c&&g>0&&r(`{n} turns kept so far.`,{n:String(g)}),` `,(0,R.jsx)(`a`,{href:_,target:`_blank`,rel:`noopener noreferrer`,className:`text-accent underline-offset-2 hover:underline`,children:r(`Privacy policy`)})]}),c&&g>0&&(0,R.jsxs)(Ah,{className:`mt-3`,children:[(0,R.jsx)(Mh,{icon:d?(0,R.jsx)(A,{size:22,className:`animate-spin`}):(0,R.jsx)(fn,{size:22}),label:r(`Delete the kept conversations`),value:r(`{n} turns`,{n:String(g)}),onClick:()=>void y(),chevron:!1}),(0,R.jsx)(jh,{inset:16}),(0,R.jsx)(Fh,{className:`px-4 pb-2.5 pt-2`,children:r(`Removes every turn kept from this account, whether the switch is on or off now. Turning the switch off keeps what was kept until you delete it here.`)})]})]})}function zh({signedIn:e}){let t=s(),{toast:n}=E(),[r,i]=(0,L.useState)(null),[a,o]=(0,L.useState)(!1),c=r?.relay?.counts??{conversations:0,messages:0},l=e&&(c.conversations>0||c.messages>0),u=async()=>{try{i(await M.syncState())}catch{}};(0,L.useEffect)(()=>{u()},[e]);let d=async(e,t)=>{o(!0);try{i(await e()),n(t)}catch(e){n(e.message),await u()}finally{o(!1)}},f=e=>{(e||!l||window.confirm(t(`Off deletes the synced conversations from nanoMuse Cloud. The chats on each device stay.`)))&&d(()=>M.syncSetState(e),t(e?`On. Your devices show the same conversations from now on.`:`Off. Nothing is kept on nanoMuse Cloud any more.`))},p=()=>{window.confirm(t(`The synced conversations are removed from nanoMuse Cloud. The chats on each device stay. This cannot be undone.`))&&d(()=>M.syncDelete(),t(`Synced conversations deleted.`))},m=e=>{d(()=>M.syncSetSideChats(e),t(e?`On. This device's side chats go to the account; the other devices' are on their way.`:`Off. Side chats stay on this device from now on.`))},h=e&&!!r?.enabled;return(0,R.jsxs)(`div`,{className:`mb-6`,children:[(0,R.jsx)(Ah,{children:(0,R.jsx)(Nh,{label:t(`Sync conversations between my devices`),checked:h,disabled:a||!e||!r,onChange:f})}),(0,R.jsxs)(Fh,{children:[t(`The text of your chats is kept on nanoMuse Cloud so every device shows the same conversations. Files and images stay on the device they were made on.`),` `,e?r?.paused?t(`Paused: sign in again to continue.`):l&&t(`{c} chats, {m} messages kept so far.`,{c:String(c.conversations),m:String(c.messages)}):t(`Sign in to nanoMuse Cloud to use it.`)]}),r&&`side_chats`in r&&(0,R.jsxs)(R.Fragment,{children:[(0,R.jsx)(Ah,{className:`mt-3`,children:(0,R.jsx)(Nh,{label:t(`Also sync side chats`),checked:h&&!!r.side_chats,disabled:a||!h,onChange:m})}),(0,R.jsx)(Fh,{children:t(`Off: side chats stay on this device. On: this device's side chats go to the account and the other devices' side chats come here.`)})]}),l&&(0,R.jsxs)(Ah,{className:`mt-3`,children:[(0,R.jsx)(Mh,{icon:a?(0,R.jsx)(A,{size:22,className:`animate-spin`}):(0,R.jsx)(fn,{size:22}),label:t(`Delete synced conversations`),value:t(`{n} chats`,{n:String(c.conversations)}),onClick:p,chevron:!1}),(0,R.jsx)(jh,{inset:16}),(0,R.jsx)(Fh,{className:`px-4 pb-2.5 pt-2`,children:t(`Removes what nanoMuse Cloud stores for this account; the chats on each device stay, and the switch stays on. Deleting a chat on one device deletes it on all of them.`)})]})]})}var Bh=`nm.invite`;function Vh(){try{let e=new URLSearchParams(window.location.search).get(`invite`);if(e){let t=Hh(e);t&&localStorage.setItem(Bh,t)}return localStorage.getItem(Bh)??``}catch{return``}}function Hh(e){return e.toUpperCase().replace(/[^A-Z0-9]/g,``).slice(0,8)}function Uh(e){return/^\s*[+\d]/.test(e)?`tel`:`email`}function Wh({onSignedIn:e,useAsModel:t=!1,cta:n,autoFocus:r=!0}){let a=s(),o=(0,L.useId)(),c=Ce(),[l,u]=(0,L.useState)(`code`),[d,f]=(0,L.useState)(``),[p,m]=(0,L.useState)(``),[h,g]=(0,L.useState)(``),[_,v]=(0,L.useState)(!1),[y,b]=(0,L.useState)(null),[x,S]=(0,L.useState)(null),[C,w]=(0,L.useState)(``),[T,E]=(0,L.useState)(!1);(0,L.useEffect)(()=>{let e=Vh();e&&(w(e),E(!0))},[]);let D=async()=>{if(t){b(`model`);try{await M.cloudUseAsModel()}catch{}}await e()},O=async()=>{let e=d.trim();if(e){b(`code`),S(null);try{await M.cloudCode(e),v(!0)}catch(e){S(a(e.message))}finally{b(null)}}},k=async()=>{let e=d.trim();if(!(!e||p.trim().length<4)){b(`verify`),S(null);try{(await M.cloudVerify(e,p.trim(),C.trim())).created&&Vf(),m(``),v(!1);try{localStorage.removeItem(Bh)}catch{}await D()}catch(e){S(a(e.message))}finally{b(null)}}},ee=async()=>{let e=d.trim();if(e&&h){b(`login`),S(null);try{await M.cloudLogin(e,h),g(``),await D()}catch(e){S(a(e.message))}finally{b(null)}}},te=()=>void(l===`password`?ee():_?k():O()),j=n??a(t?`Sign in and use its model`:`Sign in`);return(0,R.jsxs)(`form`,{className:`space-y-3`,onSubmit:e=>{e.preventDefault(),te()},children:[(0,R.jsxs)(`div`,{className:`grid grid-cols-2 gap-1 rounded-2xl bg-surface-2/70 p-1 text-[13px] font-medium`,children:[(0,R.jsx)(Gh,{active:l===`code`,onClick:()=>u(`code`),icon:(0,R.jsx)(Mt,{size:14}),label:a(`With a code`)}),(0,R.jsx)(Gh,{active:l===`password`,onClick:()=>u(`password`),icon:(0,R.jsx)(xt,{size:14}),label:a(`With a password`)})]}),(0,R.jsxs)(`div`,{children:[(0,R.jsx)(`label`,{htmlFor:`${o}-id`,className:`text-[12px] text-muted`,children:se()?a(`Mainland China phone number or e-mail`):a(`E-mail (or a mainland China phone number)`)}),(0,R.jsx)(`input`,{id:`${o}-id`,value:d,onChange:e=>{f(e.target.value),v(!1)},inputMode:Uh(d),autoComplete:`username`,autoFocus:r,placeholder:a(`138 0000 0000 or you@example.com`),className:i(Ie,`mt-1`)}),l===`code`&&!_&&(!se()||oe(d))&&(0,R.jsx)(`p`,{className:`mt-1.5 text-[12px] text-muted`,children:a(`Text-message codes reach mainland-China numbers only. Use an e-mail address instead.`)})]}),l===`password`?(0,R.jsxs)(`div`,{children:[(0,R.jsx)(`label`,{htmlFor:`${o}-password`,className:`text-[12px] text-muted`,children:a(`Password`)}),(0,R.jsx)(`input`,{id:`${o}-password`,type:`password`,value:h,onChange:e=>g(e.target.value),autoComplete:`current-password`,className:i(Ie,`mt-1`)}),(0,R.jsx)(`p`,{className:`mt-1.5 text-[12px] text-muted`,children:a(`No password yet? Use a code first; set one under Account.`)})]}):(0,R.jsxs)(R.Fragment,{children:[_&&(0,R.jsxs)(`div`,{children:[(0,R.jsx)(`label`,{htmlFor:`${o}-code`,className:`text-[12px] text-muted`,children:a(`The code you received`)}),(0,R.jsx)(`input`,{id:`${o}-code`,value:p,onChange:e=>m(e.target.value.replace(/\D/g,``).slice(0,8)),inputMode:`numeric`,autoComplete:`one-time-code`,placeholder:`123456`,autoFocus:!0,className:i(`w-full rounded-2xl bg-surface-2 px-3.5 py-2.5 text-[14.5px] outline-none focus:ring-2 focus:ring-accent/40`,`mt-1 tracking-[0.3em]`)})]}),T?(0,R.jsxs)(`div`,{children:[(0,R.jsx)(`label`,{htmlFor:`${o}-invite`,className:`text-[12px] text-muted`,children:a(`Invite code (optional)`)}),(0,R.jsx)(`input`,{id:`${o}-invite`,value:C,onChange:e=>w(Hh(e.target.value)),autoComplete:`off`,placeholder:`ABCD2345`,className:i(Ie,`mt-1 tracking-[0.2em] uppercase`)}),(0,R.jsx)(`p`,{className:`mt-1.5 text-[12px] text-muted`,children:a(`A friend's code counts for a new account: you both get ¥{invite} more allowance.`,{invite:(c.invite_bonus_cny??5).toFixed(0)})})]}):(0,R.jsx)(`button`,{type:`button`,onClick:()=>E(!0),className:`text-[12px] text-muted underline-offset-2 hover:underline`,children:a(`Have an invite code?`)})]}),x&&(0,R.jsx)(`div`,{className:`rounded-2xl bg-rose-500/12 px-3 py-2 text-[12.5px] text-rose-700 dark:text-rose-300`,children:x}),(0,R.jsx)(`div`,{className:`flex gap-2`,children:l===`code`&&_?(0,R.jsxs)(R.Fragment,{children:[(0,R.jsx)(`button`,{type:`button`,disabled:y!==null,onClick:()=>void O(),className:je,children:a(`Send again`)}),(0,R.jsxs)(`button`,{type:`submit`,disabled:y!==null||p.trim().length<4,className:i(Ne,`flex-1 py-3`),children:[y?(0,R.jsx)(A,{size:15,className:`animate-spin`}):null,` `,j]})]}):l===`code`?(0,R.jsxs)(`button`,{type:`submit`,disabled:y!==null||!d.trim(),className:i(Ne,`flex-1 py-3`),children:[y===`code`?(0,R.jsx)(A,{size:15,className:`animate-spin`}):null,` `,a(`Send me a code`)]}):(0,R.jsxs)(`button`,{type:`submit`,disabled:y!==null||!d.trim()||!h,className:i(Ne,`flex-1 py-3`),children:[y?(0,R.jsx)(A,{size:15,className:`animate-spin`}):null,` `,j]})})]})}function Gh({active:e,onClick:t,icon:n,label:r}){return(0,R.jsxs)(`button`,{type:`button`,onClick:t,"aria-pressed":e,className:i(`flex items-center justify-center gap-1.5 rounded-xl px-2 py-2 transition`,e?`bg-surface text-fg shadow-sm`:`text-muted hover:text-fg`),children:[n,` `,r]})}function Kh(){let{state:e,refreshSettings:t,refreshHub:n,toast:r,skipSignIn:i}=E(),a=s(),o=e.profile?.name??`nanoMuse`,c=(0,R.jsxs)(`ul`,{className:`grid grid-cols-2 gap-2 text-[12.5px] wide:grid-cols-1 wide:gap-1.5 wide:text-[13.5px]`,children:[(0,R.jsx)(qh,{icon:(0,R.jsx)(It,{size:15}),text:a(`Every device of yours, one nanoMuse`)}),(0,R.jsx)(qh,{icon:(0,R.jsx)(st,{size:15}),text:a(`A model with a free allowance, or your own key`)}),(0,R.jsx)(qh,{icon:(0,R.jsx)(vt,{size:15}),text:a(`It uses your phone and computers for you`)}),(0,R.jsx)(qh,{icon:(0,R.jsx)(Qt,{size:15}),text:a(`Keys in your vault; nothing you say is kept on the relay`)})]});return(0,R.jsxs)(`div`,{className:`relative mx-auto flex h-[100dvh] w-full max-w-[760px] flex-col overflow-hidden bg-bg sm:border-x sm:border-border wide:max-w-none wide:border-0`,children:[(0,R.jsx)(`div`,{className:`pointer-events-none absolute inset-x-0 top-0 h-[46vh] bg-[radial-gradient(ellipse_at_top,rgba(0,100,212,0.14),transparent_65%)] dark:bg-[radial-gradient(ellipse_at_top,rgba(23,147,255,0.2),transparent_65%)] wide:inset-y-0 wide:h-auto wide:bg-[radial-gradient(ellipse_at_left,rgba(0,100,212,0.12),transparent_60%)] wide:dark:bg-[radial-gradient(ellipse_at_left,rgba(23,147,255,0.16),transparent_60%)]`}),(0,R.jsx)(`div`,{className:`titlebar-room relative`}),(0,R.jsx)(`div`,{className:`relative flex-1 overflow-y-auto px-6 pb-8 wide:flex wide:items-center wide:px-12`,children:(0,R.jsxs)(`div`,{className:`mx-auto w-full wide:grid wide:max-w-[980px] wide:grid-cols-[1.1fr_1fr] wide:items-center wide:gap-16`,children:[(0,R.jsxs)(`div`,{className:`safe-top flex flex-col items-center pt-14 text-center wide:items-start wide:pt-0 wide:text-left`,children:[(0,R.jsx)(xn,{size:88,className:`drop-shadow-[0_20px_40px_rgba(0,100,212,0.28)]`}),(0,R.jsx)(`h1`,{className:`mt-6 text-[28px] font-bold tracking-tight wide:text-[34px]`,children:a(`Sign in to {name}`,{name:o})}),(0,R.jsx)(`p`,{className:`mt-2 max-w-sm text-[14.5px] leading-relaxed text-muted wide:max-w-md wide:text-[15.5px]`,children:a(`One free account. It is what lets your phone and computers work as one and brings a model to start with.`)}),(0,R.jsx)(`div`,{className:`mt-7 hidden w-full wide:block`,children:c}),(0,R.jsx)(Te,{compact:!0,className:`mt-6 hidden w-full wide:block`})]}),(0,R.jsxs)(`div`,{children:[(0,R.jsx)(`div`,{className:`mt-8 rounded-[28px] border border-border/70 bg-surface p-5 shadow-sm wide:mt-0 wide:p-7`,children:(0,R.jsx)(Wh,{onSignedIn:async()=>{r(a(`Signed in to nanoMuse Cloud.`)),await Promise.all([t(),n()])}})}),(0,R.jsx)(`button`,{type:`button`,onClick:i,className:`mt-4 w-full rounded-2xl border border-border/70 px-4 py-2.5 text-[13.5px] text-fg/80 hover:bg-surface-2`,"data-testid":`sign-in-skip`,children:a(`Use your own API key instead`)}),(0,R.jsx)(`p`,{className:`mt-2 text-center text-[11.5px] leading-relaxed text-muted`,children:a(`You can sign in later under Connections, for sync and your devices.`)}),(0,R.jsx)(`div`,{className:`mt-6 wide:hidden`,children:c}),(0,R.jsx)(Te,{compact:!0,className:`mt-6 wide:hidden`}),(0,R.jsxs)(`p`,{className:`mt-4 text-center text-[11.5px] leading-relaxed text-muted wide:mt-5`,children:[a(`The relay keeps an account id, a masked identifier, usage counts and your agent's name and look; what else, and what is yours to switch off, is in the`),` `,(0,R.jsx)(`a`,{href:Lh,target:`_blank`,rel:`noopener noreferrer`,className:`underline decoration-dotted underline-offset-2 hover:text-fg`,children:a(`privacy policy`)}),`.`]})]})]})})]})}function qh({icon:e,text:t}){return(0,R.jsxs)(`li`,{className:`flex items-start gap-2 rounded-2xl bg-surface-2/60 px-3 py-2.5 text-fg/80 wide:bg-transparent wide:px-0 wide:py-1`,children:[(0,R.jsx)(`span`,{className:`mt-0.5 text-accent`,children:e}),(0,R.jsx)(`span`,{className:`leading-snug`,children:t})]})}function Jh(e,t,n){return!e||!e.account.required||e.account.signed_in||t?.llm_ready?!1:!n}var Yh=`modulepreload`,Xh=function(e){return`/`+e},Zh={},Qh=function(e){return e.pathname.endsWith(`.css`)},$h=function(e,t,n){let r=Promise.resolve();if(t&&t.length>0){let e,i=document.querySelector(`meta[property=csp-nonce]`),a=i?.nonce||i?.getAttribute(`nonce`);function o(e){return Promise.all(e.map(e=>Promise.resolve(e).then(e=>({status:`fulfilled`,value:e}),e=>({status:`rejected`,reason:e}))))}function s(e){return import.meta.resolve?new URL(import.meta.resolve(e)):new URL(e,import.meta.url)}r=o(t.map(t=>{t=Xh(t,n);let r=s(t);if(r.href in Zh)return;Zh[r.href]=!0;let i=Qh(r);if(e===void 0){e={all:new Set,styles:new Set};let t=document.getElementsByTagName(`link`);for(let n=t.length-1;n>=0;n--){let r=t[n];e.all.add(r.href),r.rel===`stylesheet`&&e.styles.add(r.href)}}if((i?e.styles:e.all).has(r.href))return;let o=document.createElement(`link`);if(o.rel=i?`stylesheet`:Yh,i||(o.as=`script`),o.crossOrigin=``,o.href=r.href,a&&o.setAttribute(`nonce`,a),document.head.appendChild(o),i)return new Promise((e,t)=>{o.addEventListener(`load`,e),o.addEventListener(`error`,()=>t(Error(`Unable to preload CSS for ${r}`)))})}).filter(e=>e!==void 0))}function i(e){let t=new Event(`vite:preloadError`,{cancelable:!0});if(t.payload=e,window.dispatchEvent(t),!t.defaultPrevented)throw e}return r.then(t=>{for(let e of t||[])e.status===`rejected`&&i(e.reason);return e().catch(i)})},eg=(0,L.lazy)(()=>$h(()=>import(`./AccountScreen-bHMDrVr5.js`).then(e=>({default:e.AccountScreen})),__vite__mapDeps([0,1,2,3,4,5,6,7,8]))),tg=(0,L.lazy)(()=>$h(()=>import(`./AvatarStudioScreen-DD2X0R8P.js`).then(e=>({default:e.AvatarStudioScreen})),__vite__mapDeps([9,1,2,3,4,10,8,11]))),ng=(0,L.lazy)(()=>$h(()=>import(`./ChannelsScreen-mBzj7BLf.js`).then(e=>({default:e.ChannelsScreen})),__vite__mapDeps([12,1,3,4,10,8]))),rg=(0,L.lazy)(()=>$h(()=>import(`./CodingScreen-C_tutsx0.js`).then(e=>({default:e.CodingScreen})),__vite__mapDeps([13,1,4,10,8]))),ig=(0,L.lazy)(()=>$h(()=>import(`./ConnectionsScreen-CMt7GOff.js`).then(e=>({default:e.ConnectionsScreen})),__vite__mapDeps([14,1,2,3,4,5,7,15,10,8,16]))),ag=(0,L.lazy)(()=>$h(()=>import(`./DevicesScreen-g6FUY327.js`).then(e=>({default:e.DevicesScreen})),__vite__mapDeps([17,1,3,4,10,8,16]))),og=(0,L.lazy)(()=>$h(()=>import(`./GoalsScreen-Dp2fRaLA.js`).then(e=>({default:e.GoalsScreen})),__vite__mapDeps([18,1,2,3,4]))),sg=(0,L.lazy)(()=>$h(()=>import(`./IdeasScreen-CGfvq5H-.js`).then(e=>({default:e.IdeasScreen})),__vite__mapDeps([19,1,10]))),cg=(0,L.lazy)(()=>$h(()=>import(`./LibraryScreen-B8JlrC_n.js`).then(e=>({default:e.LibraryScreen})),__vite__mapDeps([20,1]))),lg=(0,L.lazy)(()=>$h(()=>import(`./MemoryScreen-M8j03G3u.js`).then(e=>({default:e.MemoryScreen})),__vite__mapDeps([21,1,8]))),ug=(0,L.lazy)(()=>$h(()=>import(`./Onboarding-CtVO6gdK.js`).then(e=>({default:e.Onboarding})),__vite__mapDeps([22,1,2,3,4,23,11,14,5,7,15,10,8,16]))),dg=(0,L.lazy)(()=>$h(()=>import(`./SettingsScreen-CHVg61To.js`).then(e=>({default:e.SettingsScreen})),__vite__mapDeps([24,1,2,3,4,5,6,15,23,11,8]))),fg=(0,L.lazy)(()=>$h(()=>import(`./SkillsScreen-Dr-d7iS7.js`).then(e=>({default:e.SkillsScreen})),__vite__mapDeps([25,1,8])));function pg(){return(0,R.jsx)(`div`,{className:`flex h-full min-h-[40vh] items-center justify-center text-muted`,children:(0,R.jsx)(A,{className:`animate-spin`,size:20})})}var mg=e=>({size:26,strokeWidth:e?2:1.7,fill:e?`currentColor`:`none`,fillOpacity:e?.18:0}),hg=[{id:`chat`,label:`Chat`,icon:e=>(0,R.jsx)(At,{...mg(e)})},{id:`feed`,label:`Feed`,icon:e=>(0,R.jsx)(Bt,{...mg(e)})},{id:`ideas`,label:`Ideas`,icon:e=>(0,R.jsx)(Ct,{...mg(e)})},{id:`goals`,label:`Goals`,icon:e=>(0,R.jsx)(rn,{...mg(e)})},{id:`library`,label:`Library`,icon:e=>(0,R.jsx)(St,{...mg(e)})}];function gg(){let{state:e,setTab:t,openFile:n}=E(),r=Wf(),a=s();(0,L.useEffect)(()=>{let t=e.profile?.name?.trim();document.title=t&&t.toLowerCase()!==`nanomuse`?`${t} · nanoMuse`:`nanoMuse`},[e.profile?.name]),(0,L.useEffect)(()=>{let e=Sn()?.onQuickChat?.(()=>{t(`chat`),requestAnimationFrame(()=>window.dispatchEvent(new Event(`nanomuse:quick-chat`)))});return()=>{typeof e==`function`&&e()}},[t]),(0,L.useEffect)(()=>{let e=()=>{let e=window.location.hash.slice(1);(e&&hg.some(t=>t.id===e)||e===`devices`||e===`you`||e===`memory`||e===`connections`||e===`channels`||e===`skills`||e===`account`||e===`coding`||e===`avatar`)&&t(e)};return e(),window.addEventListener(`hashchange`,e),()=>window.removeEventListener(`hashchange`,e)},[t]);let o=r&&e.hub?.account.signed_in?(0,R.jsx)(Gf,{}):null,c=e.lite&&e.settings!==null&&!e.settings.onboarded;if((0,L.useEffect)(()=>{c&&M.onboarded(!0).catch(()=>void 0)},[c]),e.authError)return(0,R.jsx)(vg,{});if(!e.loaded)return(0,R.jsx)(_g,{error:e.error});if(Jh(e.hub,e.settings,e.signInSkipped))return(0,R.jsx)(Kh,{});if(!e.lite&&e.settings&&!e.settings.onboarded&&!e.onboardingDismissed&&!e.threads.some(e=>e.events>0))return(0,R.jsxs)(L.Suspense,{fallback:(0,R.jsx)(pg,{}),children:[(0,R.jsx)(ug,{}),o]});let l=e.pendingApprovals.length,u=e.goals.filter(e=>e.proposal&&e.status!==`cancelled`).length,d=e.pendingApprovals.filter(t=>t.ts>e.feedSeenAt).length;return(0,R.jsxs)(`div`,{className:i(`mx-auto flex h-[100dvh] max-w-[760px] flex-col bg-bg sm:border-x sm:border-border`,!e.lite&&`wide:max-w-none wide:flex-row wide:border-x-0`),children:[!e.lite&&(0,R.jsx)(`div`,{className:`hidden wide:block wide:h-full`,children:(0,R.jsx)(uh,{})}),(0,R.jsxs)(`div`,{className:`relative flex min-h-0 min-w-0 flex-1 flex-col`,children:[e.gone&&(0,R.jsxs)(`div`,{className:`flex items-center justify-center gap-2 bg-surface-2 text-muted text-[12.5px] py-1`,children:[(0,R.jsx)(vn,{size:14}),` `,a(e.lite?`This demo has ended.`:`This nanoMuse has stopped. Reload the page once it is running again.`)]}),!e.gone&&!e.connected&&e.loaded&&(0,R.jsxs)(`div`,{className:`flex items-center justify-center gap-2 bg-amber-500/15 text-amber-700 dark:text-amber-300 text-[12.5px] py-1`,children:[(0,R.jsx)(vn,{size:14}),` `,a(`Reconnecting to your nanoMuse…`)]}),!e.lite&&(0,R.jsx)(En,{}),(0,R.jsx)(`main`,{className:i(`tabbar-room mx-auto min-h-0 w-full flex-1 wide:max-w-[900px]`,!e.lite&&`wide:pb-0`),children:(0,R.jsxs)(L.Suspense,{fallback:(0,R.jsx)(pg,{}),children:[e.tab===`chat`&&(0,R.jsx)(Wm,{}),e.tab===`feed`&&(0,R.jsx)(dh,{}),e.tab===`ideas`&&(0,R.jsx)(sg,{}),e.tab===`goals`&&(0,R.jsx)(og,{}),e.tab===`library`&&(0,R.jsx)(cg,{}),e.tab===`memory`&&(0,R.jsx)(lg,{}),e.tab===`skills`&&(0,R.jsx)(fg,{}),e.tab===`connections`&&(0,R.jsx)(ig,{}),e.tab===`channels`&&(0,R.jsx)(ng,{}),e.tab===`devices`&&(0,R.jsx)(ag,{}),e.tab===`you`&&(0,R.jsx)(dg,{}),e.tab===`account`&&(0,R.jsx)(eg,{}),e.tab===`coding`&&(0,R.jsx)(rg,{}),e.tab===`avatar`&&(0,R.jsx)(tg,{})]})}),(0,R.jsx)(`nav`,{className:i(`tabbar-float pointer-events-none absolute inset-x-0 z-20 flex justify-center px-4`,!e.lite&&`wide:hidden`),children:(0,R.jsx)(`ul`,{className:`pointer-events-auto flex items-center gap-0.5 rounded-full bg-surface-2/55 px-3.5 py-2 ring-1 ring-border/50 backdrop-blur-2xl`,children:hg.map(n=>{let r=e.tab===n.id,o=n.id===`chat`?l:n.id===`feed`?d:n.id===`goals`?u:0;return(0,R.jsx)(`li`,{children:(0,R.jsxs)(`button`,{type:`button`,onClick:()=>t(n.id),"aria-label":a(n.label),"aria-current":r?`page`:void 0,className:i(`relative flex h-[46px] w-[60px] items-center justify-center rounded-full transition-colors duration-300`,r?`bg-accent-soft text-accent-soft-fg`:`text-muted hover:text-fg`),children:[n.icon(r),o>0&&(0,R.jsx)(`span`,{className:`absolute right-2.5 top-1 flex h-[17px] min-w-[17px] items-center justify-center rounded-full bg-rose-500 px-1 text-[10px] font-bold text-white`,children:o})]})},n.id)})})})]}),(0,R.jsx)(kn,{}),(0,R.jsx)(gf,{path:e.viewer,onClose:()=>n(null)}),o,e.toast&&(0,R.jsx)(`div`,{className:`pointer-events-none fixed inset-x-0 bottom-[calc(6rem+env(safe-area-inset-bottom))] z-[70] flex justify-center px-4`,children:(0,R.jsx)(`div`,{className:`rise rounded-2xl bg-fg text-bg px-4 py-2 text-[13.5px] shadow-lg max-w-sm text-center`,children:e.toast})})]})}function _g({error:e}){let t=s();return(0,R.jsxs)(`div`,{className:`mx-auto flex h-[100dvh] max-w-sm flex-col items-center justify-center px-6 text-center`,children:[(0,R.jsx)(xn,{size:72}),e?(0,R.jsxs)(R.Fragment,{children:[(0,R.jsx)(`p`,{className:`mt-6 text-[15px] font-medium`,children:t(`Could not reach your nanoMuse.`)}),(0,R.jsx)(`p`,{className:`mt-1.5 text-[13px] text-muted`,children:t(e)}),(0,R.jsx)(`button`,{type:`button`,onClick:()=>window.location.reload(),className:`mt-5 rounded-full bg-fg px-5 py-2 text-[14px] font-medium text-bg`,children:t(`Try again`)})]}):(0,R.jsxs)(`p`,{className:`mt-6 flex items-center gap-2 text-[14px] text-muted`,children:[(0,R.jsx)(A,{className:`animate-spin`,size:16}),` `,t(`Connecting to your nanoMuse…`)]})]})}function vg(){let[e,t]=(0,L.useState)(``),n=s();return(0,R.jsxs)(`div`,{className:`mx-auto flex h-[100dvh] max-w-md flex-col items-center justify-center px-6 text-center`,children:[(0,R.jsx)(xn,{size:88}),(0,R.jsx)(`h1`,{className:`mt-4 text-[22px] font-bold`,children:n(`Connect to your nanoMuse`)}),(0,R.jsxs)(`p`,{className:`mt-2 text-[14px] text-muted`,children:[n(`This app talks to the nanoMuse server you run yourself. Scan the QR code printed by`),` `,(0,R.jsx)(`code`,{className:`rounded bg-surface-2 px-1`,children:`nanomuse serve`}),n(`, or paste the access token below.`)]}),(0,R.jsxs)(`form`,{className:`mt-5 w-full flex gap-2`,onSubmit:t=>{t.preventDefault(),e.trim()&&(g(e.trim()),window.location.reload())},children:[(0,R.jsx)(`input`,{value:e,onChange:e=>t(e.target.value),"aria-label":n(`Access token`),placeholder:n(`Access token`),className:`flex-1 rounded-2xl bg-surface-2 px-4 py-2.5 text-[15px] outline-none focus:ring-2 focus:ring-accent/40`}),(0,R.jsx)(`button`,{type:`submit`,className:`rounded-2xl bg-accent text-accent-fg px-4 font-medium`,children:n(`Connect`)})]})]})}a(),ee(),wn(),bn.createRoot(document.getElementById(`root`)).render((0,R.jsx)(L.StrictMode,{children:(0,R.jsx)(T,{children:(0,R.jsx)(gg,{})})}));export{Ut as $,Ff as A,gn as B,Jp as C,Ze as Ct,rp as D,Ke as Dt,ip as E,qe as Et,hf as F,tn as G,sn as H,Mn as I,Xt as J,Qt as K,Sn as L,Nf as M,Pf as N,Zf as O,Af as P,Gt as Q,Cn as R,tm as S,Qe as St,op as T,Je as Tt,on as U,fn as V,nn as W,qt as X,Jt as Y,I as Z,nm as _,ct as _t,Ah as a,Nt as at,rm as b,rt as bt,Ih as c,Tt as ct,Um as d,F as dt,Ht as et,Em as f,vt as ft,Xp as g,ut as gt,Qp as h,pt as ht,Fh as i,It as it,jf as j,$f as k,Nh as l,wt as lt,Yp as m,mt,Rh as n,Rt as nt,jh as o,At as ot,Zp as p,gt as pt,Zt as q,Lh as r,Lt as rt,Mh as s,Et as st,Wh as t,Vt as tt,Vm as u,xt as ut,im as v,st as vt,Op as w,Xe as wt,$p as x,tt as xt,em as y,at as yt,yn as z}; \ No newline at end of file +`).replace(/\\([,;\\])/g,`$1`),a=(e,t)=>{if(/VALUE=DATE(?![-])/i.test(t)||/^\d{8}$/.test(e)){let t=/^(\d{4})(\d{2})(\d{2})/.exec(e);return{at:t?new Date(+t[1],t[2]-1,+t[3]):null,allDay:!0}}let n=/^(\d{4})(\d{2})(\d{2})T(\d{2})(\d{2})(\d{2})?(Z?)$/.exec(e);if(!n)return{at:null,allDay:!1};let r=[+n[1],n[2]-1,+n[3],+n[4],+n[5],+(n[6]??0)];return{at:n[7]?new Date(Date.UTC(...r)):new Date(...r),allDay:!1}};for(let e of t)if(e===`BEGIN:VEVENT`)r={summary:``,location:``,description:``,start:null,end:null,allDay:!1};else if(e===`END:VEVENT`&&r)n.push(r),r=null;else if(r){let t=e.indexOf(`:`);if(t<0)continue;let[n,...o]=e.slice(0,t).split(`;`),s=e.slice(t+1),c=o.join(`;`);if(n===`SUMMARY`)r.summary=i(s);else if(n===`LOCATION`)r.location=i(s);else if(n===`DESCRIPTION`)r.description=i(s);else if(n===`DTSTART`){let e=a(s,c);r.start=e.at,r.allDay=e.allDay}else n===`DTEND`&&(r.end=a(s,c).at)}return n}function Sf(e){if(!e.start)return``;let t=m(),n=e=>e.toLocaleDateString(t,{weekday:`short`,year:`numeric`,month:`short`,day:`numeric`}),r=e=>e.toLocaleTimeString(t,{hour:`numeric`,minute:`2-digit`});if(e.allDay){let t=e.end?new Date(e.end.getTime()-864e5):e.start;return t>e.start?`${n(e.start)} – ${n(t)}`:`${n(e.start)} · ${_(`all day`)}`}return e.end?e.start.toDateString()===e.end.toDateString()?`${n(e.start)} ${r(e.start)}–${r(e.end)}`:`${n(e.start)} ${r(e.start)} – ${n(e.end)} ${r(e.end)}`:`${n(e.start)} ${r(e.start)}`}function Cf({path:e,kind:t}){let{text:n,error:r}=vf(e);return r?(0,R.jsx)(Ef,{error:r}):n===null?(0,R.jsx)(Tf,{}):t===`text`&&/\.md$/i.test(e)?(0,R.jsx)(`div`,{className:`mx-auto max-w-[720px] px-5 py-4`,children:(0,R.jsx)(hf,{text:n})}):t===`data`&&/\.csv$/i.test(e)?(0,R.jsx)(wf,{text:n}):(0,R.jsx)(`pre`,{className:`whitespace-pre-wrap break-words px-4 py-3 font-mono text-[12.5px] leading-relaxed`,children:n})}function wf({text:e}){let t=s(),n=e.split(/\r?\n/).filter(e=>e.trim()).slice(0,500).map(e=>e.split(`,`));if(!n.length)return(0,R.jsx)(`div`,{className:`p-6 text-muted text-center`,children:t(`Empty file.`)});let[r,...i]=n;return(0,R.jsx)(`div`,{className:`overflow-auto p-3`,children:(0,R.jsxs)(`table`,{className:`min-w-full text-[13px] border-separate border-spacing-0`,children:[(0,R.jsx)(`thead`,{children:(0,R.jsx)(`tr`,{children:r.map((e,t)=>(0,R.jsx)(`th`,{className:`sticky top-0 bg-surface-2 text-left font-semibold px-3 py-2 border-b border-border whitespace-nowrap`,children:e},t))})}),(0,R.jsx)(`tbody`,{children:i.map((e,t)=>(0,R.jsx)(`tr`,{className:`odd:bg-surface`,children:e.map((e,t)=>(0,R.jsx)(`td`,{className:`px-3 py-1.5 border-b border-border/60 whitespace-nowrap`,children:e},t))},t))})]})})}function Tf(){return(0,R.jsx)(`div`,{className:`flex h-full items-center justify-center text-muted`,children:(0,R.jsx)(A,{className:`animate-spin`,size:22})})}function Ef({error:e}){let t=s();return(0,R.jsx)(`div`,{className:`p-8 text-center text-rose-600 dark:text-rose-300 text-[14px]`,children:t(`Could not load the file: {error}`,{error:e})})}var Df=`OpenAI's terms cover using a ChatGPT plan inside OpenAI's own Codex; other apps have had this access cut off before (OpenCode, January 2026). If it stops working, an API key does.`,Of=2e3,kf=6e5;function Af({compact:e,onChanged:t}){let n=s(),{toast:r}=E(),[a,o]=(0,L.useState)(null),[c,l]=(0,L.useState)(`unknown`),[u,d]=(0,L.useState)(null),[f,p]=(0,L.useState)(null),[m,h]=(0,L.useState)(!0),[g,_]=(0,L.useState)(``),[v,y]=(0,L.useState)(null),b=(0,L.useRef)(0),x=(0,L.useCallback)(async()=>{try{let e=await M.chatgptStatus();return o(e),l(`yes`),e}catch(e){return/not found/i.test(e.message)?l(`no`):y(e.message),null}},[]);(0,L.useEffect)(()=>{x().then(e=>{e?.pending&&e.url&&(b.current=Date.now(),h(e.port_bound!==!1),p(e.url))})},[x]),(0,L.useEffect)(()=>{if(!f)return;let e=setInterval(()=>{x().then(e=>{e?.signed_in?(p(null),Ee(),r(n(`Signed in with {label}.`,{label:e.label||`ChatGPT`})),t?.()):e&&e.pending===!1&&e.error?(p(null),y(n(e.error))):Date.now()-b.current>kf&&(p(null),y(n(`The sign-in did not finish in ten minutes. Try again.`)))})},Of);return()=>clearInterval(e)},[f,x,t,r,n]);let S=async()=>{d(`login`),y(null);try{let e=await M.chatgptLogin();b.current=Date.now(),h(e.port_bound!==!1),_(``),p(e.url),window.open(e.url,`_blank`,`noopener`)}catch(e){/not found/i.test(e.message)?l(`no`):y(e.message)}finally{d(null)}},C=async()=>{let e=g.trim();if(e){d(`paste`),y(null);try{await M.chatgptCallback(e),_(``)}catch(e){let t=e.message;/state/i.test(t)?y(n(`That address belongs to another sign-in attempt. Open the page again and paste the address it ends on.`)):/no sign-in|409/i.test(t)?(p(null),y(n(`The sign-in did not finish in ten minutes. Try again.`))):y(t)}finally{d(null)}}},w=async()=>{d(`use`),y(null);try{await M.setLLM({provider:`chatgpt`,model:a?.models?.[0]??``,base_url:``,api_key:``}),Ee(),r(n(`ChatGPT answers the chat now.`)),t?.()}catch(e){y(e.message)}finally{d(null)}},T=async()=>{d(`logout`),y(null);try{await M.chatgptLogout(),Ee(),await x(),t?.()}catch(e){y(e.message)}finally{d(null)}},D=n(`Covers chat and the hands. Pictures and clips are not part of it; those need a provider with image or video models.`);return(0,R.jsxs)(`div`,{className:i(`space-y-2`,!e&&`rounded-2xl bg-surface-2/60 p-3`),children:[!e&&(0,R.jsxs)(`div`,{className:`flex items-center gap-2 text-[13px] font-medium`,children:[(0,R.jsx)(Mt,{size:15,className:`text-accent`}),` `,n(`Sign in with ChatGPT`)]}),c===`no`?(0,R.jsxs)(`p`,{className:`text-[12.5px] text-muted`,children:[n(`This nanoMuse has no sign-in route yet. In a terminal on this computer, run`),` `,(0,R.jsx)(`code`,{className:`rounded bg-surface-2 px-1 py-0.5 text-[12px]`,children:`nanomuse chatgpt login`}),` `,n(`and reload this page.`)]}):a?.signed_in?(0,R.jsxs)(`div`,{className:`space-y-2`,children:[(0,R.jsxs)(`p`,{className:`text-[12.5px]`,children:[(0,R.jsx)(`span`,{className:`font-medium`,children:n(`Signed in with {label}.`,{label:a.label||`ChatGPT`})}),` `,(0,R.jsx)(`span`,{className:`text-muted`,children:D})]}),(0,R.jsxs)(`div`,{className:`flex flex-wrap gap-2`,children:[(0,R.jsxs)(`button`,{type:`button`,disabled:u!==null,onClick:()=>void w(),className:i(Ne,`inline-flex items-center gap-1.5 py-2`),children:[u===`use`?(0,R.jsx)(A,{size:14,className:`animate-spin`}):(0,R.jsx)(Mt,{size:14}),` `,n(`Use it for the chat`)]}),(0,R.jsxs)(`button`,{type:`button`,disabled:u!==null,onClick:()=>void T(),className:i(je,`inline-flex items-center gap-1.5`),children:[u===`logout`?(0,R.jsx)(A,{size:14,className:`animate-spin`}):(0,R.jsx)(Tt,{size:14}),` `,n(`Sign out of ChatGPT`)]})]})]}):f?(0,R.jsxs)(`div`,{className:`space-y-2`,children:[(0,R.jsxs)(`p`,{className:`flex items-start gap-2 text-[12.5px] text-muted`,children:[(0,R.jsx)(A,{size:14,className:`mt-0.5 shrink-0 animate-spin`}),(0,R.jsx)(`span`,{children:n(m?`A page from OpenAI opened in a new tab. Sign in there; this card follows on its own.`:`A page from OpenAI opened in a new tab. Sign in there; when the browser ends on an address that will not load, paste that address below.`)})]}),(0,R.jsxs)(`div`,{className:`flex flex-wrap gap-2`,children:[(0,R.jsxs)(`a`,{href:f,target:`_blank`,rel:`noopener noreferrer`,className:i(je,`inline-flex items-center gap-1.5`),children:[(0,R.jsx)(Ae,{size:14}),` `,n(`Open the page again`)]}),(0,R.jsx)(`button`,{type:`button`,onClick:()=>p(null),className:je,children:n(`Cancel`)})]}),(0,R.jsxs)(`form`,{className:`flex flex-wrap items-center gap-2`,onSubmit:e=>{e.preventDefault(),C()},children:[(0,R.jsx)(`input`,{type:`url`,value:g,onChange:e=>_(e.target.value),placeholder:`http://localhost:1455/auth/callback?code=…`,"aria-label":n(`The address the browser ended on`),className:`min-w-0 flex-1 rounded-lg border border-border bg-surface px-2 py-1.5 text-[12.5px]`}),(0,R.jsxs)(`button`,{type:`submit`,disabled:u!==null||!g.trim(),className:i(je,`inline-flex items-center gap-1.5`),children:[u===`paste`?(0,R.jsx)(A,{size:14,className:`animate-spin`}):null,` `,n(`Use this address`)]})]}),!m&&(0,R.jsx)(`p`,{className:`text-[11.5px] text-muted`,children:n(`This nanoMuse runs where the browser cannot reach port 1455, so it cannot pick the sign-in up by itself.`)})]}):(0,R.jsxs)(`div`,{className:`space-y-2`,children:[(0,R.jsx)(`p`,{className:`text-[12.5px] text-muted`,children:D}),(0,R.jsxs)(`button`,{type:`button`,disabled:u!==null||c===`unknown`,onClick:()=>void S(),className:i(Ne,`inline-flex items-center gap-1.5 py-2`),children:[u===`login`?(0,R.jsx)(A,{size:14,className:`animate-spin`}):(0,R.jsx)(wt,{size:14}),` `,n(`Sign in with ChatGPT`)]})]}),(0,R.jsx)(`p`,{className:`text-[11.5px] leading-snug text-muted`,children:n(Df)}),v&&(0,R.jsx)(`p`,{className:`text-[12px] text-rose-600 dark:text-rose-300`,children:v})]})}var jf=xe,Mf=`nm.connections.preset`;function Nf(e,t=_e().preset){try{sessionStorage.setItem(Mf,t)}catch{}e(`connections`)}function Pf(){try{let e=sessionStorage.getItem(Mf);return e&&sessionStorage.removeItem(Mf),e}catch{return null}}function Ff({info:e,exhausted:t,compact:n}){let r=s(),{toast:a,setTab:o,state:l}=E(),u=l.hub?.account,d=_e(u),f=ae(u),p=c(),m=e.invite_bonus_cny??5,h=e.own_key_docs||e.guidance?.docs||jf,g=e.invite_url||``,[_,v]=(0,L.useState)(!1),[y,b]=(0,L.useState)(!1),x=(e.guidance?.providers??de(f)).filter(e=>e.id!==d.id).map(e=>({id:e.id,name:De(e,p),keyUrl:e.key_url,covers:`covers`in e?e.covers:e.capabilities})),S=Oe().map(e=>e.name),C=async e=>{try{await navigator.clipboard.writeText(e),a(r(`Copied`))}catch{a(e)}},w=async()=>{let e=r(`Try nanoMuse with me, a fully open-source personal agent, free to use. Sign up with my link: {link}`,{link:g}),t=navigator;if(t.share)try{await t.share({text:e});return}catch{}await C(e)},T=Ce(),[D,O]=me(`exhausted`,t),k=ve(be(r,`exhausted`)),ee=t?r(`The free allowance is used up.`):r(`Nearly used up: ¥{left} of ¥{grant} left.`,{left:(e.left??0).toFixed(2),grant:(e.grant??0).toFixed(0)});return(0,R.jsxs)(`div`,{className:i(`space-y-2.5`,!n&&`pt-1`),children:[(0,R.jsxs)(`div`,{children:[(0,R.jsx)(`div`,{className:i(`font-semibold`,n?`text-[13.5px]`:`text-[15px]`),children:ee}),(0,R.jsx)(`div`,{className:`mt-0.5 text-[12.5px] text-muted`,children:r(`Three ways on; your sign-in and your devices keep working whichever you pick.`)})]}),(0,R.jsxs)(If,{icon:(0,R.jsx)(xt,{size:16}),tone:`bg-accent/12 text-accent`,title:r(`Use your own model key`),children:[(0,R.jsx)(`p`,{className:`text-[12.5px] text-muted`,children:ie(r,u)}),(0,R.jsxs)(`div`,{className:`flex flex-wrap gap-2`,children:[(0,R.jsxs)(`button`,{type:`button`,onClick:()=>Nf(o,d.preset),className:i(Ne,`inline-flex items-center gap-1.5 py-2`),children:[(0,R.jsx)(xt,{size:14}),` `,r(`Set it up`)]}),(0,R.jsxs)(`a`,{href:d.keyUrl,target:`_blank`,rel:`noopener noreferrer`,className:i(je,`inline-flex items-center gap-1.5`),children:[(0,R.jsx)(Ae,{size:14}),` `,r(`Get a key from {vendor}`,{vendor:d.label})]}),(0,R.jsxs)(`a`,{href:h,target:`_blank`,rel:`noopener noreferrer`,className:i(je,`inline-flex items-center gap-1.5`),children:[(0,R.jsx)(Ae,{size:14}),` `,r(`Step-by-step guide`)]})]}),x.length>0&&(0,R.jsxs)(`div`,{children:[(0,R.jsxs)(`button`,{type:`button`,onClick:()=>v(!_),className:`inline-flex items-center gap-1 text-[12px] text-muted`,children:[_?(0,R.jsx)(Le,{size:13}):(0,R.jsx)(Me,{size:13}),` `,r(`Other providers and what each key covers`)]}),_&&(0,R.jsx)(`ul`,{className:`mt-1.5 space-y-1 text-[12.5px]`,children:x.map(e=>(0,R.jsxs)(`li`,{className:`flex flex-wrap items-baseline justify-between gap-x-3`,children:[(0,R.jsxs)(`span`,{children:[(0,R.jsx)(`span`,{className:`font-medium`,children:e.name}),` `,(0,R.jsxs)(`span`,{className:`text-muted`,children:[`· `,he(r,e.covers)]})]}),(0,R.jsxs)(`span`,{className:`flex gap-2`,children:[(0,R.jsx)(`button`,{type:`button`,onClick:()=>Nf(o,pe(e.id)),className:`text-accent`,children:r(`Set it up`)}),(0,R.jsxs)(`a`,{href:e.keyUrl,target:`_blank`,rel:`noopener noreferrer`,className:`inline-flex items-center gap-0.5 text-accent`,children:[r(`Get a key`),` `,(0,R.jsx)(Ae,{size:11})]})]})]},e.id))})]})]}),(0,R.jsxs)(If,{icon:(0,R.jsx)(wt,{size:16}),tone:`bg-emerald-500/12 text-emerald-600 dark:text-emerald-300`,title:r(`Sign in with a plan you already pay for`),children:[(0,R.jsx)(`p`,{className:`text-[12.5px] text-muted`,children:r(`{plans}: the plan's models answer here, no key to make. ChatGPT works on every device, the others on the phones. A ChatGPT sign-in covers chat and the hands; pictures and clips still want a key.`,{plans:S.join(r(`, `))})}),y?(0,R.jsx)(Af,{compact:!0,onChanged:()=>b(!1)}):(0,R.jsxs)(`button`,{type:`button`,onClick:()=>b(!0),className:i(je,`inline-flex items-center gap-1.5`),children:[(0,R.jsx)(wt,{size:14}),` `,r(`Sign in with ChatGPT`)]})]}),(0,R.jsx)(If,{icon:(0,R.jsx)(hn,{size:16}),tone:`bg-violet-500/12 text-violet-600 dark:text-violet-300`,title:r(`Invite a friend: +¥{bonus} for you and +¥{bonus} for them, for each new person who signs up with your link.`,{bonus:m.toFixed(0)}),children:g?(0,R.jsxs)(`div`,{className:`flex flex-wrap gap-2`,children:[(0,R.jsxs)(`button`,{type:`button`,onClick:()=>void w(),className:i(je,`inline-flex items-center gap-1.5`),children:[(0,R.jsx)(Xt,{size:14}),` `,r(`Share the link`)]}),(0,R.jsxs)(`button`,{type:`button`,onClick:()=>void C(g),className:i(je,`inline-flex items-center gap-1.5`),children:[(0,R.jsx)(ut,{size:14}),` `,r(`Copy the link`)]})]}):(0,R.jsxs)(`button`,{type:`button`,onClick:()=>o(`account`),className:i(je,`inline-flex items-center gap-1.5`),children:[(0,R.jsx)(Xt,{size:14}),` `,r(`Your invite link is under Account`)]})}),t&&D&&(0,R.jsxs)(If,{icon:(0,R.jsx)(ce,{size:16}),tone:`bg-amber-400/15 text-amber-600 dark:text-amber-300`,title:k,children:[(0,R.jsxs)(`button`,{type:`button`,onClick:()=>fe(T.repo_url),className:i(`flex items-center justify-center gap-1.5 rounded-2xl border border-border px-4 py-2.5 text-[14px] font-medium text-muted disabled:opacity-40`,`inline-flex items-center gap-1.5`),children:[(0,R.jsx)(ce,{size:14}),` `,r(`Star on GitHub`)]}),(0,R.jsx)(`button`,{type:`button`,onClick:()=>{ge(),O(!1)},className:i(`flex items-center justify-center gap-1.5 rounded-2xl border border-border px-4 py-2.5 text-[14px] font-medium text-muted disabled:opacity-40`,`inline-flex items-center gap-1.5`),children:r(`I already starred`)})]})]})}function If({icon:e,tone:t,title:n,children:r}){return(0,R.jsxs)(`div`,{className:`flex gap-3 rounded-2xl bg-surface-2/60 p-3`,children:[(0,R.jsx)(`span`,{className:i(`flex h-8 w-8 shrink-0 items-center justify-center rounded-xl`,t),children:e}),(0,R.jsxs)(`div`,{className:`min-w-0 flex-1 space-y-2`,children:[(0,R.jsx)(`div`,{className:`text-[13px] font-medium leading-snug`,children:n}),r]})]})}var Lf=`nm.cloud.warned_grant`;function Rf(){let e=s(),{state:t,setTab:n}=E(),[r,i]=(0,L.useState)(null),a=(0,L.useRef)(0),o=t.hub?.account,c=!!o?.signed_in&&!!o.is_model,l=t.finishedAt;if((0,L.useEffect)(()=>{if(!c||!l||r||Date.now()-a.current<6e4)return;a.current=Date.now();let e=!1;return M.cloudMe().then(t=>{if(e)return;let n=t.spend,r=n.grant??n.allowance_cny??0,a=n.left??null;if(n.unlimited||!n.warn||a===null||a<=0)return;let o=null;try{o=localStorage.getItem(Lf)}catch{}o!==String(r)&&i({left:a,grant:r,invite_url:t.invite?.url,invite_bonus_cny:n.invite_bonus_cny,invitee_bonus_cny:n.invitee_bonus_cny,own_key_docs:n.own_key_docs,guidance:n.guidance})}).catch(()=>{}),()=>{e=!0}},[c,l,r]),!r)return null;let u=()=>{try{localStorage.setItem(Lf,String(r.grant??0))}catch{}i(null)};return(0,R.jsxs)(`div`,{className:`rise mx-3 mb-1.5 flex items-start gap-2 rounded-2xl bg-amber-500/12 px-3 py-2 text-[12.5px] leading-snug text-amber-800 dark:text-amber-200`,children:[(0,R.jsx)(nn,{size:14,className:`mt-0.5 shrink-0`}),(0,R.jsxs)(`div`,{className:`min-w-0 flex-1`,children:[e(`Nearly used up: ¥{left} of ¥{grant} left.`,{left:(r.left??0).toFixed(2),grant:(r.grant??0).toFixed(0)}),` `,e(`Invite a friend (+¥{invite} for each of you) or bring your own key; your sign-in keeps working either way.`,{invite:(r.invite_bonus_cny??5).toFixed(0)}),` `,(0,R.jsx)(`button`,{type:`button`,onClick:()=>{u(),n(`account`)},className:`font-semibold underline decoration-dotted underline-offset-2`,children:e(`See the ways`)})]}),(0,R.jsx)(`button`,{type:`button`,onClick:u,"aria-label":e(`Dismiss`),className:`shrink-0 rounded-full p-0.5 opacity-70 hover:opacity-100`,children:(0,R.jsx)(Fe,{size:14})})]})}var zf=`nm.cloud.first_sign_in`,Bf=`nm:first-sign-in`;function Vf(){try{sessionStorage.setItem(zf,`1`)}catch{}window.dispatchEvent(new Event(Bf))}function Hf(){try{sessionStorage.removeItem(zf)}catch{}window.dispatchEvent(new Event(Bf))}function Uf(){try{return sessionStorage.getItem(zf)===`1`}catch{return!1}}function Wf(){let[e,t]=(0,L.useState)(Uf);return(0,L.useEffect)(()=>{let e=()=>t(Uf());return window.addEventListener(Bf,e),()=>window.removeEventListener(Bf,e)},[]),e}function Gf(){let e=s(),{toast:t,refreshHub:n,setTab:r,state:a}=E(),o=_e(a.hub?.account),[c,l]=(0,L.useState)(`password`),[u,d]=(0,L.useState)(``),[f,p]=(0,L.useState)(``),[m,h]=(0,L.useState)(!1),[g,_]=(0,L.useState)(null),v=async()=>{Hf(),await n().catch(()=>void 0)},y=async()=>{if(!(u.length<8||u!==f)){h(!0),_(null);try{await M.cloudPassword(u),t(e(`Password set.`)),d(``),p(``),l(`source`)}catch(t){_(e(t.message))}finally{h(!1)}}},b=async()=>{await v(),Nf(r,o.preset)},x=(0,L.useRef)(null);On(x,!0);let S=f.length>0&&f!==u;return(0,R.jsx)(`div`,{className:`fixed inset-0 z-50 flex items-end justify-center bg-black/40 backdrop-blur-[2px] sm:items-center`,role:`dialog`,"aria-modal":`true`,children:(0,R.jsxs)(`div`,{ref:x,className:`safe-bottom w-full max-w-[520px] rounded-t-[28px] bg-bg p-6 shadow-2xl sm:rounded-[28px]`,children:[(0,R.jsxs)(`div`,{className:`mb-4 flex gap-1`,children:[(0,R.jsx)(`span`,{className:i(`h-1.5 w-5 rounded-full bg-accent`)}),(0,R.jsx)(`span`,{className:i(`h-1.5 rounded-full transition-all`,c===`source`?`w-5 bg-accent`:`w-1.5 bg-border`)})]}),c===`password`?(0,R.jsxs)(`form`,{className:`space-y-4`,onSubmit:e=>{e.preventDefault(),y()},children:[(0,R.jsxs)(`div`,{className:`flex items-start gap-3`,children:[(0,R.jsx)(`span`,{className:`flex h-11 w-11 shrink-0 items-center justify-center rounded-2xl bg-accent/12 text-accent`,children:(0,R.jsx)(xt,{size:20})}),(0,R.jsxs)(`div`,{children:[(0,R.jsx)(`h2`,{className:`text-[20px] font-bold tracking-tight`,children:e(`Set a password`)}),(0,R.jsx)(`p`,{className:`mt-1 text-[13.5px] leading-relaxed text-muted`,children:e(`Your account is in. With a password, your phone and your other computers sign in at once, without waiting for a code. Optional; you can set one later under Account.`)})]})]}),(0,R.jsxs)(`div`,{className:`space-y-2`,children:[(0,R.jsx)(`input`,{type:`password`,value:u,onChange:e=>d(e.target.value),autoComplete:`new-password`,autoFocus:!0,placeholder:e(`At least 8 characters`),className:Ie}),(0,R.jsx)(`input`,{type:`password`,value:f,onChange:e=>p(e.target.value),autoComplete:`new-password`,placeholder:e(`Once more`),className:i(Ie,S&&`border-rose-400`)}),S&&(0,R.jsx)(`p`,{className:`text-[12px] text-rose-600 dark:text-rose-300`,children:e(`The two do not match.`)})]}),g&&(0,R.jsx)(`div`,{className:`rounded-2xl bg-rose-500/12 px-3 py-2 text-[12.5px] text-rose-700 dark:text-rose-300`,children:g}),(0,R.jsxs)(`div`,{className:`flex gap-2`,children:[(0,R.jsx)(`button`,{type:`button`,disabled:m,onClick:()=>l(`source`),className:je,children:e(`Skip`)}),(0,R.jsxs)(`button`,{type:`submit`,disabled:m||u.length<8||u!==f,className:i(Ne,`flex-1 py-3`),children:[m?(0,R.jsx)(A,{size:15,className:`animate-spin`}):null,` `,e(`Set the password`),` `,(0,R.jsx)(qe,{size:16})]})]})]}):(0,R.jsxs)(`div`,{className:`space-y-4`,children:[(0,R.jsxs)(`div`,{className:`flex items-start gap-3`,children:[(0,R.jsx)(`span`,{className:`flex h-11 w-11 shrink-0 items-center justify-center rounded-2xl bg-accent/12 text-accent`,children:(0,R.jsx)(ot,{size:20})}),(0,R.jsxs)(`div`,{children:[(0,R.jsx)(`h2`,{className:`text-[20px] font-bold tracking-tight`,children:e(`Which model answers?`)}),(0,R.jsx)(`p`,{className:`mt-1 text-[13.5px] leading-relaxed text-muted`,children:e(`Your account already brings one. You can add your own API key as well and switch at any time.`)})]})]}),(0,R.jsxs)(`ul`,{className:`space-y-2 text-[13px] leading-snug`,children:[(0,R.jsxs)(`li`,{className:`flex items-start gap-2.5 rounded-2xl bg-surface-2 px-3 py-2.5`,children:[(0,R.jsx)(ot,{size:16,className:`mt-0.5 shrink-0 text-accent`}),(0,R.jsxs)(`span`,{children:[(0,R.jsx)(`span`,{className:`font-medium`,children:e(`Use the nanoMuse Cloud model`)}),(0,R.jsx)(`span`,{className:`block text-muted`,children:e(`DeepSeek for the chat and Qwen for the hands, with a free allowance per account paid by the developer. Nothing to configure.`)})]})]}),(0,R.jsxs)(`li`,{className:`flex items-start gap-2.5 rounded-2xl bg-surface-2 px-3 py-2.5`,children:[(0,R.jsx)(xt,{size:16,className:`mt-0.5 shrink-0 text-accent`}),(0,R.jsxs)(`span`,{children:[(0,R.jsx)(`span`,{className:`font-medium`,children:e(`I have my own API key`)}),(0,R.jsx)(`span`,{className:`block text-muted`,children:o.preset===`qwen`?e(`Alibaba Cloud Bailian first (one key covers chat, the hands, pictures and clips), then DeepSeek, Kimi, Zhipu, OpenAI, OpenRouter and any OpenAI-compatible endpoint. The key stays on this device.`):e(`OpenRouter first (one account, one key, pay as you go), then OpenAI, Anthropic, Gemini, DeepSeek and any OpenAI-compatible endpoint. The key stays on this device.`)})]})]}),(0,R.jsxs)(`li`,{className:`flex items-start gap-2.5 rounded-2xl bg-surface-2 px-3 py-2.5`,children:[(0,R.jsx)(wt,{size:16,className:`mt-0.5 shrink-0 text-accent`}),(0,R.jsxs)(`span`,{children:[(0,R.jsx)(`span`,{className:`font-medium`,children:e(`Sign in with a plan you already pay for`)}),(0,R.jsx)(`span`,{className:`block text-muted`,children:e(`A ChatGPT plan signs in from Connections and answers the chat and the hands. Pictures and clips still want a key.`)})]})]})]}),(0,R.jsxs)(`div`,{className:`flex gap-2`,children:[(0,R.jsx)(`button`,{type:`button`,disabled:m,onClick:()=>void b(),className:je,children:e(`I have my own API key`)}),(0,R.jsxs)(`button`,{type:`button`,disabled:m,onClick:()=>void v(),className:i(Ne,`flex-1 py-3`),children:[e(`Use the nanoMuse Cloud model`),` `,(0,R.jsx)(qe,{size:16})]})]})]})]})})}var Kf=`nanomuse_devtools`;function qf(){try{return localStorage.getItem(Kf)===`1`}catch{return!1}}var Jf=qf(),Yf=new Set;function Xf(){return Jf}function Zf(e){Jf=e;try{localStorage.setItem(Kf,e?`1`:`0`)}catch{}Yf.forEach(e=>e())}function Qf(e){return Yf.add(e),()=>Yf.delete(e)}function $f(){return(0,L.useSyncExternalStore)(Qf,Xf,Xf)}function ep(e,t,n){if(!n.signedIn||n.chatOnCloud||n.deviceChat)return;let r=e[t];if(r?.type===`notice`&&r.level===`error`&&r.code&&r.code!==`allowance`&&!r.model_used)for(let n=t-1;n>=0;n--){let t=e[n];if(t?.type===`user`){let e=(t.files??[]).map(e=>e.path);return t.text||e.length>0?{text:t.text,files:e}:void 0}}}var tp=[`idle`,`working`,`waiting`,`happy`,`error`];function np({event:e,name:t=`nanoMuse`}){let n=s(),{toast:r}=E(),[a,o]=(0,L.useState)(null),c=e.cost??{},l=e.candidates??[null,null,null,null],u=e.moods??{},d=e.clips??{},f=async(e,t)=>{o(e);try{await t()}catch(e){r(e.message)}finally{o(null)}},p=e.stage===`estimate`||e.stage===`drawing`||e.stage===`choose`||e.stage===`posing`||e.stage===`animating`,m=c.clips?n(`{n} pictures and {c} clips`,{n:c.pictures??8,c:c.clips}):n(`{n} pictures`,{n:c.pictures??8}),g=(()=>{if(c.cloud===!1)return n(`{what}, made with your own key at your provider's prices.`,{what:m});if(c.error)return n(`The cost could not be checked: {error}`,{error:c.error});if(typeof c.cny!=`number`)return n(`Checking the cost…`);if(c.unlimited)return n(`About ¥{cny} for {what}; your account has no limit.`,{cny:c.cny.toFixed(2),what:m});let e=typeof c.left_cny==`number`?c.left_cny.toFixed(2):`?`;return c.affordable===!1?n(`About ¥{cny} for {what}, more than the ¥{left} left in your allowance.`,{cny:c.cny.toFixed(2),what:m,left:e}):n(`About ¥{cny} for {what}; ¥{left} left in your allowance.`,{cny:c.cny.toFixed(2),what:m,left:e})})();return(0,R.jsx)(`div`,{className:`rise flex justify-start pr-8`,children:(0,R.jsxs)(`div`,{className:i(`w-full max-w-[360px] overflow-hidden rounded-3xl rounded-tl-lg border bg-surface shadow-sm`,p?`border-accent/50`:`border-border/70`),children:[(0,R.jsxs)(`div`,{className:`flex items-start gap-3 px-4 pt-3.5 pb-2`,children:[(0,R.jsx)(`div`,{className:i(`mt-0.5 rounded-full p-2`,p?`bg-accent/12 text-accent`:`bg-surface-2 text-fg/80`),children:(0,R.jsx)(nn,{size:18})}),(0,R.jsxs)(`div`,{className:`min-w-0 flex-1`,children:[(0,R.jsxs)(`div`,{className:`text-[12.5px] font-medium text-muted`,children:[e.stage===`estimate`&&n(`A new look for {name}`,{name:t}),e.stage===`drawing`&&n(`Drawing four to choose from…`),e.stage===`choose`&&n(`Pick one: tap it, or say which`),e.stage===`posing`&&n(`Drawing the poses…`),e.stage===`animating`&&n(`The new look is on; making the clips…`),e.stage===`done`&&n(`The new look is on`),e.stage===`cancelled`&&n(`Not this time`),e.stage===`failed`&&n(`That did not work`)]}),(0,R.jsx)(`div`,{className:`mt-0.5 text-[14px] leading-snug`,children:e.description}),e.reference&&(0,R.jsxs)(`div`,{className:`mt-1.5 flex items-center gap-2 text-[12px] text-muted`,children:[(0,R.jsx)(`img`,{src:h(e.reference),alt:``,draggable:!1,className:`h-9 w-9 rounded-lg object-cover`}),n(`drawn from the picture you attached`)]})]})]}),e.stage===`estimate`&&(0,R.jsxs)(`div`,{className:`px-4 pb-3.5 space-y-2.5`,children:[(0,R.jsx)(`p`,{className:`text-[12.5px] text-muted`,children:g}),(0,R.jsxs)(`div`,{className:`flex gap-2`,children:[(0,R.jsxs)(`button`,{type:`button`,disabled:a!==null||c.cloud!==!1&&typeof c.cny!=`number`&&!c.error,onClick:()=>f(`start`,()=>M.avatarStart(e.session)),className:i(`flex items-center justify-center gap-1.5 rounded-2xl bg-accent text-accent-fg px-4 py-2.5 text-[14px] font-medium disabled:opacity-40`,`inline-flex items-center gap-1.5 py-2`),children:[a===`start`?(0,R.jsx)(A,{size:14,className:`animate-spin`}):(0,R.jsx)(nn,{size:14}),` `,n(`Draw`)]}),(0,R.jsxs)(`button`,{type:`button`,disabled:a!==null,onClick:()=>f(`cancel`,()=>M.avatarCancel(e.session)),className:i(`flex items-center justify-center gap-1.5 rounded-2xl border border-border px-4 py-2.5 text-[14px] font-medium text-muted disabled:opacity-40`,`inline-flex items-center gap-1.5`),children:[(0,R.jsx)(Fe,{size:14}),` `,n(`Not now`)]})]})]}),(e.stage===`drawing`||e.stage===`choose`)&&(0,R.jsxs)(`div`,{className:`px-4 pb-3.5 space-y-2.5`,children:[(0,R.jsx)(`div`,{className:`grid grid-cols-2 gap-2`,children:l.map((t,r)=>(0,R.jsxs)(`button`,{type:`button`,disabled:!t||e.stage!==`choose`||a!==null,onClick:()=>f(`pick${r}`,()=>M.avatarChoose(e.session,r)),"aria-label":n(`Candidate {n}`,{n:r+1}),className:i(`relative aspect-square overflow-hidden rounded-2xl bg-[#f1efeb] transition`,t&&e.stage===`choose`?`hover:ring-2 hover:ring-accent`:``),children:[t?(0,R.jsx)(`img`,{src:h(t),alt:``,draggable:!1,className:`h-full w-full object-cover`}):(0,R.jsx)(`span`,{className:`absolute inset-0 flex items-center justify-center text-muted`,children:e.stage===`drawing`?(0,R.jsx)(A,{size:20,className:`animate-spin`}):(0,R.jsx)(Fe,{size:18,className:`opacity-50`})}),a===`pick${r}`&&(0,R.jsx)(`span`,{className:`absolute inset-0 flex items-center justify-center bg-bg/60`,children:(0,R.jsx)(A,{size:20,className:`animate-spin`})}),(0,R.jsx)(`span`,{className:`absolute left-1.5 top-1.5 rounded-full bg-bg/80 px-1.5 text-[10.5px] font-semibold text-fg/80`,children:r+1})]},r))}),e.errors&&e.errors.length>0&&(0,R.jsx)(`p`,{className:`text-[12px] text-rose-600 dark:text-rose-300`,children:n(e.errors[0])}),e.stage===`choose`&&(0,R.jsxs)(`div`,{className:`flex gap-2`,children:[(0,R.jsxs)(`button`,{type:`button`,disabled:a!==null,onClick:()=>f(`redraw`,()=>M.avatarStart(e.session)),className:i(`flex items-center justify-center gap-1.5 rounded-2xl border border-border px-4 py-2.5 text-[14px] font-medium text-muted disabled:opacity-40`,`inline-flex items-center gap-1.5`),children:[a===`redraw`?(0,R.jsx)(A,{size:14,className:`animate-spin`}):(0,R.jsx)(Re,{size:14}),` `,n(`Redraw`)]}),(0,R.jsxs)(`button`,{type:`button`,disabled:a!==null,onClick:()=>f(`cancel`,()=>M.avatarCancel(e.session)),className:i(`flex items-center justify-center gap-1.5 rounded-2xl border border-border px-4 py-2.5 text-[14px] font-medium text-muted disabled:opacity-40`,`inline-flex items-center gap-1.5`),children:[(0,R.jsx)(Fe,{size:14}),` `,n(`Not now`)]})]})]}),(e.stage===`posing`||e.stage===`animating`||e.stage===`done`)&&(0,R.jsxs)(`div`,{className:`px-4 pb-3.5 space-y-2`,children:[(0,R.jsx)(`div`,{className:`flex gap-1.5`,children:tp.map(t=>(0,R.jsxs)(`div`,{className:`relative aspect-square flex-1 overflow-hidden rounded-xl bg-[#f1efeb]`,children:[d[t]?(0,R.jsx)(`video`,{src:h(d[t]),poster:u[t]?h(u[t]):void 0,autoPlay:!0,loop:!0,muted:!0,playsInline:!0,disablePictureInPicture:!0,className:`h-full w-full object-cover`},d[t]):u[t]?(0,R.jsx)(`img`,{src:h(u[t]),alt:``,draggable:!1,className:`h-full w-full object-cover`}):(0,R.jsx)(`span`,{className:`absolute inset-0 flex items-center justify-center text-muted`,children:(0,R.jsx)(A,{size:14,className:`animate-spin`})}),e.stage===`animating`&&u[t]&&!d[t]&&t!==`error`&&(0,R.jsx)(`span`,{className:`absolute bottom-1 right-1 rounded-full bg-white/80 p-0.5 text-muted`,children:(0,R.jsx)(A,{size:10,className:`animate-spin`})})]},t))}),e.stage===`done`?(0,R.jsxs)(`p`,{className:`flex items-center gap-1.5 text-[12.5px] text-muted`,children:[(0,R.jsx)(ke,{size:14,className:`text-emerald-600`}),` `,n(`Idle, working, waiting, happy, sorry: the face follows what {name} is doing.`,{name:t})]}):e.stage===`animating`?(0,R.jsx)(`p`,{className:`text-[12.5px] text-muted`,children:n(`The face is already on; four short clips are being made from the poses, a few minutes.`)}):(0,R.jsx)(`p`,{className:`text-[12.5px] text-muted`,children:n(`Four more pictures from the one you picked; this takes a minute or two.`)}),e.errors&&e.errors.length>0&&e.stage===`done`&&(0,R.jsxs)(`p`,{className:`text-[12px] text-muted`,children:[e.errors.some(e=>!e.includes(` clip:`))&&n(`Some poses could not be drawn and show the idle picture instead.`),` `,e.errors.some(e=>e.includes(` clip:`))&&n(`Some clips could not be made; those moods stay still.`)]})]}),(e.stage===`failed`||e.stage===`cancelled`)&&e.message&&(0,R.jsx)(`p`,{className:`px-4 pb-3.5 text-[12.5px] text-muted`,children:n(e.message)})]})})}function rp(){let e=ip();if(!e||typeof e.keepRunning!=`function`)return null;try{return JSON.parse(e.keepRunning())}catch{return null}}function ip(){return window.NanoMuseAndroid??null}function ap(){let e=ip();return!!e&&typeof e.takeOverBrowser==`function`&&(typeof e.hasBrowser!=`function`||e.hasBrowser())}function op(){let e=ip();if(!e||typeof e.accessibilityState!=`function`)return null;let t=e.accessibilityState();return t===`on`||t===`off`||t===`unsupported`?t:null}function sp(e,t=15){switch(e){case`web_search`:return(0,R.jsx)(qt,{size:t});case`web_fetch`:case`browser`:return(0,R.jsx)(gt,{size:t});case`files`:return(0,R.jsx)(mt,{size:t});case`shell`:return(0,R.jsx)(dn,{size:t});case`python_execute`:return(0,R.jsx)(ct,{size:t});case`read_emails`:case`send_email`:return(0,R.jsx)(Et,{size:t});case`goals`:return(0,R.jsx)(un,{size:t});case`remember`:case`recall`:case`forget`:return(0,R.jsx)(Qe,{size:t});case`ask_user`:return(0,R.jsx)(kt,{size:t});case`devices`:return(0,R.jsx)(It,{size:t});case`device_shell`:return(0,R.jsx)(dn,{size:t});case`device_files`:case`device_get`:case`device_put`:return(0,R.jsx)(mt,{size:t});case`device_open`:return(0,R.jsx)(Ae,{size:t});case`device_screen`:return(0,R.jsx)(Lt,{size:t});case`device_notify`:return(0,R.jsx)(Xe,{size:t});case`delegate`:return(0,R.jsx)(Jt,{size:t});case`computer_screen`:return(0,R.jsx)(Lt,{size:t});case`computer_act`:return(0,R.jsx)(zt,{size:t});case`computer_task`:case`computer_app`:return(0,R.jsx)(vt,{size:t});case`phone_screen`:case`phone_act`:case`phone_task`:return(0,R.jsx)(tn,{size:t});default:return(0,R.jsx)(Ze,{size:t})}}function cp({device:e,className:t}){let n=s();return(0,R.jsxs)(`span`,{className:i(`inline-flex max-w-full items-center gap-1 rounded-full bg-accent/12 px-2 py-0.5 text-[11px] font-medium text-accent`,t),children:[(0,R.jsx)(It,{size:11,className:`shrink-0`}),` `,(0,R.jsx)(`span`,{className:`truncate`,children:n(`on {device}`,{device:e})})]})}var lp={safe:`bg-emerald-500/15 text-emerald-700 dark:text-emerald-300`,moderate:`bg-amber-500/15 text-amber-700 dark:text-amber-300`,sensitive:`bg-rose-500/15 text-rose-700 dark:text-rose-300`};function up({risk:e}){return(0,R.jsx)(`span`,{className:i(`px-2 py-0.5 rounded-full text-[11px] font-semibold uppercase tracking-wide`,lp[e]),children:_(e)})}function dp({args:e}){let t=Object.entries(e??{}).filter(([,e])=>e!=null&&e!==``);return t.length?(0,R.jsx)(`dl`,{className:`mt-2 grid grid-cols-[auto_1fr] gap-x-3 gap-y-1 text-[13px]`,children:t.map(([e,t])=>(0,R.jsxs)(`div`,{className:`contents`,children:[(0,R.jsx)(`dt`,{className:`text-muted`,children:e}),(0,R.jsx)(`dd`,{className:`break-words whitespace-pre-wrap font-mono text-[12.5px] leading-snug`,children:String(t)})]},e))}):null}function fp({event:e}){let[t,n]=(0,L.useState)(!1),r=e.status===`running`?(0,R.jsx)(A,{size:14,className:`animate-spin text-accent`}):e.status===`ok`?(0,R.jsx)(ke,{size:14,className:`text-emerald-500`}):e.status===`blocked`?(0,R.jsx)(Ye,{size:14,className:`text-rose-500`}):(0,R.jsx)(Fe,{size:14,className:`text-rose-500`});return(0,R.jsx)(`div`,{className:`rise flex justify-start pr-8`,children:(0,R.jsxs)(`button`,{type:`button`,onClick:()=>n(e=>!e),className:`max-w-full text-left rounded-2xl bg-surface-2/80 border border-border/60 px-3 py-1.5 text-[13px] text-muted hover:text-fg transition`,children:[(0,R.jsxs)(`span`,{className:`flex items-center gap-2`,children:[(0,R.jsx)(`span`,{className:`text-muted`,children:sp(e.tool)}),(0,R.jsx)(`span`,{className:`truncate flex-1`,children:e.title||e.summary||e.tool}),e.device&&(0,R.jsx)(cp,{device:e.device}),r,e.output?t?(0,R.jsx)(Me,{size:13}):(0,R.jsx)(rt,{size:13}):null]}),t&&(0,R.jsxs)(`div`,{className:`mt-2 text-fg`,children:[(0,R.jsx)(dp,{args:e.args}),e.output&&(0,R.jsx)(`pre`,{className:`mt-2 max-h-52 overflow-auto whitespace-pre-wrap break-words rounded-xl bg-bg p-2 text-[12px] leading-snug`,children:e.output})]})]})})}function pp(e,t,n){if(!t)return e.replace(/_/g,` `);switch(e){case`shell`:return _(`{what} commands`,{what:t.split(`,`).join(`, `)});case`send_email`:return _(`email to {who}`,{who:t.split(`,`).join(`, `)});case`remote_control`:return _(`the device {name}`,{name:typeof n?.device==`string`&&n.device?n.device:t});case`computer_app`:return _(`the hands in {app}`,{app:typeof n?.name==`string`&&n.name?n.name:t});default:return t}}function mp(e,t,n,r){switch(e){case`once`:return _(`Once`);case`conversation`:return _(`For this conversation`);case`session`:return _(`Until restart`);case`24h`:return _(`For 24 hours`);case`always`:return _(`Always for {subject}`,{subject:pp(t,n,r)});default:return e}}function hp({event:e,name:t=`nanoMuse`,onDecide:n}){let[r,a]=(0,L.useState)(!1),[o,c]=(0,L.useState)(!1),[l,d]=(0,L.useState)(!1),[f,p]=(0,L.useState)(!1),m=(e,t)=>{f||(p(!0),Promise.resolve(n(e,t)).finally(()=>p(!1)))},h=(0,L.useRef)(null),g=(0,L.useRef)(null),_=s(),y=e.status===`pending`,b=e.risk===`sensitive`,x=(e.grant_options??[`once`]).filter(e=>e!==`once`),S=e.egress_target||([`web_fetch`,`browser`,`web_search`].includes(e.tool)?e.target:null),C=e.tool===`send_email`?e.target:null,w=Object.values(e.args??{}).some(e=>e!=null&&e!==``);return(0,L.useEffect)(()=>{let e=g.current;e&&!r&&d(e.scrollHeight>e.clientHeight+2)},[e.args,r]),(0,L.useEffect)(()=>{(r||o)&&h.current?.scrollIntoView({block:`end`,behavior:`smooth`})},[r,o]),(0,R.jsx)(`div`,{className:`rise flex justify-start`,ref:h,children:(0,R.jsxs)(`div`,{className:i(`w-full max-w-[600px] overflow-hidden rounded-[22px] bg-surface shadow-[0_2px_12px_rgba(0,0,0,0.12)] dark:border dark:border-border dark:shadow-none`,y&&b&&`border border-rose-400/60`),children:[(0,R.jsxs)(`div`,{className:`flex items-start gap-3 px-4 pt-4 pb-2`,children:[(0,R.jsx)(`div`,{className:i(`flex h-10 w-10 shrink-0 items-center justify-center rounded-full`,b?`bg-rose-500/12 text-rose-500`:`bg-surface-2 text-fg`),children:b?(0,R.jsx)(Zt,{size:22}):sp(e.tool,22)}),(0,R.jsxs)(`div`,{className:`min-w-0 flex-1`,children:[(0,R.jsxs)(`div`,{className:`flex flex-wrap items-center gap-1.5 text-[12.5px] font-medium text-muted`,children:[(0,R.jsx)(`span`,{children:e.remote?_(`{name} on {device} wants to`,{name:t,device:e.remote.name}):_(`{name} wants to`,{name:t})}),e.remote&&(0,R.jsx)(cp,{device:e.remote.name})]}),(0,R.jsx)(`div`,{className:`mt-0.5 break-words text-[17px] font-semibold leading-[22px]`,children:e.summary}),S?(0,R.jsxs)(`div`,{className:`mt-1 flex items-center gap-1 text-[13px] text-muted`,children:[(0,R.jsx)(gt,{size:12}),` `,(0,R.jsx)(`span`,{className:`truncate`,children:_(`at {host}`,{host:S})})]}):C?(0,R.jsxs)(`div`,{className:`mt-1 flex items-center gap-1 text-[13px] text-muted`,children:[(0,R.jsx)(Et,{size:12}),` `,(0,R.jsx)(`span`,{className:`truncate`,children:_(`to {recipient}`,{recipient:C})})]}):null,e.purpose&&(0,R.jsx)(`div`,{className:`mt-1.5 break-words text-[13px] leading-snug text-muted line-clamp-2`,children:e.purpose}),b&&(0,R.jsx)(`div`,{className:`mt-1.5`,children:(0,R.jsx)(up,{risk:e.risk})})]})]}),e.warnings?.length>0&&(0,R.jsx)(`div`,{className:`space-y-1 px-4 pb-2`,children:e.warnings.map(e=>(0,R.jsxs)(`div`,{className:`flex items-start gap-1.5 text-[12.5px] text-rose-600 dark:text-rose-300`,children:[(0,R.jsx)(pn,{size:13,className:`mt-0.5 shrink-0`}),` `,(0,R.jsx)(`span`,{children:_(e)})]},e))}),(w||e.reasons?.length>0)&&(0,R.jsx)(`div`,{className:`px-4 pb-2`,children:(0,R.jsxs)(`div`,{className:`rounded-xl bg-surface-2 px-3 py-2.5`,children:[(0,R.jsx)(`div`,{className:`text-[11px] font-medium text-muted`,children:_(`Exactly what will run`)}),(0,R.jsxs)(`div`,{ref:g,className:i(`-mt-1`,!r&&`max-h-40 overflow-hidden`),children:[(0,R.jsx)(dp,{args:e.args}),e.reasons?.length>0&&(0,R.jsx)(`div`,{className:`mt-1.5 text-[12px] text-muted`,children:_(`Why it asks: {reasons}`,{reasons:e.reasons.map(v).join(` · `)})})]}),(l||r)&&(0,R.jsxs)(`button`,{type:`button`,className:`mt-1 flex items-center gap-1 text-[12.5px] text-accent`,onClick:()=>a(e=>!e),children:[r?(0,R.jsx)(Me,{size:13}):(0,R.jsx)(rt,{size:13}),` `,_(r?`Fewer options`:`Show all`)]})]})}),y?(0,R.jsxs)(`div`,{className:`flex flex-col gap-2 px-4 pb-4 pt-2`,children:[(0,R.jsx)(`button`,{type:`button`,onClick:()=>m(!0,`once`),disabled:f,className:`h-[46px] w-full rounded-full bg-accent text-[15px] font-semibold text-accent-fg transition active:scale-[0.98] disabled:opacity-60`,children:_(`Allow once`)}),x.filter(e=>o||e===`conversation`||e===`always`).map(t=>(0,R.jsx)(`button`,{type:`button`,onClick:()=>m(!0,t),disabled:f,className:`h-11 w-full truncate rounded-full bg-surface-2 px-4 text-[15px] font-medium transition active:scale-[0.98] disabled:opacity-60`,children:mp(t,e.tool,e.target,e.args)},t)),(0,R.jsx)(`button`,{type:`button`,onClick:()=>m(!1,`once`),disabled:f,className:`h-11 w-full rounded-full bg-surface-2 text-[15px] font-medium transition active:scale-[0.98] disabled:opacity-60`,children:_(`Deny`)}),x.length===0?(0,R.jsx)(`div`,{className:`text-center text-[12px] text-muted`,children:_(`This kind of action is approved one at a time.`)}):!o&&x.some(e=>e!==`conversation`&&e!==`always`)&&(0,R.jsx)(`button`,{type:`button`,className:`self-center text-[12.5px] text-muted`,onClick:()=>c(!0),children:_(`Allow {subject} for longer…`,{subject:pp(e.tool,e.target,e.args)})})]}):(0,R.jsxs)(`div`,{className:i(`flex items-center gap-1.5 border-t border-border px-4 py-2.5 text-[13px] font-medium`,e.status===`approved`?`text-emerald-600 dark:text-emerald-300`:`text-muted`),children:[e.status===`approved`?(0,R.jsx)(ke,{size:15}):(0,R.jsx)(Fe,{size:15}),e.status===`approved`?`${_(`Approved`)}${e.scope&&e.scope!==`once`?` · ${mp(e.scope,e.tool,e.target).toLowerCase()}`:``}`:e.status===`denied`?_(`Denied`):_(`Expired without an answer`),(0,R.jsx)(`span`,{className:`ml-auto font-normal`,children:u(e.updated_ts??e.ts)})]})]})})}function gp({event:e,name:t}){let n=s();return(0,R.jsx)(`div`,{className:`rise flex justify-start pr-8`,children:(0,R.jsxs)(`div`,{className:`max-w-full rounded-[20px] rounded-bl-md border border-accent/30 bg-surface px-4 py-3`,children:[(0,R.jsxs)(`div`,{className:`flex items-center gap-1.5 text-[12.5px] font-medium text-accent`,children:[(0,R.jsx)(kt,{size:14}),` `,n(`{name} asks`,{name:t})]}),(0,R.jsx)(`div`,{className:`mt-1 text-[15px] leading-snug whitespace-pre-wrap break-words`,children:e.text}),e.status===`pending`&&(0,R.jsx)(`div`,{className:`mt-1.5 text-[12.5px] text-muted`,children:n(`Reply below to continue.`)}),e.status===`answered`&&e.answer&&(0,R.jsxs)(`div`,{className:`mt-2 text-[13px] text-muted border-t border-border pt-2`,children:[n(`You:`),` `,(0,R.jsx)(`span`,{className:`text-fg`,children:e.answer})]})]})})}function _p(e){return e.source===`reminder`||e.source===`memory`?t(e.text):_(e.text,e.vars)}function vp({event:e,onCloudRetry:t}){let n=s(),[r,a]=(0,L.useState)(!1),[o,c]=(0,L.useState)(!1),[l,u]=(0,L.useState)(null),d=e.detail&&e.detail!==e.text?e.detail:null;return e.code===`allowance`&&e.allowance?(0,R.jsxs)(`div`,{className:`rise flex flex-col items-center gap-2 px-6`,children:[(0,R.jsx)(`div`,{className:`max-w-full rounded-2xl bg-amber-500/12 px-3 py-1.5 text-center text-[12.5px] leading-snug text-amber-700 dark:text-amber-300`,children:n(e.text)}),(0,R.jsx)(`div`,{className:`w-full max-w-[520px]`,children:(0,R.jsx)(Ff,{info:e.allowance,exhausted:!0,compact:!0})})]}):(0,R.jsx)(`div`,{className:`rise flex justify-center px-6`,children:(0,R.jsxs)(`div`,{className:i(`max-w-full rounded-2xl px-3 py-1.5 text-center text-[12.5px] leading-snug`,e.level===`info`&&`bg-surface-2/70 text-muted`,e.level===`warn`&&`bg-amber-500/12 text-amber-700 dark:text-amber-300`,e.level===`error`&&`bg-rose-500/12 text-rose-700 dark:text-rose-300`),children:[_p(e),d&&(0,R.jsxs)(R.Fragment,{children:[` `,(0,R.jsx)(`button`,{type:`button`,onClick:()=>a(e=>!e),className:`underline decoration-dotted underline-offset-2 opacity-70 hover:opacity-100`,children:n(r?`Hide details`:`Details`)}),r&&(0,R.jsx)(`div`,{className:`mt-1.5 break-all text-left font-mono text-[11px] opacity-80`,children:d})]}),t&&(0,R.jsxs)(`div`,{className:`mt-1.5 flex flex-col items-center gap-1`,children:[(0,R.jsx)(`button`,{type:`button`,disabled:o,onClick:()=>{t&&(c(!0),u(null),t().catch(e=>u(n(e.message||`Could not send`))).finally(()=>c(!1)))},className:`rounded-full bg-accent/12 px-3 py-1 text-[12px] font-medium text-accent disabled:opacity-50`,children:n(`Use nanoMuse Cloud this time`)}),l&&(0,R.jsx)(`div`,{className:`text-[12px] text-rose-700 dark:text-rose-300`,children:l})]})]})})}function yp({event:e,onOpen:t}){let[r,i]=(0,L.useState)(!1),a=s(),o=e.status===`live`,c=e.url;try{c=new URL(e.url).host}catch{}return(0,R.jsx)(`div`,{className:`rise flex justify-start pr-8`,children:(0,R.jsxs)(`button`,{type:`button`,onClick:()=>t(e.id),"aria-label":a(`Browser: {title}`,{title:e.title||c}),className:`w-full max-w-[340px] overflow-hidden rounded-3xl rounded-tl-lg border border-border bg-surface shadow-sm hover:bg-surface-2 transition text-left`,children:[(0,R.jsxs)(`div`,{className:`relative aspect-[16/10] bg-surface-2`,children:[r?(0,R.jsxs)(`div`,{className:`absolute inset-0 flex flex-col items-center justify-center gap-1 text-muted`,children:[(0,R.jsx)(gt,{size:22}),(0,R.jsx)(`span`,{className:`text-[12px]`,children:a(`Frame no longer available`)})]}):(0,R.jsx)(`img`,{src:n(e.thread,e.frame),alt:e.title||c,onError:()=>i(!0),className:`absolute inset-0 h-full w-full object-cover object-top`},e.frame),(0,R.jsx)(`div`,{className:`absolute left-2.5 top-2.5 flex items-center gap-1.5 rounded-full bg-black/60 px-2 py-0.5 text-[10.5px] font-semibold text-white`,children:o?(0,R.jsxs)(R.Fragment,{children:[(0,R.jsx)(`span`,{className:`h-1.5 w-1.5 rounded-full bg-rose-400 animate-pulse`}),` `,a(`LIVE`)]}):(0,R.jsxs)(R.Fragment,{children:[(0,R.jsx)(gt,{size:11}),` `,a(`BROWSER`)]})})]}),(0,R.jsxs)(`div`,{className:`flex items-center gap-2 px-3.5 py-2.5`,children:[(0,R.jsxs)(`div`,{className:`min-w-0 flex-1`,children:[(0,R.jsx)(`div`,{className:`text-[13.5px] font-medium truncate`,children:e.title||c}),(0,R.jsxs)(`div`,{className:`text-[12px] text-muted truncate`,children:[e.by_user&&e.action.startsWith(`You`)?a(`You`)+e.action.slice(3):e.action,` · `,c]})]}),(0,R.jsx)(rt,{size:16,className:`text-muted shrink-0`})]})]})})}function bp({event:e,name:t=`nanoMuse`}){let n=s(),{state:r,toast:a}=E(),[o,c]=(0,L.useState)(!1),[l,d]=(0,L.useState)(!1),f=e.status===`live`,p=e.last,m=[e.app,e.title].filter(Boolean).join(` · `),h=r.holds.find(t=>t.thread===e.thread&&t.tool===`computer`),g=async()=>{c(!0);try{await M.stopHands()}catch{}finally{c(!1)}},_=async()=>{d(!0);try{await M.openHold(e.thread,`computer`)}catch(e){a(e.message)}finally{d(!1)}};return(0,R.jsx)(`div`,{className:`rise flex justify-start pr-8`,children:(0,R.jsxs)(`div`,{className:i(`w-full max-w-[360px] overflow-hidden rounded-3xl rounded-tl-lg border bg-surface shadow-sm`,f?`border-accent/50`:`border-border/70`),children:[(0,R.jsxs)(`div`,{className:`flex items-start gap-3 px-4 pt-3.5 pb-2`,children:[(0,R.jsx)(`div`,{className:i(`mt-0.5 rounded-full p-2`,f?`bg-accent/12 text-accent`:`bg-surface-2 text-fg/80`),children:(0,R.jsx)(vt,{size:18})}),(0,R.jsxs)(`div`,{className:`min-w-0 flex-1`,children:[(0,R.jsxs)(`div`,{className:`flex items-center gap-2 text-[12.5px] font-medium text-muted`,children:[(0,R.jsx)(`span`,{children:f?n(`{name} is using this computer`,{name:t}):e.status===`stopped`?n(`Hands stopped`):n(`Hands done`)}),f&&(0,R.jsxs)(`span`,{className:`flex items-center gap-1 rounded-full bg-accent/12 px-2 py-0.5 text-[10.5px] font-semibold text-accent`,children:[(0,R.jsx)(`span`,{className:`h-1.5 w-1.5 animate-pulse rounded-full bg-accent`}),` `,n(`LIVE`)]})]}),e.text&&(0,R.jsx)(`div`,{className:`mt-0.5 break-words text-[15px] font-semibold leading-snug`,children:e.text}),p?.action&&(0,R.jsxs)(`div`,{className:`mt-1.5 flex items-center gap-1.5 text-[13px] text-fg/90`,children:[(0,R.jsx)(zt,{size:13,className:`shrink-0 text-muted`}),(0,R.jsx)(`span`,{className:`truncate`,children:Tp(p,n)})]}),m&&(0,R.jsx)(`div`,{className:`mt-1 truncate text-[12px] text-muted`,children:m}),e.notice&&(0,R.jsx)(`div`,{className:`mt-1.5 rounded-2xl bg-amber-500/12 px-3 py-1.5 text-[12.5px] text-amber-700 dark:text-amber-300`,children:e.notice}),f&&h&&(0,R.jsx)(xp,{hold:h})]})]}),(0,R.jsxs)(`div`,{className:`flex items-center gap-2 border-t border-border/70 px-4 py-2 text-[12px] text-muted`,children:[(0,R.jsx)(`span`,{children:n(`{n} steps`,{n:e.steps})}),(0,R.jsx)(`span`,{className:`ml-auto`,children:u(e.updated_ts??e.ts)}),f&&!h&&(0,R.jsxs)(`button`,{type:`button`,onClick:()=>void _(),disabled:l,className:`ml-1 inline-flex items-center gap-1.5 rounded-full bg-accent/12 px-3 py-1 text-[12.5px] font-semibold text-accent transition active:scale-95 disabled:opacity-60`,children:[(0,R.jsx)(vt,{size:11}),` `,n(`Take over`)]}),f&&(0,R.jsxs)(`button`,{type:`button`,onClick:()=>void g(),disabled:o,className:`ml-1 inline-flex items-center gap-1.5 rounded-full bg-fg px-3 py-1 text-[12.5px] font-semibold text-bg transition active:scale-95 disabled:opacity-60`,children:[(0,R.jsx)(sn,{size:10,fill:`currentColor`}),` `,n(`Stop`)]})]})]})})}function xp({hold:e,compact:t}){let n=s(),[r,a]=(0,L.useState)(!1),o=async()=>{a(!0);try{await M.doneHold(e.id)}catch{}finally{a(!1)}};return(0,R.jsxs)(`div`,{className:i(`flex items-center gap-2 rounded-2xl bg-amber-500/12 px-3 text-amber-800 dark:text-amber-200`,t?`py-1.5 text-[12.5px]`:`mt-1.5 py-2 text-[13px]`),children:[(0,R.jsx)(vt,{size:14,className:`shrink-0`}),(0,R.jsx)(`span`,{className:`min-w-0 flex-1 leading-snug`,children:Cp(e,n)}),(0,R.jsx)(`button`,{type:`button`,onClick:()=>void o(),disabled:r,className:`shrink-0 rounded-full bg-fg px-3 py-1 text-[12.5px] font-semibold text-bg transition active:scale-95 disabled:opacity-60`,children:r?(0,R.jsx)(A,{size:13,className:`animate-spin`}):n(`Done`)})]})}function Sp(e,t){return t(e===`browser`?`the browser`:e===`phone`?`the phone`:`this computer`)}function Cp(e,t){return e.by===`agent`?e.reason?t(`Your turn: {reason}`,{reason:e.reason}):t(`Your turn`):t(`You took over {thing}`,{thing:Sp(e.tool,t)})}function wp({event:e,name:t=`nanoMuse`}){let n=s(),[r,a]=(0,L.useState)(!1),o=e.status===`on`,c=Sp(e.tool,n),l=async()=>{a(!0);try{await M.doneHold(e.id)}catch{}finally{a(!1)}},d=e.timed_out?n(`{name} waited ten minutes and went on without you.`,{name:t}):e.stale?n(`Ended when the runtime restarted.`):e.by===`agent`?n(`You did it; {name} carried on.`,{name:t}):n(`Handed back; {name} carried on.`,{name:t});return(0,R.jsx)(`div`,{className:`rise flex justify-start pr-8`,children:(0,R.jsxs)(`div`,{className:i(`w-full max-w-[360px] overflow-hidden rounded-3xl rounded-tl-lg border bg-surface shadow-sm`,o?`border-amber-500/50`:`border-border/70 opacity-70`),children:[(0,R.jsxs)(`div`,{className:`flex items-start gap-3 px-4 pt-3.5 pb-3`,children:[(0,R.jsx)(`div`,{className:i(`mt-0.5 rounded-full p-2`,o?`bg-amber-500/15 text-amber-700 dark:text-amber-300`:`bg-surface-2 text-fg/70`),children:(0,R.jsx)(vt,{size:18})}),(0,R.jsxs)(`div`,{className:`min-w-0 flex-1`,children:[(0,R.jsx)(`div`,{className:`text-[12.5px] font-medium text-muted`,children:e.tool===`browser`?n(`The browser`):e.tool===`phone`?n(`The phone`):n(`This computer`)}),(0,R.jsx)(`div`,{className:`mt-0.5 break-words text-[15px] font-semibold leading-snug`,children:e.by===`agent`?n(`Your turn`):n(`You took over {thing}`,{thing:c})}),e.by===`agent`&&e.reason&&(0,R.jsx)(`div`,{className:`mt-1 break-words text-[13.5px] leading-snug text-fg/90`,children:e.reason}),(0,R.jsx)(`div`,{className:`mt-1.5 text-[12.5px] leading-snug text-muted`,children:o?e.by===`agent`?n(`Do this part yourself, then press Done. {name} looks again and carries on from there.`,{name:t}):n(`{name} waits. Press Done when you are finished and it looks again.`,{name:t}):d})]})]}),(0,R.jsxs)(`div`,{className:`flex items-center gap-2 border-t border-border/70 px-4 py-2 text-[12px] text-muted`,children:[(0,R.jsx)(`span`,{children:u(e.ts)}),o&&(0,R.jsxs)(`button`,{type:`button`,onClick:()=>void l(),disabled:r,className:`ml-auto inline-flex items-center gap-1.5 rounded-full bg-fg px-3.5 py-1 text-[12.5px] font-semibold text-bg transition active:scale-95 disabled:opacity-60`,children:[r?(0,R.jsx)(A,{size:13,className:`animate-spin`}):(0,R.jsx)(ke,{size:12}),` `,n(`Done`)]})]})]})})}function Tp(e,t){let n=e.label?`“${e.label}”`:``;switch(e.action){case`click`:return n?t(`Clicked {label}`,{label:n}):t(`Clicked`);case`double_click`:return n?t(`Double-clicked {label}`,{label:n}):t(`Double-clicked`);case`right_click`:case`middle_click`:return n?t(`Right-clicked {label}`,{label:n}):t(`Right-clicked`);case`move`:return n?t(`Pointed at {label}`,{label:n}):t(`Moved the mouse`);case`type`:return t(`Typed {n} characters`,{n:(e.text??``).length});case`key`:return t(`Pressed {keys}`,{keys:(e.keys??[]).join(`+`)});case`scroll`:return t(`Scrolled`);case`drag`:return t(`Dragged`);case`open_app`:return n?t(`Opened {label}`,{label:n}):t(`Opened an application`);case`wait`:return t(`Waited`);default:return e.action??``}}function Ep({event:e,onOpen:t}){let n=s(),a=r(e.name),o=n(a===`html`?`Page`:a===`image`?`Image`:a===`data`?`Data`:a===`code`?`Code`:a===`event`?`Event`:`Document`),c=e.action===`update`?`${o} · ${n(`updated`)}`:o,l=a===`html`||a===`image`;return(0,R.jsx)(`div`,{className:`rise flex justify-start pr-8`,children:(0,R.jsxs)(`button`,{type:`button`,onClick:()=>t(e.path),className:i(`max-w-full overflow-hidden rounded-[20px] border border-border bg-surface text-left shadow-[0_4px_20px_-12px_rgba(0,0,0,0.2)] transition hover:bg-surface-2`,l?`w-[300px]`:``),children:[l&&(0,R.jsx)(Dp,{path:e.path,kind:a}),(0,R.jsxs)(`div`,{className:`flex items-center gap-3 px-4 py-3`,children:[!l&&(0,R.jsx)(`div`,{className:`rounded-2xl bg-accent/12 p-2.5 text-accent`,children:a===`code`?(0,R.jsx)(ct,{size:20}):a===`event`?(0,R.jsx)(tt,{size:20}):(0,R.jsx)(mt,{size:20})}),(0,R.jsxs)(`div`,{className:`min-w-0 flex-1`,children:[(0,R.jsx)(`div`,{className:`text-[11px] font-semibold uppercase tracking-wide text-muted`,children:c}),(0,R.jsx)(`div`,{className:`truncate text-[14.5px] font-medium`,children:e.name}),(0,R.jsx)(`div`,{className:`truncate text-[12px] text-muted`,children:e.path})]}),(0,R.jsx)(rt,{size:16,className:`ml-1 shrink-0 text-muted`})]})]})})}function Dp({path:e,kind:t}){return t===`image`?(0,R.jsx)(`img`,{src:h(e),alt:``,loading:`lazy`,className:`h-40 w-full object-cover`}):(0,R.jsx)(`div`,{className:`pointer-events-none relative h-40 w-full overflow-hidden bg-white`,children:(0,R.jsx)(`iframe`,{title:e,src:h(e),sandbox:``,tabIndex:-1,loading:`lazy`,scrolling:`no`,className:`absolute left-0 top-0 h-[480px] w-[900px] origin-top-left scale-[0.3333] border-0`})})}function Op({open:e,onClose:t,title:n,children:r,footer:i}){let a=s(),o=(0,L.useRef)(null);return On(o,e),(0,L.useEffect)(()=>{if(!e)return;let n=e=>e.key===`Escape`&&t();return window.addEventListener(`keydown`,n),()=>window.removeEventListener(`keydown`,n)},[e,t]),e?(0,R.jsxs)(`div`,{className:`fixed inset-0 z-50 flex items-end sm:items-center sm:justify-center`,children:[(0,R.jsx)(`div`,{className:`absolute inset-0 bg-black/45 backdrop-blur-[2px]`,onClick:t}),(0,R.jsxs)(`div`,{ref:o,role:`dialog`,"aria-modal":`true`,className:`sheet-in relative w-full sm:max-w-lg max-h-[92dvh] flex flex-col bg-surface rounded-t-3xl sm:rounded-3xl shadow-2xl border border-border`,children:[(0,R.jsxs)(`div`,{className:`flex items-center gap-3 px-5 pt-4 pb-2`,children:[(0,R.jsx)(`div`,{className:`sm:hidden absolute left-1/2 -translate-x-1/2 top-2 h-1 w-10 rounded-full bg-border`}),(0,R.jsx)(`div`,{className:`flex-1 font-semibold text-[17px] mt-1`,children:n}),(0,R.jsx)(`button`,{type:`button`,onClick:t,"aria-label":a(`Close`),className:`p-2 -mr-2 rounded-full text-muted hover:bg-surface-2`,children:(0,R.jsx)(Fe,{size:20})})]}),(0,R.jsx)(`div`,{className:`flex-1 overflow-y-auto px-5 pb-4`,children:r}),i&&(0,R.jsx)(`div`,{className:`px-5 pt-2 pb-4 safe-bottom border-t border-border`,children:i})]})]}):null}var kp=1e3;function Ap({thread:e,eventId:t,onClose:r}){let{state:a,toast:o}=E(),c=s(),l=(a.events[e]??[]).find(e=>e.id===t),u=a.holds.find(t=>t.thread===e&&t.tool===`browser`),[d,f]=(0,L.useState)(null),[p,m]=(0,L.useState)(null),[h,g]=(0,L.useState)(``),[_,v]=(0,L.useState)(``),[y,b]=(0,L.useState)(!1),x=(0,L.useRef)(null),S=d?d===`on`:!!u;(0,L.useEffect)(()=>b(!1),[l?.frame]),(0,L.useEffect)(()=>f(null),[u?.id,u?.status]);let C=l?.backend===`device`&&ap();(0,L.useEffect)(()=>{if(!C)return;let t=t=>{let n=t.detail;n?.thread&&n.thread!==e||M.browserControl(e,{action:`handed_back`}).catch(e=>o(e.message))};return window.addEventListener(`nanomuse:browser-handed-back`,t),()=>window.removeEventListener(`nanomuse:browser-handed-back`,t)},[C,e,o]);let w=(0,L.useCallback)(async t=>{m(t.action);try{await M.browserControl(e,t)}catch(e){o(e.message)}finally{m(null)}},[e,o]),T=()=>{if(C){ip()?.takeOverBrowser?.(e),M.browserControl(e,{action:`take_over`}).catch(()=>void 0);return}f(`on`),w({action:`take_over`})},D=()=>{f(`off`),w({action:`handed_back`})};(0,L.useEffect)(()=>{if(!S||C||!l||l.status!==`live`)return;let t=window.setInterval(()=>{document.hidden||M.browserControl(e,{action:`look`}).catch(()=>void 0)},kp);return()=>window.clearInterval(t)},[S,C,e,l]);let O=e=>{if(!S||p)return;let t=e.currentTarget.getBoundingClientRect(),n=(e.clientX-t.left)/t.width,r=(e.clientY-t.top)/t.height;w({action:`click`,x:Math.min(Math.max(n,0),1),y:Math.min(Math.max(r,0),1)})},k=e=>{!S||p||Math.abs(e.deltaY)<8||w({action:`scroll`,dy:Math.max(-2e3,Math.min(2e3,Math.round(e.deltaY*2)))})};if(!l)return null;let ee=l.url;try{ee=new URL(l.url).host}catch{}let te=l.status===`live`,j=a.profile?.name??`nanoMuse`,ne=u?c(`{name} is waiting for you`,{name:j}):a.status.state!==`idle`&&a.status.thread===e?c(`{name} is working`,{name:j}):l.action;return(0,R.jsxs)(Op,{open:!0,onClose:r,title:(0,R.jsxs)(`div`,{className:`flex items-center gap-2 min-w-0`,children:[(0,R.jsx)(gt,{size:17,className:`text-accent shrink-0`}),(0,R.jsx)(`span`,{className:`truncate`,children:l.title||ee}),te&&(0,R.jsxs)(`span`,{className:`ml-1 flex items-center gap-1 rounded-full bg-rose-500/12 px-2 py-0.5 text-[10.5px] font-semibold text-rose-500`,children:[(0,R.jsx)(`span`,{className:`h-1.5 w-1.5 rounded-full bg-rose-500 animate-pulse`}),` `,c(`LIVE`)]})]}),footer:S?(0,R.jsxs)(`div`,{className:`space-y-2`,children:[(0,R.jsxs)(`form`,{className:`flex items-center gap-2`,onSubmit:e=>{e.preventDefault(),h&&w({action:`type`,text:h}).then(()=>g(``))},children:[(0,R.jsx)(`input`,{value:h,onChange:e=>g(e.target.value),placeholder:c(`Type into the focused field…`),className:`flex-1 rounded-2xl bg-surface-2 px-3.5 py-2.5 text-[14px] outline-none`,autoComplete:`off`,autoCapitalize:`off`}),(0,R.jsx)(`button`,{type:`submit`,disabled:!h||!!p,"aria-label":c(`Type`),className:`rounded-full bg-accent p-2.5 text-white disabled:opacity-40`,children:p===`type`?(0,R.jsx)(A,{size:16,className:`animate-spin`}):(0,R.jsx)(qe,{size:16})}),(0,R.jsx)(`button`,{type:`button`,onClick:()=>void w({action:`key`,key:`Enter`}),disabled:!!p,"aria-label":c(`Press Enter`),className:`rounded-full bg-surface-2 p-2.5 text-fg disabled:opacity-40`,children:(0,R.jsx)(dt,{size:16})})]}),(0,R.jsxs)(`form`,{className:`flex items-center gap-2`,onSubmit:e=>{e.preventDefault(),_&&w({action:`navigate`,url:_}).then(()=>v(``))},children:[(0,R.jsx)(`button`,{type:`button`,onClick:()=>void w({action:`back`}),disabled:!!p,"aria-label":c(`Back`),className:`rounded-full bg-surface-2 p-2 text-fg disabled:opacity-40`,children:(0,R.jsx)(Ke,{size:15})}),(0,R.jsx)(`input`,{value:_,onChange:e=>v(e.target.value),placeholder:c(`Open a URL…`),inputMode:`url`,autoCapitalize:`off`,className:`flex-1 min-w-0 rounded-2xl bg-surface-2 px-3.5 py-2 text-[13px] outline-none`}),(0,R.jsx)(`button`,{type:`submit`,disabled:!_||!!p,className:`rounded-2xl bg-surface-2 px-3 py-2 text-[13px] font-medium disabled:opacity-40`,children:c(`Go`)}),(0,R.jsx)(`button`,{type:`button`,onClick:()=>void w({action:`scroll`,dy:-600}),disabled:!!p,"aria-label":c(`Scroll up`),className:`rounded-full bg-surface-2 p-2 text-fg disabled:opacity-40`,children:(0,R.jsx)(Je,{size:15})}),(0,R.jsx)(`button`,{type:`button`,onClick:()=>void w({action:`scroll`,dy:600}),disabled:!!p,"aria-label":c(`Scroll down`),className:`rounded-full bg-surface-2 p-2 text-fg disabled:opacity-40`,children:(0,R.jsx)(Ge,{size:15})})]}),(0,R.jsxs)(`div`,{className:`flex items-center justify-between gap-2`,children:[(0,R.jsx)(`span`,{className:`min-w-0 truncate text-[12px] text-muted`,children:c(`Tap the page to click. If the browser was closed, open a URL first.`)}),(0,R.jsxs)(`button`,{type:`button`,onClick:D,disabled:p===`handed_back`,className:`flex shrink-0 items-center gap-1.5 whitespace-nowrap rounded-full bg-fg px-3.5 py-1.5 text-[13px] font-semibold text-bg disabled:opacity-60`,children:[p===`handed_back`?(0,R.jsx)(A,{size:14,className:`animate-spin`}):(0,R.jsx)(ke,{size:14}),` `,c(`Done`)]})]})]}):(0,R.jsxs)(`div`,{className:`flex items-center justify-between gap-2`,children:[(0,R.jsxs)(`div`,{className:`min-w-0 text-[12.5px] text-muted truncate`,children:[ne,` · `,ee]}),(0,R.jsxs)(`div`,{className:`flex items-center gap-2 shrink-0`,children:[(0,R.jsx)(`button`,{type:`button`,onClick:()=>void w({action:`look`}),disabled:!!p,"aria-label":c(`Refresh`),className:`rounded-full bg-surface-2 p-2 text-muted disabled:opacity-40`,children:p===`look`?(0,R.jsx)(A,{size:15,className:`animate-spin`}):(0,R.jsx)(Re,{size:15})}),(0,R.jsxs)(`button`,{type:`button`,onClick:T,disabled:d===`on`,className:`flex items-center gap-1.5 rounded-full bg-accent px-3.5 py-2 text-[13px] font-semibold text-white disabled:opacity-60`,children:[(0,R.jsx)(vt,{size:14}),` `,c(`Take over`)]})]})]}),children:[u&&u.by===`agent`&&(0,R.jsx)(`div`,{className:`mb-2`,children:(0,R.jsx)(xp,{hold:u,compact:!0})}),(0,R.jsxs)(`div`,{className:i(`relative overflow-hidden rounded-2xl border border-border bg-surface-2`,S&&`ring-2 ring-accent`),children:[y?(0,R.jsxs)(`div`,{className:`flex aspect-[16/10] flex-col items-center justify-center gap-1 text-muted`,children:[(0,R.jsx)(gt,{size:24}),(0,R.jsx)(`span`,{className:`text-[12.5px]`,children:c(`This frame is no longer available.`)}),(0,R.jsx)(`button`,{type:`button`,onClick:()=>void w({action:`look`}),className:`text-accent text-[13px] font-medium`,children:c(`Look again`)})]}):(0,R.jsx)(`img`,{ref:x,src:n(e,l.frame),alt:l.title||ee,onError:()=>b(!0),onClick:O,onWheel:k,draggable:!1,className:i(`block w-full select-none`,S?`cursor-crosshair`:``)},l.frame),p&&p!==`look`&&(0,R.jsx)(`div`,{className:`absolute inset-0 flex items-center justify-center bg-black/20`,children:(0,R.jsx)(A,{size:26,className:`animate-spin text-white`})})]}),(0,R.jsxs)(`div`,{className:`mt-2 flex items-center justify-between text-[12px] text-muted`,children:[(0,R.jsx)(`span`,{className:`truncate`,children:l.url}),(0,R.jsx)(`span`,{className:`shrink-0 ml-2`,children:l.frames===1?c(`1 frame`):c(`{n} frames`,{n:l.frames})})]}),S&&(0,R.jsxs)(`div`,{className:`mt-3 rounded-2xl bg-accent/8 px-3.5 py-2.5 text-[13px] leading-snug`,children:[(0,R.jsx)(`div`,{className:`font-medium`,children:u&&u.by===`agent`?Cp(u,c):c(`You have the page. Press Done when you are finished.`)}),(0,R.jsx)(`div`,{className:`mt-1 text-muted`,children:c(`{name} waits meanwhile, then looks at the page as you left it and carries on. Passwords you type here go to the website, never to the model.`,{name:j})})]})]})}function jp(){if(typeof window>`u`)return null;let e=window;return e.SpeechRecognition??e.webkitSpeechRecognition??null}function Mp(){return jp()!==null}function Np(e,t){let[n,r]=(0,L.useState)(!1),i=(0,L.useRef)(null),a=(0,L.useRef)(``),o=s(),c=(0,L.useCallback)(()=>{i.current?.stop()},[]),l=(0,L.useCallback)(()=>{let n=jp();if(!n)return;let s=new n;s.lang=navigator.language||`en-US`,s.continuous=!0,s.interimResults=!0,a.current=``,s.onresult=t=>{let n=``;for(let e=t.resultIndex;e{let n=e.error||``;n!==`aborted`&&n!==`no-speech`&&t?.(n===`not-allowed`||n===`service-not-allowed`?o(`The microphone is not allowed. Allow it in the browser and try again.`):o(`Voice input stopped ({code}).`,{code:n}))},s.onend=()=>{i.current=null,r(!1)},i.current=s;try{s.start(),r(!0)}catch{i.current=null,r(!1)}},[e,t,o]),u=(0,L.useCallback)(()=>{i.current?c():l()},[l,c]);return(0,L.useEffect)(()=>()=>i.current?.abort(),[]),{supported:Mp(),listening:n,toggle:u,stop:c}}function Pp({listening:e,onClick:t,className:n}){let r=s();return(0,R.jsx)(`button`,{type:`button`,onClick:t,"aria-label":r(e?`Stop voice input`:`Voice input`),"aria-pressed":e,className:i(`flex h-9 w-9 shrink-0 items-center justify-center rounded-full transition active:scale-95`,e?`bg-accent/15 text-accent animate-pulse`:`text-fg/70 hover:bg-surface-2`,n),children:e?(0,R.jsx)(Pt,{size:19}):(0,R.jsx)(Ft,{size:19})})}function Fp({lines:e}){return(0,R.jsx)(`div`,{className:`flex items-end gap-2 pr-10`,children:(0,R.jsx)(`div`,{className:`min-w-0 max-w-full`,children:e.map((e,t)=>(0,R.jsx)(`div`,{className:`my-1 max-w-[340px] rounded-[20px] bg-surface-2 px-3.5 py-2.5 text-[14.5px] leading-snug whitespace-pre-wrap break-words wide:max-w-[600px]`,children:e},t))})})}function Ip({chips:e,chosen:t,busy:n,onPick:r,onElse:a}){let o=s();return e.length===0&&!t?null:(0,R.jsxs)(`section`,{className:`rise mx-1 my-2 rounded-[22px] border border-border/70 bg-surface p-3.5`,children:[(0,R.jsxs)(`div`,{className:`flex items-center gap-2 text-[13px] font-medium text-fg`,children:[(0,R.jsx)(nn,{size:14,className:`text-accent`}),` `,o(`Pick a name for me, or type one`)]}),(0,R.jsxs)(`div`,{className:`mt-2.5 flex flex-wrap gap-2`,children:[e.map(e=>{let a=t===e;return(0,R.jsxs)(`button`,{type:`button`,disabled:n||!!t,onClick:()=>r(e),className:i(`inline-flex items-center gap-1.5 rounded-full px-3.5 py-1.5 text-[13.5px] font-medium transition-colors disabled:opacity-60`,a?`bg-accent text-accent-fg`:`bg-surface-2 hover:bg-border/60`),children:[a&&(0,R.jsx)(ke,{size:13,strokeWidth:3}),e]},e)}),!t&&(0,R.jsx)(`button`,{type:`button`,disabled:n,onClick:a,className:`rounded-full border border-border px-3.5 py-1.5 text-[13.5px] text-muted hover:bg-surface-2 disabled:opacity-60`,children:o(`Something else`)})]})]})}var Lp=[{id:`pink`,background:`#F9D9E3`,accent:`#B5476A`,mood:`idle`},{id:`blue`,background:`#D6E6FA`,accent:`#2F5FA8`,mood:`working`},{id:`yellow`,background:`#FBEFC7`,accent:`#9A6B12`,mood:`waiting`},{id:`purple`,background:`#E4DDF7`,accent:`#5D44A6`,mood:`happy`},{id:`green`,background:`#D9F0DF`,accent:`#2E7D4F`,mood:`error`}],Rp=`github.com/nano-muse/nanoMuse`,zp=540,Bp=720;function Vp(e,t){return!e||w(e.avatar)?j(t):e.avatar?re(e.avatar,t):null}function Hp(e){return new Promise(t=>{let n=new Image;n.crossOrigin=`anonymous`,n.onload=()=>t(n),n.onerror=()=>t(null),n.src=e})}function Up(e,t,n){let r=t.includes(` `)?t.split(` `):Array.from(t),i=t.includes(` `)?` `:``,a=[],o=``;for(let t of r){let r=o?o+i+t:t;e.measureText(r).width>n&&o?(a.push(o),o=t):o=r}return o&&a.push(o),a}function Wp(e,t,n,r,i,a){e.beginPath(),e.moveTo(t+a,n),e.arcTo(t+r,n,t+r,n+i,a),e.arcTo(t+r,n+i,t,n+i,a),e.arcTo(t,n+i,t,n,a),e.arcTo(t,n,t+r,n,a),e.closePath()}async function Gp(e,t,n,r,i,a=2){let o=document.createElement(`canvas`);o.width=zp*a,o.height=Bp*a;let s=o.getContext(`2d`);if(!s)return o;s.scale(a,a),s.fillStyle=e.background,Wp(s,0,0,zp,Bp,36),s.fill(),s.font=`600 22px system-ui, -apple-system, 'Segoe UI', sans-serif`;let c=Up(s,r,400),l=Math.max(...c.map(e=>s.measureText(e).width))+48,u=c.length*30+36,d=(zp-l)/2;s.fillStyle=`#ffffff`,Wp(s,d,56,l,u,24),s.fill(),s.beginPath(),s.moveTo(zp/2-14,56+u-1),s.lineTo(zp/2,56+u+18),s.lineTo(284,56+u-1),s.closePath(),s.fill(),s.fillStyle=e.accent,s.textAlign=`center`,s.textBaseline=`top`,c.forEach((e,t)=>s.fillText(e,zp/2,74+t*30+3));let f=56+u+54;s.fillStyle=`#ffffff`,s.beginPath(),s.arc(zp/2,f+150,158,0,Math.PI*2),s.fill();let p=Vp(t,e.mood),m=p?await Hp(p):null;return s.save(),s.beginPath(),s.arc(zp/2,f+150,150,0,Math.PI*2),s.clip(),m?(s.fillStyle=`#f1efeb`,s.fillRect(120,f,300,300),s.drawImage(m,120,f,300,300)):(s.fillStyle=t?.color??`#0064d4`,s.fillRect(120,f,300,300),s.font=`150px system-ui, 'Apple Color Emoji', 'Segoe UI Emoji', sans-serif`,s.textAlign=`center`,s.textBaseline=`middle`,s.fillStyle=`#ffffff`,s.fillText(t?.emoji??`✨`,zp/2,f+150+6)),s.restore(),s.fillStyle=e.accent,s.textAlign=`center`,s.textBaseline=`top`,s.font=`700 30px system-ui, -apple-system, 'Segoe UI', sans-serif`,s.fillText(n,zp/2,f+300+34),s.font=`500 15px system-ui, -apple-system, 'Segoe UI', sans-serif`,s.globalAlpha=.8,Up(s,i,460).forEach((e,t)=>s.fillText(e,zp/2,644+t*22)),s.globalAlpha=1,o}function Kp(e){return new Promise(t=>e.toBlob(t,`image/png`))}function qp({open:e,onClose:t}){let{state:n,toast:r}=E(),a=s(),o=n.profile,c=o?.name??`nanoMuse`,[l,u]=(0,L.useState)(0),[d,f]=(0,L.useState)([]),[p,m]=(0,L.useState)(!1),h=(0,L.useRef)(!0),g=a(`Hi, I'm {name}, a personal AI agent. Meet nanoMuse: open source, runs on your phone.`,{name:c}),_=a(`Your personal AI agent, open source · {repo}`,{repo:Rp});(0,L.useEffect)(()=>{if(h.current=!0,e)return u(0),(async()=>{let e=[];for(let t of Lp){let n=await Gp(t,o,c,g,_,1);e.push(n.toDataURL(`image/png`))}h.current&&f(e)})(),()=>{h.current=!1}},[e,o?.avatar,o?.emoji,o?.color,c]);let v=async()=>{m(!0);try{let e=await Kp(await Gp(Lp[l]??Lp[0],o,c,g,_,2));if(!e)throw Error(a(`The card could not be drawn.`));let n=new File([e],`${c}-nanomuse.png`,{type:`image/png`}),i=`${g}\nhttps://${Rp}`,s=navigator;if(typeof s.share==`function`&&(!s.canShare||s.canShare({files:[n]})))try{await s.share({files:[n],text:i,title:c}),t();return}catch(e){if(e.name===`AbortError`)return}let u=document.createElement(`a`);u.href=URL.createObjectURL(e),u.download=n.name,u.click(),window.setTimeout(()=>URL.revokeObjectURL(u.href),2e3),r(a(`Saved the card as a picture.`))}catch(e){r(e.message)}finally{m(!1)}};return(0,R.jsxs)(Op,{open:e,onClose:t,title:a(`Share my avatar`),children:[(0,R.jsx)(`p`,{className:`mb-3 text-[13px] text-muted`,children:a(`Pick a card. It goes out through the system share sheet, or saves as a picture where there is none.`)}),(0,R.jsx)(`div`,{className:`grid grid-cols-3 gap-2.5 sm:grid-cols-5`,children:Lp.map((e,t)=>(0,R.jsx)(`button`,{type:`button`,"aria-label":e.id,"aria-pressed":l===t,onClick:()=>u(t),className:i(`overflow-hidden rounded-2xl border-2 transition`,l===t?`border-accent`:`border-transparent`),style:{background:e.background,aspectRatio:`${zp} / ${Bp}`},children:d[t]?(0,R.jsx)(`img`,{src:d[t],alt:``,className:`h-full w-full object-cover`}):(0,R.jsx)(A,{size:18,className:`mx-auto my-8 animate-spin text-muted`})},e.id))}),d[l]&&(0,R.jsx)(`img`,{src:d[l],alt:``,className:`mx-auto mt-4 w-[260px] rounded-[20px] shadow-md`}),(0,R.jsxs)(`div`,{className:`mt-4 flex justify-end gap-2`,children:[(0,R.jsx)(`button`,{type:`button`,onClick:t,className:je,children:a(`Later`)}),(0,R.jsxs)(`button`,{type:`button`,disabled:p||!d.length,onClick:()=>void v(),className:Ne,children:[p?(0,R.jsx)(A,{size:15,className:`animate-spin`}):typeof navigator.share==`function`?(0,R.jsx)(Xt,{size:15}):(0,R.jsx)(ft,{size:15}),` `,typeof navigator.share==`function`?a(`Share`):a(`Save picture`)]})]})]})}function Jp({message:e,onRetry:t}){let n=s();return(0,R.jsxs)(`div`,{className:`flex flex-col items-center gap-3 px-8 py-10 text-center`,children:[(0,R.jsx)(`p`,{className:`text-[14px] text-rose-600 dark:text-rose-300`,children:n(e)||n(`Could not load.`)}),(0,R.jsxs)(`button`,{type:`button`,onClick:t,className:`flex h-10 items-center gap-1.5 rounded-full bg-surface px-4 text-[13.5px] font-medium shadow-[0_1px_4px_rgba(0,0,0,0.14)] dark:border dark:border-border dark:shadow-none`,children:[(0,R.jsx)(Re,{size:14}),` `,n(`Try again`)]})]})}var Yp=[{id:`health`,label:`Health`,icon:e=>(0,R.jsx)(yt,{...e}),tone:`bg-rose-500/12 text-rose-600 dark:text-rose-300`},{id:`finance`,label:`Finance`,icon:e=>(0,R.jsx)(Wt,{...e}),tone:`bg-emerald-500/12 text-emerald-600 dark:text-emerald-300`},{id:`career`,label:`Career`,icon:e=>(0,R.jsx)($e,{...e}),tone:`bg-sky-500/12 text-sky-600 dark:text-sky-300`},{id:`learning`,label:`Learning`,icon:e=>(0,R.jsx)(_t,{...e}),tone:`bg-violet-500/12 text-violet-600 dark:text-violet-300`},{id:`relationships`,label:`Relationships`,icon:e=>(0,R.jsx)(le,{...e}),tone:`bg-pink-500/12 text-pink-600 dark:text-pink-300`},{id:`family`,label:`Family`,icon:e=>(0,R.jsx)(hn,{...e}),tone:`bg-amber-500/12 text-amber-600 dark:text-amber-300`},{id:`home`,label:`Home`,icon:e=>(0,R.jsx)(bt,{...e}),tone:`bg-orange-500/12 text-orange-600 dark:text-orange-300`},{id:`travel`,label:`Travel`,icon:e=>(0,R.jsx)(lt,{...e}),tone:`bg-cyan-500/12 text-cyan-600 dark:text-cyan-300`},{id:`creative`,label:`Creative`,icon:e=>(0,R.jsx)(Vt,{...e}),tone:`bg-fuchsia-500/12 text-fuchsia-600 dark:text-fuchsia-300`},{id:`other`,label:`Other`,icon:e=>(0,R.jsx)(ln,{...e}),tone:`bg-surface-2 text-muted`}];function Xp(e){return Yp.find(t=>t.id===e)??null}var Zp=[{id:``,label:`No reminders`},{id:`daily`,label:`Every day`},{id:`weekdays`,label:`Weekdays`},{id:`weekly`,label:`Once a week`},{id:`monthly`,label:`Once a month`}],Qp=[`mon`,`tue`,`wed`,`thu`,`fri`,`sat`,`sun`];function $p(e){let t=/^(daily|weekdays|weekly|monthly)(?:\s+(\S+?))?(?:\s+(\d{1,2}:\d{2}))?$/.exec(e.trim());if(!t)return{cadence:``,anchor:``,time:`09:00`};let n=t[2]??``,r=t[3]??`09:00`;return n&&/^\d{1,2}:\d{2}$/.test(n)&&(r=n,n=``),{cadence:t[1],anchor:n,time:r.padStart(5,`0`)}}function em(e,t,n){return e?[e,t,n].filter(Boolean).join(` `):``}function tm(e){let t=Qp.indexOf(e);return t<0?e:new Date(2024,0,1+t).toLocaleDateString(m(),{weekday:`long`})}function nm(e){let{cadence:t,anchor:n,time:r}=$p(e);switch(t){case`daily`:return _(`Daily at {time}`,{time:r});case`weekdays`:return _(`Weekdays at {time}`,{time:r});case`weekly`:return n&&Qp.includes(n)?_(`{day}s at {time}`,{day:tm(n),time:r}):_(`Weekly at {time}`,{time:r});case`monthly`:return _(`Monthly on the {day} at {time}`,{day:rm(Number(n||1)),time:r});default:return``}}function rm(e){if(c()!==`en`)return String(e);let t=[`th`,`st`,`nd`,`rd`],n=e%100;return`${e}${t[(n-20)%10]??t[n]??t[0]}`}function im(e,t){if(!e)return``;let n=new Date(`${e}T00:00:00`),r=n.toLocaleDateString(m(),{month:`short`,day:`numeric`,year:n.getFullYear()===new Date().getFullYear()?void 0:`numeric`});if(t)return _(`Was due {date}`,{date:r});let i=Math.ceil((n.getTime()-Date.now())/864e5);return i<=0?_(`Due today`):i===1?_(`Due tomorrow`):i<=14?_(`Due in {n} days`,{n:i}):_(`By {date}`,{date:r})}function am({open:e,onClose:t}){let{state:n,setTab:r,draft:a,toast:o}=E(),[c,l]=(0,L.useState)(0),[u,d]=(0,L.useState)(!1),[f,p]=(0,L.useState)(!1),[m,h]=(0,L.useState)(!1),g=n.profile?.name??`nanoMuse`,_=n.pendingApprovals.length,v=s();(0,L.useEffect)(()=>{e&&(l(+(_>0)),d(!1),p(!1))},[e]);let y=(e,n)=>{t(),n&&history.replaceState(null,``,`${window.location.pathname}${window.location.search}#${n}`),r(e)},b=n.status.state===`working`,x=_>0?_>1?v(`{n} approvals waiting for you`,{n:_}):v(`1 approval waiting for you`):b?n.status.detail||v(`On it`):n.status.state===`waiting`?v(`Waiting for you`):v(`online`),S=async()=>{h(!0);try{(await M.stopThread(n.status.thread||`main`)).ok||o(v(`Nothing to stop`))}catch(e){o(e.message)}finally{h(!1)}},C=[{icon:(0,R.jsx)(it,{size:22}),label:v(`Activity`)},{icon:(0,R.jsx)(Qt,{size:22}),label:v(`Approvals`),badge:_},{icon:(0,R.jsx)(at,{size:22}),label:v(`Daily`)},{icon:(0,R.jsx)(ht,{size:22}),label:v(`Soul & memory`)}];return(0,R.jsxs)(Op,{open:e,onClose:t,children:[(0,R.jsxs)(`div`,{className:`relative flex flex-col items-center px-1 pb-3 text-center`,children:[(0,R.jsx)(`button`,{type:`button`,"aria-label":v(`Share avatar`),title:v(`Share avatar`),onClick:()=>p(!0),className:`absolute right-0 top-0 flex h-9 w-9 items-center justify-center rounded-full bg-surface-2/70 text-fg hover:bg-surface-2`,children:(0,R.jsx)(Xt,{size:16})}),(0,R.jsxs)(`div`,{className:`relative`,children:[(0,R.jsx)(D,{profile:n.profile,status:n.status,size:72}),(0,R.jsx)(`button`,{type:`button`,"aria-label":v(`Edit`),"aria-expanded":u,onClick:()=>d(e=>!e),className:`absolute -bottom-0.5 -right-0.5 flex h-6 w-6 items-center justify-center rounded-full bg-surface text-fg shadow-[0_1px_4px_rgba(0,0,0,0.18)] hover:bg-surface-2 dark:border dark:border-border`,children:(0,R.jsx)(Ht,{size:13})}),u&&(0,R.jsxs)(`div`,{className:`absolute left-1/2 top-full z-20 mt-2 w-56 -translate-x-1/2 overflow-hidden rounded-2xl border border-border/70 bg-surface py-1 text-left text-[14px] shadow-lg`,children:[(0,R.jsx)(`button`,{type:`button`,onClick:()=>{a(v(`Change your avatar to `)),t(),r(`chat`)},className:`block w-full px-4 py-2.5 text-left hover:bg-surface-2`,children:v(`Change avatar`)}),(0,R.jsx)(`button`,{type:`button`,onClick:()=>y(`you`,`who`),className:`block w-full px-4 py-2.5 text-left hover:bg-surface-2`,children:v(`Edit name`)}),(0,R.jsx)(`button`,{type:`button`,onClick:()=>y(`avatar`),className:`block w-full px-4 py-2.5 text-left text-muted hover:bg-surface-2`,children:v(`Avatar studio…`)})]})]}),(0,R.jsx)(`div`,{className:`mt-2.5 text-[21px] font-semibold leading-[26px]`,children:g}),(0,R.jsxs)(`div`,{className:i(`mt-0.5 flex items-center gap-1.5 text-[14px]`,b||_>0?`text-fg`:`text-muted`),children:[b&&(0,R.jsx)(A,{size:13,className:`animate-spin text-accent`}),(0,R.jsx)(`span`,{className:`line-clamp-2`,children:x})]}),(b||n.status.state===`waiting`)&&(0,R.jsxs)(`button`,{type:`button`,onClick:()=>void S(),disabled:m,className:`mt-2.5 inline-flex items-center gap-1.5 rounded-full bg-fg px-4 py-1.5 text-[13.5px] font-semibold text-bg transition active:scale-95 disabled:opacity-60`,children:[(0,R.jsx)(sn,{size:12,fill:`currentColor`}),` `,v(`Stop`)]})]}),(0,R.jsx)(`div`,{role:`tablist`,className:`mb-5 flex rounded-2xl bg-surface-2/60 p-1`,children:C.map((e,t)=>(0,R.jsxs)(`button`,{type:`button`,role:`tab`,"aria-selected":c===t,"aria-label":e.label,title:e.label,onClick:()=>l(t),className:i(`relative flex h-11 flex-1 items-center justify-center rounded-[13px] text-fg transition`,c===t&&`bg-surface shadow-sm`),children:[e.icon,e.badge?(0,R.jsx)(`span`,{className:`absolute right-1.5 top-1 flex h-[17px] min-w-[17px] items-center justify-center rounded-full bg-rose-500 px-1 text-[10px] font-bold text-white`,children:e.badge}):null]},e.label))}),c===0&&(0,R.jsx)(ym,{open:e}),c===1&&(0,R.jsxs)(R.Fragment,{children:[_>0&&(0,R.jsx)(cm,{onDone:()=>void 0}),(0,R.jsx)(bm,{open:e})]}),c===2&&(0,R.jsx)(lm,{onSettings:()=>y(`you`,`proactivity`)}),c===3&&(0,R.jsx)(om,{name:g,onEdit:()=>y(`you`,`who`),onMemory:()=>y(`memory`)}),(0,R.jsx)(qp,{open:f,onClose:()=>p(!1)})]})}function om({name:e,onEdit:t,onMemory:n}){let{state:r}=E(),i=s(),a=r.profile?.tagline?.trim()??``;return(0,R.jsxs)(`div`,{className:`pb-2`,children:[(0,R.jsx)(`div`,{className:`px-1 text-[15px]`,children:e}),(0,R.jsxs)(`button`,{type:`button`,onClick:t,className:`mt-2 flex h-[50px] w-full items-center justify-center gap-2 rounded-2xl bg-surface-2/70 text-[15px] font-medium hover:bg-surface-2`,children:[(0,R.jsx)(Ht,{size:18}),` `,i(`Edit`)]}),(0,R.jsxs)(`div`,{className:`mt-4 grid grid-cols-2 gap-3`,children:[(0,R.jsx)(sm,{title:`SOUL`,caption:i(`Handle with care`),foot:a,colors:`from-[#7d6bc7] to-[#574494]`,onClick:t}),(0,R.jsx)(sm,{title:i(`Memory`),caption:i(`Handle with care`),foot:r.settings?.memory_enabled===!1?i(`Off`):``,colors:`from-[#b0413e] to-[#7a1f1f]`,onClick:n})]})]})}function sm({title:e,caption:t,foot:n,colors:r,onClick:a}){return(0,R.jsxs)(`button`,{type:`button`,onClick:a,className:i(`flex h-[130px] flex-col items-start rounded-[18px] bg-gradient-to-b p-3.5 text-left text-white transition active:scale-[0.98]`,r),children:[(0,R.jsx)(`span`,{className:`text-[17px] font-semibold`,children:e}),(0,R.jsx)(`span`,{className:`mt-0.5 text-[11px] text-white/85`,children:t}),(0,R.jsx)(`span`,{className:`mt-auto text-[12px] text-white/90`,children:n})]})}function cm({onDone:e}){let{state:t,decide:n,openThread:r,toast:i}=E(),a=t.profile?.name??`nanoMuse`,o=s(),c=[...t.pendingApprovals].sort((e,t)=>e.ts.localeCompare(t.ts)),l=e=>{let n=t.threads.find(t=>t.id===e);return n?n.id===`main`?o(n.title):n.title:e};return(0,L.useEffect)(()=>{if(c.length===0){let t=window.setTimeout(e,600);return()=>window.clearTimeout(t)}},[c.length,e]),c.length===0?(0,R.jsxs)(`div`,{className:`py-10 text-center text-muted text-[14px]`,children:[(0,R.jsx)(ke,{size:26,className:`mx-auto mb-2 text-emerald-500`}),o(`Nothing is waiting for you.`)]}):(0,R.jsxs)(`div`,{className:`space-y-4 pb-2`,children:[(0,R.jsx)(`p`,{className:`text-[12.5px] text-muted`,children:o(`Actions {name} wants to take but cannot without you. Each one shows what will run and why; a permission you grant is bound to that exact tool and target.`,{name:a})}),c.map(e=>(0,R.jsxs)(`div`,{children:[(0,R.jsxs)(`button`,{type:`button`,onClick:()=>r(e.thread),className:`mb-1 px-1 text-[12px] font-semibold uppercase tracking-wide text-muted hover:text-accent`,children:[l(e.thread),` · `,u(e.ts)]}),(0,R.jsx)(`div`,{className:`rounded-[22px] border border-border/70`,children:(0,R.jsx)(hp,{event:e,onDecide:(t,r)=>n(e.id,t,r).catch(e=>i(e.message))})})]},e.id))]})}function lm({onSettings:t}){let{state:n,refreshSettings:r,toast:a}=E(),[o,c]=(0,L.useState)(null),[l,d]=(0,L.useState)(null),[f,p]=(0,L.useState)(null),m=n.profile?.name??`nanoMuse`,h=s(),g=()=>M.upcoming().then(e=>{c(e),d(null)}).catch(e=>o===null?d(e.message):a(e.message));(0,L.useEffect)(()=>{g()},[n.goalsVersion,n.remindersVersion,n.profile?.proactive,n.profile?.goal_interval_minutes]);let _=async()=>{try{await M.updateSettings({profile:{proactive:!n.profile?.proactive}}),await r()}catch(e){a(e.message)}},v=async e=>{p(e);try{await M.advanceGoal(e),a(h(`{name} is working on it in the main chat`,{name:m}))}catch(e){a(e.message)}finally{p(null)}};return o?(0,R.jsxs)(`div`,{className:`space-y-4 pb-2`,children:[(0,R.jsxs)(`div`,{className:`rounded-2xl border border-border p-3.5`,children:[(0,R.jsxs)(`div`,{className:`flex items-center justify-between gap-3`,children:[(0,R.jsxs)(`div`,{children:[(0,R.jsx)(`div`,{className:`font-medium`,children:h(`Background work`)}),(0,R.jsx)(`div`,{className:`text-[12.5px] text-muted`,children:o.proactive?`${h(o.proactivity[0].toUpperCase()+o.proactivity.slice(1))} · ${h(`every {n} min {name} picks one active goal and works on its next step.`,{n:o.effective_interval_minutes,name:m})}${o.quiet_until?` ${h(`Quiet hours until {time}.`,{time:u(o.quiet_until)})}`:o.next_pass_at?` ${h(`Next around {time}.`,{time:u(o.next_pass_at)})}`:``}`:h(`Off. {name} only works when you ask.`,{name:m})})]}),(0,R.jsx)(`button`,{type:`button`,role:`switch`,"aria-checked":o.proactive,onClick:()=>void _(),className:i(`relative h-7 w-12 shrink-0 rounded-full transition`,o.proactive?`bg-accent`:`bg-border`),children:(0,R.jsx)(`span`,{className:i(`absolute top-0.5 h-6 w-6 rounded-full bg-white shadow transition`,o.proactive?`left-[26px]`:`left-0.5`)})})]}),(0,R.jsx)(`button`,{type:`button`,onClick:t,className:`mt-2 text-[12.5px] text-accent font-medium`,children:h(`Level, interval and quiet hours in Settings`)})]}),(0,R.jsxs)(`div`,{children:[(0,R.jsx)(`div`,{className:`text-[12px] uppercase tracking-wide text-muted font-semibold mb-1.5`,children:h(`In line`)}),o.queue.length===0?(0,R.jsx)(`div`,{className:`text-[13px] text-muted`,children:h(`No active goal has a next step. Add one in Goals and {name} will pick it up.`,{name:m})}):(0,R.jsx)(`ul`,{className:`space-y-1.5`,children:o.queue.map((e,t)=>(0,R.jsxs)(`li`,{className:`flex items-center gap-2.5 rounded-2xl bg-surface-2/60 px-3 py-2`,children:[(0,R.jsx)(`span`,{className:`w-5 text-center text-[12px] font-semibold text-muted`,children:t+1}),(0,R.jsxs)(`div`,{className:`min-w-0 flex-1`,children:[(0,R.jsx)(`div`,{className:`text-[13.5px] font-medium truncate`,children:e.title}),(0,R.jsxs)(`div`,{className:`text-[11.5px] text-muted truncate`,children:[e.next_step??`—`,` · `,h(`{done}/{total} done`,{done:e.progress.done,total:e.progress.total})]})]}),(0,R.jsx)(`button`,{type:`button`,onClick:()=>void v(e.goal_id),disabled:f!==null||o.busy,"aria-label":h(`Work on {title} now`,{title:e.title}),className:`rounded-full bg-accent/12 p-2 text-accent disabled:opacity-50`,children:f===e.goal_id?(0,R.jsx)(A,{size:15,className:`animate-spin`}):(0,R.jsx)(Gt,{size:15})})]},e.goal_id))})]}),o.check_ins.length>0&&(0,R.jsxs)(`div`,{children:[(0,R.jsx)(`div`,{className:`text-[12px] uppercase tracking-wide text-muted font-semibold mb-1.5`,children:h(`Check-ins`)}),(0,R.jsx)(`ul`,{className:`space-y-1.5`,children:o.check_ins.map(t=>(0,R.jsxs)(`li`,{className:`flex items-center gap-2.5 rounded-2xl bg-surface-2/60 px-3 py-2`,children:[(0,R.jsx)(Xe,{size:15,className:`text-muted shrink-0`}),(0,R.jsxs)(`div`,{className:`min-w-0 flex-1`,children:[(0,R.jsx)(`div`,{className:`text-[13.5px] font-medium truncate`,children:t.title}),(0,R.jsxs)(`div`,{className:`text-[11.5px] text-muted truncate`,children:[e(t.at),` · `,u(t.at),` · `,nm(t.cadence).toLowerCase()]})]})]},t.goal_id))}),(0,R.jsx)(`div`,{className:`mt-1.5 text-[12px] text-muted`,children:h(`Goal nudges you asked for; they arrive whatever the proactivity level, but wait out quiet hours.`)})]}),(0,R.jsx)(um,{items:o.reminders,name:m,onChange:()=>void g()}),(0,R.jsx)(mm,{data:o.triggers,name:m,onChange:()=>void g()})]}):l?(0,R.jsx)(Jp,{message:l,onRetry:()=>void g()}):(0,R.jsx)(`div`,{className:`py-10 flex justify-center text-muted`,children:(0,R.jsx)(A,{className:`animate-spin`,size:20})})}function um({items:t,name:n,onChange:r}){let{toast:i}=E(),a=s(),[o,c]=(0,L.useState)(null),[l,d]=(0,L.useState)(!1),f=t.filter(e=>e.status===`active`),p=t.filter(e=>e.status!==`active`),m=async e=>{c(e.id);try{await M.cancelReminder(e.id),r()}catch(e){i(e.message)}finally{c(null)}},h=async e=>{c(e.id);try{await M.fireReminder(e.id),i(e.kind===`task`?a(`{name} is on it`,{name:n}):a(`{name} will say it now`,{name:n})),r()}catch(e){i(e.message)}finally{c(null)}};return(0,R.jsxs)(`div`,{children:[(0,R.jsxs)(`div`,{className:`flex items-center justify-between mb-1.5`,children:[(0,R.jsx)(`div`,{className:`text-[12px] uppercase tracking-wide text-muted font-semibold`,children:a(`Reminders & routines`)}),!l&&(0,R.jsx)(`button`,{type:`button`,onClick:()=>d(!0),className:`text-[12.5px] text-accent font-medium`,children:a(`+ Add`)})]}),l&&(0,R.jsx)(dm,{onDone:()=>{d(!1),r()},onCancel:()=>d(!1)}),f.length===0&&!l?(0,R.jsx)(`div`,{className:`text-[13px] text-muted`,children:a(`Nothing scheduled. Tell {name} “remind me at six to call mum” or “every weekday morning, summarise my unread email”.`,{name:n})}):(0,R.jsx)(`ul`,{className:`space-y-1.5`,children:f.map(t=>(0,R.jsxs)(`li`,{className:`flex items-center gap-2.5 rounded-2xl bg-surface-2/60 px-3 py-2`,children:[t.kind===`task`?(0,R.jsx)(Kt,{size:15,className:`text-muted shrink-0`}):(0,R.jsx)(We,{size:15,className:`text-muted shrink-0`}),(0,R.jsxs)(`div`,{className:`min-w-0 flex-1`,children:[(0,R.jsx)(`div`,{className:`text-[13.5px] font-medium truncate`,children:t.text}),(0,R.jsxs)(`div`,{className:`text-[11.5px] text-muted truncate`,children:[t.next_at?`${e(t.next_at)} · ${u(t.next_at)}`:`—`,t.repeat&&` · ${nm(t.repeat).toLowerCase()}`,t.kind===`task`&&` · ${a(`does the work`)}`]})]}),(0,R.jsx)(`button`,{type:`button`,onClick:()=>void h(t),disabled:o!==null,"aria-label":t.kind===`task`?a(`Do “{text}” now`,{text:t.text}):a(`Remind me now: {text}`,{text:t.text}),className:`rounded-full bg-accent/12 p-2 text-accent disabled:opacity-50`,children:o===t.id?(0,R.jsx)(A,{size:15,className:`animate-spin`}):(0,R.jsx)(Gt,{size:15})}),(0,R.jsx)(`button`,{type:`button`,onClick:()=>void m(t),disabled:o!==null,"aria-label":a(`Cancel: {text}`,{text:t.text}),className:`rounded-full p-2 text-muted hover:text-fg disabled:opacity-50`,children:(0,R.jsx)(Fe,{size:15})})]},t.id))}),p.length>0&&(0,R.jsxs)(`details`,{className:`mt-2`,children:[(0,R.jsx)(`summary`,{className:`text-[12px] text-muted cursor-pointer select-none`,children:a(`{n} finished recently`,{n:p.length})}),(0,R.jsx)(`ul`,{className:`mt-1.5 space-y-1`,children:p.map(t=>(0,R.jsxs)(`li`,{className:`flex items-center gap-2 px-3 text-[12.5px] text-muted`,children:[(0,R.jsx)(`span`,{className:`min-w-0 flex-1 truncate line-through decoration-border`,children:t.text}),(0,R.jsx)(`span`,{className:`shrink-0`,children:t.status===`done`?t.last_fired_at?e(t.last_fired_at):a(`done`):a(`cancelled`)})]},t.id))})]}),(0,R.jsx)(`div`,{className:`mt-1.5 text-[12px] text-muted`,children:a(`A time you named is kept whatever the level or the quiet hours. Reminders just say it; routines do the work and report.`)})]})}function dm({onDone:e,onCancel:t}){let{toast:n}=E(),r=s(),[a,o]=(0,L.useState)(``),[c,l]=(0,L.useState)(`remind`),[u,d]=(0,L.useState)(`once`),[f,p]=(0,L.useState)(()=>_m()),[h,g]=(0,L.useState)(`daily`),[_,v]=(0,L.useState)(`09:00`),[y,b]=(0,L.useState)(`mon`),[x,S]=(0,L.useState)(`1`),[C,w]=(0,L.useState)(!1),T=h===`weekly`?`weekly ${y} ${_}`:h===`monthly`?`monthly ${x} ${_}`:`${h} ${_}`,D=async()=>{if(a.trim()){w(!0);try{await M.createReminder(u===`once`?{text:a.trim(),kind:c,at:f.replace(`T`,` `)}:{text:a.trim(),kind:c,repeat:T}),e()}catch(e){n(e.message)}finally{w(!1)}}},O=`h-9 rounded-xl bg-surface border border-border px-3 text-[13px] outline-none focus:border-accent`;return(0,R.jsxs)(`div`,{className:`mb-2 rounded-2xl border border-border p-3 space-y-2`,children:[(0,R.jsx)(`input`,{autoFocus:!0,value:a,onChange:e=>o(e.target.value),placeholder:r(c===`task`?`What should be done…`:`What to remind you of…`),className:i(O,`w-full h-10 text-[14px]`)}),(0,R.jsxs)(`div`,{className:`flex gap-1.5 text-[12.5px]`,children:[(0,R.jsx)(gm,{options:[[`remind`,r(`Remind me`)],[`task`,r(`Do it for me`)]],value:c,onChange:e=>l(e)}),(0,R.jsx)(gm,{options:[[`once`,r(`Once`)],[`repeat`,r(`Repeat`)]],value:u,onChange:e=>d(e)})]}),u===`once`?(0,R.jsx)(`input`,{type:`datetime-local`,value:f,onChange:e=>p(e.target.value),className:i(O,`w-full`)}):(0,R.jsxs)(`div`,{className:`flex flex-wrap gap-1.5`,children:[(0,R.jsxs)(`select`,{value:h,onChange:e=>g(e.target.value),className:O,children:[(0,R.jsx)(`option`,{value:`daily`,children:r(`Every day`)}),(0,R.jsx)(`option`,{value:`weekdays`,children:r(`Weekdays`)}),(0,R.jsx)(`option`,{value:`weekly`,children:r(`Weekly`)}),(0,R.jsx)(`option`,{value:`monthly`,children:r(`Monthly`)})]}),h===`weekly`&&(0,R.jsx)(`select`,{value:y,onChange:e=>b(e.target.value),className:O,children:[`mon`,`tue`,`wed`,`thu`,`fri`,`sat`,`sun`].map((e,t)=>(0,R.jsx)(`option`,{value:e,children:new Date(2024,0,1+t).toLocaleDateString(m(),{weekday:`long`})},e))}),h===`monthly`&&(0,R.jsx)(`select`,{value:x,onChange:e=>S(e.target.value),className:O,children:Array.from({length:28},(e,t)=>String(t+1)).map(e=>(0,R.jsx)(`option`,{value:e,children:r(`Day {d}`,{d:e})},e))}),(0,R.jsx)(`input`,{type:`time`,value:_,onChange:e=>v(e.target.value),className:O})]}),(0,R.jsxs)(`div`,{className:`flex justify-end gap-2 pt-0.5`,children:[(0,R.jsx)(`button`,{type:`button`,onClick:t,className:`rounded-full px-3 py-1.5 text-[13px] text-muted`,children:r(`Cancel`)}),(0,R.jsx)(`button`,{type:`button`,onClick:()=>void D(),disabled:C||!a.trim(),className:`rounded-full bg-accent px-3.5 py-1.5 text-[13px] font-medium text-accent-fg disabled:opacity-50`,children:r(C?`Saving…`:u===`once`?`Set reminder`:`Set routine`)})]})]})}var fm={mail:Et,event:et,hook:_n};function pm(e,t){if(e.kind===`mail`)return e.match?t(`mail matching “{match}”`,{match:e.match}):t(`any new mail`);if(e.kind===`event`){let n=e.match?t(`events matching “{match}”`,{match:e.match}):t(`any event`);return t(`{n} min before {what}`,{n:e.lead_minutes,what:n})}return e.match?t(`webhook “{match}”`,{match:e.match}):t(`webhook`)}function mm({data:t,name:n,onChange:r}){let{toast:a}=E(),o=s(),[c,l]=(0,L.useState)(null),[u,d]=(0,L.useState)(!1),f=t.items.filter(e=>e.status===`active`),p=f.some(e=>e.kind===`mail`),m=async e=>{l(e.id);try{await M.cancelTrigger(e.id),r()}catch(e){a(e.message)}finally{l(null)}},h=async e=>{l(e.id);try{await M.fireTrigger(e.id),a(o(`{name} is on it`,{name:n})),r()}catch(e){a(e.message)}finally{l(null)}},g=async e=>{if(e.url)try{await navigator.clipboard.writeText(e.url),a(o(`Webhook URL copied`))}catch{a(e.url)}};return(0,R.jsxs)(`div`,{children:[(0,R.jsxs)(`div`,{className:`flex items-center justify-between mb-1.5`,children:[(0,R.jsx)(`div`,{className:`text-[12px] uppercase tracking-wide text-muted font-semibold`,children:o(`When something happens`)}),!u&&(0,R.jsx)(`button`,{type:`button`,onClick:()=>d(!0),className:`text-[12.5px] text-accent font-medium`,children:o(`+ Add`)})]}),u&&(0,R.jsx)(hm,{available:t.available,onDone:()=>{d(!1),r()},onCancel:()=>d(!1)}),f.length===0&&!u?(0,R.jsx)(`div`,{className:`text-[13px] text-muted`,children:o(`Nothing yet. Tell {name} “when the landlord writes back, summarise it and draft a reply” or “half an hour before any review, brief me”.`,{name:n})}):(0,R.jsx)(`ul`,{className:`space-y-1.5`,children:f.map(t=>{let n=fm[t.kind];return(0,R.jsxs)(`li`,{className:`flex items-start gap-2.5 rounded-2xl bg-surface-2/60 px-3 py-2`,children:[(0,R.jsx)(n,{size:15,className:`text-muted shrink-0 mt-[3px]`}),(0,R.jsxs)(`div`,{className:`min-w-0 flex-1`,children:[(0,R.jsx)(`div`,{className:`text-[13.5px] font-medium`,children:pm(t,o)}),(0,R.jsx)(`div`,{className:`text-[12px] leading-snug text-fg/80 line-clamp-2`,children:t.text}),(0,R.jsxs)(`div`,{className:`text-[11.5px] text-muted flex flex-wrap items-center gap-x-1.5`,children:[t.fired>0?(0,R.jsxs)(`span`,{children:[o(`fired {n}×`,{n:t.fired}),t.last_fired_at&&` · ${e(t.last_fired_at)}`]}):(0,R.jsx)(`span`,{children:o(`not fired yet`)}),t.kind===`hook`&&t.url&&(0,R.jsxs)(`button`,{type:`button`,onClick:()=>void g(t),className:`inline-flex items-center gap-1 text-accent font-medium`,children:[(0,R.jsx)(ut,{size:11}),` `,o(`Copy URL`)]})]})]}),(0,R.jsx)(`button`,{type:`button`,onClick:()=>void h(t),disabled:c!==null,"aria-label":o(`Run now: {text}`,{text:t.text}),className:`rounded-full bg-accent/12 p-2 text-accent disabled:opacity-50`,children:c===t.id?(0,R.jsx)(A,{size:15,className:`animate-spin`}):(0,R.jsx)(Gt,{size:15})}),(0,R.jsx)(`button`,{type:`button`,onClick:()=>void m(t),disabled:c!==null,"aria-label":o(`Cancel: {text}`,{text:t.text}),className:`rounded-full p-2 text-muted hover:text-fg disabled:opacity-50`,children:(0,R.jsx)(Fe,{size:15})})]},t.id)})}),p&&(0,R.jsx)(`div`,{className:i(`mt-1.5 text-[12px]`,t.mail_error?`text-rose-500`:`text-muted`),children:t.mail_error?o(`The inbox could not be read: {error}`,{error:t.mail_error}):t.mail_checked_at?o(`Inbox checked {when}; {name} looks every {n} min.`,{when:e(t.mail_checked_at),name:n,n:t.mail_poll_minutes}):o(`{name} will look at the inbox shortly, then every {n} min.`,{name:n,n:t.mail_poll_minutes})}),(0,R.jsx)(`div`,{className:`mt-1.5 text-[12px] text-muted`,children:o(`Each time it happens {name} does the work in the chat it was set from and reports in the Feed. A mail or a request is treated as data, never as instructions.`,{name:n})})]})}function hm({available:e,onDone:t,onCancel:n}){let{toast:r}=E(),a=s(),o=[`mail`,`event`,`hook`].find(t=>e[t])??`hook`,[c,l]=(0,L.useState)(o),[u,d]=(0,L.useState)(``),[f,p]=(0,L.useState)(`30`),[m,h]=(0,L.useState)(``),[g,_]=(0,L.useState)(!1),[v,y]=(0,L.useState)(null),b=async()=>{if(m.trim()){_(!0);try{let e=await M.createTrigger({kind:c,text:m.trim(),match:u.trim(),lead_minutes:Number(f)||30});e.kind===`hook`&&e.url?y(e):t()}catch(e){r(e.message)}finally{_(!1)}}},x=`h-9 rounded-xl bg-surface border border-border px-3 text-[13px] outline-none focus:border-accent`;if(v)return(0,R.jsxs)(`div`,{className:`mb-2 rounded-2xl border border-border p-3 space-y-2`,children:[(0,R.jsx)(`div`,{className:`text-[13.5px] font-medium`,children:a(`Webhook ready`)}),(0,R.jsx)(`div`,{className:`text-[12.5px] text-muted`,children:a(`POST anything to this URL and the work starts. The key is in the URL; share it only with the program that will call it.`)}),(0,R.jsx)(`code`,{className:`block break-all rounded-xl bg-surface-2 px-3 py-2 text-[12px]`,children:v.url}),(0,R.jsxs)(`div`,{className:`flex justify-end gap-2 pt-0.5`,children:[(0,R.jsx)(`button`,{type:`button`,onClick:()=>void navigator.clipboard.writeText(v.url??``).then(()=>r(a(`Webhook URL copied`)),()=>r(v.url??``)),className:`rounded-full px-3 py-1.5 text-[13px] text-accent font-medium`,children:a(`Copy`)}),(0,R.jsx)(`button`,{type:`button`,onClick:t,className:`rounded-full bg-accent px-3.5 py-1.5 text-[13px] font-medium text-accent-fg`,children:a(`Done`)})]})]});let S=[[`mail`,a(`New mail`)],[`event`,a(`Before an event`)],[`hook`,a(`Webhook`)]];return(0,R.jsxs)(`div`,{className:`mb-2 rounded-2xl border border-border p-3 space-y-2`,children:[(0,R.jsx)(gm,{options:S,value:c,onChange:e=>l(e)}),!e[c]&&(0,R.jsx)(`div`,{className:`text-[12.5px] text-rose-500`,children:a(c===`mail`?`Connect a mailbox under Connections first.`:`Add a calendar under Connections first.`)}),(0,R.jsxs)(`div`,{className:`flex gap-1.5`,children:[(0,R.jsx)(`input`,{value:u,onChange:e=>d(e.target.value),placeholder:a(c===`mail`?`Words in the sender or subject (empty: any mail)`:c===`event`?`Words in the title or place (empty: any event)`:`A name for this hook`),className:i(x,`min-w-0 flex-1`)}),c===`event`&&(0,R.jsxs)(`label`,{className:`flex items-center gap-1 text-[12.5px] text-muted`,children:[(0,R.jsx)(`input`,{type:`number`,min:0,max:1440,value:f,onChange:e=>p(e.target.value),className:i(x,`w-[64px] px-2`),"aria-label":a(`Minutes before`)}),a(`min before`)]})]}),(0,R.jsx)(`input`,{value:m,onChange:e=>h(e.target.value),placeholder:a(`What should be done each time…`),className:i(x,`w-full h-10 text-[14px]`)}),(0,R.jsx)(`div`,{className:`text-[12px] text-muted`,children:a(`When {condition}`,{condition:pm({kind:c,match:u.trim(),lead_minutes:Number(f)||30},a)})}),(0,R.jsxs)(`div`,{className:`flex justify-end gap-2 pt-0.5`,children:[(0,R.jsx)(`button`,{type:`button`,onClick:n,className:`rounded-full px-3 py-1.5 text-[13px] text-muted`,children:a(`Cancel`)}),(0,R.jsx)(`button`,{type:`button`,onClick:()=>void b(),disabled:g||!m.trim()||!e[c],className:`rounded-full bg-accent px-3.5 py-1.5 text-[13px] font-medium text-accent-fg disabled:opacity-50`,children:a(g?`Saving…`:`Set trigger`)})]})]})}function gm({options:e,value:t,onChange:n}){return(0,R.jsx)(`div`,{className:`flex rounded-full bg-surface-2 p-0.5`,children:e.map(([e,r])=>(0,R.jsx)(`button`,{type:`button`,onClick:()=>n(e),className:i(`rounded-full px-2.5 py-1 transition`,t===e?`bg-surface shadow-sm font-medium`:`text-muted`),children:r},e))})}function _m(){let e=new Date(Date.now()+36e5);e.setMinutes(0,0,0);let t=e=>String(e).padStart(2,`0`);return`${e.getFullYear()}-${t(e.getMonth()+1)}-${t(e.getDate())}T${t(e.getHours())}:${t(e.getMinutes())}`}function vm(e){let[t,n]=(0,L.useState)(null),[r,i]=(0,L.useState)(null),a=async()=>{try{n(await M.activity(150)),i(null)}catch(e){i(e.message||`Could not load.`)}};return(0,L.useEffect)(()=>{if(!e)return;a();let t=window.setInterval(()=>void a(),4e3);return()=>window.clearInterval(t)},[e]),[t,a,r]}function ym({open:e}){let[t,n,r]=vm(e),{state:i}=E(),a=s(),o=i.profile?.name??`nanoMuse`,c=(t?.audit??[]).filter(e=>e.event===`tool_call`).reverse(),l=c.filter(e=>e.channel===`gui`).length;return(0,R.jsxs)(`div`,{className:`pb-2`,children:[(0,R.jsx)(`p`,{className:`text-[12.5px] text-muted mb-2`,children:a(`Every tool call goes through the Sentinel and is written to the audit log, including the ones it refused.`)}),l>0&&(0,R.jsx)(`p`,{className:`text-[12.5px] text-muted mb-2`,children:a(`On the phone's screen: {gui} of {total} steps ({pct}%). The screen is the last resort; a skill, a fetch or the browser comes first.`,{gui:String(l),total:String(c.length),pct:String(Math.round(l/c.length*100))})}),!t&&r&&(0,R.jsx)(Jp,{message:r,onRetry:()=>void n()}),!t&&!r&&(0,R.jsx)(`div`,{className:`py-10 flex justify-center text-muted`,children:(0,R.jsx)(A,{className:`animate-spin`,size:20})}),t&&c.length===0&&(0,R.jsx)(`div`,{className:`py-8 text-center text-muted text-[14px]`,children:a(`Nothing yet today. What you ask for and what {name} does about it shows up here.`,{name:o})}),(0,R.jsx)(`ul`,{className:`space-y-1.5`,children:c.map((e,t)=>(0,R.jsx)(Tm,{entry:e},`${e.ts}-${t}`))})]})}function bm({open:e}){let{state:t,toast:n}=E(),r=s(),[i,a]=vm(e),o=async()=>{if(window.confirm(r(`Forget every permission you granted? {name} will ask again next time.`,{name:t.profile?.name??`nanoMuse`})))try{await M.resetApprovals(),await a(),n(r(`Permissions reset`))}catch(e){n(e.message)}},c=async e=>{try{await M.revokeGrant(e.key),await a(),n(r(`Revoked: {subject}`,{subject:pp(e.tool,e.target)}))}catch(e){n(e.message)}},l=t.settings?.sentinel.mode;return(0,R.jsxs)(`div`,{className:`space-y-4 pb-2`,children:[(0,R.jsxs)(`div`,{className:`rounded-2xl border border-border p-3.5`,children:[(0,R.jsxs)(`div`,{className:`flex items-center gap-2 font-medium`,children:[(0,R.jsx)(Qt,{size:18,className:`text-accent`}),` `,r(`Sentinel mode:`),` `,(0,R.jsx)(`span`,{className:`capitalize`,children:l===`ask`?r(`balanced`):l===`strict`?r(`cautious`):l===`auto`?r(`hands-off`):l})]}),(0,R.jsxs)(`p`,{className:`mt-1 text-[12.5px] text-muted`,children:[l===`ask`&&r(`Safe and moderate actions run freely; anything sensitive (email, shell, purchases) waits for you.`),l===`strict`&&r(`Moderate and sensitive actions both wait for your approval.`),l===`auto`&&r(`Everything is approved automatically except explicit deny rules. Use with care.`)]}),i?.tainted&&(0,R.jsxs)(`p`,{className:`mt-2 text-[12.5px] text-amber-600 dark:text-amber-300 flex items-center gap-1.5`,children:[(0,R.jsx)($t,{size:14}),` `,r(`Private data was read this session: network calls to new destinations need approval.`)]})]}),(0,R.jsx)(Cm,{grants:i?.grants??[],onRevoke:c}),(0,R.jsx)(wm,{title:r(`Always ask (from config)`),tools:t.settings?.sentinel.always_ask_tools??[],muted:!0}),(i?.grants.length??0)>0&&(0,R.jsx)(`button`,{type:`button`,onClick:()=>void o(),className:`w-full rounded-2xl border border-border py-2.5 text-[14px] font-medium`,children:r(`Reset all granted permissions`)})]})}function xm(e,t){switch(e.scope){case`conversation`:return t(`for this conversation`);case`session`:return t(`until restart`);case`24h`:return e.expires_at?t(`until {time}`,{time:u(e.expires_at)}):t(`for 24 hours`);case`always`:return t(`always`);default:return e.scope}}var Sm=[`sensitive`,`moderate`,`low`,`safe`];function Cm({grants:e,onRevoke:t}){let n=s(),{state:r}=E(),i=e=>r.settings?.tools.find(t=>t.name===e)?.risk??`moderate`,a=Sm.map(t=>({risk:t,rows:e.filter(e=>i(e.tool)===t)})).filter(e=>e.rows.length>0);return(0,R.jsx)(`div`,{className:`space-y-3`,children:e.length===0?(0,R.jsxs)(`div`,{children:[(0,R.jsx)(`div`,{className:`text-[12px] uppercase tracking-wide text-muted font-semibold mb-1.5`,children:n(`Permissions you granted`)}),(0,R.jsx)(`div`,{className:`text-[13px] text-muted`,children:n(`No standing approvals. When you answer “always allow” to a risky step, it is listed here and can be revoked; approvals you give once are not kept.`)})]}):a.map((e,r)=>(0,R.jsxs)(`div`,{children:[(0,R.jsxs)(`div`,{className:`text-[12px] uppercase tracking-wide text-muted font-semibold mb-1.5`,children:[r===0?`${n(`Permissions you granted`)} · `:``,n(e.risk)]}),(0,R.jsx)(`ul`,{className:`space-y-1.5`,children:e.rows.map(e=>(0,R.jsxs)(`li`,{className:`flex items-center gap-2.5 rounded-2xl bg-surface-2/60 px-3 py-2`,children:[(0,R.jsx)(`span`,{className:`text-accent`,children:sp(e.tool,15)}),(0,R.jsxs)(`div`,{className:`min-w-0 flex-1`,children:[(0,R.jsx)(`div`,{className:`text-[13.5px] font-medium truncate`,children:pp(e.tool,e.target)}),(0,R.jsxs)(`div`,{className:`text-[11.5px] text-muted`,children:[e.tool,` · `,xm(e,n),` · `,n(`granted {time}`,{time:u(e.granted_at)})]})]}),(0,R.jsx)(`button`,{type:`button`,"aria-label":n(`Revoke {what}`,{what:mp(e.scope,e.tool,e.target)}),onClick:()=>t(e),className:`rounded-full p-1.5 text-muted hover:bg-surface active:scale-95`,children:(0,R.jsx)(Fe,{size:15})})]},e.key))})]},e.risk))})}function wm({title:e,tools:t,muted:n}){let r=s();return(0,R.jsxs)(`div`,{children:[(0,R.jsx)(`div`,{className:`text-[12px] uppercase tracking-wide text-muted font-semibold mb-1.5`,children:e}),t.length===0?(0,R.jsx)(`div`,{className:`text-[13px] text-muted`,children:r(`None`)}):(0,R.jsx)(`div`,{className:`flex flex-wrap gap-1.5`,children:t.map(e=>(0,R.jsxs)(`span`,{className:i(`rounded-full px-2.5 py-1 text-[12.5px] flex items-center gap-1`,n?`bg-surface-2 text-muted`:`bg-accent/12 text-accent`),children:[sp(e,12),` `,e]},e))})]})}function Tm({entry:e}){let t=s(),n=e.decision===`deny`,r=e.ok===!1&&!n;return(0,R.jsxs)(`li`,{className:`flex items-start gap-2.5 rounded-2xl bg-surface-2/60 px-3 py-2`,children:[(0,R.jsx)(`div`,{className:i(`mt-0.5`,n?`text-rose-500`:r?`text-amber-500`:`text-muted`),children:n||r?(0,R.jsx)(Ye,{size:15}):(0,R.jsx)(ke,{size:15})}),(0,R.jsxs)(`div`,{className:`min-w-0 flex-1`,children:[(0,R.jsxs)(`div`,{className:`flex items-center gap-2 text-[13.5px]`,children:[(0,R.jsx)(`span`,{className:`text-muted`,children:sp(e.tool??``,13)}),(0,R.jsx)(`span`,{className:`font-medium truncate`,children:e.summary||e.tool})]}),(0,R.jsxs)(`div`,{className:`mt-0.5 flex flex-wrap items-center gap-x-2 gap-y-0.5 text-[11.5px] text-muted`,children:[(0,R.jsx)(`span`,{children:u(e.ts)}),e.risk&&(0,R.jsx)(up,{risk:e.risk}),e.approved===!0&&(0,R.jsxs)(`span`,{className:`text-emerald-600 dark:text-emerald-300`,children:[t(`approved by you`),e.approval_scope&&e.approval_scope!==`once`?` (${e.approval_scope})`:``]}),e.approved==null&&e.approval_scope&&e.approval_scope!==`once`&&(0,R.jsx)(`span`,{className:`text-emerald-600 dark:text-emerald-300`,children:t(`covered by your {scope} permission`,{scope:e.approval_scope})}),n&&(0,R.jsx)(`span`,{className:`text-rose-500`,children:t(`blocked`)}),r&&(0,R.jsx)(`span`,{className:`text-amber-600`,children:t(`failed`)}),typeof e.duration_ms==`number`&&(0,R.jsxs)(`span`,{children:[(e.duration_ms/1e3).toFixed(1),`s`]})]}),n&&e.reasons&&e.reasons.length>0&&(0,R.jsx)(`div`,{className:`mt-0.5 text-[12px] text-muted`,children:e.reasons.map(v).join(` · `)})]})]})}function Em({title:e,actions:t=[],trailing:n,children:r}){let{state:i,setDrawer:a}=E(),o=s(),[c,l]=(0,L.useState)(!1),u=i.profile?.name||`nanoMuse`,d=i.pendingApprovals.length,f=d>0?d>1?o(`{n} approvals waiting for you`,{n:d}):o(`1 approval waiting for you`):i.status.state===`working`?i.status.detail||o(`On it`):i.status.state===`waiting`?o(`Waiting for you`):null;return(0,R.jsxs)(R.Fragment,{children:[(0,R.jsx)(ne,{profile:i.profile,status:i.status,name:u,statusLine:f,statusTone:f?`accent`:`muted`,spinning:i.status.state===`working`&&d===0,badge:d,onAvatar:()=>l(!0),leading:(0,R.jsx)(te,{onClick:()=>a(!0),label:o(`Chats`),className:`wide:invisible`,children:(0,R.jsx)(Ot,{size:22})}),trailing:n??(0,R.jsx)(Dm,{actions:t})}),(e||r)&&(0,R.jsxs)(`div`,{className:`flex shrink-0 items-center gap-3 pr-5`,children:[(0,R.jsx)(k,{className:`flex-1`,children:e}),r]}),(0,R.jsx)(am,{open:c,onClose:()=>l(!1)})]})}function Dm({actions:e=[]}){let{setTab:t}=E(),n=s(),[r,i]=(0,L.useState)(!1),a=(0,L.useRef)(null);(0,L.useEffect)(()=>{if(!r)return;let e=e=>{a.current?.contains(e.target)||i(!1)},t=e=>{e.key===`Escape`&&i(!1)};return window.addEventListener(`pointerdown`,e),window.addEventListener(`keydown`,t),()=>{window.removeEventListener(`pointerdown`,e),window.removeEventListener(`keydown`,t)}},[r]);let o=e=>{i(!1),t(e)},c=[...e.map(e=>({label:e.label,onClick:()=>{i(!1),e.onClick()}})),{label:n(`Memory`),onClick:()=>o(`memory`)},{label:n(`Settings`),onClick:()=>o(`you`)}];return(0,R.jsxs)(`div`,{ref:a,className:`relative`,children:[(0,R.jsx)(te,{onClick:()=>i(e=>!e),label:n(`More`),expanded:r,children:(0,R.jsx)(pt,{size:22})}),r&&(0,R.jsx)(`ul`,{role:`menu`,className:`absolute right-0 top-12 z-30 min-w-[180px] overflow-hidden rounded-2xl border border-border bg-surface py-1 shadow-xl`,children:c.map(e=>(0,R.jsx)(`li`,{children:(0,R.jsx)(`button`,{type:`button`,role:`menuitem`,onClick:e.onClick,className:`w-full px-4 py-2.5 text-left text-[14.5px] hover:bg-surface-2`,children:e.label})},e.label))})]})}var Om=`nanomuse-naming`;function km(e){return e.replace(/[.*+?^${}()|[\]\\]/g,`\\$&`)}function Am(e,t,n=!1){let r="```"+t,i=e;if(i.includes(r)){let e=RegExp("```"+km(t)+"[ \\t]*\\r?\\n[\\s\\S]*?```",`g`);i=i.replace(e,``);let n=i.lastIndexOf(r);n>=0&&(i=i.slice(0,n))}if(n){let e=i.lastIndexOf("```");e>=0&&r.startsWith(i.slice(e))&&(i=i.slice(0,e))}return i===e?e:i.replace(/\s+$/,``)}function jm(e,t=!1){return Am(e,Om,t)}function Mm(e){return e.filter(e=>!e.this&&e.kind!==`web`&&e.name.trim()!==``)}function Nm(e){let t=/^@([^\s,:;,:;]*)$/.exec(e);return t?t[1]:null}function Pm(e,t,n=6){let r=Nm(e);if(r===null)return[];let i=r.toLowerCase();return Mm(t).filter(e=>e.name.toLowerCase().startsWith(i)).sort((e,t)=>Number(t.online)-Number(e.online)||e.name.localeCompare(t.name)).slice(0,n)}function Fm(e,t){let n=e.trimStart();if(!n.startsWith(`@`))return null;let r=n.slice(1),i=r.toLowerCase(),a=Mm(t),o=a.filter(e=>{let t=e.name.trim().toLowerCase();if(!i.startsWith(t))return!1;let n=r.charAt(t.length);return n===``||/[\s,:;,:;]/.test(n)}).sort((e,t)=>t.name.length-e.name.length);if(o[0])return o[0];let s=/^[^\s,:;,:;]+/.exec(r)?.[0]?.toLowerCase()??``;if(!s)return null;let c=a.filter(e=>e.name.trim().toLowerCase().startsWith(s));if(c.length===1)return c[0];let l=c.filter(e=>e.online);return l.length===1?l[0]:null}var Im=`nm.show_steps`;function Lm(){try{return localStorage.getItem(Im)!==`0`}catch{return!0}}var Rm=Lm(),zm=new Set;function Bm(){return Rm}function Vm(e){Rm=e;try{localStorage.setItem(Im,e?`1`:`0`)}catch{}zm.forEach(e=>e())}function Hm(e){return zm.add(e),()=>zm.delete(e)}function Um(){return(0,L.useSyncExternalStore)(Hm,Bm,Bm)}function Wm(){let{state:e,send:t,sendViaCloud:n,decide:r,loadEvents:i,openFile:a,toast:o,setDrawer:c,setTab:l}=E(),u=s(),{profile:d,status:f,activeThread:p,threads:m}=e,h=e.events[p],g=(0,L.useMemo)(()=>h??[],[h]),_=h!==void 0,v=e.streams[p],b=m.find(e=>e.id===p),[x,S]=(0,L.useState)(!1),[C,w]=(0,L.useState)(null),T=d?.name??`nanoMuse`,D=b?.device?e.hub?.devices.find(e=>e.id===b.device)?.online??null:null,O=nh(e.working[p]),k=(0,L.useRef)(null),ee=(0,L.useRef)(null),A=(0,L.useRef)(!0),[j,re]=(0,L.useState)(!1),N=e.firstrun,P=!!N&&N.phase!==`none`&&N.session_id===p,ie=P&&N.running,ae=y()===`zh-CN`?`zh`:`en`,[oe,se]=(0,L.useState)(null);(0,L.useEffect)(()=>{if(!P||oe?.lang===ae)return;let e=!0;return M.firstrun(ae).then(t=>e&&t.intro&&se({lang:ae,lines:t.intro})).catch(()=>void 0),()=>{e=!1}},[P,ae,oe?.lang]);let ce=e=>{M.firstrunPick(e).then(()=>t(p,e)).catch(e=>o(e.message||u(`Could not send`)))},le=()=>window.dispatchEvent(new Event(`nanomuse:quick-chat`)),[ue,de]=(0,L.useState)(null),fe=e.settings?.onboarded===!0,pe=(0,L.useRef)(!1),me=(0,L.useRef)(!1);(0,L.useEffect)(()=>{if(b?.busy){pe.current||(me.current=ie),pe.current=!0;return}pe.current&&(pe.current=!1,fe&&!me.current&&!ie&&ch(g)&&de(Se()))},[b?.busy,g,fe,ie]);let[he,ge]=(0,L.useState)(null);(0,L.useEffect)(()=>{let{days:e,fresh:t}=ye();t&&ge(e)},[]);let _e=(0,L.useCallback)(()=>{let e=k.current;e&&(e.scrollTop=e.scrollHeight,re(!1))},[]),ve=(0,L.useCallback)(()=>{let e=k.current;if(!e)return;let t=e.scrollHeight-e.scrollTop-e.clientHeight;A.current=t<120,re(t>400)},[]),be=(0,L.useRef)(null);(0,L.useLayoutEffect)(()=>{be.current!==p&&(be.current=p,A.current=!0),A.current&&_e()},[g,v?.text,p,_e]),(0,L.useEffect)(()=>{let e=k.current,t=ee.current;if(!e||!t||typeof ResizeObserver>`u`)return;let n=new ResizeObserver(()=>{A.current?_e():ve()});return n.observe(e),n.observe(t),()=>n.disconnect()},[_e,ve]);let xe=()=>{let e=k.current;e&&e.scrollTo({top:e.scrollHeight,behavior:`smooth`})},Ce=e.pendingApprovals.length,Te=e.pendingApprovals.filter(e=>e.thread===p).length,Ee=(0,L.useMemo)(()=>{let e=!f.thread||f.thread===p;if(Te>0&&!(e&&f.state===`working`))return Te>1?u(`{n} approvals waiting for you`,{n:Te}):u(`1 approval waiting for you`);if(!e)return b?.busy?u(`On it`):void 0;if(f.state===`idle`&&!b?.busy)return;if(f.detail)return f.detail;if(f.state===`waiting`)return u(`Waiting for you`);let t=sh(g);return t?u(`On it: {request}`,{request:t}):u(`On it`)},[f,b,p,Te,g,u]),De=g.filter(e=>e.type===`approval`&&e.status===`pending`).length,Oe=Um(),ke=(0,L.useMemo)(()=>Oe?g:g.filter(e=>e.type!==`tool`),[g,Oe]),Ae={signedIn:!!e.hub?.account.signed_in,chatOnCloud:!!e.settings?.llm.cloud,deviceChat:!!b?.device},je=e=>{let t=ep(ke,e,Ae);return t?()=>n(p,t.text,t.files):void 0},Ne=(0,L.useMemo)(()=>Array.from(new Set(g.flatMap(e=>e.type===`artifact`?[e.path]:[]))),[g]);return(0,R.jsxs)(`div`,{className:`flex h-full flex-col`,children:[(0,R.jsx)(ne,{profile:d,status:f,name:T,statusLine:Ee,statusTone:f.state===`idle`&&!b?.busy?`muted`:`accent`,spinning:(f.state===`working`&&f.thread===p||!!b?.busy)&&Te===0,badge:Ce,onAvatar:()=>S(!0),leading:(0,R.jsx)(te,{onClick:()=>c(!0),label:u(`Chats`),dot:m.length>1&&p!==`main`,className:`wide:invisible`,children:(0,R.jsx)(Ot,{size:22})}),trailing:(0,R.jsx)(Dm,{actions:[{label:u(`Coding agents`),onClick:()=>l(`coding`)}]}),under:b&&b.id!==`main`?b.device?(0,R.jsxs)(`span`,{className:`flex max-w-full items-center gap-1 rounded-full bg-accent/12 px-2.5 py-0.5 text-[11.5px] font-medium text-accent`,children:[D===!1?(0,R.jsx)(`span`,{className:`h-1.5 w-1.5 rounded-full bg-border`}):(0,R.jsx)(`span`,{className:`h-1.5 w-1.5 rounded-full bg-emerald-500`}),(0,R.jsx)(`span`,{className:`truncate`,children:u(`on {device}`,{device:b.device_name||b.device})})]}):b.remote_from?(0,R.jsxs)(`span`,{className:`flex max-w-full items-center gap-1 rounded-full bg-surface-2 px-2.5 py-0.5 text-[11.5px] font-medium text-fg/80`,children:[(0,R.jsx)(It,{size:11}),` `,(0,R.jsx)(`span`,{className:`truncate`,children:u(`from {device}`,{device:b.remote_from.name})})]}):(0,R.jsx)(`span`,{className:`truncate rounded-full bg-surface-2 px-2.5 py-0.5 text-[11.5px] font-medium text-fg/80`,children:b.title}):void 0}),(0,R.jsxs)(`div`,{ref:k,onScroll:ve,className:`relative flex-1 overflow-y-auto px-3 py-3`,children:[(0,R.jsxs)(`div`,{ref:ee,className:`space-y-2.5`,children:[e.hasMore[p]&&g.length>0&&(0,R.jsx)(`div`,{className:`flex justify-center`,children:(0,R.jsx)(`button`,{type:`button`,className:`text-[12.5px] text-accent px-3 py-1 rounded-full bg-surface-2`,onClick:()=>void i(p,g[0]?.id),children:u(`Load earlier messages`)})}),P&&_&&!e.hasMore[p]&&oe&&(0,R.jsx)(Fp,{lines:oe.lines}),_&&g.length===0&&!v&&!P&&(0,R.jsx)(ih,{name:T,device:b?.device?b.device_name||b.device:void 0,onSend:e=>t(p,e).catch(e=>o(e.message||u(`Could not send`)))}),ke.map((e,t)=>(0,R.jsx)(Gm,{event:e,prev:ke[t-1],name:T,onDecide:(t,n)=>r(e.id,t,n).catch(e=>o(e.message||u(`Could not send decision`))),onOpenFile:a,onOpenBrowser:w,files:Ne,onCloudRetry:je(t)},e.id)),v&&v.text&&(0,R.jsx)($m,{text:v.text,streaming:!0,files:Ne,onOpenFile:a}),(b?.busy||f.state!==`idle`)&&!v?.text&&f.state!==`waiting`&&(0,R.jsx)(th,{label:b?.queued?u(`{n} queued`,{n:b.queued}):void 0}),P&&N.phase===`ask_agent_name`&&!b?.busy&&(0,R.jsx)(Ip,{chips:N.chips,chosen:N.chosen,onPick:ce,onElse:le}),O&&!b?.busy&&(0,R.jsx)(rh,{who:O}),!b?.busy&&f.state===`idle`&&ue!==null&&(0,R.jsx)(we,{moment:`tasks`,n:ue,className:`mx-1 my-2`}),!b?.busy&&f.state===`idle`&&he!==null&&(0,R.jsx)(we,{moment:`days_used`,n:he,className:`mx-1 my-2`})]}),j&&(0,R.jsxs)(`button`,{type:`button`,onClick:xe,className:`sticky bottom-2 left-1/2 -translate-x-1/2 rounded-full bg-surface border border-border shadow px-3 py-1.5 text-[12.5px] flex items-center gap-1`,children:[(0,R.jsx)(Me,{size:14}),` `,u(`Latest`),De?` · ${u(`{n} approval`,{n:De})}`:``]})]}),(0,R.jsx)(Rf,{}),(0,R.jsx)(ah,{name:T,busy:!!b?.busy&&De===0,waiting:g.some(e=>e.type===`question`&&e.status===`pending`),onSend:(e,n)=>t(p,e,n).catch(e=>{throw o(e.message||u(`Could not send`)),e})}),(0,R.jsx)(am,{open:x,onClose:()=>S(!1)}),C&&(0,R.jsx)(Ap,{thread:p,eventId:C,onClose:()=>w(null)})]})}function Gm({event:e,prev:t,name:n,onDecide:r,onOpenFile:i,onOpenBrowser:a,files:o,onCloudRetry:s}){let c=qm(t,e)?(0,R.jsx)(Jm,{ts:e.ts}):null,l=(()=>{switch(e.type){case`user`:return(0,R.jsx)(Ym,{event:e,onOpenFile:i});case`assistant`:return e.quiet?(0,R.jsx)(eh,{text:e.text,about:e.about,ts:e.ts}):(0,R.jsx)($m,{text:e.text,reasoning:e.reasoning,continued:t?.type===`assistant`,files:o,onOpenFile:i,spoken:e.via===`call`,modelUsed:e.model_used});case`tool`:return(0,R.jsx)(fp,{event:e});case`approval`:return(0,R.jsx)(hp,{event:e,name:n,onDecide:r});case`question`:return(0,R.jsx)(gp,{event:e,name:n});case`notice`:return(0,R.jsx)(vp,{event:e,onCloudRetry:s});case`artifact`:return(0,R.jsx)(Ep,{event:e,onOpen:i});case`browser`:return(0,R.jsx)(yp,{event:e,onOpen:a});case`hands`:return(0,R.jsx)(bp,{event:e,name:n});case`hold`:return(0,R.jsx)(wp,{event:e,name:n});case`avatar`:return(0,R.jsx)(np,{event:e,name:n});default:return null}})();return l?(0,R.jsxs)(R.Fragment,{children:[c,l]}):null}var Km=6e5;function qm(e,t){return t.ts?!e?.ts||new Date(t.ts).getTime()-new Date(e.ts).getTime()>=Km:!1}function Jm({ts:e}){let t=l(e);return t?(0,R.jsx)(`div`,{className:`pt-2 pb-0.5 text-center text-[11.5px] font-medium text-muted`,children:t}):null}function Ym({event:e,onOpenFile:t}){let n=s(),r=e.files??[],a=r.filter(e=>e.kind===`image`),o=r.filter(e=>e.kind!==`image`);return(0,R.jsxs)(`div`,{className:`rise flex flex-col items-end pl-12`,children:[e.via===`call`?(0,R.jsxs)(`span`,{className:`mb-1 flex items-center gap-1 text-[11.5px] font-medium text-muted`,children:[(0,R.jsx)(Ut,{size:11}),` `,n(`said on a call`)]}):e.via?(0,R.jsx)(`span`,{className:`mb-1 text-[11.5px] font-medium text-muted`,children:n(`asked from {device}`,{device:e.via})}):e.to_device_name||e.to_device?(0,R.jsxs)(`span`,{className:`mb-1 flex items-center gap-1 text-[11.5px] font-medium text-accent`,children:[(0,R.jsx)(It,{size:11}),` `,n(`to {device}`,{device:e.to_device_name||e.to_device||``})]}):(e.via_device_name||e.via_device)&&(0,R.jsx)(`span`,{className:`mb-1 text-[11.5px] font-medium text-muted`,children:n(`From {device}`,{device:e.via_device_name||e.via_device||``})}),a.length>0&&(0,R.jsx)(`div`,{className:`mb-1 flex max-w-full flex-wrap justify-end gap-1.5`,children:a.map(e=>(0,R.jsx)(`button`,{type:`button`,onClick:()=>t(e.path),"aria-label":e.name,className:i(`overflow-hidden rounded-2xl border border-border/60 bg-surface-2 shadow-sm active:scale-[0.98] transition`,a.length===1?`max-h-64 max-w-[240px]`:`h-28 w-28`),children:(0,R.jsx)(`img`,{src:h(e.path),alt:e.name,loading:`lazy`,className:i(`object-cover`,a.length===1?`max-h-64 w-auto max-w-full`:`h-full w-full`)})},e.path))}),o.map(e=>(0,R.jsxs)(`button`,{type:`button`,onClick:()=>t(e.path),className:`mb-1 flex max-w-full items-center gap-2.5 rounded-2xl border border-border bg-surface px-3 py-2 text-left shadow-sm hover:bg-surface-2 active:scale-[0.98] transition`,children:[(0,R.jsx)(`span`,{className:`rounded-xl bg-accent/12 p-2 text-accent`,children:e.kind===`data`?(0,R.jsx)(cn,{size:17}):(0,R.jsx)(mt,{size:17})}),(0,R.jsxs)(`span`,{className:`min-w-0`,children:[(0,R.jsx)(`span`,{className:`block truncate text-[14px] font-medium`,children:e.name}),(0,R.jsx)(`span`,{className:`block text-[11.5px] text-muted`,children:Xm(e.size)})]})]},e.path)),e.text&&(0,R.jsx)(`div`,{className:`bubble-user max-w-full rounded-[20px] bg-bubble-user px-4 py-2.5 text-bubble-user-fg`,children:(0,R.jsx)(`div`,{className:`md text-[15px] leading-[1.45] whitespace-pre-wrap break-words`,children:e.text})})]})}function Xm(e){return e<1024?`${e} B`:e<1048576?`${Math.round(e/1024)} KB`:`${(e/1048576).toFixed(1)} MB`}function Zm(e){let t=e.toLowerCase().split(`.`).pop()??``;return[`csv`,`tsv`,`json`,`xlsx`,`xls`].includes(t)?`data`:`other`}var Qm=`image/*,.pdf,.txt,.md,.csv,.tsv,.json,.log,.html,.xml,.yaml,.yml,.toml,.ics,.vcf,.xlsx,.xls,.docx`;function $m({text:e,reasoning:t,streaming:n,continued:r,files:a,onOpenFile:o,spoken:c,modelUsed:l}){let[u,d]=(0,L.useState)(!1),f=s(),p=(0,L.useMemo)(()=>mf(jm(e,!!n)),[e,n]);return p.length===0&&!n&&!t?null:(0,R.jsx)(`div`,{className:i(`rise flex items-end gap-2 pr-10`,r&&`-mt-1`),children:(0,R.jsxs)(`div`,{className:`min-w-0 max-w-full`,children:[t&&(0,R.jsx)(`button`,{type:`button`,className:`mb-1 ml-1 text-[12px] text-muted`,onClick:()=>d(e=>!e),children:f(u?`Hide thinking`:`Show thinking`)}),t&&u&&(0,R.jsx)(`div`,{className:`mb-1.5 rounded-2xl bg-surface-2/70 px-3 py-2 text-[13px] text-muted whitespace-pre-wrap break-words`,children:t}),p.map((e,t)=>e.bare?(0,R.jsx)(`div`,{className:`my-1 max-w-full`,children:(0,R.jsx)(hf,{text:e.text,files:a,onOpenFile:o})},t):(0,R.jsxs)(`div`,{className:i(`my-1 max-w-[340px] rounded-[20px] bg-surface-2 px-3.5 py-2.5 wide:max-w-[600px]`,c&&`border border-accent/15`),children:[c&&t===0&&(0,R.jsxs)(`div`,{className:`mb-0.5 flex items-center gap-1 text-[11px] font-medium text-accent/80`,children:[(0,R.jsx)(Ut,{size:10}),` `,f(`said on a call`)]}),(0,R.jsx)(hf,{text:e.text,files:a,onOpenFile:o}),n&&t===p.length-1&&(0,R.jsx)(`span`,{className:`inline-block w-1.5 h-4 ml-0.5 align-middle bg-accent/70 animate-pulse rounded-sm`})]},t)),p.length===0&&n&&(0,R.jsx)(`div`,{className:`my-1 rounded-[20px] bg-surface-2 px-3.5 py-2.5`,children:(0,R.jsx)(`span`,{className:`inline-block w-1.5 h-4 align-middle bg-accent/70 animate-pulse rounded-sm`})}),l&&!n&&(0,R.jsx)(`div`,{className:`ml-1 text-[11px] text-muted`,children:f(`Answered by nanoMuse Cloud this time ({model})`,{model:l})})]})})}function eh({text:e,about:n,ts:r}){let[i,a]=(0,L.useState)(!1),o=s(),c=n?t(n.replace(/^Working on your goal: /,``)):o(`background check`);return(0,R.jsx)(`div`,{className:`rise flex justify-center px-6`,children:(0,R.jsxs)(`button`,{type:`button`,onClick:()=>a(e=>!e),className:`max-w-full rounded-2xl px-3 py-1.5 text-[12px] text-muted text-center leading-snug`,children:[(0,R.jsxs)(`span`,{className:`inline-flex items-center gap-1.5`,children:[(0,R.jsx)(Rt,{size:12}),` `,o(`Checked on {label}: nothing new`,{label:c}),r?` · ${u(r)}`:``]}),i&&(0,R.jsx)(`span`,{className:`block mt-1 text-left whitespace-pre-wrap text-[12.5px]`,children:e})]})})}function th({label:e}){return(0,R.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,R.jsxs)(`div`,{className:`rounded-[20px] rounded-bl-md bg-surface-2 px-3.5 py-2.5 flex items-center gap-1`,children:[(0,R.jsx)(`span`,{className:`typing-dot h-2 w-2 rounded-full bg-muted`}),(0,R.jsx)(`span`,{className:`typing-dot h-2 w-2 rounded-full bg-muted`}),(0,R.jsx)(`span`,{className:`typing-dot h-2 w-2 rounded-full bg-muted`})]}),e&&(0,R.jsx)(`span`,{className:`text-[12px] text-muted`,children:e})]})}function nh(e){let t=e?e.at*1e3+N:0,[n,r]=(0,L.useState)(0);return(0,L.useEffect)(()=>{if(!t)return;let e=t-Date.now();if(e<=0){r(t);return}let n=window.setTimeout(()=>r(t),e+50);return()=>window.clearTimeout(n)},[t]),!e||n===t?null:e}function rh({who:e}){let t=s();return(0,R.jsxs)(`div`,{className:`flex items-center gap-1.5 px-1 text-[12px] text-muted`,children:[(0,R.jsx)(A,{size:12,className:`animate-spin`}),(0,R.jsx)(`span`,{children:t(`{device} is working…`,{device:e.device_name||e.device})})]})}function ih({name:e,device:t,onSend:n}){let r=s(),i=t?[r(`What is on your screen right now?`),r(`Which folder are you in, and what is in it?`),r(`Check for updates and tell me what needs a restart`)]:[r(`What can you do for me?`),r(`Plan my week: ask me what's on my plate`),r(`Research and compare two options for me`),r(`Set up a long-term goal and track it`)];return(0,R.jsxs)(`div`,{className:`flex flex-col items-center text-center px-6 pt-10 pb-6 gap-3`,children:[(0,R.jsx)(`div`,{className:`text-[20px] font-semibold`,children:t?r(`This chat goes to {device}.`,{device:t}):r(`Hi, I'm {name}.`,{name:e})}),(0,R.jsx)(`p`,{className:`text-muted text-[14.5px] leading-snug max-w-sm`,children:t?r(`Whatever you ask here, the {name} on {device} does where it is: its shell, its files, its screen. Every step shows up here, and anything that needs an approval asks you here.`,{name:e,device:t}):r(`I don't just answer; I get things done: research, plans, files, code, email, long-running goals. Everything I do shows up here, and anything hard to undo waits for your approval.`)}),(0,R.jsx)(`div`,{className:`mt-2 flex flex-wrap justify-center gap-2`,children:i.map(e=>(0,R.jsx)(`button`,{type:`button`,onClick:()=>n(e),className:`rounded-full bg-surface-2 px-3.5 py-1.5 text-[13.5px] hover:bg-border/60`,children:e},e))})]})}function ah({name:e,busy:t,waiting:n,onSend:r}){let{state:a,draft:o,draftFiles:c,toast:l}=E(),[u,d]=(0,L.useState)(``),[f,p]=(0,L.useState)(!1),m=(0,L.useRef)(``),g=Np((0,L.useCallback)((e,t)=>{let n=m.current,r=n&&!/\s$/.test(n)?` `:``;d(n+r+e+t)},[]),(0,L.useCallback)(e=>l(e),[l])),_=()=>{g.listening||(m.current=u),g.toggle()},[v,y]=(0,L.useState)([]),[b,x]=(0,L.useState)([]);(0,L.useEffect)(()=>{if(!a.draftFiles)return;let e=a.draftFiles.map(e=>({key:`shared-${e.path}`,file:new File([],e.name),preview:e.kind===`image`?h(e.path):null,info:e,error:null}));x(t=>[...t.filter(t=>!e.some(e=>e.key===t.key)),...e].slice(0,10)),c(null)},[a.draftFiles]);let S=(0,L.useRef)(null),C=(0,L.useRef)(null),w=s();(0,L.useEffect)(()=>()=>b.forEach(e=>e.preview?.startsWith(`blob:`)&&URL.revokeObjectURL(e.preview)),[b]),(0,L.useEffect)(()=>{let e=()=>S.current?.focus();return window.addEventListener(`nanomuse:quick-chat`,e),()=>window.removeEventListener(`nanomuse:quick-chat`,e)},[]);let T=e=>{let t=Array.from(e).slice(0,Math.max(0,10-b.length));if(t.length===0)return;let n=t.map(e=>({key:`${e.name}-${e.size}-${e.lastModified}-${Math.random().toString(36).slice(2,7)}`,file:e,preview:e.type.startsWith(`image/`)?URL.createObjectURL(e):null,info:null,error:null}));x(e=>[...e,...n]);for(let e of n)M.upload(e.file).then(t=>x(n=>n.map(n=>n.key===e.key?{...n,info:t}:n))).catch(t=>{let n=t.message?P(t.message):w(`Upload failed`);x(t=>t.map(t=>t.key===e.key?{...t,error:n}:t)),l(n)})},D=e=>x(t=>t.filter(t=>t.key!==e)),O=b.some(e=>!e.info&&!e.error),k=b.flatMap(e=>e.info?[e.info.path]:[]);(0,L.useEffect)(()=>{let e=S.current;e&&(e.style.height=`0px`,e.style.height=`${Math.min(e.scrollHeight,160)}px`)},[u]),(0,L.useEffect)(()=>{if(a.draft===null)return;d(a.draft),o(null);let e=S.current;e&&(e.focus(),e.setSelectionRange(e.value.length,e.value.length))},[a.draft]);let ee=a.settings?.skills?.enabled!==!1;(0,L.useEffect)(()=>{ee&&M.skills().then(e=>y(e.skills.filter(e=>e.enabled))).catch(()=>y([]))},[ee,a.skillsVersion]);let te=/^\/([a-z0-9-]*)$/i.exec(u),j=te?v.filter(e=>e.name.startsWith(te[1].toLowerCase())).slice(0,6):[],ne=e=>{d(`/${e.name} `),S.current?.focus()},re=a.hub?.devices??[],N=Pm(u,re),ie=N.length===0?Fm(u,re):null,ae=e=>{d(`@${e.name} `),S.current?.focus()},oe=e=>{e?.preventDefault();let t=u.trim();if(!t&&k.length===0||O||f)return;g.listening&&g.stop();let n=b;p(!0),d(``),x([]),S.current?.focus(),r(t,k).catch(()=>{d(e=>e||t),x(e=>e.length?e:n)}).finally(()=>p(!1))};return(0,R.jsxs)(`form`,{onSubmit:oe,className:`shrink-0 bg-bg px-3 pt-1.5 pb-1`,children:[t&&!n&&(0,R.jsx)(`div`,{className:`px-2 pb-1 text-[12px] text-muted`,children:w(`{name} is working; anything you send now is picked up right away.`,{name:e})}),j.length>0&&(0,R.jsx)(`ul`,{className:`mb-2 max-h-72 overflow-y-auto rounded-3xl border border-border/70 bg-surface shadow-lg divide-y divide-border/70`,role:`listbox`,"aria-label":w(`Skills`),children:j.map(e=>(0,R.jsx)(`li`,{children:(0,R.jsxs)(`button`,{type:`button`,onClick:()=>ne(e),className:`flex w-full items-center gap-3 px-4 py-2.5 text-left hover:bg-surface-2/70 active:bg-surface-2`,children:[(0,R.jsx)(gn,{size:16,className:`shrink-0 text-accent`}),(0,R.jsxs)(`span`,{className:`min-w-0 flex-1`,children:[(0,R.jsxs)(`span`,{className:`block text-[14px] font-medium`,children:[`/`,e.name]}),(0,R.jsx)(`span`,{className:`block truncate text-[12.5px] text-muted`,children:e.description})]})]})},e.name))}),N.length>0&&(0,R.jsx)(`ul`,{className:`mb-2 max-h-72 overflow-y-auto rounded-3xl border border-border/70 bg-surface shadow-lg divide-y divide-border/70`,role:`listbox`,"aria-label":w(`Devices`),children:N.map(e=>(0,R.jsx)(`li`,{children:(0,R.jsxs)(`button`,{type:`button`,onClick:()=>ae(e),className:`flex w-full items-center gap-3 px-4 py-2.5 text-left hover:bg-surface-2/70 active:bg-surface-2`,children:[(0,R.jsx)(`span`,{className:`shrink-0 text-accent`,children:e.kind===`computer`?(0,R.jsx)(Lt,{size:16}):(0,R.jsx)(tn,{size:16})}),(0,R.jsxs)(`span`,{className:`min-w-0 flex-1`,children:[(0,R.jsxs)(`span`,{className:`block text-[14px] font-medium`,children:[`@`,e.name]}),(0,R.jsx)(`span`,{className:`block truncate text-[12.5px] text-muted`,children:e.online?w(`Runs this there and reports back`):w(`Offline`)})]})]})},e.id))}),ie&&(0,R.jsxs)(`div`,{className:`flex items-center gap-1.5 px-2 pb-1 text-[12px] text-muted`,children:[(0,R.jsx)(It,{size:12}),` `,w(`This goes to {device}.`,{device:ie.name})]}),b.length>0&&(0,R.jsx)(`div`,{className:`mb-1 flex gap-2.5 overflow-x-auto px-1 pt-2.5 pb-1 pr-3`,role:`list`,"aria-label":w(`Attachments`),children:b.map(e=>(0,R.jsxs)(`div`,{role:`listitem`,className:i(`relative shrink-0 rounded-2xl border bg-surface-2`,e.error?`border-danger/60`:`border-border/70`),children:[e.preview?(0,R.jsx)(`img`,{src:e.preview,alt:e.file.name,className:`h-16 w-16 rounded-2xl object-cover`}):(0,R.jsxs)(`div`,{className:`flex h-16 w-40 items-center gap-2 px-2.5`,children:[(0,R.jsx)(`span`,{className:`rounded-xl bg-accent/12 p-1.5 text-accent`,children:Zm(e.file.name)===`data`?(0,R.jsx)(cn,{size:16}):(0,R.jsx)(mt,{size:16})}),(0,R.jsxs)(`span`,{className:`min-w-0`,children:[(0,R.jsx)(`span`,{className:`block truncate text-[12.5px] font-medium`,children:e.file.name}),(0,R.jsx)(`span`,{className:`block text-[11px] text-muted`,children:e.error?w(`Upload failed`):Xm(e.info?.size??e.file.size)})]})]}),!e.info&&!e.error&&(0,R.jsx)(`div`,{className:`absolute inset-0 flex items-center justify-center rounded-2xl bg-bg/50`,children:(0,R.jsx)(A,{size:18,className:`animate-spin text-accent`})}),(0,R.jsx)(`button`,{type:`button`,onClick:()=>D(e.key),"aria-label":w(`Remove`),className:`absolute -right-1.5 -top-1.5 flex h-6 w-6 items-center justify-center rounded-full border border-border bg-surface text-muted shadow-sm`,children:(0,R.jsx)(Fe,{size:13})})]},e.key))}),(0,R.jsxs)(`div`,{className:`flex items-end gap-2 rounded-[26px] border border-border bg-surface px-1.5 py-1.5 shadow-[0_2px_12px_-6px_rgba(0,0,0,0.12)] focus-within:border-fg/20`,children:[(0,R.jsx)(`input`,{ref:C,type:`file`,multiple:!0,accept:Qm,className:`hidden`,onChange:e=>{e.target.files&&T(e.target.files),e.target.value=``}}),(0,R.jsx)(`button`,{type:`button`,onClick:()=>C.current?.click(),"aria-label":w(`Attach a file`),className:`flex h-9 w-9 shrink-0 items-center justify-center rounded-full text-fg/70 transition hover:bg-surface-2 active:scale-95`,children:(0,R.jsx)(I,{size:22})}),(0,R.jsx)(`textarea`,{ref:S,value:u,onChange:e=>d(e.target.value),onPaste:e=>{let t=Array.from(e.clipboardData?.files??[]);t.length>0&&(e.preventDefault(),T(t))},onKeyDown:e=>{if(e.key===`Tab`&&j.length>0&&j[0]){e.preventDefault(),ne(j[0]);return}if(e.key===`Tab`&&N.length>0&&N[0]){e.preventDefault(),ae(N[0]);return}e.key===`Enter`&&!e.shiftKey&&!e.nativeEvent.isComposing&&(e.preventDefault(),oe())},rows:1,placeholder:n?w(`Answer {name}…`,{name:e}):b.length>0?w(`Say what to do with it…`):w(`Message`),className:`flex-1 resize-none bg-transparent px-1 py-2 text-[15px] leading-[1.4] outline-none placeholder:text-muted`}),g.supported&&(0,R.jsx)(Pp,{listening:g.listening,onClick:_}),(0,R.jsx)(`button`,{type:`submit`,disabled:!u.trim()&&k.length===0||O,"aria-label":w(`Send`),className:i(`flex h-9 w-9 shrink-0 items-center justify-center rounded-full transition active:scale-95`,u.trim()||k.length>0?`bg-accent text-accent-fg`:`bg-surface-2 text-muted`,`disabled:opacity-60`),children:(0,R.jsx)(Je,{size:19,strokeWidth:2.5})})]})]})}function oh({threads:e,active:t,onPick:n,onCleared:r,compact:a=!1,grouped:o=!1}){let{state:c,toast:l,dispatch:d}=E(),f=s(),[p,m]=(0,L.useState)(``),[h,g]=(0,L.useState)(!1),_=(0,L.useRef)(null),v=(c.hub?.devices??[]).filter(e=>!e.this&&e.kind!==`web`&&e.online),y=e=>c.hub?.devices.find(t=>t.id===e)?.kind??`phone`,b=async e=>{try{let t=await M.askDevice(e.id);d({type:`ws`,msg:{kind:`thread`,thread:t.thread}}),n(t.thread.id)}catch(e){l(e.message)}},x=async()=>{g(!0);try{let e=await M.createThread(p.trim()||f(`Side chat`));d({type:`ws`,msg:{kind:`thread`,thread:e}}),m(``),n(e.id)}catch(e){l(e.message)}finally{g(!1)}},S=async e=>{if(window.confirm(f(`Delete this side chat and its history?`)))try{await M.deleteThread(e),d({type:`ws`,msg:{kind:`thread_deleted`,thread:e}})}catch(e){l(e.message)}},C=async e=>{if(window.confirm(f(`Clear this conversation? Memory and goals are kept.`)))try{await M.clearThread(e),d({type:`ws`,msg:{kind:`thread_cleared`,thread:e}}),r?.()}catch(e){l(e.message)}},w=e=>(0,R.jsxs)(`li`,{className:i(`group flex items-center gap-2 px-3`,a?`py-2 rounded-xl hover:bg-surface-2/60`:`py-2.5`,e.id===t&&`bg-surface-2/60`),children:[(0,R.jsxs)(`button`,{type:`button`,onClick:()=>n(e.id),className:`flex-1 text-left min-w-0`,children:[(0,R.jsxs)(`div`,{className:i(`font-medium truncate flex items-center gap-2`,a?`text-[13.5px]`:`text-[15px]`),children:[e.device?(0,R.jsx)(`span`,{className:`text-accent`,children:y(e.device)===`computer`?(0,R.jsx)(Lt,{size:14}):(0,R.jsx)(tn,{size:14})}):e.remote_from?(0,R.jsx)(It,{size:14,className:`text-muted`}):null,(0,R.jsx)(`span`,{className:`truncate`,children:e.id===`main`?f(e.title):e.title}),e.busy&&(0,R.jsx)(`span`,{className:`h-1.5 w-1.5 shrink-0 rounded-full bg-amber-400 animate-pulse`})]}),(0,R.jsxs)(`div`,{className:i(`text-muted`,a?`text-[11.5px]`:`text-[12px]`),children:[f(`{n} events`,{n:e.events}),e.queued?` · ${f(`{n} queued`,{n:e.queued})}`:``,` · `,u(e.updated_at)]})]}),(0,R.jsx)(`button`,{type:`button`,"aria-label":f(`Clear`),onClick:()=>void C(e.id),className:i(`p-2 text-muted hover:text-fg`,a&&`opacity-0 group-hover:opacity-100 focus:opacity-100`),children:(0,R.jsx)(Fe,{size:16})}),e.id!==`main`&&(0,R.jsx)(`button`,{type:`button`,"aria-label":f(`Delete`),onClick:()=>void S(e.id),className:i(`p-2 text-muted hover:text-rose-500`,a&&`opacity-0 group-hover:opacity-100 focus:opacity-100`),children:(0,R.jsx)(fn,{size:16})})]},e.id),T=i(`divide-y divide-border overflow-hidden`,a?`rounded-xl`:`rounded-2xl border border-border`),D=`px-3 pb-1 pt-3 text-[11.5px] font-semibold uppercase tracking-wide text-muted`;return(0,R.jsxs)(`div`,{children:[o?(0,R.jsxs)(R.Fragment,{children:[(0,R.jsx)(`div`,{className:D,children:f(`Main chat`)}),(0,R.jsx)(`ul`,{className:T,children:e.filter(e=>e.id===`main`).map(w)}),(0,R.jsxs)(`div`,{className:i(D,`flex items-center justify-between pr-1`),children:[(0,R.jsx)(`span`,{children:f(`Side chats`)}),(0,R.jsx)(`button`,{type:`button`,"aria-label":f(`New side chat`),onClick:()=>_.current?.focus(),className:`flex h-6 w-6 items-center justify-center rounded-full text-muted hover:bg-surface-2 hover:text-fg`,children:(0,R.jsx)(I,{size:15})})]}),(0,R.jsx)(`ul`,{className:T,children:e.filter(e=>e.id!==`main`).map(w)}),e.every(e=>e.id===`main`)&&(0,R.jsx)(`p`,{className:`px-3 py-2 text-[12px] text-muted`,children:f(`A side chat keeps one topic apart from the rest.`)})]}):(0,R.jsx)(`ul`,{className:T,children:e.map(w)}),v.length>0&&(0,R.jsxs)(`div`,{className:`mt-4`,children:[(0,R.jsx)(`div`,{className:`mb-1.5 text-[12px] font-medium text-muted`,children:f(`Ask one of your devices`)}),(0,R.jsx)(`div`,{className:`flex flex-wrap gap-2`,children:v.map(e=>(0,R.jsxs)(`button`,{type:`button`,onClick:()=>void b(e),className:`flex items-center gap-1.5 rounded-full border border-border bg-surface px-3 py-1.5 text-[13px] font-medium hover:bg-surface-2`,children:[e.kind===`phone`?(0,R.jsx)(tn,{size:14,className:`text-accent`}):(0,R.jsx)(Lt,{size:14,className:`text-accent`}),e.name]},e.id))})]}),(0,R.jsxs)(`div`,{className:i(`flex gap-2`,a?`mt-3`:`mt-4`),children:[(0,R.jsx)(`input`,{ref:_,value:p,onChange:e=>m(e.target.value),onKeyDown:e=>{e.key===`Enter`&&!h&&x()},placeholder:f(a?`New side chat`:`New side chat, e.g. “Trip to Kyoto”`),className:i(`min-w-0 flex-1 bg-surface-2 outline-none focus:ring-2 focus:ring-accent/40`,a?`rounded-xl px-3 py-2 text-[13px]`:`rounded-2xl px-3.5 py-2.5 text-[14px]`)}),(0,R.jsxs)(`button`,{type:`button`,disabled:h,onClick:()=>void x(),"aria-label":f(`New`),className:i(`flex items-center gap-1.5 bg-accent text-accent-fg font-medium disabled:opacity-50`,a?`rounded-xl px-2.5`:`rounded-2xl px-3.5 py-2.5`),children:[(0,R.jsx)(jt,{size:18}),` `,!a&&f(`New`)]})]})]})}function sh(e){let t=[...e].reverse().find(e=>e.type===`user`),n=(((t?.type===`user`?t.text:``)||``).split(/\r?\n/).map(e=>e.trim()).find(e=>e.length>0)??``).replace(/\s+/g,` `);if(n.length<=36)return n;let r=n.slice(0,36),i=r.lastIndexOf(` `);return(i>16?r.slice(0,i):r).trimEnd()+`…`}function ch(e){let t=!1;for(let n=e.length-1;n>=0;n--){let r=e[n];if(r.type===`assistant`){if(!r.text||r.quiet)return!1;t=!0;continue}if(r.type===`user`)return t&&!r.via;if(r.type===`notice`)return!1}return!1}function lh(e){let t=Sn(),n=t?`Desktop app (${t.platform}, shell ${t.version})`:`Web app (${navigator.userAgent})`;return`https://github.com/nano-muse/nanoMuse/issues/new?${new URLSearchParams({template:`bug_report.yml`,version:e||``,os:n}).toString()}`}function uh(){let{state:e,setTab:t,openThread:n}=E(),r=s(),[a,o]=(0,L.useState)(!1),[c,l]=(0,L.useState)(!1),[u,d]=(0,L.useState)(``),f=(0,L.useRef)(null),p=$f(),{profile:m,status:h}=e,g=m?.name??`nanoMuse`,_=e.pendingApprovals.length,v=e.goals.filter(e=>e.proposal&&e.status!==`cancelled`).length,y=e.pendingApprovals.filter(t=>t.ts>e.feedSeenAt).length,b=(e.hub?.devices??[]).filter(e=>!e.this&&e.kind!==`web`&&e.online).length,x=_>0?_>1?r(`{n} approvals waiting for you`,{n:_}):r(`1 approval waiting for you`):h.state===`idle`?r(`Idle`):h.detail||(h.state===`waiting`?r(`Waiting for you`):r(`Working…`));(0,L.useEffect)(()=>{if(!c)return;let e=e=>{f.current?.contains(e.target)||l(!1)},t=e=>{e.key===`Escape`&&l(!1)};return document.addEventListener(`mousedown`,e),document.addEventListener(`keydown`,t),()=>{document.removeEventListener(`mousedown`,e),document.removeEventListener(`keydown`,t)}},[c]);let S=[{id:`chat`,label:`Chat`,icon:(0,R.jsx)(At,{size:21}),badge:_},{id:`feed`,label:`Feed`,icon:(0,R.jsx)(Bt,{size:21}),badge:y},{id:`ideas`,label:`Ideas`,icon:(0,R.jsx)(Ct,{size:21})},{id:`goals`,label:`Goals`,icon:(0,R.jsx)(rn,{size:21}),badge:v},{id:`library`,label:`Library`,icon:(0,R.jsx)(St,{size:21})},{id:`devices`,label:`Devices`,icon:(0,R.jsx)(It,{size:21}),dot:b>0},...p?[{id:`coding`,label:`Coding`,icon:(0,R.jsx)(on,{size:21})}]:[]],C=u.trim().toLowerCase(),w=C?e.threads.filter(e=>e.id===`main`||(e.id===`main`?r(e.title):e.title).toLowerCase().includes(C)||(e.device_name??``).toLowerCase().includes(C)):e.threads,T=e=>i(`relative flex w-[60px] flex-col items-center gap-[3px] rounded-xl py-1.5 text-[10.5px] font-medium leading-none transition`,e?`bg-surface-2 text-fg`:`text-fg/65 hover:bg-surface-2/60 hover:text-fg`);return(0,R.jsxs)(`div`,{className:`flex h-full shrink-0`,children:[(0,R.jsxs)(`aside`,{className:`relative flex h-full w-[76px] shrink-0 flex-col items-center border-r border-border bg-surface/70`,children:[(0,R.jsx)(`div`,{className:`titlebar-room`}),(0,R.jsxs)(`button`,{type:`button`,onClick:()=>o(!0),className:`relative mt-3 rounded-full transition hover:scale-[1.04]`,"aria-label":r(`Activity`),title:`${g} · ${x}`,children:[(0,R.jsx)(D,{profile:m,status:h,size:44}),_>0&&(0,R.jsx)(`span`,{className:`pointer-events-none absolute -right-1 -top-1 flex h-[18px] min-w-[18px] items-center justify-center rounded-full border-2 border-surface bg-rose-500 px-1 text-[10.5px] font-bold text-white`,children:_})]}),(0,R.jsx)(`span`,{className:`mt-1.5 max-w-[68px] truncate px-1 text-[11px] font-semibold leading-tight`,children:g}),(0,R.jsx)(`nav`,{className:`mt-3 flex w-full flex-1 flex-col items-center gap-0.5 overflow-y-auto overflow-x-hidden px-2`,children:S.map(n=>{let a=e.tab===n.id;return(0,R.jsxs)(`button`,{type:`button`,onClick:()=>t(n.id),"aria-current":a?`page`:void 0,className:T(a),children:[(0,R.jsx)(`span`,{className:i(a?`text-accent`:`text-fg/60`),children:n.icon}),(0,R.jsx)(`span`,{className:`max-w-full truncate`,children:r(n.label)}),n.badge?(0,R.jsx)(`span`,{className:`absolute right-1.5 top-1 flex h-[17px] min-w-[17px] items-center justify-center rounded-full bg-rose-500 px-1 text-[10px] font-bold text-white`,children:n.badge}):n.dot?(0,R.jsxs)(R.Fragment,{children:[(0,R.jsx)(`span`,{"aria-hidden":`true`,className:`absolute right-3 top-2 h-2 w-2 rounded-full border-2 border-surface bg-emerald-500`}),(0,R.jsx)(`span`,{className:`sr-only`,children:r(`{n} online`,{n:b})})]}):null]},n.id)})}),(0,R.jsxs)(`div`,{className:`flex w-full flex-col items-center gap-0.5 px-2 pb-3 pt-2`,children:[(0,R.jsxs)(`button`,{type:`button`,onClick:()=>t(`account`),"aria-current":e.tab===`account`?`page`:void 0,className:T(e.tab===`account`),title:e.hub?.account.signed_in?e.hub.account.hint:r(`Account`),children:[(0,R.jsx)(mn,{size:21,className:e.tab===`account`?`text-accent`:`text-fg/60`}),(0,R.jsx)(`span`,{className:`max-w-full truncate`,children:r(`Account`)})]}),(0,R.jsxs)(`button`,{type:`button`,onClick:()=>t(`you`),"aria-current":e.tab===`you`?`page`:void 0,className:T(e.tab===`you`),children:[(0,R.jsx)(en,{size:21,className:e.tab===`you`?`text-accent`:`text-fg/60`}),(0,R.jsx)(`span`,{className:`max-w-full truncate`,children:r(`Settings`)})]}),(0,R.jsxs)(`div`,{ref:f,className:`relative w-full`,children:[(0,R.jsxs)(`button`,{type:`button`,onClick:()=>l(e=>!e),"aria-expanded":c,"aria-haspopup":`menu`,className:i(T(c),`mx-auto`),children:[(0,R.jsx)(Ot,{size:21,className:`text-fg/60`}),(0,R.jsx)(`span`,{children:r(`More`)})]}),c&&(0,R.jsxs)(`div`,{role:`menu`,className:`absolute bottom-0 left-[68px] z-30 w-[232px] rounded-2xl border border-border bg-surface p-1.5 shadow-[0_12px_40px_-12px_rgba(0,0,0,0.3)]`,children:[(0,R.jsxs)(`a`,{role:`menuitem`,href:lh(e.version),target:`_blank`,rel:`noreferrer`,onClick:()=>l(!1),className:`flex items-center gap-2.5 rounded-xl px-2.5 py-2 text-[13px] font-medium hover:bg-surface-2`,children:[(0,R.jsx)(ue,{size:16,className:`text-fg/60`}),` `,r(`Report a bug`)]}),(0,R.jsxs)(`button`,{type:`button`,role:`menuitem`,onClick:()=>{l(!1),t(`you`),window.location.hash=`developer`},className:`flex w-full items-center gap-2.5 rounded-xl px-2.5 py-2 text-left text-[13px] font-medium hover:bg-surface-2`,children:[(0,R.jsx)(yn,{size:16,className:`text-fg/60`}),(0,R.jsx)(`span`,{className:`flex-1`,children:r(`Developer tools`)}),(0,R.jsx)(`span`,{className:`text-[11.5px] font-normal text-muted`,children:r(p?`On`:`Off`)})]}),e.version&&(0,R.jsxs)(`div`,{className:`px-2.5 pb-1 pt-1.5 text-[11.5px] text-muted`,children:[`nanoMuse `,e.version]})]})]})]}),(0,R.jsx)(am,{open:a,onClose:()=>o(!1)})]}),e.tab===`chat`&&(0,R.jsxs)(`section`,{className:`flex h-full w-[248px] shrink-0 flex-col border-r border-border bg-surface/40`,"aria-label":r(`Chats`),children:[(0,R.jsx)(`div`,{className:`titlebar-room`}),(0,R.jsxs)(`div`,{className:`px-3 pb-2 pt-4`,children:[(0,R.jsx)(`h2`,{className:`px-1 text-[15px] font-semibold tracking-tight`,children:r(`Chats`)}),(0,R.jsxs)(`label`,{className:`mt-2 flex items-center gap-2 rounded-xl bg-surface-2 px-2.5 py-1.5 text-muted focus-within:ring-2 focus-within:ring-accent/40`,children:[(0,R.jsx)(qt,{size:14,className:`shrink-0`}),(0,R.jsx)(`input`,{value:u,onChange:e=>d(e.target.value),placeholder:r(`Search`),"aria-label":r(`Search chats`),className:`min-w-0 flex-1 bg-transparent text-[13px] text-fg outline-none placeholder:text-muted`}),u&&(0,R.jsx)(`button`,{type:`button`,onClick:()=>d(``),"aria-label":r(`Clear`),className:`shrink-0 hover:text-fg`,children:(0,R.jsx)(Fe,{size:14})})]})]}),(0,R.jsx)(`div`,{className:`min-h-0 flex-1 overflow-y-auto px-2 pb-3`,children:(0,R.jsx)(oh,{threads:w,active:e.activeThread,onPick:e=>n(e),compact:!0,grouped:!0})})]})]})}function dh(){let{state:e,send:t,openThread:n,openFile:r,markFeedSeen:i,setTab:a,toast:o}=E(),[c,l]=(0,L.useState)(null),[u,p]=(0,L.useState)(null),[h,g]=(0,L.useState)(null),[_,v]=(0,L.useState)(null),b=e.profile?.name??`nanoMuse`,x=s(),S=y();(0,L.useEffect)(()=>{let e=!0;return M.feed(80).then(t=>e&&l(t)).catch(e=>o(e.message)),M.upcoming().then(t=>e&&g(t)).catch(()=>void 0),M.feedPosts().then(t=>e&&p(t)).catch(()=>void 0),()=>{e=!1}},[e.feedVersion,e.remindersVersion]),(0,L.useEffect)(()=>{let e=!0;return M.calendar().then(t=>e&&v(t)).catch(()=>void 0),()=>{e=!1}},[e.calendarVersion,e.connectionsVersion]),(0,L.useEffect)(()=>{c&&c.length&&c[0].ts>e.feedSeenAt&&i(c[0].ts)},[c,e.feedSeenAt,i]);let C=(0,L.useMemo)(()=>kh(c??[]),[c,S]),[w,T]=(0,L.useState)(!1),[D,O]=(0,L.useState)(null),[k,ee]=(0,L.useState)(()=>d(fh)===`1`),[j,ne]=(0,L.useState)(!1),re=()=>{f(fh,`1`),ee(!0)},N=async()=>{ne(!0);try{let e=await M.refreshFeedPosts();p(e),e.error&&o(x(`Could not write posts: {error}`,{error:e.error}))}catch(e){o(e.message)}finally{ne(!1)}},P=e=>{t(`main`,e.prompt||`${x(`About this post from my feed:`)}\n\n**${e.title}**\n\n${e.body.slice(0,1200)}`).catch(e=>o(e.message||x(`Could not send`))),n(`main`)},ie=(0,L.useMemo)(()=>mh(u?.posts??[]),[u]),ae=u!==null&&u.posts.length===0;return(0,R.jsxs)(`div`,{className:`flex h-full flex-col`,children:[(0,R.jsx)(Em,{title:``,trailing:(0,R.jsx)(te,{onClick:()=>T(!0),label:x(`Feed settings`),children:(0,R.jsx)(en,{size:22})})}),(0,R.jsxs)(`div`,{className:`flex-1 overflow-y-auto px-3.5 pb-7`,children:[ie.length===0&&(0,R.jsxs)(R.Fragment,{children:[(0,R.jsx)(gh,{text:hh(ph(),new Date)}),!k&&(0,R.jsx)(xh,{instructions:u?.instructions??``,onEdit:()=>T(!0),onAck:re}),ae&&(0,R.jsxs)(R.Fragment,{children:[(0,R.jsx)(Sh,{emoji:`🖼️`,title:x(`Nothing in the feed yet`),body:x(`As we get to know each other, new posts will show up here. Every day at {time} I read what I remember about you (your memory files, the last week of diary, your goals) and write a few short posts.`,{time:u?.time??`08:00`})}),(0,R.jsx)(Sh,{emoji:`📝`,title:x(`Steer it with one sentence`),body:x(`Tap the sliders at the top right to tell me what you want more of, switch the daily routine off, or have me write the first day now.`)}),e.settings&&!e.settings.llm_ready&&(0,R.jsx)(_h,{children:(0,R.jsxs)(`button`,{type:`button`,onClick:()=>a(`you`),className:`flex w-full items-center gap-2 p-4 text-left text-[14px] text-muted`,children:[(0,R.jsx)(F,{size:16,className:`shrink-0 text-accent`}),` `,x(`Add a model first; the feed is written by your agent.`)]})}),(0,R.jsx)(_h,{children:(0,R.jsx)(`div`,{className:`p-4`,children:j?(0,R.jsxs)(`div`,{className:`flex items-center justify-center gap-2.5 text-[15px]`,children:[(0,R.jsx)(A,{size:18,className:`animate-spin text-accent`}),` `,x(`Writing…`)]}):(0,R.jsx)(`button`,{type:`button`,onClick:()=>void N(),className:`h-[46px] w-full rounded-full bg-accent text-[15px] font-semibold text-accent-fg`,children:x(`Write it now`)})})})]})]}),ie.map(([e,t],n)=>(0,R.jsxs)(`section`,{children:[(0,R.jsx)(gh,{text:hh(e,new Date(t[0].ts))}),n===0&&!k&&(0,R.jsx)(xh,{instructions:u?.instructions??``,onEdit:()=>T(!0),onAck:re}),n===0&&j&&(0,R.jsx)(_h,{children:(0,R.jsxs)(`div`,{className:`flex items-center gap-2.5 p-4 text-[15px]`,children:[(0,R.jsx)(A,{size:18,className:`animate-spin text-accent`}),` `,x(`Writing…`)]})}),t.map(e=>(0,R.jsx)(bh,{post:e,onDiscuss:()=>P(e),onInfo:()=>O(e)},e.id))]},e)),(0,R.jsxs)(`div`,{className:`space-y-4 px-0.5 pt-3`,children:[h&&(0,R.jsx)(Th,{data:h,name:b,onSettings:()=>a(`you`),onGoals:()=>a(`goals`)}),_?.configured&&(0,R.jsx)(Eh,{data:_,onAsk:()=>n(`main`)}),c&&c.length===0&&(!u||u.posts.length===0)&&(0,R.jsxs)(`div`,{className:`py-10 text-center text-muted text-[14px] px-6`,children:[(0,R.jsx)(Rt,{size:28,className:`mx-auto mb-2 opacity-60`}),x(`Nothing yet. Once {name} works on a goal in the background or needs your approval, it shows up here.`,{name:b})]}),c&&c.length>0&&(0,R.jsx)(`div`,{className:`px-1 pt-1 text-[12px] font-semibold uppercase tracking-wide text-muted`,children:x(`While you were away`)}),C.map(([t,i])=>(0,R.jsxs)(`section`,{children:[(0,R.jsx)(`div`,{className:`px-1 mb-1.5 text-[12px] uppercase tracking-wide text-muted font-semibold`,children:t}),(0,R.jsx)(`ul`,{className:`space-y-2`,children:i.map(t=>(0,R.jsx)(`li`,{children:(0,R.jsx)(Oh,{item:t,unseen:t.ts>e.feedSeenAt,onOpen:()=>{t.kind===`artifact`&&t.path?r(t.path):n(t.thread)}})},t.id))})]},t))]})]}),(0,R.jsx)(wh,{open:w,onClose:()=>T(!1),data:u,writing:j,onChange:p,onWriteNow:()=>void N()}),(0,R.jsx)(Op,{open:D!==null,onClose:()=>O(null),title:D?.title,children:D&&(0,R.jsxs)(`div`,{className:`space-y-3 px-1 pb-2`,children:[(0,R.jsx)(Ch,{label:x(`Post type`),value:yh(D.area)}),(0,R.jsx)(Ch,{label:x(`Written`),value:new Date(D.ts).toLocaleString(m(),{dateStyle:`medium`,timeStyle:`short`})}),(0,R.jsx)(`button`,{type:`button`,onClick:async()=>{let e=D.id;O(null);try{await M.deleteFeedPost(e),p(t=>t&&{...t,posts:t.posts.filter(t=>t.id!==e)})}catch(e){o(e.message)}},className:`w-full rounded-full bg-surface-2 py-2.5 text-[15px] font-medium text-rose-500`,children:x(`Delete this post`)})]})})]})}var fh=`nanomuse.feed.introAck`;function ph(){let e=new Date;return`${e.getFullYear()}-${String(e.getMonth()+1).padStart(2,`0`)}-${String(e.getDate()).padStart(2,`0`)}`}function mh(e){let t=new Map;for(let n of e){let e=new Date(n.ts),r=`${e.getFullYear()}-${String(e.getMonth()+1).padStart(2,`0`)}-${String(e.getDate()).padStart(2,`0`)}`,i=t.get(r);i?i.push(n):t.set(r,[n])}return[...t.entries()]}function hh(e,t){let n=ph(),r=new Date;r.setDate(r.getDate()-1);let i=`${r.getFullYear()}-${String(r.getMonth()+1).padStart(2,`0`)}-${String(r.getDate()).padStart(2,`0`)}`,a=t.toLocaleDateString(m(),{weekday:`long`});if(e===n){let e=new Date().getHours(),t=_(e<12?`morning`:e<18?`afternoon`:`evening`);return _(`{weekday} {part}`,{weekday:a,part:t})}return e===i?_(`Yesterday`):`${a} · ${t.toLocaleDateString(m(),{month:`short`,day:`numeric`})}`}function gh({text:e}){return(0,R.jsx)(`h2`,{className:`px-1.5 pt-3.5 pb-2 text-[22px] font-bold leading-7`,children:e})}function _h({children:e,className:t}){return(0,R.jsx)(`div`,{className:i(`my-1.5 overflow-hidden rounded-[18px] bg-surface dark:border dark:border-border`,t),children:e})}var vh={planning:`🗓️`,research:`🔍`,goals:`🎯`,money:`💰`,health:`🌿`,home:`🏠`,learning:`📚`,people:`👥`,files:`📄`,fun:`🎈`};function yh(e){switch(e){case`planning`:return _(`Planning`);case`research`:return _(`Research`);case`goals`:return _(`Goals`);case`money`:return _(`Money`);case`health`:return _(`Health`);case`home`:return _(`Home`);case`learning`:return _(`Learning`);case`people`:return _(`People`);case`files`:return _(`Files`);case`fun`:return _(`Fun`);default:return _(`Note`)}}function bh({post:e,onDiscuss:t,onInfo:n}){let r=s();return(0,R.jsx)(_h,{children:(0,R.jsxs)(`article`,{className:`pl-3.5 pr-2.5 pt-3.5 pb-1.5`,children:[(0,R.jsxs)(`div`,{className:`flex items-start gap-3`,children:[(0,R.jsx)(`div`,{className:`flex h-11 w-11 shrink-0 items-center justify-center rounded-xl bg-surface-2 text-[22px] leading-none`,children:vh[e.area]??`📝`}),(0,R.jsxs)(`div`,{className:`min-w-0 flex-1`,children:[(0,R.jsx)(`h3`,{className:`text-[16px] font-semibold leading-[22px]`,children:e.title}),(0,R.jsx)(`div`,{className:`md mt-1 text-[15px] leading-[22px] text-fg/85`,children:(0,R.jsx)(hf,{text:e.body})})]})]}),(0,R.jsxs)(`div`,{className:`mt-1.5 flex items-center`,children:[(0,R.jsxs)(`button`,{type:`button`,onClick:t,className:`flex items-center gap-1.5 rounded-full px-2 py-2 text-[14px] hover:bg-surface-2`,children:[(0,R.jsx)(At,{size:22,strokeWidth:1.8}),` `,r(`Discuss`)]}),(0,R.jsx)(`button`,{type:`button`,onClick:n,"aria-label":r(`About this post`),className:`ml-auto rounded-full p-2 hover:bg-surface-2`,children:(0,R.jsx)(F,{size:22,strokeWidth:1.8})})]})]})})}function xh({instructions:e,onEdit:t,onAck:n}){let r=s();return(0,R.jsxs)(_h,{children:[(0,R.jsxs)(`div`,{className:`px-4 py-3.5`,children:[(0,R.jsx)(`div`,{className:`text-[17px] font-semibold`,children:r(`About the feed`)}),(0,R.jsx)(`p`,{className:`mt-1 text-[13px] leading-[18px] text-muted`,children:r(`Short posts your agent writes for you from what it remembers: your memory files, the last week of diary, your goals. The sentence below steers every post from now on; edit it any time.`)})]}),(0,R.jsxs)(`div`,{className:`border-t border-border/70 px-4 py-3.5`,children:[(0,R.jsx)(`p`,{className:`text-[15px] leading-[22px]`,children:e||r(`Build me a feed about what I care about. Keep it short and direct, easy to skim, no clickbait.`)}),(0,R.jsxs)(`div`,{className:`mt-3.5 flex justify-end gap-2.5`,children:[(0,R.jsx)(`button`,{type:`button`,onClick:t,className:`rounded-full bg-surface-2 px-6 py-2.5 text-[15px] font-medium`,children:r(`Edit`)}),(0,R.jsx)(`button`,{type:`button`,onClick:n,className:`rounded-full bg-accent px-6 py-2.5 text-[15px] font-semibold text-accent-fg`,children:r(`Got it`)})]})]})]})}function Sh({emoji:e,title:t,body:n}){return(0,R.jsx)(_h,{children:(0,R.jsxs)(`div`,{className:`flex items-start gap-3 p-3.5`,children:[(0,R.jsx)(`div`,{className:`flex h-11 w-11 shrink-0 items-center justify-center rounded-xl bg-surface-2 text-[22px] leading-none`,children:e}),(0,R.jsxs)(`div`,{className:`min-w-0 flex-1`,children:[(0,R.jsx)(`div`,{className:`text-[16px] font-semibold leading-[22px]`,children:t}),(0,R.jsx)(`p`,{className:`mt-1 text-[15px] leading-[22px] text-fg/85`,children:n})]})]})})}function Ch({label:e,value:t}){return(0,R.jsxs)(`div`,{className:`flex items-start gap-3 text-[14.5px]`,children:[(0,R.jsx)(`span`,{className:`w-14 shrink-0 text-muted`,children:e}),(0,R.jsx)(`span`,{className:`min-w-0 flex-1 break-words`,children:t})]})}function wh({open:e,onClose:t,data:n,writing:r,onChange:i,onWriteNow:a}){let{toast:o,state:c}=E(),l=s(),[u,d]=(0,L.useState)(``),[f,p]=(0,L.useState)(!1);(0,L.useEffect)(()=>{e&&d(n?.instructions??``)},[e,n]);let m=async()=>{p(!0);try{i(await M.setFeedInstructions({instructions:u})),t()}catch(e){o(e.message)}finally{p(!1)}},h=async e=>{try{i(await M.setFeedInstructions(e))}catch(e){o(e.message)}},g=c.settings?.llm_ready!==!1;return(0,R.jsx)(Op,{open:e,onClose:t,title:l(`Feed`),children:(0,R.jsxs)(`div`,{className:`space-y-3 px-1 pb-2`,children:[(0,R.jsx)(`p`,{className:`text-[13px] leading-[18px] text-muted`,children:l(`Your feed is driven by the instruction below. Any edit you make here applies to every post from now on.`)}),(0,R.jsx)(`textarea`,{value:u,onChange:e=>d(e.target.value),rows:4,maxLength:2e3,placeholder:l(`Build me a feed about what I care about. Keep it short and direct, easy to skim, no clickbait.`),className:`w-full resize-none rounded-2xl bg-surface-2 px-3.5 py-2.5 text-[15px] leading-snug outline-none focus:ring-2 focus:ring-accent/40`}),(0,R.jsxs)(`div`,{className:`space-y-2 rounded-2xl bg-surface-2 px-3.5 py-2.5`,children:[(0,R.jsx)(Pe,{label:l(`Write it every day`),hint:n?.daily===!1?void 0:l(`Daily at {time}`,{time:n?.time??`08:00`}),checked:n?.daily!==!1,onChange:e=>void h({daily:e}),disabled:!n}),n?.daily!==!1&&(0,R.jsxs)(`label`,{className:`flex items-center justify-between gap-3 text-[13px] text-muted`,children:[(0,R.jsx)(`span`,{children:l(`Time of day`)}),(0,R.jsx)(`input`,{type:`time`,value:n?.time??`08:00`,onChange:e=>e.target.value&&void h({time:e.target.value}),className:`rounded-lg bg-surface px-2 py-1 text-[13px] text-fg outline-none focus:ring-2 focus:ring-accent/40`})]}),!g&&(0,R.jsx)(`div`,{className:`text-[12.5px] text-muted`,children:l(`Add a model first; the feed is written by your agent.`)})]}),(0,R.jsxs)(`button`,{type:`button`,onClick:a,disabled:r||!n||!g,className:`flex w-full items-center justify-center gap-2 rounded-full bg-surface-2 py-2.5 text-[15px] font-medium disabled:opacity-60`,children:[r?(0,R.jsx)(A,{size:16,className:`animate-spin`}):(0,R.jsx)(nn,{size:16,className:`text-accent`}),l(r?`Writing…`:`Write it now`)]}),(0,R.jsx)(`button`,{type:`button`,onClick:()=>void m(),disabled:f,className:`h-[46px] w-full rounded-full bg-accent text-[15px] font-semibold text-accent-fg disabled:opacity-60`,children:l(`Save`)})]})})}function Th({data:t,name:n,onSettings:r,onGoals:i}){let a=s(),o=t.queue[0],c=t.reminders.filter(e=>e.status===`active`&&!!e.next_at),l=c[0],d=c.length;return(0,R.jsxs)(`div`,{className:`rounded-3xl border border-border/70 bg-surface shadow-sm px-4 py-3.5`,children:[(0,R.jsxs)(`div`,{className:`flex items-center gap-2 text-[12px] uppercase tracking-wide text-muted font-semibold`,children:[(0,R.jsx)(Xe,{size:13}),` `,a(`Next up`)]}),t.proactive?o?(0,R.jsxs)(`div`,{className:`mt-1.5 text-[14px] leading-snug`,children:[t.busy?a(`Working now`):t.quiet_until?a(`Quiet hours after {time}`,{time:u(t.quiet_until)}):t.next_pass_at?a(`Around {time}`,{time:u(t.next_pass_at)}):a(`Soon`),`: `,(0,R.jsx)(`span`,{className:`font-medium`,children:o.title}),o.next_step&&(0,R.jsxs)(`span`,{className:`text-muted`,children:[` · `,o.next_step]}),o.overdue&&(0,R.jsxs)(`span`,{className:`text-rose-500 font-medium`,children:[` · `,a(`overdue`)]}),t.queue.length>1&&(0,R.jsxs)(`span`,{className:`text-muted`,children:[` · `,a(`{n} more in line`,{n:t.queue.length-1})]})]}):(0,R.jsxs)(`div`,{className:`mt-1.5 text-[14px] leading-snug`,children:[a(`No goal has a next step to work on.`),` `,(0,R.jsx)(`button`,{type:`button`,onClick:i,className:`text-accent font-medium`,children:a(`Add one`)})]}):(0,R.jsxs)(`div`,{className:`mt-1.5 text-[14px] leading-snug`,children:[a(`Background work is off. {name} only acts when you ask.`,{name:n}),` `,(0,R.jsx)(`button`,{type:`button`,onClick:r,className:`text-accent font-medium`,children:a(`Turn it on`)})]}),t.check_ins[0]&&(0,R.jsxs)(`div`,{className:`mt-1.5 text-[12.5px] text-muted`,children:[a(`Check-in on`),` `,(0,R.jsx)(`span`,{className:`font-medium text-fg`,children:t.check_ins[0].title}),` `,e(t.check_ins[0].at),t.check_ins.length>1&&` · ${a(`{n} more`,{n:t.check_ins.length-1})}`]}),l&&(0,R.jsxs)(`div`,{className:`mt-1.5 text-[12.5px] text-muted`,children:[l.kind===`task`?a(`Routine`):a(`Reminder`),` `,(0,R.jsx)(`span`,{className:`font-medium text-fg`,children:l.text}),` `,e(l.next_at),d>1&&` · ${a(`{n} more`,{n:d-1})}`]})]})}function Eh({data:e,onAsk:t}){let n=s(),r=t=>t.start.slice(0,10)<=e.today,a=e.events.filter(r),o=e.events.filter(e=>!r(e)),c=new Date,l=e=>!e.all_day&&new Date(e.end)e.error),d=a.every(l)&&o.length>0,f=d?o:a;return(0,R.jsxs)(`div`,{className:`rounded-3xl border border-border/70 bg-surface shadow-sm px-4 py-3.5`,children:[(0,R.jsxs)(`div`,{className:`flex items-center gap-2 text-[12px] uppercase tracking-wide text-muted font-semibold`,children:[(0,R.jsx)(tt,{size:13}),` `,n(d?`Tomorrow`:`Today`),f.length>0&&(0,R.jsx)(`span`,{className:`ml-auto normal-case tracking-normal font-normal`,children:n(`{n} scheduled`,{n:f.length})})]}),f.length===0?(0,R.jsx)(`div`,{className:`mt-1.5 text-[14px] leading-snug text-muted`,children:n(`Nothing on the calendar today.`)}):(0,R.jsx)(`ul`,{className:`mt-1.5 space-y-1`,children:f.map(e=>(0,R.jsxs)(`li`,{className:i(`flex items-baseline gap-2.5 text-[14px] leading-snug`,!d&&l(e)&&`opacity-50`),children:[(0,R.jsx)(`span`,{className:`w-[86px] shrink-0 tabular-nums text-[12.5px] text-muted`,children:e.all_day?n(`all day`):`${e.start.slice(11,16)}–${e.end.slice(11,16)}`}),(0,R.jsxs)(`span`,{className:`min-w-0 flex-1`,children:[(0,R.jsx)(`span`,{className:`font-medium`,children:e.summary}),e.location&&(0,R.jsxs)(`span`,{className:`text-muted text-[12.5px]`,children:[` `,(0,R.jsx)(Dt,{size:11,className:`inline -mt-0.5`}),` `,e.location]})]})]},`${e.uid}-${e.start}`))}),u.length>0&&(0,R.jsx)(`div`,{className:`mt-1.5 text-[12px] text-rose-500`,children:n(`{name} could not be read`,{name:u.map(e=>e.name).join(`, `)})}),(0,R.jsx)(`button`,{type:`button`,onClick:t,className:`mt-2 text-[12.5px] text-accent font-medium`,children:n(`Ask about your week`)})]})}function Dh(e){return e.replace(/```[\s\S]*?```/g,` `).replace(/^#{1,6}\s+/gm,``).replace(/(\*\*|__|`)/g,``).replace(/^\s*[-*+]\s+/gm,`• `).replace(/\[([^\]]+)\]\([^)]*\)/g,`$1`).trim()}function Oh({item:n,unseen:r,onOpen:a}){let o=s(),c=n.kind===`approval`?(0,R.jsx)(Zt,{size:18}):n.kind===`question`?(0,R.jsx)(kt,{size:18}):n.kind===`artifact`?(0,R.jsx)(mt,{size:18}):n.quiet?(0,R.jsx)(Rt,{size:18}):n.title.startsWith(`New mail: `)?(0,R.jsx)(Et,{size:18}):n.title.startsWith(`Coming up: `)?(0,R.jsx)(et,{size:18}):n.title.startsWith(`Webhook: `)?(0,R.jsx)(_n,{size:18}):(0,R.jsx)(nn,{size:18}),l=n.kind===`approval`?`bg-amber-500/12 text-amber-600 dark:text-amber-300`:n.kind===`question`?`bg-accent/12 text-accent`:`bg-surface-2 text-muted`;return n.quiet?(0,R.jsxs)(`button`,{type:`button`,onClick:a,className:`w-full text-left px-2 py-1.5 flex items-center gap-2 text-[12.5px] text-muted`,children:[(0,R.jsx)(Rt,{size:13,className:`shrink-0`}),(0,R.jsxs)(`span`,{className:`truncate`,children:[o(`{label}: nothing new`,{label:t(n.title.replace(/^Working on your goal: /,``))}),n.text?`: ${n.text}`:``]}),(0,R.jsx)(`span`,{className:`ml-auto shrink-0`,children:e(n.ts)})]}):(0,R.jsx)(`button`,{type:`button`,onClick:a,className:i(`w-full text-left rounded-3xl border bg-surface shadow-sm px-4 py-3 active:scale-[0.99] transition`,r?`border-accent/40`:`border-border/70`),children:(0,R.jsxs)(`div`,{className:`flex items-start gap-3`,children:[(0,R.jsx)(`div`,{className:i(`rounded-2xl p-2 mt-0.5`,l),children:c}),(0,R.jsxs)(`div`,{className:`flex-1 min-w-0`,children:[(0,R.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,R.jsx)(`div`,{className:`font-semibold text-[14.5px] leading-snug truncate`,children:t(n.title)}),r&&(0,R.jsx)(`span`,{className:`h-2 w-2 rounded-full bg-accent shrink-0`})]}),n.text&&(0,R.jsx)(`div`,{className:`mt-0.5 text-[13.5px] text-muted leading-snug line-clamp-3 whitespace-pre-wrap`,children:Dh(n.text)}),(0,R.jsxs)(`div`,{className:`mt-1.5 flex items-center gap-2 text-[12px] text-muted`,children:[(0,R.jsx)(`span`,{children:e(n.ts)}),(0,R.jsx)(`span`,{children:`·`}),(0,R.jsx)(`span`,{className:`truncate`,children:n.thread===`main`?o(n.thread_title):n.thread_title}),(0,R.jsxs)(`span`,{className:`ml-auto flex items-center gap-1 text-accent font-medium`,children:[n.kind===`artifact`?o(`Open`):n.kind===`approval`||n.kind===`question`?o(`Answer`):o(`Open chat`),(0,R.jsx)(qe,{size:13})]})]})]})]})})}function kh(e){let t=new Date,n=new Date(t);n.setDate(t.getDate()-1);let r=e=>{let r=new Date(e);return r.toDateString()===t.toDateString()?_(`Today`):r.toDateString()===n.toDateString()?_(`Yesterday`):r.toLocaleDateString(m(),{weekday:`long`,month:`short`,day:`numeric`})},i=new Map;for(let t of e){let e=r(t.ts);i.set(e,[...i.get(e)??[],t])}return[...i.entries()]}function Ah({children:e,className:t}){return(0,R.jsx)(`div`,{className:i(`mx-4 overflow-hidden rounded-2xl bg-surface dark:border dark:border-border`,t),children:e})}function jh({inset:e=52}){return(0,R.jsx)(`div`,{className:i(`border-t border-border/60`,e===52?`ml-[52px]`:`ml-4`)})}function Mh({icon:e,label:t,value:n,onClick:r,external:a=!1,trailing:o,chevron:s=!0}){let c=(0,R.jsxs)(R.Fragment,{children:[e&&(0,R.jsx)(`span`,{className:`shrink-0 text-fg`,children:e}),(0,R.jsx)(`span`,{className:i(`min-w-0 truncate text-[16px] leading-[21px]`,n?`max-w-[60%] shrink-0`:`flex-1`),children:t}),n&&(0,R.jsx)(`span`,{className:`min-w-0 flex-1 truncate pl-3 text-right text-[14px] leading-[18px] text-muted`,children:n}),o??(s?a?(0,R.jsx)(Ae,{size:16,className:`shrink-0 text-muted/70`}):(0,R.jsx)(rt,{size:18,className:`shrink-0 text-muted/70`}):null)]}),l=`flex min-h-[54px] w-full items-center gap-3.5 px-4 py-2 text-left`;return r?(0,R.jsx)(`button`,{type:`button`,onClick:r,className:i(l,`hover:bg-surface-2/60`),children:c}):(0,R.jsx)(`div`,{className:l,children:c})}function Nh({icon:e,label:t,value:n,checked:r,disabled:a=!1,onChange:o}){return(0,R.jsxs)(`button`,{type:`button`,role:`switch`,"aria-checked":r,disabled:a,onClick:()=>o(!r),className:i(`flex min-h-[54px] w-full items-center gap-3.5 px-4 py-2 text-left`,a?`opacity-60`:`hover:bg-surface-2/60`),children:[e&&(0,R.jsx)(`span`,{className:`shrink-0 text-fg`,children:e}),(0,R.jsx)(`span`,{className:i(`min-w-0 truncate text-[16px] leading-[21px]`,n?`max-w-[60%] shrink-0`:`flex-1`),children:t}),n&&(0,R.jsx)(`span`,{className:`min-w-0 flex-1 truncate pl-3 text-right text-[14px] leading-[18px] text-muted`,children:n}),(0,R.jsx)(Ph,{checked:r})]})}function Ph({checked:e}){return(0,R.jsx)(`span`,{"aria-hidden":!0,className:i(`relative h-7 w-12 shrink-0 rounded-full transition`,e?`bg-accent`:`bg-surface-2 border border-border`),children:(0,R.jsx)(`span`,{className:i(`absolute top-0.5 h-6 w-6 rounded-full bg-white shadow transition`,e?`left-[22px]`:`left-0.5`)})})}function Fh({children:e,className:t}){return(0,R.jsx)(`p`,{className:i(`px-8 py-2 text-[13px] leading-[18px] text-muted`,t),children:e})}function Ih({children:e}){return(0,R.jsx)(`p`,{className:`px-8 pb-2 pt-[18px] text-[13px] leading-[18px] text-muted`,children:e})}var Lh=`https://nanomuse.cn/privacy/`;function Rh({me:e,onChanged:t,flush:n=!1}){let r=s(),{state:a,toast:o}=E(),c=!!a.hub?.account.signed_in,[l,u]=(0,L.useState)(null),[d,f]=(0,L.useState)(!1),p=e??l,m=async()=>{if(c&&!e)try{u(await M.cloudMe())}catch{}};(0,L.useEffect)(()=>{m()},[c,e]);let h=p?.contribute??{on:!1,samples:0},g=h.samples??0,_=h.privacy_url||`https://nanomuse.cn/privacy/`,v=async n=>{f(!0);try{await M.cloudContribute(n),o(r(n?`On. Turn it off here at any time.`:`Off. Nothing more is kept.`)),e?t?.():await m()}catch(e){o(e.message)}finally{f(!1)}},y=async()=>{if(window.confirm(r(`The kept conversations are removed from the server. This cannot be undone.`))){f(!0);try{let n=await M.cloudDeleteSamples();o(r(`{n} turns deleted`,{n:String(n.deleted)})),e?t?.():await m()}catch(e){o(e.message)}finally{f(!1)}}};return(0,R.jsxs)(`div`,{className:i(n&&`-mx-4`),children:[(0,R.jsx)(zh,{signedIn:c}),(0,R.jsx)(Ah,{children:(0,R.jsx)(Nh,{label:r(`Help improve nanoMuse's AI models`),checked:c&&h.on,disabled:d||!c||!p,onChange:e=>void v(e)})}),(0,R.jsxs)(Fh,{children:[r(`While this is on, the text of your chats with the nanoMuse Cloud models (what you wrote, what it answered and the tools it chose to call) is kept on the relay to train the community's own open model. Not your memory or SOUL (the system prompt), not what tools returned, not pictures, and never next to who you are. Your own API key never passes through the relay.`),` `,c?h.default_on!==void 0&&(h.default_on?r(`New accounts start with it on.`):r(`New accounts start with it off.`)):r(`Sign in to nanoMuse Cloud to use it.`),` `,c&&g>0&&r(`{n} turns kept so far.`,{n:String(g)}),` `,(0,R.jsx)(`a`,{href:_,target:`_blank`,rel:`noopener noreferrer`,className:`text-accent underline-offset-2 hover:underline`,children:r(`Privacy policy`)})]}),c&&g>0&&(0,R.jsxs)(Ah,{className:`mt-3`,children:[(0,R.jsx)(Mh,{icon:d?(0,R.jsx)(A,{size:22,className:`animate-spin`}):(0,R.jsx)(fn,{size:22}),label:r(`Delete the kept conversations`),value:r(`{n} turns`,{n:String(g)}),onClick:()=>void y(),chevron:!1}),(0,R.jsx)(jh,{inset:16}),(0,R.jsx)(Fh,{className:`px-4 pb-2.5 pt-2`,children:r(`Removes every turn kept from this account, whether the switch is on or off now. Turning the switch off keeps what was kept until you delete it here.`)})]})]})}function zh({signedIn:e}){let t=s(),{toast:n}=E(),[r,i]=(0,L.useState)(null),[a,o]=(0,L.useState)(!1),c=r?.relay?.counts??{conversations:0,messages:0},l=e&&(c.conversations>0||c.messages>0),u=async()=>{try{i(await M.syncState())}catch{}};(0,L.useEffect)(()=>{u()},[e]);let d=async(e,t)=>{o(!0);try{i(await e()),n(t)}catch(e){n(e.message),await u()}finally{o(!1)}},f=e=>{(e||!l||window.confirm(t(`Off deletes the synced conversations from nanoMuse Cloud. The chats on each device stay.`)))&&d(()=>M.syncSetState(e),t(e?`On. Your devices show the same conversations from now on.`:`Off. Nothing is kept on nanoMuse Cloud any more.`))},p=()=>{window.confirm(t(`The synced conversations are removed from nanoMuse Cloud. The chats on each device stay. This cannot be undone.`))&&d(()=>M.syncDelete(),t(`Synced conversations deleted.`))},m=e=>{d(()=>M.syncSetSideChats(e),t(e?`On. This device's side chats go to the account; the other devices' are on their way.`:`Off. Side chats stay on this device from now on.`))},h=e&&!!r?.enabled;return(0,R.jsxs)(`div`,{className:`mb-6`,children:[(0,R.jsx)(Ah,{children:(0,R.jsx)(Nh,{label:t(`Sync conversations between my devices`),checked:h,disabled:a||!e||!r,onChange:f})}),(0,R.jsxs)(Fh,{children:[t(`The text of your chats is kept on nanoMuse Cloud so every device shows the same conversations. Files and images stay on the device they were made on.`),` `,e?r?.paused?t(`Paused: sign in again to continue.`):l&&t(`{c} chats, {m} messages kept so far.`,{c:String(c.conversations),m:String(c.messages)}):t(`Sign in to nanoMuse Cloud to use it.`)]}),r&&`side_chats`in r&&(0,R.jsxs)(R.Fragment,{children:[(0,R.jsx)(Ah,{className:`mt-3`,children:(0,R.jsx)(Nh,{label:t(`Also sync side chats`),checked:h&&!!r.side_chats,disabled:a||!h,onChange:m})}),(0,R.jsx)(Fh,{children:t(`Off: side chats stay on this device. On: this device's side chats go to the account and the other devices' side chats come here.`)})]}),l&&(0,R.jsxs)(Ah,{className:`mt-3`,children:[(0,R.jsx)(Mh,{icon:a?(0,R.jsx)(A,{size:22,className:`animate-spin`}):(0,R.jsx)(fn,{size:22}),label:t(`Delete synced conversations`),value:t(`{n} chats`,{n:String(c.conversations)}),onClick:p,chevron:!1}),(0,R.jsx)(jh,{inset:16}),(0,R.jsx)(Fh,{className:`px-4 pb-2.5 pt-2`,children:t(`Removes what nanoMuse Cloud stores for this account; the chats on each device stay, and the switch stays on. Deleting a chat on one device deletes it on all of them.`)})]})]})}var Bh=`nm.invite`;function Vh(){try{let e=new URLSearchParams(window.location.search).get(`invite`);if(e){let t=Hh(e);t&&localStorage.setItem(Bh,t)}return localStorage.getItem(Bh)??``}catch{return``}}function Hh(e){return e.toUpperCase().replace(/[^A-Z0-9]/g,``).slice(0,8)}function Uh(e){return/^\s*[+\d]/.test(e)?`tel`:`email`}function Wh({onSignedIn:e,useAsModel:t=!1,cta:n,autoFocus:r=!0}){let a=s(),o=(0,L.useId)(),c=Ce(),[l,u]=(0,L.useState)(`code`),[d,f]=(0,L.useState)(``),[p,m]=(0,L.useState)(``),[h,g]=(0,L.useState)(``),[_,v]=(0,L.useState)(!1),[y,b]=(0,L.useState)(null),[x,S]=(0,L.useState)(null),[C,w]=(0,L.useState)(``),[T,E]=(0,L.useState)(!1);(0,L.useEffect)(()=>{let e=Vh();e&&(w(e),E(!0))},[]);let D=async()=>{if(t){b(`model`);try{await M.cloudUseAsModel()}catch{}}await e()},O=async()=>{let e=d.trim();if(e){b(`code`),S(null);try{await M.cloudCode(e),v(!0)}catch(e){S(a(e.message))}finally{b(null)}}},k=async()=>{let e=d.trim();if(!(!e||p.trim().length<4)){b(`verify`),S(null);try{(await M.cloudVerify(e,p.trim(),C.trim())).created&&Vf(),m(``),v(!1);try{localStorage.removeItem(Bh)}catch{}await D()}catch(e){S(a(e.message))}finally{b(null)}}},ee=async()=>{let e=d.trim();if(e&&h){b(`login`),S(null);try{await M.cloudLogin(e,h),g(``),await D()}catch(e){S(a(e.message))}finally{b(null)}}},te=()=>void(l===`password`?ee():_?k():O()),j=n??a(t?`Sign in and use its model`:`Sign in`);return(0,R.jsxs)(`form`,{className:`space-y-3`,onSubmit:e=>{e.preventDefault(),te()},children:[(0,R.jsxs)(`div`,{className:`grid grid-cols-2 gap-1 rounded-2xl bg-surface-2/70 p-1 text-[13px] font-medium`,children:[(0,R.jsx)(Gh,{active:l===`code`,onClick:()=>u(`code`),icon:(0,R.jsx)(Mt,{size:14}),label:a(`With a code`)}),(0,R.jsx)(Gh,{active:l===`password`,onClick:()=>u(`password`),icon:(0,R.jsx)(xt,{size:14}),label:a(`With a password`)})]}),(0,R.jsxs)(`div`,{children:[(0,R.jsx)(`label`,{htmlFor:`${o}-id`,className:`text-[12px] text-muted`,children:se()?a(`Mainland China phone number or e-mail`):a(`E-mail (or a mainland China phone number)`)}),(0,R.jsx)(`input`,{id:`${o}-id`,value:d,onChange:e=>{f(e.target.value),v(!1)},inputMode:Uh(d),autoComplete:`username`,autoFocus:r,placeholder:a(`138 0000 0000 or you@example.com`),className:i(Ie,`mt-1`)}),l===`code`&&!_&&(!se()||oe(d))&&(0,R.jsx)(`p`,{className:`mt-1.5 text-[12px] text-muted`,children:a(`Text-message codes reach mainland-China numbers only. Use an e-mail address instead.`)})]}),l===`password`?(0,R.jsxs)(`div`,{children:[(0,R.jsx)(`label`,{htmlFor:`${o}-password`,className:`text-[12px] text-muted`,children:a(`Password`)}),(0,R.jsx)(`input`,{id:`${o}-password`,type:`password`,value:h,onChange:e=>g(e.target.value),autoComplete:`current-password`,className:i(Ie,`mt-1`)}),(0,R.jsx)(`p`,{className:`mt-1.5 text-[12px] text-muted`,children:a(`No password yet? Use a code first; set one under Account.`)})]}):(0,R.jsxs)(R.Fragment,{children:[_&&(0,R.jsxs)(`div`,{children:[(0,R.jsx)(`label`,{htmlFor:`${o}-code`,className:`text-[12px] text-muted`,children:a(`The code you received`)}),(0,R.jsx)(`input`,{id:`${o}-code`,value:p,onChange:e=>m(e.target.value.replace(/\D/g,``).slice(0,8)),inputMode:`numeric`,autoComplete:`one-time-code`,placeholder:`123456`,autoFocus:!0,className:i(`w-full rounded-2xl bg-surface-2 px-3.5 py-2.5 text-[14.5px] outline-none focus:ring-2 focus:ring-accent/40`,`mt-1 tracking-[0.3em]`)})]}),T?(0,R.jsxs)(`div`,{children:[(0,R.jsx)(`label`,{htmlFor:`${o}-invite`,className:`text-[12px] text-muted`,children:a(`Invite code (optional)`)}),(0,R.jsx)(`input`,{id:`${o}-invite`,value:C,onChange:e=>w(Hh(e.target.value)),autoComplete:`off`,placeholder:`ABCD2345`,className:i(Ie,`mt-1 tracking-[0.2em] uppercase`)}),(0,R.jsx)(`p`,{className:`mt-1.5 text-[12px] text-muted`,children:a(`A friend's code counts for a new account: you both get ¥{invite} more allowance.`,{invite:(c.invite_bonus_cny??5).toFixed(0)})})]}):(0,R.jsx)(`button`,{type:`button`,onClick:()=>E(!0),className:`text-[12px] text-muted underline-offset-2 hover:underline`,children:a(`Have an invite code?`)})]}),x&&(0,R.jsx)(`div`,{className:`rounded-2xl bg-rose-500/12 px-3 py-2 text-[12.5px] text-rose-700 dark:text-rose-300`,children:x}),(0,R.jsx)(`div`,{className:`flex gap-2`,children:l===`code`&&_?(0,R.jsxs)(R.Fragment,{children:[(0,R.jsx)(`button`,{type:`button`,disabled:y!==null,onClick:()=>void O(),className:je,children:a(`Send again`)}),(0,R.jsxs)(`button`,{type:`submit`,disabled:y!==null||p.trim().length<4,className:i(Ne,`flex-1 py-3`),children:[y?(0,R.jsx)(A,{size:15,className:`animate-spin`}):null,` `,j]})]}):l===`code`?(0,R.jsxs)(`button`,{type:`submit`,disabled:y!==null||!d.trim(),className:i(Ne,`flex-1 py-3`),children:[y===`code`?(0,R.jsx)(A,{size:15,className:`animate-spin`}):null,` `,a(`Send me a code`)]}):(0,R.jsxs)(`button`,{type:`submit`,disabled:y!==null||!d.trim()||!h,className:i(Ne,`flex-1 py-3`),children:[y?(0,R.jsx)(A,{size:15,className:`animate-spin`}):null,` `,j]})})]})}function Gh({active:e,onClick:t,icon:n,label:r}){return(0,R.jsxs)(`button`,{type:`button`,onClick:t,"aria-pressed":e,className:i(`flex items-center justify-center gap-1.5 rounded-xl px-2 py-2 transition`,e?`bg-surface text-fg shadow-sm`:`text-muted hover:text-fg`),children:[n,` `,r]})}function Kh(){let{state:e,refreshSettings:t,refreshHub:n,toast:r,skipSignIn:i}=E(),a=s(),o=e.profile?.name??`nanoMuse`,c=(0,R.jsxs)(`ul`,{className:`grid grid-cols-2 gap-2 text-[12.5px] wide:grid-cols-1 wide:gap-1.5 wide:text-[13.5px]`,children:[(0,R.jsx)(qh,{icon:(0,R.jsx)(It,{size:15}),text:a(`Every device of yours, one nanoMuse`)}),(0,R.jsx)(qh,{icon:(0,R.jsx)(st,{size:15}),text:a(`A model with a free allowance, or your own key`)}),(0,R.jsx)(qh,{icon:(0,R.jsx)(vt,{size:15}),text:a(`It uses your phone and computers for you`)}),(0,R.jsx)(qh,{icon:(0,R.jsx)(Qt,{size:15}),text:a(`Keys in your vault; nothing you say is kept on the relay`)})]});return(0,R.jsxs)(`div`,{className:`relative mx-auto flex h-[100dvh] w-full max-w-[760px] flex-col overflow-hidden bg-bg sm:border-x sm:border-border wide:max-w-none wide:border-0`,children:[(0,R.jsx)(`div`,{className:`pointer-events-none absolute inset-x-0 top-0 h-[46vh] bg-[radial-gradient(ellipse_at_top,rgba(0,100,212,0.14),transparent_65%)] dark:bg-[radial-gradient(ellipse_at_top,rgba(23,147,255,0.2),transparent_65%)] wide:inset-y-0 wide:h-auto wide:bg-[radial-gradient(ellipse_at_left,rgba(0,100,212,0.12),transparent_60%)] wide:dark:bg-[radial-gradient(ellipse_at_left,rgba(23,147,255,0.16),transparent_60%)]`}),(0,R.jsx)(`div`,{className:`titlebar-room relative`}),(0,R.jsx)(`div`,{className:`relative flex-1 overflow-y-auto px-6 pb-8 wide:flex wide:items-center wide:px-12`,children:(0,R.jsxs)(`div`,{className:`mx-auto w-full wide:grid wide:max-w-[980px] wide:grid-cols-[1.1fr_1fr] wide:items-center wide:gap-16`,children:[(0,R.jsxs)(`div`,{className:`safe-top flex flex-col items-center pt-14 text-center wide:items-start wide:pt-0 wide:text-left`,children:[(0,R.jsx)(xn,{size:88,className:`drop-shadow-[0_20px_40px_rgba(0,100,212,0.28)]`}),(0,R.jsx)(`h1`,{className:`mt-6 text-[28px] font-bold tracking-tight wide:text-[34px]`,children:a(`Sign in to {name}`,{name:o})}),(0,R.jsx)(`p`,{className:`mt-2 max-w-sm text-[14.5px] leading-relaxed text-muted wide:max-w-md wide:text-[15.5px]`,children:a(`One free account. It is what lets your phone and computers work as one and brings a model to start with.`)}),(0,R.jsx)(`div`,{className:`mt-7 hidden w-full wide:block`,children:c}),(0,R.jsx)(Te,{compact:!0,className:`mt-6 hidden w-full wide:block`})]}),(0,R.jsxs)(`div`,{children:[(0,R.jsx)(`div`,{className:`mt-8 rounded-[28px] border border-border/70 bg-surface p-5 shadow-sm wide:mt-0 wide:p-7`,children:(0,R.jsx)(Wh,{onSignedIn:async()=>{r(a(`Signed in to nanoMuse Cloud.`)),await Promise.all([t(),n()])}})}),(0,R.jsx)(`button`,{type:`button`,onClick:i,className:`mt-4 w-full rounded-2xl border border-border/70 px-4 py-2.5 text-[13.5px] text-fg/80 hover:bg-surface-2`,"data-testid":`sign-in-skip`,children:a(`Use your own API key instead`)}),(0,R.jsx)(`p`,{className:`mt-2 text-center text-[11.5px] leading-relaxed text-muted`,children:a(`You can sign in later under Connections, for sync and your devices.`)}),(0,R.jsx)(`div`,{className:`mt-6 wide:hidden`,children:c}),(0,R.jsx)(Te,{compact:!0,className:`mt-6 wide:hidden`}),(0,R.jsxs)(`p`,{className:`mt-4 text-center text-[11.5px] leading-relaxed text-muted wide:mt-5`,children:[a(`The relay keeps an account id, a masked identifier, usage counts and your agent's name and look; what else, and what is yours to switch off, is in the`),` `,(0,R.jsx)(`a`,{href:Lh,target:`_blank`,rel:`noopener noreferrer`,className:`underline decoration-dotted underline-offset-2 hover:text-fg`,children:a(`privacy policy`)}),`.`]})]})]})})]})}function qh({icon:e,text:t}){return(0,R.jsxs)(`li`,{className:`flex items-start gap-2 rounded-2xl bg-surface-2/60 px-3 py-2.5 text-fg/80 wide:bg-transparent wide:px-0 wide:py-1`,children:[(0,R.jsx)(`span`,{className:`mt-0.5 text-accent`,children:e}),(0,R.jsx)(`span`,{className:`leading-snug`,children:t})]})}function Jh(e,t,n){return!e||!e.account.required||e.account.signed_in||t?.llm_ready?!1:!n}var Yh=`modulepreload`,Xh=function(e){return`/`+e},Zh={},Qh=function(e){return e.pathname.endsWith(`.css`)},$h=function(e,t,n){let r=Promise.resolve();if(t&&t.length>0){let e,i=document.querySelector(`meta[property=csp-nonce]`),a=i?.nonce||i?.getAttribute(`nonce`);function o(e){return Promise.all(e.map(e=>Promise.resolve(e).then(e=>({status:`fulfilled`,value:e}),e=>({status:`rejected`,reason:e}))))}function s(e){return import.meta.resolve?new URL(import.meta.resolve(e)):new URL(e,import.meta.url)}r=o(t.map(t=>{t=Xh(t,n);let r=s(t);if(r.href in Zh)return;Zh[r.href]=!0;let i=Qh(r);if(e===void 0){e={all:new Set,styles:new Set};let t=document.getElementsByTagName(`link`);for(let n=t.length-1;n>=0;n--){let r=t[n];e.all.add(r.href),r.rel===`stylesheet`&&e.styles.add(r.href)}}if((i?e.styles:e.all).has(r.href))return;let o=document.createElement(`link`);if(o.rel=i?`stylesheet`:Yh,i||(o.as=`script`),o.crossOrigin=``,o.href=r.href,a&&o.setAttribute(`nonce`,a),document.head.appendChild(o),i)return new Promise((e,t)=>{o.addEventListener(`load`,e),o.addEventListener(`error`,()=>t(Error(`Unable to preload CSS for ${r}`)))})}).filter(e=>e!==void 0))}function i(e){let t=new Event(`vite:preloadError`,{cancelable:!0});if(t.payload=e,window.dispatchEvent(t),!t.defaultPrevented)throw e}return r.then(t=>{for(let e of t||[])e.status===`rejected`&&i(e.reason);return e().catch(i)})},eg=(0,L.lazy)(()=>$h(()=>import(`./AccountScreen-BltVqMHJ.js`).then(e=>({default:e.AccountScreen})),__vite__mapDeps([0,1,2,3,4,5,6,7,8]))),tg=(0,L.lazy)(()=>$h(()=>import(`./AvatarStudioScreen-BFsBKlhk.js`).then(e=>({default:e.AvatarStudioScreen})),__vite__mapDeps([9,1,2,3,4,10,8,11]))),ng=(0,L.lazy)(()=>$h(()=>import(`./ChannelsScreen-Cil6hJ5n.js`).then(e=>({default:e.ChannelsScreen})),__vite__mapDeps([12,1,3,4,10,8]))),rg=(0,L.lazy)(()=>$h(()=>import(`./CodingScreen-BulrK8KC.js`).then(e=>({default:e.CodingScreen})),__vite__mapDeps([13,1,4,10,8]))),ig=(0,L.lazy)(()=>$h(()=>import(`./ConnectionsScreen-DzFdAyKl.js`).then(e=>({default:e.ConnectionsScreen})),__vite__mapDeps([14,1,2,3,4,5,7,15,10,8,16]))),ag=(0,L.lazy)(()=>$h(()=>import(`./DevicesScreen-Cox4s7Rb.js`).then(e=>({default:e.DevicesScreen})),__vite__mapDeps([17,1,3,4,10,8,16]))),og=(0,L.lazy)(()=>$h(()=>import(`./GoalsScreen-ChIUN2rA.js`).then(e=>({default:e.GoalsScreen})),__vite__mapDeps([18,1,2,3,4]))),sg=(0,L.lazy)(()=>$h(()=>import(`./IdeasScreen-DKf-8dhs.js`).then(e=>({default:e.IdeasScreen})),__vite__mapDeps([19,1,10]))),cg=(0,L.lazy)(()=>$h(()=>import(`./LibraryScreen-CLqu6Lu-.js`).then(e=>({default:e.LibraryScreen})),__vite__mapDeps([20,1]))),lg=(0,L.lazy)(()=>$h(()=>import(`./MemoryScreen-B7ALbqAO.js`).then(e=>({default:e.MemoryScreen})),__vite__mapDeps([21,1,8]))),ug=(0,L.lazy)(()=>$h(()=>import(`./Onboarding-D3RCeowq.js`).then(e=>({default:e.Onboarding})),__vite__mapDeps([22,1,2,3,4,23,11,14,5,7,15,10,8,16]))),dg=(0,L.lazy)(()=>$h(()=>import(`./SettingsScreen-xI3hlacs.js`).then(e=>({default:e.SettingsScreen})),__vite__mapDeps([24,1,2,3,4,5,6,15,23,11,8]))),fg=(0,L.lazy)(()=>$h(()=>import(`./SkillsScreen-qZE6bdL9.js`).then(e=>({default:e.SkillsScreen})),__vite__mapDeps([25,1,8])));function pg(){return(0,R.jsx)(`div`,{className:`flex h-full min-h-[40vh] items-center justify-center text-muted`,children:(0,R.jsx)(A,{className:`animate-spin`,size:20})})}var mg=e=>({size:26,strokeWidth:e?2:1.7,fill:e?`currentColor`:`none`,fillOpacity:e?.18:0}),hg=[{id:`chat`,label:`Chat`,icon:e=>(0,R.jsx)(At,{...mg(e)})},{id:`feed`,label:`Feed`,icon:e=>(0,R.jsx)(Bt,{...mg(e)})},{id:`ideas`,label:`Ideas`,icon:e=>(0,R.jsx)(Ct,{...mg(e)})},{id:`goals`,label:`Goals`,icon:e=>(0,R.jsx)(rn,{...mg(e)})},{id:`library`,label:`Library`,icon:e=>(0,R.jsx)(St,{...mg(e)})}];function gg(){let{state:e,setTab:t,openFile:n}=E(),r=Wf(),a=s();(0,L.useEffect)(()=>{let t=e.profile?.name?.trim();document.title=t&&t.toLowerCase()!==`nanomuse`?`${t} · nanoMuse`:`nanoMuse`},[e.profile?.name]),(0,L.useEffect)(()=>{let e=Sn()?.onQuickChat?.(()=>{t(`chat`),requestAnimationFrame(()=>window.dispatchEvent(new Event(`nanomuse:quick-chat`)))});return()=>{typeof e==`function`&&e()}},[t]),(0,L.useEffect)(()=>{let e=()=>{let e=window.location.hash.slice(1);(e&&hg.some(t=>t.id===e)||e===`devices`||e===`you`||e===`memory`||e===`connections`||e===`channels`||e===`skills`||e===`account`||e===`coding`||e===`avatar`)&&t(e)};return e(),window.addEventListener(`hashchange`,e),()=>window.removeEventListener(`hashchange`,e)},[t]);let o=r&&e.hub?.account.signed_in?(0,R.jsx)(Gf,{}):null,c=e.lite&&e.settings!==null&&!e.settings.onboarded;if((0,L.useEffect)(()=>{c&&M.onboarded(!0).catch(()=>void 0)},[c]),e.authError)return(0,R.jsx)(vg,{});if(!e.loaded)return(0,R.jsx)(_g,{error:e.error});if(Jh(e.hub,e.settings,e.signInSkipped))return(0,R.jsx)(Kh,{});if(!e.lite&&e.settings&&!e.settings.onboarded&&!e.onboardingDismissed&&!e.threads.some(e=>e.events>0))return(0,R.jsxs)(L.Suspense,{fallback:(0,R.jsx)(pg,{}),children:[(0,R.jsx)(ug,{}),o]});let l=e.pendingApprovals.length,u=e.goals.filter(e=>e.proposal&&e.status!==`cancelled`).length,d=e.pendingApprovals.filter(t=>t.ts>e.feedSeenAt).length;return(0,R.jsxs)(`div`,{className:i(`mx-auto flex h-[100dvh] max-w-[760px] flex-col bg-bg sm:border-x sm:border-border`,!e.lite&&`wide:max-w-none wide:flex-row wide:border-x-0`),children:[!e.lite&&(0,R.jsx)(`div`,{className:`hidden wide:block wide:h-full`,children:(0,R.jsx)(uh,{})}),(0,R.jsxs)(`div`,{className:`relative flex min-h-0 min-w-0 flex-1 flex-col`,children:[e.gone&&(0,R.jsxs)(`div`,{className:`flex items-center justify-center gap-2 bg-surface-2 text-muted text-[12.5px] py-1`,children:[(0,R.jsx)(vn,{size:14}),` `,a(e.lite?`This demo has ended.`:`This nanoMuse has stopped. Reload the page once it is running again.`)]}),!e.gone&&!e.connected&&e.loaded&&(0,R.jsxs)(`div`,{className:`flex items-center justify-center gap-2 bg-amber-500/15 text-amber-700 dark:text-amber-300 text-[12.5px] py-1`,children:[(0,R.jsx)(vn,{size:14}),` `,a(`Reconnecting to your nanoMuse…`)]}),!e.lite&&(0,R.jsx)(En,{}),(0,R.jsx)(`main`,{className:i(`tabbar-room mx-auto min-h-0 w-full flex-1 wide:max-w-[900px]`,!e.lite&&`wide:pb-0`),children:(0,R.jsxs)(L.Suspense,{fallback:(0,R.jsx)(pg,{}),children:[e.tab===`chat`&&(0,R.jsx)(Wm,{}),e.tab===`feed`&&(0,R.jsx)(dh,{}),e.tab===`ideas`&&(0,R.jsx)(sg,{}),e.tab===`goals`&&(0,R.jsx)(og,{}),e.tab===`library`&&(0,R.jsx)(cg,{}),e.tab===`memory`&&(0,R.jsx)(lg,{}),e.tab===`skills`&&(0,R.jsx)(fg,{}),e.tab===`connections`&&(0,R.jsx)(ig,{}),e.tab===`channels`&&(0,R.jsx)(ng,{}),e.tab===`devices`&&(0,R.jsx)(ag,{}),e.tab===`you`&&(0,R.jsx)(dg,{}),e.tab===`account`&&(0,R.jsx)(eg,{}),e.tab===`coding`&&(0,R.jsx)(rg,{}),e.tab===`avatar`&&(0,R.jsx)(tg,{})]})}),(0,R.jsx)(`nav`,{className:i(`tabbar-float pointer-events-none absolute inset-x-0 z-20 flex justify-center px-4`,!e.lite&&`wide:hidden`),children:(0,R.jsx)(`ul`,{className:`pointer-events-auto flex items-center gap-0.5 rounded-full bg-surface-2/55 px-3.5 py-2 ring-1 ring-border/50 backdrop-blur-2xl`,children:hg.map(n=>{let r=e.tab===n.id,o=n.id===`chat`?l:n.id===`feed`?d:n.id===`goals`?u:0;return(0,R.jsx)(`li`,{children:(0,R.jsxs)(`button`,{type:`button`,onClick:()=>t(n.id),"aria-label":a(n.label),"aria-current":r?`page`:void 0,className:i(`relative flex h-[46px] w-[60px] items-center justify-center rounded-full transition-colors duration-300`,r?`bg-accent-soft text-accent-soft-fg`:`text-muted hover:text-fg`),children:[n.icon(r),o>0&&(0,R.jsx)(`span`,{className:`absolute right-2.5 top-1 flex h-[17px] min-w-[17px] items-center justify-center rounded-full bg-rose-500 px-1 text-[10px] font-bold text-white`,children:o})]})},n.id)})})})]}),(0,R.jsx)(kn,{}),(0,R.jsx)(gf,{path:e.viewer,onClose:()=>n(null)}),o,e.toast&&(0,R.jsx)(`div`,{className:`pointer-events-none fixed inset-x-0 bottom-[calc(6rem+env(safe-area-inset-bottom))] z-[70] flex justify-center px-4`,children:(0,R.jsx)(`div`,{className:`rise rounded-2xl bg-fg text-bg px-4 py-2 text-[13.5px] shadow-lg max-w-sm text-center`,children:e.toast})})]})}function _g({error:e}){let t=s();return(0,R.jsxs)(`div`,{className:`mx-auto flex h-[100dvh] max-w-sm flex-col items-center justify-center px-6 text-center`,children:[(0,R.jsx)(xn,{size:72}),e?(0,R.jsxs)(R.Fragment,{children:[(0,R.jsx)(`p`,{className:`mt-6 text-[15px] font-medium`,children:t(`Could not reach your nanoMuse.`)}),(0,R.jsx)(`p`,{className:`mt-1.5 text-[13px] text-muted`,children:t(e)}),(0,R.jsx)(`button`,{type:`button`,onClick:()=>window.location.reload(),className:`mt-5 rounded-full bg-fg px-5 py-2 text-[14px] font-medium text-bg`,children:t(`Try again`)})]}):(0,R.jsxs)(`p`,{className:`mt-6 flex items-center gap-2 text-[14px] text-muted`,children:[(0,R.jsx)(A,{className:`animate-spin`,size:16}),` `,t(`Connecting to your nanoMuse…`)]})]})}function vg(){let[e,t]=(0,L.useState)(``),n=s();return(0,R.jsxs)(`div`,{className:`mx-auto flex h-[100dvh] max-w-md flex-col items-center justify-center px-6 text-center`,children:[(0,R.jsx)(xn,{size:88}),(0,R.jsx)(`h1`,{className:`mt-4 text-[22px] font-bold`,children:n(`Connect to your nanoMuse`)}),(0,R.jsxs)(`p`,{className:`mt-2 text-[14px] text-muted`,children:[n(`This app talks to the nanoMuse server you run yourself. Scan the QR code printed by`),` `,(0,R.jsx)(`code`,{className:`rounded bg-surface-2 px-1`,children:`nanomuse serve`}),n(`, or paste the access token below.`)]}),(0,R.jsxs)(`form`,{className:`mt-5 w-full flex gap-2`,onSubmit:t=>{t.preventDefault(),e.trim()&&(g(e.trim()),window.location.reload())},children:[(0,R.jsx)(`input`,{value:e,onChange:e=>t(e.target.value),"aria-label":n(`Access token`),placeholder:n(`Access token`),className:`flex-1 rounded-2xl bg-surface-2 px-4 py-2.5 text-[15px] outline-none focus:ring-2 focus:ring-accent/40`}),(0,R.jsx)(`button`,{type:`submit`,className:`rounded-2xl bg-accent text-accent-fg px-4 font-medium`,children:n(`Connect`)})]})]})}a(),ee(),wn(),bn.createRoot(document.getElementById(`root`)).render((0,R.jsx)(L.StrictMode,{children:(0,R.jsx)(T,{children:(0,R.jsx)(gg,{})})}));export{Ut as $,Ff as A,gn as B,Jp as C,Ze as Ct,rp as D,Ke as Dt,ip as E,qe as Et,hf as F,tn as G,sn as H,Mn as I,Xt as J,Qt as K,Sn as L,Nf as M,Pf as N,Zf as O,Af as P,Gt as Q,Cn as R,tm as S,Qe as St,op as T,Je as Tt,on as U,fn as V,nn as W,qt as X,Jt as Y,I as Z,nm as _,ct as _t,Ah as a,Nt as at,rm as b,rt as bt,Ih as c,Tt as ct,Um as d,F as dt,Ht as et,Em as f,vt as ft,Xp as g,ut as gt,Qp as h,pt as ht,Fh as i,It as it,jf as j,$f as k,Nh as l,wt as lt,Yp as m,mt,Rh as n,Rt as nt,jh as o,At as ot,Zp as p,gt as pt,Zt as q,Lh as r,Lt as rt,Mh as s,Et as st,Wh as t,Vt as tt,Vm as u,xt as ut,im as v,st as vt,Op as w,Xe as wt,$p as x,tt as xt,em as y,at as yt,yn as z}; \ No newline at end of file diff --git a/nanomuse/server/static/assets/index-e3JVbMkJ.css b/nanomuse/server/static/assets/index-e3JVbMkJ.css new file mode 100644 index 000000000..e6d4bac89 --- /dev/null +++ b/nanomuse/server/static/assets/index-e3JVbMkJ.css @@ -0,0 +1,2 @@ +/*! tailwindcss v4.3.3 | MIT License | https://tailwindcss.com */ +@layer properties{@supports (((-webkit-hyphens:none)) and (not (margin-trim:inline))) or ((-moz-orient:inline) and (not (color:rgb(from red r g b)))){*,:before,:after,::backdrop{--tw-border-spacing-x:0;--tw-border-spacing-y:0;--tw-translate-x:0;--tw-translate-y:0;--tw-translate-z:0;--tw-space-y-reverse:0;--tw-divide-y-reverse:0;--tw-border-style:solid;--tw-gradient-position:initial;--tw-gradient-from:#0000;--tw-gradient-via:#0000;--tw-gradient-to:#0000;--tw-gradient-stops:initial;--tw-gradient-via-stops:initial;--tw-gradient-from-position:0%;--tw-gradient-via-position:50%;--tw-gradient-to-position:100%;--tw-leading:initial;--tw-font-weight:initial;--tw-tracking:initial;--tw-ordinal:initial;--tw-slashed-zero:initial;--tw-numeric-figure:initial;--tw-numeric-spacing:initial;--tw-numeric-fraction:initial;--tw-shadow:0 0 #0000;--tw-shadow-color:initial;--tw-shadow-alpha:100%;--tw-inset-shadow:0 0 #0000;--tw-inset-shadow-color:initial;--tw-inset-shadow-alpha:100%;--tw-ring-color:initial;--tw-ring-shadow:0 0 #0000;--tw-inset-ring-color:initial;--tw-inset-ring-shadow:0 0 #0000;--tw-ring-inset:initial;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-offset-shadow:0 0 #0000;--tw-blur:initial;--tw-brightness:initial;--tw-contrast:initial;--tw-grayscale:initial;--tw-hue-rotate:initial;--tw-invert:initial;--tw-opacity:initial;--tw-saturate:initial;--tw-sepia:initial;--tw-drop-shadow:initial;--tw-drop-shadow-color:initial;--tw-drop-shadow-alpha:100%;--tw-drop-shadow-size:initial;--tw-backdrop-blur:initial;--tw-backdrop-brightness:initial;--tw-backdrop-contrast:initial;--tw-backdrop-grayscale:initial;--tw-backdrop-hue-rotate:initial;--tw-backdrop-invert:initial;--tw-backdrop-opacity:initial;--tw-backdrop-saturate:initial;--tw-backdrop-sepia:initial;--tw-duration:initial;--tw-scale-x:1;--tw-scale-y:1;--tw-scale-z:1}}}@layer theme{:root,:host{--font-sans:"Figtree", ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", "Noto Sans CJK SC", sans-serif;--font-mono:ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;--color-red-400:oklch(70.4% .191 22.216);--color-red-500:oklch(63.7% .237 25.331);--color-red-600:oklch(57.7% .245 27.325);--color-orange-300:oklch(83.7% .128 66.29);--color-orange-400:oklch(75% .183 55.934);--color-orange-500:oklch(70.5% .213 47.604);--color-orange-600:oklch(64.6% .222 41.116);--color-amber-50:oklch(98.7% .022 95.277);--color-amber-200:oklch(92.4% .12 95.746);--color-amber-300:oklch(87.9% .169 91.605);--color-amber-400:oklch(82.8% .189 84.429);--color-amber-500:oklch(76.9% .188 70.08);--color-amber-600:oklch(66.6% .179 58.318);--color-amber-700:oklch(55.5% .163 48.998);--color-amber-800:oklch(47.3% .137 46.201);--color-emerald-300:oklch(84.5% .143 164.978);--color-emerald-400:oklch(76.5% .177 163.223);--color-emerald-500:oklch(69.6% .17 162.48);--color-emerald-600:oklch(59.6% .145 163.225);--color-emerald-700:oklch(50.8% .118 165.612);--color-teal-700:oklch(51.1% .096 186.391);--color-cyan-300:oklch(86.5% .127 207.078);--color-cyan-500:oklch(71.5% .143 215.221);--color-cyan-600:oklch(60.9% .126 221.723);--color-sky-300:oklch(82.8% .111 230.318);--color-sky-400:oklch(74.6% .16 232.661);--color-sky-500:oklch(68.5% .169 237.323);--color-sky-600:oklch(58.8% .158 241.966);--color-violet-300:oklch(81.1% .111 293.571);--color-violet-500:oklch(60.6% .25 292.717);--color-violet-600:oklch(54.1% .281 293.009);--color-fuchsia-300:oklch(83.3% .145 321.434);--color-fuchsia-500:oklch(66.7% .295 322.15);--color-fuchsia-600:oklch(59.1% .293 322.896);--color-pink-300:oklch(82.3% .12 346.018);--color-pink-500:oklch(65.6% .241 354.308);--color-pink-600:oklch(59.2% .249 .584);--color-rose-300:oklch(81% .117 11.638);--color-rose-400:oklch(71.2% .194 13.428);--color-rose-500:oklch(64.5% .246 16.439);--color-rose-600:oklch(58.6% .253 17.585);--color-rose-700:oklch(51.4% .222 16.935);--color-slate-400:oklch(70.4% .04 256.788);--color-slate-600:oklch(44.6% .043 257.281);--color-slate-700:oklch(37.2% .044 257.287);--color-slate-900:oklch(20.8% .042 265.755);--color-black:#000;--color-white:#fff;--spacing:.25rem;--container-sm:24rem;--container-md:28rem;--container-lg:32rem;--font-weight-normal:400;--font-weight-medium:500;--font-weight-semibold:600;--font-weight-bold:700;--tracking-tight:-.025em;--tracking-normal:0em;--tracking-wide:.025em;--leading-tight:1.25;--leading-snug:1.375;--leading-relaxed:1.625;--radius-sm:.25rem;--radius-md:.375rem;--radius-lg:.5rem;--radius-xl:.75rem;--radius-2xl:1rem;--radius-3xl:1.5rem;--drop-shadow-sm:0 1px 2px #00000026;--animate-spin:spin 1s linear infinite;--animate-pulse:pulse 2s cubic-bezier(.4, 0, .6, 1) infinite;--blur-2xl:40px;--blur-3xl:64px;--default-transition-duration:.15s;--default-transition-timing-function:cubic-bezier(.4, 0, .2, 1);--default-font-family:var(--font-sans);--default-mono-font-family:var(--font-mono);--color-bg:var(--om-bg);--color-surface:var(--om-surface);--color-surface-2:var(--om-surface-2);--color-border:var(--om-border);--color-fg:var(--om-fg);--color-muted:var(--om-muted);--color-accent:var(--om-accent);--color-accent-fg:#fff;--color-accent-soft:var(--om-accent-soft);--color-accent-soft-fg:var(--om-accent-soft-fg);--color-bubble-user:var(--om-bubble-user);--color-bubble-user-fg:var(--om-bubble-user-fg)}}@layer base{*,:after,:before,::backdrop{box-sizing:border-box;border:0 solid;margin:0;padding:0}::file-selector-button{box-sizing:border-box;border:0 solid;margin:0;padding:0}html,:host{-webkit-text-size-adjust:100%;tab-size:4;line-height:1.5;font-family:var(--default-font-family,-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", "Noto Sans", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji");font-feature-settings:var(--default-font-feature-settings,normal);font-variation-settings:var(--default-font-variation-settings,normal);-webkit-tap-highlight-color:transparent}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,samp,pre{font-family:var(--default-mono-font-family,ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace);font-feature-settings:var(--default-mono-font-feature-settings,normal);font-variation-settings:var(--default-mono-font-variation-settings,normal);font-size:1em}small{font-size:80%}sub,sup{vertical-align:baseline;font-size:75%;line-height:0;position:relative}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}:-moz-focusring:where(:not(iframe)){outline:auto}progress{vertical-align:baseline}summary{display:list-item}ol,ul,menu{list-style:none}img,svg,video,canvas,audio,iframe,embed,object{vertical-align:middle;display:block}img,video{max-width:100%;height:auto}button,input,select,optgroup,textarea{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}::file-selector-button{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}:where(select:is([multiple],[size])) optgroup{font-weight:bolder}:where(select:is([multiple],[size])) optgroup option{padding-inline-start:20px}::file-selector-button{margin-inline-end:4px}::placeholder{opacity:1}@supports (not ((-webkit-appearance:-apple-pay-button))) or (contain-intrinsic-size:1px){::placeholder{color:currentColor}@supports (color:color-mix(in lab, red, red)){::placeholder{color:color-mix(in oklab, currentcolor 50%, transparent)}}}textarea{resize:vertical}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-date-and-time-value{min-height:1lh;text-align:inherit}::-webkit-datetime-edit{display:inline-flex}::-webkit-datetime-edit-fields-wrapper{padding:0}::-webkit-datetime-edit{padding-block:0}::-webkit-datetime-edit-year-field{padding-block:0}::-webkit-datetime-edit-month-field{padding-block:0}::-webkit-datetime-edit-day-field{padding-block:0}::-webkit-datetime-edit-hour-field{padding-block:0}::-webkit-datetime-edit-minute-field{padding-block:0}::-webkit-datetime-edit-second-field{padding-block:0}::-webkit-datetime-edit-millisecond-field{padding-block:0}::-webkit-datetime-edit-meridiem-field{padding-block:0}::-webkit-calendar-picker-indicator{line-height:1}:-moz-ui-invalid{box-shadow:none}button,input:where([type=button],[type=reset],[type=submit]){appearance:button}::file-selector-button{appearance:button}::-webkit-inner-spin-button{height:auto}::-webkit-outer-spin-button{height:auto}[hidden]:where(:not([hidden=until-found])){display:none!important}}@layer components;@layer utilities{.\@container{container-type:inline-size}.pointer-events-auto{pointer-events:auto}.pointer-events-none{pointer-events:none}.visible{visibility:visible}.sr-only{clip-path:inset(50%);white-space:nowrap;border-width:0;width:1px;height:1px;margin:-1px;padding:0;position:absolute;overflow:hidden}.absolute{position:absolute}.fixed{position:fixed}.relative{position:relative}.static{position:static}.sticky{position:sticky}.inset-0{inset:0}.inset-x-0{inset-inline:0}.inset-y-0{inset-block:0}.-top-1{top:calc(var(--spacing) * -1)}.-top-1\.5{top:calc(var(--spacing) * -1.5)}.-top-20{top:calc(var(--spacing) * -20)}.top-0{top:0}.top-0\.5{top:calc(var(--spacing) * .5)}.top-1{top:var(--spacing)}.top-1\.5{top:calc(var(--spacing) * 1.5)}.top-1\/2{top:50%}.top-2{top:calc(var(--spacing) * 2)}.top-2\.5{top:calc(var(--spacing) * 2.5)}.top-9{top:calc(var(--spacing) * 9)}.top-12{top:calc(var(--spacing) * 12)}.top-\[3px\]{top:3px}.top-full{top:100%}.-right-0\.5{right:calc(var(--spacing) * -.5)}.-right-1{right:calc(var(--spacing) * -1)}.-right-1\.5{right:calc(var(--spacing) * -1.5)}.-right-16{right:calc(var(--spacing) * -16)}.right-0{right:0}.right-1{right:var(--spacing)}.right-1\.5{right:calc(var(--spacing) * 1.5)}.right-2{right:calc(var(--spacing) * 2)}.right-2\.5{right:calc(var(--spacing) * 2.5)}.right-3{right:calc(var(--spacing) * 3)}.right-4{right:calc(var(--spacing) * 4)}.right-\[3px\]{right:3px}.-bottom-0\.5{bottom:calc(var(--spacing) * -.5)}.bottom-0{bottom:0}.bottom-1{bottom:var(--spacing)}.bottom-2{bottom:calc(var(--spacing) * 2)}.bottom-\[calc\(6rem\+env\(safe-area-inset-bottom\)\)\]{bottom:calc(6rem + env(safe-area-inset-bottom))}.tabbar-float{bottom:calc(12px + env(safe-area-inset-bottom))}.left-0{left:0}.left-0\.5{left:calc(var(--spacing) * .5)}.left-1\.5{left:calc(var(--spacing) * 1.5)}.left-1\/2{left:50%}.left-2\.5{left:calc(var(--spacing) * 2.5)}.left-3{left:calc(var(--spacing) * 3)}.left-4{left:calc(var(--spacing) * 4)}.left-\[18px\]{left:18px}.left-\[22px\]{left:22px}.left-\[26px\]{left:26px}.left-\[68px\]{left:68px}.z-10{z-index:10}.z-20{z-index:20}.z-30{z-index:30}.z-50{z-index:50}.z-\[60\]{z-index:60}.z-\[70\]{z-index:70}.container{width:100%}@media (width>=40rem){.container{max-width:40rem}}@media (width>=48rem){.container{max-width:48rem}}@media (width>=64rem){.container{max-width:64rem}}@media (width>=80rem){.container{max-width:80rem}}@media (width>=96rem){.container{max-width:96rem}}.-mx-4{margin-inline:calc(var(--spacing) * -4)}.mx-1{margin-inline:var(--spacing)}.mx-2{margin-inline:calc(var(--spacing) * 2)}.mx-3{margin-inline:calc(var(--spacing) * 3)}.mx-4{margin-inline:calc(var(--spacing) * 4)}.mx-auto{margin-inline:auto}.my-1{margin-block:var(--spacing)}.my-1\.5{margin-block:calc(var(--spacing) * 1.5)}.my-2{margin-block:calc(var(--spacing) * 2)}.my-8{margin-block:calc(var(--spacing) * 8)}.-mt-0\.5{margin-top:calc(var(--spacing) * -.5)}.-mt-1{margin-top:calc(var(--spacing) * -1)}.-mt-2\.5{margin-top:calc(var(--spacing) * -2.5)}.mt-0\.5{margin-top:calc(var(--spacing) * .5)}.mt-1{margin-top:var(--spacing)}.mt-1\.5{margin-top:calc(var(--spacing) * 1.5)}.mt-2{margin-top:calc(var(--spacing) * 2)}.mt-2\.5{margin-top:calc(var(--spacing) * 2.5)}.mt-3{margin-top:calc(var(--spacing) * 3)}.mt-3\.5{margin-top:calc(var(--spacing) * 3.5)}.mt-4{margin-top:calc(var(--spacing) * 4)}.mt-5{margin-top:calc(var(--spacing) * 5)}.mt-6{margin-top:calc(var(--spacing) * 6)}.mt-7{margin-top:calc(var(--spacing) * 7)}.mt-8{margin-top:calc(var(--spacing) * 8)}.mt-\[2px\]{margin-top:2px}.mt-\[3px\]{margin-top:3px}.mt-\[22px\]{margin-top:22px}.mt-auto{margin-top:auto}.-mr-1\.5{margin-right:calc(var(--spacing) * -1.5)}.-mr-2{margin-right:calc(var(--spacing) * -2)}.mr-2{margin-right:calc(var(--spacing) * 2)}.mr-2\.5{margin-right:calc(var(--spacing) * 2.5)}.mr-3{margin-right:calc(var(--spacing) * 3)}.mr-5{margin-right:calc(var(--spacing) * 5)}.-mb-2{margin-bottom:calc(var(--spacing) * -2)}.mb-0\.5{margin-bottom:calc(var(--spacing) * .5)}.mb-1{margin-bottom:var(--spacing)}.mb-1\.5{margin-bottom:calc(var(--spacing) * 1.5)}.mb-2{margin-bottom:calc(var(--spacing) * 2)}.mb-3{margin-bottom:calc(var(--spacing) * 3)}.mb-4{margin-bottom:calc(var(--spacing) * 4)}.mb-5{margin-bottom:calc(var(--spacing) * 5)}.mb-6{margin-bottom:calc(var(--spacing) * 6)}.-ml-1{margin-left:calc(var(--spacing) * -1)}.ml-0\.5{margin-left:calc(var(--spacing) * .5)}.ml-1{margin-left:var(--spacing)}.ml-1\.5{margin-left:calc(var(--spacing) * 1.5)}.ml-2{margin-left:calc(var(--spacing) * 2)}.ml-2\.5{margin-left:calc(var(--spacing) * 2.5)}.ml-4{margin-left:calc(var(--spacing) * 4)}.ml-\[52px\]{margin-left:52px}.ml-\[76px\]{margin-left:76px}.ml-auto{margin-left:auto}.line-clamp-2{-webkit-line-clamp:2;-webkit-box-orient:vertical;display:-webkit-box;overflow:hidden}.line-clamp-3{-webkit-line-clamp:3;-webkit-box-orient:vertical;display:-webkit-box;overflow:hidden}.line-clamp-4{-webkit-line-clamp:4;-webkit-box-orient:vertical;display:-webkit-box;overflow:hidden}.block{display:block}.contents{display:contents}.flex{display:flex}.grid{display:grid}.hidden{display:none}.inline{display:inline}.inline-block{display:inline-block}.inline-flex{display:inline-flex}.table{display:table}.aspect-\[16\/10\]{aspect-ratio:16/10}.aspect-square{aspect-ratio:1}.h-1{height:var(--spacing)}.h-1\.5{height:calc(var(--spacing) * 1.5)}.h-2{height:calc(var(--spacing) * 2)}.h-2\.5{height:calc(var(--spacing) * 2.5)}.h-3\.5{height:calc(var(--spacing) * 3.5)}.h-4{height:calc(var(--spacing) * 4)}.h-5{height:calc(var(--spacing) * 5)}.h-6{height:calc(var(--spacing) * 6)}.h-7{height:calc(var(--spacing) * 7)}.h-8{height:calc(var(--spacing) * 8)}.h-9{height:calc(var(--spacing) * 9)}.h-10{height:calc(var(--spacing) * 10)}.h-11{height:calc(var(--spacing) * 11)}.h-12{height:calc(var(--spacing) * 12)}.h-14{height:calc(var(--spacing) * 14)}.h-16{height:calc(var(--spacing) * 16)}.h-28{height:calc(var(--spacing) * 28)}.h-40{height:calc(var(--spacing) * 40)}.h-44{height:calc(var(--spacing) * 44)}.h-48{height:calc(var(--spacing) * 48)}.h-\[9px\]{height:9px}.h-\[17px\]{height:17px}.h-\[18px\]{height:18px}.h-\[46px\]{height:46px}.h-\[46vh\]{height:46vh}.h-\[50px\]{height:50px}.h-\[72px\]{height:72px}.h-\[100dvh\]{height:100dvh}.h-\[130px\]{height:130px}.h-\[148px\]{height:148px}.h-\[480px\]{height:480px}.h-full{height:100%}.max-h-28{max-height:calc(var(--spacing) * 28)}.max-h-32{max-height:calc(var(--spacing) * 32)}.max-h-40{max-height:calc(var(--spacing) * 40)}.max-h-52{max-height:calc(var(--spacing) * 52)}.max-h-64{max-height:calc(var(--spacing) * 64)}.max-h-72{max-height:calc(var(--spacing) * 72)}.max-h-\[60vh\]{max-height:60vh}.max-h-\[92dvh\]{max-height:92dvh}.max-h-full{max-height:100%}.min-h-0{min-height:0}.min-h-\[40vh\]{min-height:40vh}.min-h-\[44px\]{min-height:44px}.min-h-\[54px\]{min-height:54px}.min-h-\[56px\]{min-height:56px}.\!w-auto{width:auto!important}.w-1{width:var(--spacing)}.w-1\.5{width:calc(var(--spacing) * 1.5)}.w-2{width:calc(var(--spacing) * 2)}.w-2\.5{width:calc(var(--spacing) * 2.5)}.w-5{width:calc(var(--spacing) * 5)}.w-6{width:calc(var(--spacing) * 6)}.w-7{width:calc(var(--spacing) * 7)}.w-8{width:calc(var(--spacing) * 8)}.w-9{width:calc(var(--spacing) * 9)}.w-10{width:calc(var(--spacing) * 10)}.w-11{width:calc(var(--spacing) * 11)}.w-12{width:calc(var(--spacing) * 12)}.w-14{width:calc(var(--spacing) * 14)}.w-16{width:calc(var(--spacing) * 16)}.w-28{width:calc(var(--spacing) * 28)}.w-40{width:calc(var(--spacing) * 40)}.w-44{width:calc(var(--spacing) * 44)}.w-48{width:calc(var(--spacing) * 48)}.w-56{width:calc(var(--spacing) * 56)}.w-\[9px\]{width:9px}.w-\[46px\]{width:46px}.w-\[60px\]{width:60px}.w-\[64px\]{width:64px}.w-\[72px\]{width:72px}.w-\[74px\]{width:74px}.w-\[76px\]{width:76px}.w-\[82vw\]{width:82vw}.w-\[86px\]{width:86px}.w-\[148px\]{width:148px}.w-\[188px\]{width:188px}.w-\[232px\]{width:232px}.w-\[248px\]{width:248px}.w-\[260px\]{width:260px}.w-\[300px\]{width:300px}.w-\[900px\]{width:900px}.w-auto{width:auto}.w-fit{width:fit-content}.w-full{width:100%}.max-w-\[60\%\]{max-width:60%}.max-w-\[68px\]{max-width:68px}.max-w-\[86\%\]{max-width:86%}.max-w-\[240px\]{max-width:240px}.max-w-\[320px\]{max-width:320px}.max-w-\[340px\]{max-width:340px}.max-w-\[360px\]{max-width:360px}.max-w-\[520px\]{max-width:520px}.max-w-\[560px\]{max-width:560px}.max-w-\[600px\]{max-width:600px}.max-w-\[720px\]{max-width:720px}.max-w-\[760px\]{max-width:760px}.max-w-\[calc\(100\%-128px\)\]{max-width:calc(100% - 128px)}.max-w-full{max-width:100%}.max-w-md{max-width:var(--container-md)}.max-w-sm{max-width:var(--container-sm)}.min-w-0{min-width:0}.min-w-\[17px\]{min-width:17px}.min-w-\[18px\]{min-width:18px}.min-w-\[180px\]{min-width:180px}.min-w-full{min-width:100%}.flex-1{flex:1}.shrink-0{flex-shrink:0}.border-separate{border-collapse:separate}.border-spacing-0{--tw-border-spacing-x:0px;--tw-border-spacing-y:0px;border-spacing:var(--tw-border-spacing-x) var(--tw-border-spacing-y)}.origin-top-left{transform-origin:0 0}.-translate-x-1\/2{--tw-translate-x:calc(calc(1 / 2 * 100%) * -1);translate:var(--tw-translate-x) var(--tw-translate-y)}.-translate-y-1\/2{--tw-translate-y:calc(calc(1 / 2 * 100%) * -1);translate:var(--tw-translate-x) var(--tw-translate-y)}.scale-\[0\.3333\]{scale:.3333}.animate-pulse{animation:var(--animate-pulse)}.animate-spin{animation:var(--animate-spin)}.cursor-crosshair{cursor:crosshair}.cursor-pointer{cursor:pointer}.resize-none{resize:none}.resize-y{resize:vertical}.scroll-mt-4{scroll-margin-top:calc(var(--spacing) * 4)}.list-decimal{list-style-type:decimal}.grid-cols-1{grid-template-columns:repeat(1,minmax(0,1fr))}.grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}.grid-cols-4{grid-template-columns:repeat(4,minmax(0,1fr))}.grid-cols-8{grid-template-columns:repeat(8,minmax(0,1fr))}.grid-cols-\[1fr_1fr_auto\]{grid-template-columns:1fr 1fr auto}.grid-cols-\[1fr_84px\]{grid-template-columns:1fr 84px}.grid-cols-\[auto_1fr\]{grid-template-columns:auto 1fr}.flex-col{flex-direction:column}.flex-wrap{flex-wrap:wrap}.items-baseline{align-items:baseline}.items-center{align-items:center}.items-end{align-items:flex-end}.items-start{align-items:flex-start}.justify-between{justify-content:space-between}.justify-center{justify-content:center}.justify-end{justify-content:flex-end}.justify-start{justify-content:flex-start}.gap-0\.5{gap:calc(var(--spacing) * .5)}.gap-1{gap:var(--spacing)}.gap-1\.5{gap:calc(var(--spacing) * 1.5)}.gap-2{gap:calc(var(--spacing) * 2)}.gap-2\.5{gap:calc(var(--spacing) * 2.5)}.gap-3{gap:calc(var(--spacing) * 3)}.gap-3\.5{gap:calc(var(--spacing) * 3.5)}.gap-4{gap:calc(var(--spacing) * 4)}.gap-\[3px\]{gap:3px}:where(.space-y-0\.5>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * .5) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * .5) * calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-1>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(var(--spacing) * var(--tw-space-y-reverse));margin-block-end:calc(var(--spacing) * calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-1\.5>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * 1.5) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * 1.5) * calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-2>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * 2) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * 2) * calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-2\.5>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * 2.5) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * 2.5) * calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-3>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * 3) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * 3) * calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-3\.5>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * 3.5) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * 3.5) * calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-4>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * 4) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * 4) * calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-5>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * 5) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * 5) * calc(1 - var(--tw-space-y-reverse)))}.gap-x-1\.5{column-gap:calc(var(--spacing) * 1.5)}.gap-x-2{column-gap:calc(var(--spacing) * 2)}.gap-x-3{column-gap:calc(var(--spacing) * 3)}.gap-x-4{column-gap:calc(var(--spacing) * 4)}.gap-y-0\.5{row-gap:calc(var(--spacing) * .5)}.gap-y-1{row-gap:var(--spacing)}.gap-y-1\.5{row-gap:calc(var(--spacing) * 1.5)}:where(.divide-y>:not(:last-child)){--tw-divide-y-reverse:0;border-bottom-style:var(--tw-border-style);border-top-style:var(--tw-border-style);border-top-width:calc(1px * var(--tw-divide-y-reverse));border-bottom-width:calc(1px * calc(1 - var(--tw-divide-y-reverse)))}:where(.divide-border>:not(:last-child)),:where(.divide-border\/60>:not(:last-child)){border-color:var(--color-border)}@supports (color:color-mix(in lab, red, red)){:where(.divide-border\/60>:not(:last-child)){border-color:color-mix(in oklab, var(--color-border) 60%, transparent)}}:where(.divide-border\/70>:not(:last-child)){border-color:var(--color-border)}@supports (color:color-mix(in lab, red, red)){:where(.divide-border\/70>:not(:last-child)){border-color:color-mix(in oklab, var(--color-border) 70%, transparent)}}.self-center{align-self:center}.self-start{align-self:flex-start}.truncate{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.overflow-auto{overflow:auto}.overflow-hidden{overflow:hidden}.overflow-x-auto{overflow-x:auto}.overflow-x-hidden{overflow-x:hidden}.overflow-y-auto{overflow-y:auto}.rounded{border-radius:.25rem}.rounded-2xl{border-radius:var(--radius-2xl)}.rounded-3xl{border-radius:var(--radius-3xl)}.rounded-\[10px\]{border-radius:10px}.rounded-\[13px\]{border-radius:13px}.rounded-\[14px\]{border-radius:14px}.rounded-\[18px\]{border-radius:18px}.rounded-\[20px\]{border-radius:20px}.rounded-\[22px\]{border-radius:22px}.rounded-\[26px\]{border-radius:26px}.rounded-\[28px\]{border-radius:28px}.rounded-full{border-radius:2147483647px}.rounded-lg{border-radius:var(--radius-lg)}.rounded-md{border-radius:var(--radius-md)}.rounded-sm{border-radius:var(--radius-sm)}.rounded-xl{border-radius:var(--radius-xl)}.rounded-t-3xl{border-top-left-radius:var(--radius-3xl);border-top-right-radius:var(--radius-3xl)}.rounded-t-\[28px\]{border-top-left-radius:28px;border-top-right-radius:28px}.rounded-tl-lg{border-top-left-radius:var(--radius-lg)}.rounded-br-lg{border-bottom-right-radius:var(--radius-lg)}.rounded-bl-lg{border-bottom-left-radius:var(--radius-lg)}.rounded-bl-md{border-bottom-left-radius:var(--radius-md)}.border{border-style:var(--tw-border-style);border-width:1px}.border-0{border-style:var(--tw-border-style);border-width:0}.border-2{border-style:var(--tw-border-style);border-width:2px}.border-\[1\.5px\]{border-style:var(--tw-border-style);border-width:1.5px}.border-y{border-block-style:var(--tw-border-style);border-block-width:1px}.border-t{border-top-style:var(--tw-border-style);border-top-width:1px}.border-r{border-right-style:var(--tw-border-style);border-right-width:1px}.border-b{border-bottom-style:var(--tw-border-style);border-bottom-width:1px}.border-dashed{--tw-border-style:dashed;border-style:dashed}.border-accent,.border-accent\/15{border-color:var(--color-accent)}@supports (color:color-mix(in lab, red, red)){.border-accent\/15{border-color:color-mix(in oklab, var(--color-accent) 15%, transparent)}}.border-accent\/25{border-color:var(--color-accent)}@supports (color:color-mix(in lab, red, red)){.border-accent\/25{border-color:color-mix(in oklab, var(--color-accent) 25%, transparent)}}.border-accent\/30{border-color:var(--color-accent)}@supports (color:color-mix(in lab, red, red)){.border-accent\/30{border-color:color-mix(in oklab, var(--color-accent) 30%, transparent)}}.border-accent\/40{border-color:var(--color-accent)}@supports (color:color-mix(in lab, red, red)){.border-accent\/40{border-color:color-mix(in oklab, var(--color-accent) 40%, transparent)}}.border-accent\/50{border-color:var(--color-accent)}@supports (color:color-mix(in lab, red, red)){.border-accent\/50{border-color:color-mix(in oklab, var(--color-accent) 50%, transparent)}}.border-amber-400\/40{border-color:#fcbb0066}@supports (color:color-mix(in lab, red, red)){.border-amber-400\/40{border-color:color-mix(in oklab, var(--color-amber-400) 40%, transparent)}}.border-amber-500\/50{border-color:#f99c0080}@supports (color:color-mix(in lab, red, red)){.border-amber-500\/50{border-color:color-mix(in oklab, var(--color-amber-500) 50%, transparent)}}.border-bg{border-color:var(--color-bg)}.border-border,.border-border\/60{border-color:var(--color-border)}@supports (color:color-mix(in lab, red, red)){.border-border\/60{border-color:color-mix(in oklab, var(--color-border) 60%, transparent)}}.border-border\/70{border-color:var(--color-border)}@supports (color:color-mix(in lab, red, red)){.border-border\/70{border-color:color-mix(in oklab, var(--color-border) 70%, transparent)}}.border-border\/80{border-color:var(--color-border)}@supports (color:color-mix(in lab, red, red)){.border-border\/80{border-color:color-mix(in oklab, var(--color-border) 80%, transparent)}}.border-current{border-color:currentColor}.border-fg{border-color:var(--color-fg)}.border-rose-400{border-color:var(--color-rose-400)}.border-rose-400\/60{border-color:#ff667f99}@supports (color:color-mix(in lab, red, red)){.border-rose-400\/60{border-color:color-mix(in oklab, var(--color-rose-400) 60%, transparent)}}.border-rose-500\/25{border-color:#ff235740}@supports (color:color-mix(in lab, red, red)){.border-rose-500\/25{border-color:color-mix(in oklab, var(--color-rose-500) 25%, transparent)}}.border-surface{border-color:var(--color-surface)}.border-transparent{border-color:#0000}.border-t-transparent{border-top-color:#0000}.bg-\[\#2fb344\]{background-color:#2fb344}.bg-\[\#f1efeb\]{background-color:#f1efeb}.bg-accent{background-color:var(--color-accent)}.bg-accent-soft{background-color:var(--color-accent-soft)}.bg-accent\/5{background-color:var(--color-accent)}@supports (color:color-mix(in lab, red, red)){.bg-accent\/5{background-color:color-mix(in oklab, var(--color-accent) 5%, transparent)}}.bg-accent\/8{background-color:var(--color-accent)}@supports (color:color-mix(in lab, red, red)){.bg-accent\/8{background-color:color-mix(in oklab, var(--color-accent) 8%, transparent)}}.bg-accent\/10{background-color:var(--color-accent)}@supports (color:color-mix(in lab, red, red)){.bg-accent\/10{background-color:color-mix(in oklab, var(--color-accent) 10%, transparent)}}.bg-accent\/12{background-color:var(--color-accent)}@supports (color:color-mix(in lab, red, red)){.bg-accent\/12{background-color:color-mix(in oklab, var(--color-accent) 12%, transparent)}}.bg-accent\/15{background-color:var(--color-accent)}@supports (color:color-mix(in lab, red, red)){.bg-accent\/15{background-color:color-mix(in oklab, var(--color-accent) 15%, transparent)}}.bg-accent\/70{background-color:var(--color-accent)}@supports (color:color-mix(in lab, red, red)){.bg-accent\/70{background-color:color-mix(in oklab, var(--color-accent) 70%, transparent)}}.bg-accent\/\[0\.06\]{background-color:var(--color-accent)}@supports (color:color-mix(in lab, red, red)){.bg-accent\/\[0\.06\]{background-color:color-mix(in oklab, var(--color-accent) 6%, transparent)}}.bg-amber-50\/70{background-color:#fffbebb3}@supports (color:color-mix(in lab, red, red)){.bg-amber-50\/70{background-color:color-mix(in oklab, var(--color-amber-50) 70%, transparent)}}.bg-amber-400{background-color:var(--color-amber-400)}.bg-amber-400\/15{background-color:#fcbb0026}@supports (color:color-mix(in lab, red, red)){.bg-amber-400\/15{background-color:color-mix(in oklab, var(--color-amber-400) 15%, transparent)}}.bg-amber-500{background-color:var(--color-amber-500)}.bg-amber-500\/10{background-color:#f99c001a}@supports (color:color-mix(in lab, red, red)){.bg-amber-500\/10{background-color:color-mix(in oklab, var(--color-amber-500) 10%, transparent)}}.bg-amber-500\/12{background-color:#f99c001f}@supports (color:color-mix(in lab, red, red)){.bg-amber-500\/12{background-color:color-mix(in oklab, var(--color-amber-500) 12%, transparent)}}.bg-amber-500\/15{background-color:#f99c0026}@supports (color:color-mix(in lab, red, red)){.bg-amber-500\/15{background-color:color-mix(in oklab, var(--color-amber-500) 15%, transparent)}}.bg-bg,.bg-bg\/50{background-color:var(--color-bg)}@supports (color:color-mix(in lab, red, red)){.bg-bg\/50{background-color:color-mix(in oklab, var(--color-bg) 50%, transparent)}}.bg-bg\/60{background-color:var(--color-bg)}@supports (color:color-mix(in lab, red, red)){.bg-bg\/60{background-color:color-mix(in oklab, var(--color-bg) 60%, transparent)}}.bg-bg\/80{background-color:var(--color-bg)}@supports (color:color-mix(in lab, red, red)){.bg-bg\/80{background-color:color-mix(in oklab, var(--color-bg) 80%, transparent)}}.bg-black\/20{background-color:#0003}@supports (color:color-mix(in lab, red, red)){.bg-black\/20{background-color:color-mix(in oklab, var(--color-black) 20%, transparent)}}.bg-black\/40{background-color:#0006}@supports (color:color-mix(in lab, red, red)){.bg-black\/40{background-color:color-mix(in oklab, var(--color-black) 40%, transparent)}}.bg-black\/45{background-color:#00000073}@supports (color:color-mix(in lab, red, red)){.bg-black\/45{background-color:color-mix(in oklab, var(--color-black) 45%, transparent)}}.bg-black\/60{background-color:#0009}@supports (color:color-mix(in lab, red, red)){.bg-black\/60{background-color:color-mix(in oklab, var(--color-black) 60%, transparent)}}.bg-border{background-color:var(--color-border)}.bg-bubble-user{background-color:var(--color-bubble-user)}.bg-cyan-500\/12{background-color:#00b7d71f}@supports (color:color-mix(in lab, red, red)){.bg-cyan-500\/12{background-color:color-mix(in oklab, var(--color-cyan-500) 12%, transparent)}}.bg-emerald-500{background-color:var(--color-emerald-500)}.bg-emerald-500\/12{background-color:#00bb7f1f}@supports (color:color-mix(in lab, red, red)){.bg-emerald-500\/12{background-color:color-mix(in oklab, var(--color-emerald-500) 12%, transparent)}}.bg-emerald-500\/15{background-color:#00bb7f26}@supports (color:color-mix(in lab, red, red)){.bg-emerald-500\/15{background-color:color-mix(in oklab, var(--color-emerald-500) 15%, transparent)}}.bg-fg,.bg-fg\/40{background-color:var(--color-fg)}@supports (color:color-mix(in lab, red, red)){.bg-fg\/40{background-color:color-mix(in oklab, var(--color-fg) 40%, transparent)}}.bg-fuchsia-500\/12{background-color:#e12afb1f}@supports (color:color-mix(in lab, red, red)){.bg-fuchsia-500\/12{background-color:color-mix(in oklab, var(--color-fuchsia-500) 12%, transparent)}}.bg-muted,.bg-muted\/35{background-color:var(--color-muted)}@supports (color:color-mix(in lab, red, red)){.bg-muted\/35{background-color:color-mix(in oklab, var(--color-muted) 35%, transparent)}}.bg-orange-500\/12{background-color:#fe6e001f}@supports (color:color-mix(in lab, red, red)){.bg-orange-500\/12{background-color:color-mix(in oklab, var(--color-orange-500) 12%, transparent)}}.bg-pink-500{background-color:var(--color-pink-500)}.bg-pink-500\/12{background-color:#f6339a1f}@supports (color:color-mix(in lab, red, red)){.bg-pink-500\/12{background-color:color-mix(in oklab, var(--color-pink-500) 12%, transparent)}}.bg-red-500{background-color:var(--color-red-500)}.bg-rose-400{background-color:var(--color-rose-400)}.bg-rose-500{background-color:var(--color-rose-500)}.bg-rose-500\/12{background-color:#ff23571f}@supports (color:color-mix(in lab, red, red)){.bg-rose-500\/12{background-color:color-mix(in oklab, var(--color-rose-500) 12%, transparent)}}.bg-rose-500\/15{background-color:#ff235726}@supports (color:color-mix(in lab, red, red)){.bg-rose-500\/15{background-color:color-mix(in oklab, var(--color-rose-500) 15%, transparent)}}.bg-rose-500\/\[0\.04\]{background-color:#ff23570a}@supports (color:color-mix(in lab, red, red)){.bg-rose-500\/\[0\.04\]{background-color:color-mix(in oklab, var(--color-rose-500) 4%, transparent)}}.bg-rose-600{background-color:var(--color-rose-600)}.bg-sky-500\/12{background-color:#00a5ef1f}@supports (color:color-mix(in lab, red, red)){.bg-sky-500\/12{background-color:color-mix(in oklab, var(--color-sky-500) 12%, transparent)}}.bg-surface{background-color:var(--color-surface)}.bg-surface-2,.bg-surface-2\/40{background-color:var(--color-surface-2)}@supports (color:color-mix(in lab, red, red)){.bg-surface-2\/40{background-color:color-mix(in oklab, var(--color-surface-2) 40%, transparent)}}.bg-surface-2\/55{background-color:var(--color-surface-2)}@supports (color:color-mix(in lab, red, red)){.bg-surface-2\/55{background-color:color-mix(in oklab, var(--color-surface-2) 55%, transparent)}}.bg-surface-2\/60{background-color:var(--color-surface-2)}@supports (color:color-mix(in lab, red, red)){.bg-surface-2\/60{background-color:color-mix(in oklab, var(--color-surface-2) 60%, transparent)}}.bg-surface-2\/70{background-color:var(--color-surface-2)}@supports (color:color-mix(in lab, red, red)){.bg-surface-2\/70{background-color:color-mix(in oklab, var(--color-surface-2) 70%, transparent)}}.bg-surface-2\/80{background-color:var(--color-surface-2)}@supports (color:color-mix(in lab, red, red)){.bg-surface-2\/80{background-color:color-mix(in oklab, var(--color-surface-2) 80%, transparent)}}.bg-surface\/40{background-color:var(--color-surface)}@supports (color:color-mix(in lab, red, red)){.bg-surface\/40{background-color:color-mix(in oklab, var(--color-surface) 40%, transparent)}}.bg-surface\/70{background-color:var(--color-surface)}@supports (color:color-mix(in lab, red, red)){.bg-surface\/70{background-color:color-mix(in oklab, var(--color-surface) 70%, transparent)}}.bg-surface\/90{background-color:var(--color-surface)}@supports (color:color-mix(in lab, red, red)){.bg-surface\/90{background-color:color-mix(in oklab, var(--color-surface) 90%, transparent)}}.bg-transparent{background-color:#0000}.bg-violet-500{background-color:var(--color-violet-500)}.bg-violet-500\/12{background-color:#8d54ff1f}@supports (color:color-mix(in lab, red, red)){.bg-violet-500\/12{background-color:color-mix(in oklab, var(--color-violet-500) 12%, transparent)}}.bg-white{background-color:var(--color-white)}.bg-white\/80{background-color:#fffc}@supports (color:color-mix(in lab, red, red)){.bg-white\/80{background-color:color-mix(in oklab, var(--color-white) 80%, transparent)}}.bg-gradient-to-b{--tw-gradient-position:to bottom in oklab;background-image:linear-gradient(var(--tw-gradient-stops))}.bg-gradient-to-br{--tw-gradient-position:to bottom right in oklab;background-image:linear-gradient(var(--tw-gradient-stops))}.bg-\[radial-gradient\(ellipse_at_top\,rgba\(0\,100\,212\,0\.14\)\,transparent_65\%\)\]{background-image:radial-gradient(at top,#0064d424,#0000 65%)}.from-\[\#7d6bc7\]{--tw-gradient-from:#7d6bc7;--tw-gradient-stops:var(--tw-gradient-via-stops,var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position))}.from-\[\#b0413e\]{--tw-gradient-from:#b0413e;--tw-gradient-stops:var(--tw-gradient-via-stops,var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position))}.from-accent{--tw-gradient-from:var(--color-accent);--tw-gradient-stops:var(--tw-gradient-via-stops,var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position))}.from-emerald-500{--tw-gradient-from:var(--color-emerald-500);--tw-gradient-stops:var(--tw-gradient-via-stops,var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position))}.from-orange-400{--tw-gradient-from:var(--color-orange-400);--tw-gradient-stops:var(--tw-gradient-via-stops,var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position))}.from-slate-400{--tw-gradient-from:var(--color-slate-400);--tw-gradient-stops:var(--tw-gradient-via-stops,var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position))}.from-slate-700{--tw-gradient-from:var(--color-slate-700);--tw-gradient-stops:var(--tw-gradient-via-stops,var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position))}.to-\[\#7a1f1f\]{--tw-gradient-to:#7a1f1f;--tw-gradient-stops:var(--tw-gradient-via-stops,var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position))}.to-\[\#574494\]{--tw-gradient-to:#574494;--tw-gradient-stops:var(--tw-gradient-via-stops,var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position))}.to-amber-600{--tw-gradient-to:var(--color-amber-600);--tw-gradient-stops:var(--tw-gradient-via-stops,var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position))}.to-sky-400{--tw-gradient-to:var(--color-sky-400);--tw-gradient-stops:var(--tw-gradient-via-stops,var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position))}.to-slate-600{--tw-gradient-to:var(--color-slate-600);--tw-gradient-stops:var(--tw-gradient-via-stops,var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position))}.to-slate-900{--tw-gradient-to:var(--color-slate-900);--tw-gradient-stops:var(--tw-gradient-via-stops,var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position))}.to-teal-700{--tw-gradient-to:var(--color-teal-700);--tw-gradient-stops:var(--tw-gradient-via-stops,var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position))}.object-contain{object-fit:contain}.object-cover{object-fit:cover}.object-top{object-position:top}.p-0\.5{padding:calc(var(--spacing) * .5)}.p-1{padding:var(--spacing)}.p-1\.5{padding:calc(var(--spacing) * 1.5)}.p-2{padding:calc(var(--spacing) * 2)}.p-2\.5{padding:calc(var(--spacing) * 2.5)}.p-3{padding:calc(var(--spacing) * 3)}.p-3\.5{padding:calc(var(--spacing) * 3.5)}.p-4{padding:calc(var(--spacing) * 4)}.p-5{padding:calc(var(--spacing) * 5)}.p-6{padding:calc(var(--spacing) * 6)}.p-8{padding:calc(var(--spacing) * 8)}.\!px-3\.5{padding-inline:calc(var(--spacing) * 3.5)!important}.px-0\.5{padding-inline:calc(var(--spacing) * .5)}.px-1{padding-inline:var(--spacing)}.px-1\.5{padding-inline:calc(var(--spacing) * 1.5)}.px-2{padding-inline:calc(var(--spacing) * 2)}.px-2\.5{padding-inline:calc(var(--spacing) * 2.5)}.px-3{padding-inline:calc(var(--spacing) * 3)}.px-3\.5{padding-inline:calc(var(--spacing) * 3.5)}.px-4{padding-inline:calc(var(--spacing) * 4)}.px-5{padding-inline:calc(var(--spacing) * 5)}.px-6{padding-inline:calc(var(--spacing) * 6)}.px-8{padding-inline:calc(var(--spacing) * 8)}.px-16{padding-inline:calc(var(--spacing) * 16)}.\!py-1\.5{padding-block:calc(var(--spacing) * 1.5)!important}.py-0\.5{padding-block:calc(var(--spacing) * .5)}.py-1{padding-block:var(--spacing)}.py-1\.5{padding-block:calc(var(--spacing) * 1.5)}.py-2{padding-block:calc(var(--spacing) * 2)}.py-2\.5{padding-block:calc(var(--spacing) * 2.5)}.py-3{padding-block:calc(var(--spacing) * 3)}.py-3\.5{padding-block:calc(var(--spacing) * 3.5)}.py-4{padding-block:calc(var(--spacing) * 4)}.py-6{padding-block:calc(var(--spacing) * 6)}.py-8{padding-block:calc(var(--spacing) * 8)}.py-10{padding-block:calc(var(--spacing) * 10)}.pt-0{padding-top:0}.pt-0\.5{padding-top:calc(var(--spacing) * .5)}.pt-1{padding-top:var(--spacing)}.pt-1\.5{padding-top:calc(var(--spacing) * 1.5)}.pt-2{padding-top:calc(var(--spacing) * 2)}.pt-2\.5{padding-top:calc(var(--spacing) * 2.5)}.pt-3{padding-top:calc(var(--spacing) * 3)}.pt-3\.5{padding-top:calc(var(--spacing) * 3.5)}.pt-4{padding-top:calc(var(--spacing) * 4)}.pt-5{padding-top:calc(var(--spacing) * 5)}.pt-6{padding-top:calc(var(--spacing) * 6)}.pt-9{padding-top:calc(var(--spacing) * 9)}.pt-10{padding-top:calc(var(--spacing) * 10)}.pt-14{padding-top:calc(var(--spacing) * 14)}.pt-\[3px\]{padding-top:3px}.pt-\[18px\]{padding-top:18px}.pt-\[22px\]{padding-top:22px}.pr-1{padding-right:var(--spacing)}.pr-2{padding-right:calc(var(--spacing) * 2)}.pr-2\.5{padding-right:calc(var(--spacing) * 2.5)}.pr-3{padding-right:calc(var(--spacing) * 3)}.pr-5{padding-right:calc(var(--spacing) * 5)}.pr-8{padding-right:calc(var(--spacing) * 8)}.pr-10{padding-right:calc(var(--spacing) * 10)}.pb-0\.5{padding-bottom:calc(var(--spacing) * .5)}.pb-1{padding-bottom:var(--spacing)}.pb-1\.5{padding-bottom:calc(var(--spacing) * 1.5)}.pb-2{padding-bottom:calc(var(--spacing) * 2)}.pb-2\.5{padding-bottom:calc(var(--spacing) * 2.5)}.pb-3{padding-bottom:calc(var(--spacing) * 3)}.pb-3\.5{padding-bottom:calc(var(--spacing) * 3.5)}.pb-4{padding-bottom:calc(var(--spacing) * 4)}.pb-5{padding-bottom:calc(var(--spacing) * 5)}.pb-6{padding-bottom:calc(var(--spacing) * 6)}.pb-7{padding-bottom:calc(var(--spacing) * 7)}.pb-8{padding-bottom:calc(var(--spacing) * 8)}.tabbar-room{padding-bottom:calc(74px + env(safe-area-inset-bottom))}.pl-3{padding-left:calc(var(--spacing) * 3)}.pl-3\.5{padding-left:calc(var(--spacing) * 3.5)}.pl-4{padding-left:calc(var(--spacing) * 4)}.pl-5{padding-left:calc(var(--spacing) * 5)}.pl-7{padding-left:calc(var(--spacing) * 7)}.pl-9{padding-left:calc(var(--spacing) * 9)}.pl-12{padding-left:calc(var(--spacing) * 12)}.pl-\[18px\]{padding-left:18px}.text-center{text-align:center}.text-left{text-align:left}.text-right{text-align:right}.align-middle{vertical-align:middle}.font-mono{font-family:var(--font-mono)}.font-sans{font-family:var(--font-sans)}.text-\[10\.5px\]{font-size:10.5px}.text-\[10px\]{font-size:10px}.text-\[11\.5px\]{font-size:11.5px}.text-\[11px\]{font-size:11px}.text-\[12\.5px\]{font-size:12.5px}.text-\[12px\]{font-size:12px}.text-\[13\.5px\]{font-size:13.5px}.text-\[13px\]{font-size:13px}.text-\[14\.5px\]{font-size:14.5px}.text-\[14px\]{font-size:14px}.text-\[15px\]{font-size:15px}.text-\[16px\]{font-size:16px}.text-\[17px\]{font-size:17px}.text-\[18px\]{font-size:18px}.text-\[20px\]{font-size:20px}.text-\[21px\]{font-size:21px}.text-\[22px\]{font-size:22px}.text-\[24px\]{font-size:24px}.text-\[26px\]{font-size:26px}.text-\[28px\]{font-size:28px}.text-\[30px\]{font-size:30px}.text-\[64px\]{font-size:64px}.leading-4{--tw-leading:calc(var(--spacing) * 4);line-height:calc(var(--spacing) * 4)}.leading-6{--tw-leading:calc(var(--spacing) * 6);line-height:calc(var(--spacing) * 6)}.leading-7{--tw-leading:calc(var(--spacing) * 7);line-height:calc(var(--spacing) * 7)}.leading-8{--tw-leading:calc(var(--spacing) * 8);line-height:calc(var(--spacing) * 8)}.leading-\[1\.4\]{--tw-leading:1.4;line-height:1.4}.leading-\[1\.5\]{--tw-leading:1.5;line-height:1.5}.leading-\[1\.45\]{--tw-leading:1.45;line-height:1.45}.leading-\[14px\]{--tw-leading:14px;line-height:14px}.leading-\[17px\]{--tw-leading:17px;line-height:17px}.leading-\[18px\]{--tw-leading:18px;line-height:18px}.leading-\[19px\]{--tw-leading:19px;line-height:19px}.leading-\[20px\]{--tw-leading:20px;line-height:20px}.leading-\[21px\]{--tw-leading:21px;line-height:21px}.leading-\[22px\]{--tw-leading:22px;line-height:22px}.leading-\[26px\]{--tw-leading:26px;line-height:26px}.leading-\[34px\]{--tw-leading:34px;line-height:34px}.leading-none{--tw-leading:1;line-height:1}.leading-relaxed{--tw-leading:var(--leading-relaxed);line-height:var(--leading-relaxed)}.leading-snug{--tw-leading:var(--leading-snug);line-height:var(--leading-snug)}.leading-tight{--tw-leading:var(--leading-tight);line-height:var(--leading-tight)}.font-bold{--tw-font-weight:var(--font-weight-bold);font-weight:var(--font-weight-bold)}.font-medium{--tw-font-weight:var(--font-weight-medium);font-weight:var(--font-weight-medium)}.font-normal{--tw-font-weight:var(--font-weight-normal);font-weight:var(--font-weight-normal)}.font-semibold{--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold)}.tracking-\[0\.2em\]{--tw-tracking:.2em;letter-spacing:.2em}.tracking-\[0\.3em\]{--tw-tracking:.3em;letter-spacing:.3em}.tracking-normal{--tw-tracking:var(--tracking-normal);letter-spacing:var(--tracking-normal)}.tracking-tight{--tw-tracking:var(--tracking-tight);letter-spacing:var(--tracking-tight)}.tracking-wide{--tw-tracking:var(--tracking-wide);letter-spacing:var(--tracking-wide)}.break-words{overflow-wrap:break-word}.break-all{word-break:break-all}.whitespace-nowrap{white-space:nowrap}.whitespace-pre-wrap{white-space:pre-wrap}.text-accent{color:var(--color-accent)}.text-accent-fg{color:var(--color-accent-fg)}.text-accent-soft-fg{color:var(--color-accent-soft-fg)}.text-accent\/80{color:var(--color-accent)}@supports (color:color-mix(in lab, red, red)){.text-accent\/80{color:color-mix(in oklab, var(--color-accent) 80%, transparent)}}.text-amber-500{color:var(--color-amber-500)}.text-amber-600{color:var(--color-amber-600)}.text-amber-700{color:var(--color-amber-700)}.text-amber-800{color:var(--color-amber-800)}.text-bg{color:var(--color-bg)}.text-bubble-user-fg{color:var(--color-bubble-user-fg)}.text-cyan-600{color:var(--color-cyan-600)}.text-emerald-500{color:var(--color-emerald-500)}.text-emerald-600{color:var(--color-emerald-600)}.text-emerald-700{color:var(--color-emerald-700)}.text-fg,.text-fg\/45{color:var(--color-fg)}@supports (color:color-mix(in lab, red, red)){.text-fg\/45{color:color-mix(in oklab, var(--color-fg) 45%, transparent)}}.text-fg\/60{color:var(--color-fg)}@supports (color:color-mix(in lab, red, red)){.text-fg\/60{color:color-mix(in oklab, var(--color-fg) 60%, transparent)}}.text-fg\/65{color:var(--color-fg)}@supports (color:color-mix(in lab, red, red)){.text-fg\/65{color:color-mix(in oklab, var(--color-fg) 65%, transparent)}}.text-fg\/70{color:var(--color-fg)}@supports (color:color-mix(in lab, red, red)){.text-fg\/70{color:color-mix(in oklab, var(--color-fg) 70%, transparent)}}.text-fg\/75{color:var(--color-fg)}@supports (color:color-mix(in lab, red, red)){.text-fg\/75{color:color-mix(in oklab, var(--color-fg) 75%, transparent)}}.text-fg\/80{color:var(--color-fg)}@supports (color:color-mix(in lab, red, red)){.text-fg\/80{color:color-mix(in oklab, var(--color-fg) 80%, transparent)}}.text-fg\/85{color:var(--color-fg)}@supports (color:color-mix(in lab, red, red)){.text-fg\/85{color:color-mix(in oklab, var(--color-fg) 85%, transparent)}}.text-fg\/90{color:var(--color-fg)}@supports (color:color-mix(in lab, red, red)){.text-fg\/90{color:color-mix(in oklab, var(--color-fg) 90%, transparent)}}.text-fuchsia-600{color:var(--color-fuchsia-600)}.text-muted,.text-muted\/70{color:var(--color-muted)}@supports (color:color-mix(in lab, red, red)){.text-muted\/70{color:color-mix(in oklab, var(--color-muted) 70%, transparent)}}.text-muted\/80{color:var(--color-muted)}@supports (color:color-mix(in lab, red, red)){.text-muted\/80{color:color-mix(in oklab, var(--color-muted) 80%, transparent)}}.text-orange-600{color:var(--color-orange-600)}.text-pink-600{color:var(--color-pink-600)}.text-red-600{color:var(--color-red-600)}.text-rose-500{color:var(--color-rose-500)}.text-rose-600{color:var(--color-rose-600)}.text-rose-700{color:var(--color-rose-700)}.text-sky-600{color:var(--color-sky-600)}.text-violet-600{color:var(--color-violet-600)}.text-white{color:var(--color-white)}.text-white\/85{color:#ffffffd9}@supports (color:color-mix(in lab, red, red)){.text-white\/85{color:color-mix(in oklab, var(--color-white) 85%, transparent)}}.text-white\/90{color:#ffffffe6}@supports (color:color-mix(in lab, red, red)){.text-white\/90{color:color-mix(in oklab, var(--color-white) 90%, transparent)}}.capitalize{text-transform:capitalize}.normal-case{text-transform:none}.uppercase{text-transform:uppercase}.ordinal{--tw-ordinal:ordinal;font-variant-numeric:var(--tw-ordinal,) var(--tw-slashed-zero,) var(--tw-numeric-figure,) var(--tw-numeric-spacing,) var(--tw-numeric-fraction,)}.tabular-nums{--tw-numeric-spacing:tabular-nums;font-variant-numeric:var(--tw-ordinal,) var(--tw-slashed-zero,) var(--tw-numeric-figure,) var(--tw-numeric-spacing,) var(--tw-numeric-fraction,)}.line-through{text-decoration-line:line-through}.underline{text-decoration-line:underline}.decoration-border{-webkit-text-decoration-color:var(--color-border);-webkit-text-decoration-color:var(--color-border);-webkit-text-decoration-color:var(--color-border);text-decoration-color:var(--color-border)}.decoration-dotted{text-decoration-style:dotted}.underline-offset-2{text-underline-offset:2px}.accent-\[var\(--om-accent\)\]{accent-color:var(--om-accent)}.accent-accent{accent-color:var(--color-accent)}.opacity-0{opacity:0}.opacity-45{opacity:.45}.opacity-50{opacity:.5}.opacity-60{opacity:.6}.opacity-70{opacity:.7}.opacity-80{opacity:.8}.opacity-90{opacity:.9}.shadow{--tw-shadow:0 1px 3px 0 var(--tw-shadow-color,#0000001a), 0 1px 2px -1px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.shadow-2xl{--tw-shadow:0 25px 50px -12px var(--tw-shadow-color,#00000040);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.shadow-\[0_1px_4px_rgba\(0\,0\,0\,0\.14\)\]{--tw-shadow:0 1px 4px var(--tw-shadow-color,#00000024);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.shadow-\[0_1px_4px_rgba\(0\,0\,0\,0\.16\)\]{--tw-shadow:0 1px 4px var(--tw-shadow-color,#00000029);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.shadow-\[0_1px_4px_rgba\(0\,0\,0\,0\.18\)\]{--tw-shadow:0 1px 4px var(--tw-shadow-color,#0000002e);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.shadow-\[0_2px_12px_-6px_rgba\(0\,0\,0\,0\.12\)\]{--tw-shadow:0 2px 12px -6px var(--tw-shadow-color,#0000001f);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.shadow-\[0_2px_12px_rgba\(0\,0\,0\,0\.12\)\]{--tw-shadow:0 2px 12px var(--tw-shadow-color,#0000001f);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.shadow-\[0_4px_20px_-12px_rgba\(0\,0\,0\,0\.2\)\]{--tw-shadow:0 4px 20px -12px var(--tw-shadow-color,#0003);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.shadow-\[0_12px_40px_-12px_rgba\(0\,0\,0\,0\.3\)\]{--tw-shadow:0 12px 40px -12px var(--tw-shadow-color,#0000004d);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.shadow-lg{--tw-shadow:0 10px 15px -3px var(--tw-shadow-color,#0000001a), 0 4px 6px -4px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.shadow-md{--tw-shadow:0 4px 6px -1px var(--tw-shadow-color,#0000001a), 0 2px 4px -2px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.shadow-sm{--tw-shadow:0 1px 3px 0 var(--tw-shadow-color,#0000001a), 0 1px 2px -1px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.shadow-xl{--tw-shadow:0 20px 25px -5px var(--tw-shadow-color,#0000001a), 0 8px 10px -6px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.ring,.ring-1{--tw-ring-shadow:var(--tw-ring-inset,) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.ring-2{--tw-ring-shadow:var(--tw-ring-inset,) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.ring-\[2\.5px\]{--tw-ring-shadow:var(--tw-ring-inset,) 0 0 0 calc(2.5px + var(--tw-ring-offset-width)) var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.ring-\[3px\]{--tw-ring-shadow:var(--tw-ring-inset,) 0 0 0 calc(3px + var(--tw-ring-offset-width)) var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.ring-accent,.ring-accent\/40{--tw-ring-color:var(--color-accent)}@supports (color:color-mix(in lab, red, red)){.ring-accent\/40{--tw-ring-color:color-mix(in oklab, var(--color-accent) 40%, transparent)}}.ring-border\/50{--tw-ring-color:var(--color-border)}@supports (color:color-mix(in lab, red, red)){.ring-border\/50{--tw-ring-color:color-mix(in oklab, var(--color-border) 50%, transparent)}}.ring-offset-2{--tw-ring-offset-width:2px;--tw-ring-offset-shadow:var(--tw-ring-inset,) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color)}.ring-offset-bg{--tw-ring-offset-color:var(--color-bg)}.blur-3xl{--tw-blur:blur(var(--blur-3xl));filter:var(--tw-blur,) var(--tw-brightness,) var(--tw-contrast,) var(--tw-grayscale,) var(--tw-hue-rotate,) var(--tw-invert,) var(--tw-saturate,) var(--tw-sepia,) var(--tw-drop-shadow,)}.drop-shadow-\[0_20px_40px_rgba\(0\,100\,212\,0\.28\)\]{--tw-drop-shadow-size:drop-shadow(0 20px 40px var(--tw-drop-shadow-color,#0064d447));--tw-drop-shadow:var(--tw-drop-shadow-size);filter:var(--tw-blur,) var(--tw-brightness,) var(--tw-contrast,) var(--tw-grayscale,) var(--tw-hue-rotate,) var(--tw-invert,) var(--tw-saturate,) var(--tw-sepia,) var(--tw-drop-shadow,)}.drop-shadow-sm{--tw-drop-shadow-size:drop-shadow(0 1px 2px var(--tw-drop-shadow-color,#00000026));--tw-drop-shadow:drop-shadow(var(--drop-shadow-sm));filter:var(--tw-blur,) var(--tw-brightness,) var(--tw-contrast,) var(--tw-grayscale,) var(--tw-hue-rotate,) var(--tw-invert,) var(--tw-saturate,) var(--tw-sepia,) var(--tw-drop-shadow,)}.filter{filter:var(--tw-blur,) var(--tw-brightness,) var(--tw-contrast,) var(--tw-grayscale,) var(--tw-hue-rotate,) var(--tw-invert,) var(--tw-saturate,) var(--tw-sepia,) var(--tw-drop-shadow,)}.backdrop-blur{--tw-backdrop-blur:blur(8px);-webkit-backdrop-filter:var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,);backdrop-filter:var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,)}.backdrop-blur-2xl{--tw-backdrop-blur:blur(var(--blur-2xl));-webkit-backdrop-filter:var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,);backdrop-filter:var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,)}.backdrop-blur-\[2px\]{--tw-backdrop-blur:blur(2px);-webkit-backdrop-filter:var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,);backdrop-filter:var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,)}.transition{transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to,opacity,box-shadow,transform,translate,scale,rotate,filter,-webkit-backdrop-filter,backdrop-filter,display,content-visibility,overlay,pointer-events;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-all{transition-property:all;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-colors{transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.duration-300{--tw-duration:.3s;transition-duration:.3s}.will-change-transform{will-change:transform}.outline-none{--tw-outline-style:none;outline-style:none}.select-all{-webkit-user-select:all;user-select:all}.select-none{-webkit-user-select:none;user-select:none}@media (hover:hover){.group-hover\:opacity-100:is(:where(.group):hover *){opacity:1}}.placeholder\:text-muted::placeholder{color:var(--color-muted)}.odd\:bg-surface:nth-child(odd){background-color:var(--color-surface)}.focus-within\:border-fg\/20:focus-within{border-color:var(--color-fg)}@supports (color:color-mix(in lab, red, red)){.focus-within\:border-fg\/20:focus-within{border-color:color-mix(in oklab, var(--color-fg) 20%, transparent)}}.focus-within\:ring-2:focus-within{--tw-ring-shadow:var(--tw-ring-inset,) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.focus-within\:ring-accent\/40:focus-within{--tw-ring-color:var(--color-accent)}@supports (color:color-mix(in lab, red, red)){.focus-within\:ring-accent\/40:focus-within{--tw-ring-color:color-mix(in oklab, var(--color-accent) 40%, transparent)}}@media (hover:hover){.hover\:scale-\[1\.04\]:hover{scale:1.04}.hover\:bg-accent\/15:hover{background-color:var(--color-accent)}@supports (color:color-mix(in lab, red, red)){.hover\:bg-accent\/15:hover{background-color:color-mix(in oklab, var(--color-accent) 15%, transparent)}}.hover\:bg-border\/60:hover{background-color:var(--color-border)}@supports (color:color-mix(in lab, red, red)){.hover\:bg-border\/60:hover{background-color:color-mix(in oklab, var(--color-border) 60%, transparent)}}.hover\:bg-rose-500\/10:hover{background-color:#ff23571a}@supports (color:color-mix(in lab, red, red)){.hover\:bg-rose-500\/10:hover{background-color:color-mix(in oklab, var(--color-rose-500) 10%, transparent)}}.hover\:bg-rose-600\/90:hover{background-color:#e70044e6}@supports (color:color-mix(in lab, red, red)){.hover\:bg-rose-600\/90:hover{background-color:color-mix(in oklab, var(--color-rose-600) 90%, transparent)}}.hover\:bg-surface:hover{background-color:var(--color-surface)}.hover\:bg-surface-2:hover,.hover\:bg-surface-2\/60:hover{background-color:var(--color-surface-2)}@supports (color:color-mix(in lab, red, red)){.hover\:bg-surface-2\/60:hover{background-color:color-mix(in oklab, var(--color-surface-2) 60%, transparent)}}.hover\:bg-surface-2\/70:hover{background-color:var(--color-surface-2)}@supports (color:color-mix(in lab, red, red)){.hover\:bg-surface-2\/70:hover{background-color:color-mix(in oklab, var(--color-surface-2) 70%, transparent)}}.hover\:text-accent:hover{color:var(--color-accent)}.hover\:text-fg:hover{color:var(--color-fg)}.hover\:text-rose-500:hover{color:var(--color-rose-500)}.hover\:underline:hover{text-decoration-line:underline}.hover\:opacity-90:hover{opacity:.9}.hover\:opacity-100:hover{opacity:1}.hover\:ring-2:hover{--tw-ring-shadow:var(--tw-ring-inset,) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.hover\:ring-accent:hover,.hover\:ring-accent\/60:hover{--tw-ring-color:var(--color-accent)}@supports (color:color-mix(in lab, red, red)){.hover\:ring-accent\/60:hover{--tw-ring-color:color-mix(in oklab, var(--color-accent) 60%, transparent)}}}.focus\:border-accent:focus{border-color:var(--color-accent)}.focus\:bg-surface-2:focus{background-color:var(--color-surface-2)}.focus\:opacity-100:focus{opacity:1}.focus\:ring-2:focus{--tw-ring-shadow:var(--tw-ring-inset,) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.focus\:ring-accent\/40:focus{--tw-ring-color:var(--color-accent)}@supports (color:color-mix(in lab, red, red)){.focus\:ring-accent\/40:focus{--tw-ring-color:color-mix(in oklab, var(--color-accent) 40%, transparent)}}.focus\:outline-none:focus{--tw-outline-style:none;outline-style:none}.active\:scale-95:active{--tw-scale-x:95%;--tw-scale-y:95%;--tw-scale-z:95%;scale:var(--tw-scale-x) var(--tw-scale-y)}.active\:scale-\[0\.98\]:active{scale:.98}.active\:scale-\[0\.99\]:active{scale:.99}.active\:bg-surface-2:active,.active\:bg-surface-2\/70:active{background-color:var(--color-surface-2)}@supports (color:color-mix(in lab, red, red)){.active\:bg-surface-2\/70:active{background-color:color-mix(in oklab, var(--color-surface-2) 70%, transparent)}}.disabled\:opacity-40:disabled{opacity:.4}.disabled\:opacity-50:disabled{opacity:.5}.disabled\:opacity-60:disabled{opacity:.6}.disabled\:opacity-70:disabled{opacity:.7}@media (width>=40rem){.sm\:hidden{display:none}.sm\:max-w-lg{max-width:var(--container-lg)}.sm\:grid-cols-5{grid-template-columns:repeat(5,minmax(0,1fr))}.sm\:items-center{align-items:center}.sm\:justify-center{justify-content:center}.sm\:rounded-3xl{border-radius:var(--radius-3xl)}.sm\:rounded-\[28px\]{border-radius:28px}.sm\:border-x{border-inline-style:var(--tw-border-style);border-inline-width:1px}.sm\:border-border{border-color:var(--color-border)}}@container (width>=42rem){.\@2xl\:grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}}.dark\:border:where([data-theme=dark],[data-theme=dark] *){border-style:var(--tw-border-style);border-width:1px}.dark\:border-border:where([data-theme=dark],[data-theme=dark] *){border-color:var(--color-border)}.dark\:bg-accent\/\[0\.10\]:where([data-theme=dark],[data-theme=dark] *){background-color:var(--color-accent)}@supports (color:color-mix(in lab, red, red)){.dark\:bg-accent\/\[0\.10\]:where([data-theme=dark],[data-theme=dark] *){background-color:color-mix(in oklab, var(--color-accent) 10%, transparent)}}.dark\:bg-amber-400\/\[0\.08\]:where([data-theme=dark],[data-theme=dark] *){background-color:#fcbb0014}@supports (color:color-mix(in lab, red, red)){.dark\:bg-amber-400\/\[0\.08\]:where([data-theme=dark],[data-theme=dark] *){background-color:color-mix(in oklab, var(--color-amber-400) 8%, transparent)}}.dark\:bg-\[radial-gradient\(ellipse_at_top\,rgba\(23\,147\,255\,0\.2\)\,transparent_65\%\)\]:where([data-theme=dark],[data-theme=dark] *){background-image:radial-gradient(at top,#1793ff33,#0000 65%)}.dark\:text-amber-200:where([data-theme=dark],[data-theme=dark] *){color:var(--color-amber-200)}.dark\:text-amber-300:where([data-theme=dark],[data-theme=dark] *){color:var(--color-amber-300)}.dark\:text-cyan-300:where([data-theme=dark],[data-theme=dark] *){color:var(--color-cyan-300)}.dark\:text-emerald-300:where([data-theme=dark],[data-theme=dark] *){color:var(--color-emerald-300)}.dark\:text-emerald-400:where([data-theme=dark],[data-theme=dark] *){color:var(--color-emerald-400)}.dark\:text-fuchsia-300:where([data-theme=dark],[data-theme=dark] *){color:var(--color-fuchsia-300)}.dark\:text-orange-300:where([data-theme=dark],[data-theme=dark] *){color:var(--color-orange-300)}.dark\:text-pink-300:where([data-theme=dark],[data-theme=dark] *){color:var(--color-pink-300)}.dark\:text-red-400:where([data-theme=dark],[data-theme=dark] *){color:var(--color-red-400)}.dark\:text-rose-300:where([data-theme=dark],[data-theme=dark] *){color:var(--color-rose-300)}.dark\:text-rose-400:where([data-theme=dark],[data-theme=dark] *){color:var(--color-rose-400)}.dark\:text-sky-300:where([data-theme=dark],[data-theme=dark] *){color:var(--color-sky-300)}.dark\:text-violet-300:where([data-theme=dark],[data-theme=dark] *){color:var(--color-violet-300)}.dark\:shadow-none:where([data-theme=dark],[data-theme=dark] *){--tw-shadow:0 0 #0000;box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}@media (width>=64rem){.wide\:invisible{visibility:hidden}}:where(html.desktop) .wide\:invisible{visibility:hidden}@media (width>=64rem){.wide\:inset-y-0{inset-block:0}}:where(html.desktop) .wide\:inset-y-0{inset-block:0}@media (width>=64rem){.wide\:mt-0{margin-top:0}}:where(html.desktop) .wide\:mt-0{margin-top:0}@media (width>=64rem){.wide\:mt-5{margin-top:calc(var(--spacing) * 5)}}:where(html.desktop) .wide\:mt-5{margin-top:calc(var(--spacing) * 5)}@media (width>=64rem){.wide\:block{display:block}}:where(html.desktop) .wide\:block{display:block}@media (width>=64rem){.wide\:flex{display:flex}}:where(html.desktop) .wide\:flex{display:flex}@media (width>=64rem){.wide\:grid{display:grid}}:where(html.desktop) .wide\:grid{display:grid}@media (width>=64rem){.wide\:hidden{display:none}}:where(html.desktop) .wide\:hidden{display:none}@media (width>=64rem){.wide\:h-auto{height:auto}}:where(html.desktop) .wide\:h-auto{height:auto}@media (width>=64rem){.wide\:h-full{height:100%}}:where(html.desktop) .wide\:h-full{height:100%}@media (width>=64rem){.wide\:max-w-\[600px\]{max-width:600px}}:where(html.desktop) .wide\:max-w-\[600px\]{max-width:600px}@media (width>=64rem){.wide\:max-w-\[900px\]{max-width:900px}}:where(html.desktop) .wide\:max-w-\[900px\]{max-width:900px}@media (width>=64rem){.wide\:max-w-\[980px\]{max-width:980px}}:where(html.desktop) .wide\:max-w-\[980px\]{max-width:980px}@media (width>=64rem){.wide\:max-w-md{max-width:var(--container-md)}}:where(html.desktop) .wide\:max-w-md{max-width:var(--container-md)}@media (width>=64rem){.wide\:max-w-none{max-width:none}}:where(html.desktop) .wide\:max-w-none{max-width:none}@media (width>=64rem){.wide\:grid-cols-1{grid-template-columns:repeat(1,minmax(0,1fr))}}:where(html.desktop) .wide\:grid-cols-1{grid-template-columns:repeat(1,minmax(0,1fr))}@media (width>=64rem){.wide\:grid-cols-4{grid-template-columns:repeat(4,minmax(0,1fr))}}:where(html.desktop) .wide\:grid-cols-4{grid-template-columns:repeat(4,minmax(0,1fr))}@media (width>=64rem){.wide\:grid-cols-\[1\.1fr_1fr\]{grid-template-columns:1.1fr 1fr}}:where(html.desktop) .wide\:grid-cols-\[1\.1fr_1fr\]{grid-template-columns:1.1fr 1fr}@media (width>=64rem){.wide\:flex-row{flex-direction:row}}:where(html.desktop) .wide\:flex-row{flex-direction:row}@media (width>=64rem){.wide\:items-center{align-items:center}}:where(html.desktop) .wide\:items-center{align-items:center}@media (width>=64rem){.wide\:items-start{align-items:flex-start}}:where(html.desktop) .wide\:items-start{align-items:flex-start}@media (width>=64rem){.wide\:gap-1\.5{gap:calc(var(--spacing) * 1.5)}}:where(html.desktop) .wide\:gap-1\.5{gap:calc(var(--spacing) * 1.5)}@media (width>=64rem){.wide\:gap-16{gap:calc(var(--spacing) * 16)}}:where(html.desktop) .wide\:gap-16{gap:calc(var(--spacing) * 16)}@media (width>=64rem){.wide\:border-0{border-style:var(--tw-border-style);border-width:0}}:where(html.desktop) .wide\:border-0{border-style:var(--tw-border-style);border-width:0}@media (width>=64rem){.wide\:border-x-0{border-inline-style:var(--tw-border-style);border-inline-width:0}}:where(html.desktop) .wide\:border-x-0{border-inline-style:var(--tw-border-style);border-inline-width:0}@media (width>=64rem){.wide\:bg-transparent{background-color:#0000}}:where(html.desktop) .wide\:bg-transparent{background-color:#0000}@media (width>=64rem){.wide\:bg-\[radial-gradient\(ellipse_at_left\,rgba\(0\,100\,212\,0\.12\)\,transparent_60\%\)\]{background-image:radial-gradient(at 0,#0064d41f,#0000 60%)}}:where(html.desktop) .wide\:bg-\[radial-gradient\(ellipse_at_left\,rgba\(0\,100\,212\,0\.12\)\,transparent_60\%\)\]{background-image:radial-gradient(at 0,#0064d41f,#0000 60%)}@media (width>=64rem){.wide\:p-7{padding:calc(var(--spacing) * 7)}}:where(html.desktop) .wide\:p-7{padding:calc(var(--spacing) * 7)}@media (width>=64rem){.wide\:px-0{padding-inline:0}}:where(html.desktop) .wide\:px-0{padding-inline:0}@media (width>=64rem){.wide\:px-12{padding-inline:calc(var(--spacing) * 12)}}:where(html.desktop) .wide\:px-12{padding-inline:calc(var(--spacing) * 12)}@media (width>=64rem){.wide\:py-1{padding-block:var(--spacing)}}:where(html.desktop) .wide\:py-1{padding-block:var(--spacing)}@media (width>=64rem){.wide\:pt-0{padding-top:0}}:where(html.desktop) .wide\:pt-0{padding-top:0}@media (width>=64rem){.wide\:pb-0{padding-bottom:0}}:where(html.desktop) .wide\:pb-0{padding-bottom:0}@media (width>=64rem){.wide\:text-left{text-align:left}}:where(html.desktop) .wide\:text-left{text-align:left}@media (width>=64rem){.wide\:text-\[13\.5px\]{font-size:13.5px}}:where(html.desktop) .wide\:text-\[13\.5px\]{font-size:13.5px}@media (width>=64rem){.wide\:text-\[15\.5px\]{font-size:15.5px}}:where(html.desktop) .wide\:text-\[15\.5px\]{font-size:15.5px}@media (width>=64rem){.wide\:text-\[34px\]{font-size:34px}}:where(html.desktop) .wide\:text-\[34px\]{font-size:34px}@media (width>=64rem){.wide\:dark\:bg-\[radial-gradient\(ellipse_at_left\,rgba\(23\,147\,255\,0\.16\)\,transparent_60\%\)\]:where([data-theme=dark],[data-theme=dark] *){background-image:radial-gradient(at 0,#1793ff29,#0000 60%)}}:where(html.desktop) .wide\:dark\:bg-\[radial-gradient\(ellipse_at_left\,rgba\(23\,147\,255\,0\.16\)\,transparent_60\%\)\]:where([data-theme=dark],[data-theme=dark] *){background-image:radial-gradient(at 0,#1793ff29,#0000 60%)}.\[\&\+\&\]\:mt-1\.5+.\[\&\+\&\]\:mt-1\.5{margin-top:calc(var(--spacing) * 1.5)}}@font-face{font-family:Figtree;font-style:normal;font-weight:300 900;font-display:swap;src:url(/fonts/figtree-latin.woff2)format("woff2");unicode-range:U+??,U+131,U+152-153,U+2BB-2BC,U+2C6,U+2DA,U+2DC,U+304,U+308,U+329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}@font-face{font-family:Figtree;font-style:normal;font-weight:300 900;font-display:swap;src:url(/fonts/figtree-latin-ext.woff2)format("woff2");unicode-range:U+100-2BA,U+2BD-2C5,U+2C7-2CC,U+2CE-2D7,U+2DD-2FF,U+304,U+308,U+329,U+1D00-1DBF,U+1E00-1E9F,U+1EF2-1EFF,U+2020,U+20A0-20AB,U+20AD-20C0,U+2113,U+2C60-2C7F,U+A720-A7FF}:root{--om-bg:#fcfcfc;--om-surface:#fff;--om-surface-2:#f2f2f4;--om-border:#e7e7ea;--om-fg:#111112;--om-muted:#6b6b71;--om-accent:#0064d4;--om-accent-soft:#e5f0ff;--om-accent-soft-fg:#012f80;--om-bubble-user:#d8e9ff;--om-bubble-user-fg:#111112;--lightningcss-light:initial;--lightningcss-dark: ;color-scheme:light}html[data-theme=dark]{--om-bg:#181819;--om-surface:#202022;--om-surface-2:#2a2a2d;--om-border:#333337;--om-fg:#fff;--om-muted:#9d9da4;--om-accent:#1793ff;--om-accent-soft:#1a2b4a;--om-accent-soft-fg:#e5f0ff;--om-bubble-user:#1c3d66;--om-bubble-user-fg:#fff;--lightningcss-light: ;--lightningcss-dark:initial;color-scheme:dark}html,body,#root{height:100%}body{background:var(--om-bg);color:var(--om-fg);font-family:var(--font-sans);-webkit-font-smoothing:antialiased;-webkit-tap-highlight-color:transparent;overscroll-behavior-y:none;margin:0}.safe-top{padding-top:env(safe-area-inset-top)}.titlebar-room{display:none}html.desktop[data-platform=darwin] .titlebar-room{-webkit-app-region:drag;flex-shrink:0;height:28px;display:block}.safe-bottom{padding-bottom:env(safe-area-inset-bottom)}*{scrollbar-width:thin;scrollbar-color:var(--om-border) transparent}::-webkit-scrollbar{width:6px;height:6px}::-webkit-scrollbar-thumb{background:var(--om-border);border-radius:999px}::-webkit-scrollbar-track{background:0 0}@media (pointer:coarse),(width<=480px){*{scrollbar-width:none}::-webkit-scrollbar{display:none}}.no-scrollbar::-webkit-scrollbar{display:none}.no-scrollbar{scrollbar-width:none}.md>:first-child{margin-top:0}.md>:last-child{margin-bottom:0}.md p{margin:.35em 0}.md ul,.md ol{margin:.35em 0;padding-left:1.3em}.md ul{list-style:outside}.md ol{list-style:decimal}.md li{margin:.15em 0}.md h1,.md h2,.md h3,.md h4{margin:.7em 0 .3em;font-weight:650;line-height:1.3}.md h1{font-size:1.15em}.md h2{font-size:1.08em}.md h3,.md h4{font-size:1em}.md a{color:var(--om-accent);text-underline-offset:2px;word-break:break-all;text-decoration:underline}.bubble-user .md a{color:var(--om-accent)}.md code{background:#7f7fa029;border-radius:6px;padding:.1em .35em;font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;font-size:.86em}.md pre{color:#eaeaf5;background:#0f0f19e6;border-radius:12px;margin:.5em 0;padding:.7em .85em;font-size:.82em;line-height:1.45;overflow-x:auto}.md pre code{font-size:inherit;background:0 0;padding:0}.md .md-file{color:var(--om-accent);background:var(--om-accent);font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;font-size:.86em}@supports (color:color-mix(in lab, red, red)){.md .md-file{background:color-mix(in srgb, var(--om-accent) 12%, transparent)}}.md .md-file{text-underline-offset:2px;word-break:break-all;border-radius:6px;padding:.1em .4em;-webkit-text-decoration:underline dotted;text-decoration:underline dotted}.md blockquote{border-left:3px solid var(--om-border);color:var(--om-muted);margin:.5em 0;padding-left:.8em}.md table{border-collapse:collapse;max-width:100%;margin:.5em 0;font-size:.9em;display:block;overflow-x:auto}.md th,.md td{border:1px solid var(--om-border);text-align:left;padding:.3em .55em}.md hr{border:0;border-top:1px solid var(--om-border);margin:.7em 0}.md img{border-radius:10px;max-width:100%}@keyframes om-breathe{0%,to{transform:translateY(0)scale(1)}50%{transform:translateY(-1.5%)scale(1.025)}}@keyframes om-sway{0%,to{transform:rotate(-4deg)translateY(0)}25%{transform:rotate(0)translateY(-2%)}50%{transform:rotate(4deg)translateY(0)}75%{transform:rotate(0)translateY(-2%)}}@keyframes om-hop{0%,70%,to{transform:translateY(0)scale(1)}78%{transform:translateY(-9%)scale(1.04,.97)}86%{transform:translateY(0)scale(.98,1.03)}92%{transform:translateY(-3%)scale(1)}}@keyframes om-wiggle{0%,to{transform:rotate(0)}20%{transform:rotate(-10deg)scale(1.06)}45%{transform:rotate(9deg)scale(1.06)}70%{transform:rotate(-5deg)}}.avatar-idle{animation:4.5s ease-in-out infinite om-breathe}.avatar-working{animation:2.6s ease-in-out infinite om-sway}.avatar-waiting{animation:3.2s ease-in-out infinite om-hop}.avatar-wiggle{animation:.6s ease-in-out om-wiggle}@keyframes om-pop{0%{transform:scale(.6)}70%{transform:scale(1.06)}to{transform:scale(1)}}.avatar-pop{animation:.55s cubic-bezier(.34,1.56,.64,1) om-pop}@media (prefers-reduced-motion:reduce){.avatar-idle,.avatar-working,.avatar-waiting,.avatar-wiggle,.avatar-pop{animation:none}}@keyframes om-blink{50%{opacity:.25}}.typing-dot{animation:1.1s infinite om-blink}.typing-dot:nth-child(2){animation-delay:.18s}.typing-dot:nth-child(3){animation-delay:.36s}@keyframes om-rise{0%{opacity:0;transform:translateY(6px)}to{opacity:1;transform:none}}.rise{animation:.18s ease-out om-rise}@keyframes om-sheet{0%{transform:translateY(100%)}to{transform:none}}.sheet-in{animation:.22s cubic-bezier(.2,.8,.2,1) om-sheet}@keyframes om-drawer-in{0%{transform:translate(-100%)}to{transform:none}}.drawer-in{animation:.2s ease-out om-drawer-in}@property --tw-border-spacing-x{syntax:"";inherits:false;initial-value:0}@property --tw-border-spacing-y{syntax:"";inherits:false;initial-value:0}@property --tw-translate-x{syntax:"*";inherits:false;initial-value:0}@property --tw-translate-y{syntax:"*";inherits:false;initial-value:0}@property --tw-translate-z{syntax:"*";inherits:false;initial-value:0}@property --tw-space-y-reverse{syntax:"*";inherits:false;initial-value:0}@property --tw-divide-y-reverse{syntax:"*";inherits:false;initial-value:0}@property --tw-border-style{syntax:"*";inherits:false;initial-value:solid}@property --tw-gradient-position{syntax:"*";inherits:false}@property --tw-gradient-from{syntax:"";inherits:false;initial-value:#0000}@property --tw-gradient-via{syntax:"";inherits:false;initial-value:#0000}@property --tw-gradient-to{syntax:"";inherits:false;initial-value:#0000}@property --tw-gradient-stops{syntax:"*";inherits:false}@property --tw-gradient-via-stops{syntax:"*";inherits:false}@property --tw-gradient-from-position{syntax:"";inherits:false;initial-value:0%}@property --tw-gradient-via-position{syntax:"";inherits:false;initial-value:50%}@property --tw-gradient-to-position{syntax:"";inherits:false;initial-value:100%}@property --tw-leading{syntax:"*";inherits:false}@property --tw-font-weight{syntax:"*";inherits:false}@property --tw-tracking{syntax:"*";inherits:false}@property --tw-ordinal{syntax:"*";inherits:false}@property --tw-slashed-zero{syntax:"*";inherits:false}@property --tw-numeric-figure{syntax:"*";inherits:false}@property --tw-numeric-spacing{syntax:"*";inherits:false}@property --tw-numeric-fraction{syntax:"*";inherits:false}@property --tw-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-shadow-color{syntax:"*";inherits:false}@property --tw-shadow-alpha{syntax:"";inherits:false;initial-value:100%}@property --tw-inset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-shadow-color{syntax:"*";inherits:false}@property --tw-inset-shadow-alpha{syntax:"";inherits:false;initial-value:100%}@property --tw-ring-color{syntax:"*";inherits:false}@property --tw-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-ring-color{syntax:"*";inherits:false}@property --tw-inset-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-ring-inset{syntax:"*";inherits:false}@property --tw-ring-offset-width{syntax:"";inherits:false;initial-value:0}@property --tw-ring-offset-color{syntax:"*";inherits:false;initial-value:#fff}@property --tw-ring-offset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-blur{syntax:"*";inherits:false}@property --tw-brightness{syntax:"*";inherits:false}@property --tw-contrast{syntax:"*";inherits:false}@property --tw-grayscale{syntax:"*";inherits:false}@property --tw-hue-rotate{syntax:"*";inherits:false}@property --tw-invert{syntax:"*";inherits:false}@property --tw-opacity{syntax:"*";inherits:false}@property --tw-saturate{syntax:"*";inherits:false}@property --tw-sepia{syntax:"*";inherits:false}@property --tw-drop-shadow{syntax:"*";inherits:false}@property --tw-drop-shadow-color{syntax:"*";inherits:false}@property --tw-drop-shadow-alpha{syntax:"";inherits:false;initial-value:100%}@property --tw-drop-shadow-size{syntax:"*";inherits:false}@property --tw-backdrop-blur{syntax:"*";inherits:false}@property --tw-backdrop-brightness{syntax:"*";inherits:false}@property --tw-backdrop-contrast{syntax:"*";inherits:false}@property --tw-backdrop-grayscale{syntax:"*";inherits:false}@property --tw-backdrop-hue-rotate{syntax:"*";inherits:false}@property --tw-backdrop-invert{syntax:"*";inherits:false}@property --tw-backdrop-opacity{syntax:"*";inherits:false}@property --tw-backdrop-saturate{syntax:"*";inherits:false}@property --tw-backdrop-sepia{syntax:"*";inherits:false}@property --tw-duration{syntax:"*";inherits:false}@property --tw-scale-x{syntax:"*";inherits:false;initial-value:1}@property --tw-scale-y{syntax:"*";inherits:false;initial-value:1}@property --tw-scale-z{syntax:"*";inherits:false;initial-value:1}@keyframes spin{to{transform:rotate(360deg)}}@keyframes pulse{50%{opacity:.5}} diff --git a/nanomuse/server/static/assets/plug-Bj_5EEV3.js b/nanomuse/server/static/assets/plug-Cn-mgW7a.js similarity index 77% rename from nanomuse/server/static/assets/plug-Bj_5EEV3.js rename to nanomuse/server/static/assets/plug-Cn-mgW7a.js index f2784dada..5e9455518 100644 --- a/nanomuse/server/static/assets/plug-Bj_5EEV3.js +++ b/nanomuse/server/static/assets/plug-Cn-mgW7a.js @@ -1 +1 @@ -import{J as e}from"./MuseHeader-Pw-NI98v.js";var t=e(`plug`,[[`path`,{d:`M12 22v-5`,key:`1ega77`}],[`path`,{d:`M15 8V2`,key:`18g5xt`}],[`path`,{d:`M17 8a1 1 0 0 1 1 1v4a4 4 0 0 1-4 4h-4a4 4 0 0 1-4-4V9a1 1 0 0 1 1-1z`,key:`1xoxul`}],[`path`,{d:`M9 8V2`,key:`14iosj`}]]);export{t}; \ No newline at end of file +import{J as e}from"./MuseHeader-BDWXHKHT.js";var t=e(`plug`,[[`path`,{d:`M12 22v-5`,key:`1ega77`}],[`path`,{d:`M15 8V2`,key:`18g5xt`}],[`path`,{d:`M17 8a1 1 0 0 1 1 1v4a4 4 0 0 1-4 4h-4a4 4 0 0 1-4-4V9a1 1 0 0 1 1-1z`,key:`1xoxul`}],[`path`,{d:`M9 8V2`,key:`14iosj`}]]);export{t}; \ No newline at end of file diff --git a/nanomuse/server/static/assets/refresh-cw-BKgIzslL.js b/nanomuse/server/static/assets/refresh-cw-qw351CFk.js similarity index 79% rename from nanomuse/server/static/assets/refresh-cw-BKgIzslL.js rename to nanomuse/server/static/assets/refresh-cw-qw351CFk.js index 7c1ec9d26..a7b25104b 100644 --- a/nanomuse/server/static/assets/refresh-cw-BKgIzslL.js +++ b/nanomuse/server/static/assets/refresh-cw-qw351CFk.js @@ -1 +1 @@ -import{J as e}from"./MuseHeader-Pw-NI98v.js";var t=e(`refresh-cw`,[[`path`,{d:`M3 12a9 9 0 0 1 9-9 9.75 9.75 0 0 1 6.74 2.74L21 8`,key:`v9h5vc`}],[`path`,{d:`M21 3v5h-5`,key:`1q7to0`}],[`path`,{d:`M21 12a9 9 0 0 1-9 9 9.75 9.75 0 0 1-6.74-2.74L3 16`,key:`3uifl3`}],[`path`,{d:`M8 16H3v5`,key:`1cv678`}]]);export{t}; \ No newline at end of file +import{J as e}from"./MuseHeader-BDWXHKHT.js";var t=e(`refresh-cw`,[[`path`,{d:`M3 12a9 9 0 0 1 9-9 9.75 9.75 0 0 1 6.74 2.74L21 8`,key:`v9h5vc`}],[`path`,{d:`M21 3v5h-5`,key:`1q7to0`}],[`path`,{d:`M21 12a9 9 0 0 1-9 9 9.75 9.75 0 0 1-6.74-2.74L3 16`,key:`3uifl3`}],[`path`,{d:`M8 16H3v5`,key:`1cv678`}]]);export{t}; \ No newline at end of file diff --git a/nanomuse/server/static/index.html b/nanomuse/server/static/index.html index b5389e5ca..e227138b8 100644 --- a/nanomuse/server/static/index.html +++ b/nanomuse/server/static/index.html @@ -25,13 +25,13 @@ nanoMuse - - - - - - - + + + + + + +
diff --git a/web/src/api.ts b/web/src/api.ts index 7cc4bc250..236641d20 100644 --- a/web/src/api.ts +++ b/web/src/api.ts @@ -13,6 +13,7 @@ import type { CodingRun, CodingSession, ConnectionsData, + CustomEndpoint, Contact, FeedItem, FeedPostsData, @@ -345,8 +346,9 @@ export const api = { setLLM: (body: Record) => request("/api/connections/llm", { method: "PUT", body: JSON.stringify(body) }), testLLM: () => request("/api/connections/llm/test", { method: "POST" }), - /** the models an endpoint offers: its own /models when it answers, else the preset's catalogue */ - llmModels: (body: { preset?: string; base_url?: string; api_key?: string }) => + /** the models an endpoint offers: its own /models when it answers, else the preset's catalogue + * (or, for a custom endpoint of the list named by `endpoint`, the models saved with it) */ + llmModels: (body: { preset?: string; base_url?: string; api_key?: string; endpoint?: string }) => request<{ models: string[]; image_models?: string[]; @@ -368,6 +370,21 @@ export const api = { "/api/llm/models", json(body), ), + /** a custom OpenAI-compatible endpoint joins the runtime's list (#294); `models` typed when it does not list them */ + addEndpoint: (body: { label?: string; base_url: string; api_key?: string; models?: string }) => + request("/api/connections/endpoints", json(body)), + /** a new name, address, key or typed models; the slots that use the endpoint follow */ + updateEndpoint: (id: string, body: { label?: string; base_url?: string; api_key?: string; models?: string }) => + request(`/api/connections/endpoints/${encodeURIComponent(id)}`, { method: "PUT", body: JSON.stringify(body) }), + /** 409 while the chat model answers through it */ + removeEndpoint: (id: string) => + request<{ ok: boolean }>(`/api/connections/endpoints/${encodeURIComponent(id)}`, { method: "DELETE" }), + /** asks the endpoint for its models again; `kept` when it did not answer and the saved list stands */ + refreshEndpointModels: (id: string) => + request( + `/api/connections/endpoints/${encodeURIComponent(id)}/models`, + json({}), + ), setEmbeddings: (body: Record) => request("/api/connections/embeddings", { method: "PUT", body: JSON.stringify(body) }), testEmbeddings: () => request("/api/connections/embeddings/test", { method: "POST" }), diff --git a/web/src/i18n/zh-CN.ts b/web/src/i18n/zh-CN.ts index 83efc3618..4b5f0a4be 100644 --- a/web/src/i18n/zh-CN.ts +++ b/web/src/i18n/zh-CN.ts @@ -1765,6 +1765,51 @@ const zhCN: Record = { "Add a provider of your own first; with nanoMuse Cloud off, nothing else could answer.": "先添加一个自己的服务商;关掉 nanoMuse Cloud 后没有别的模型能回答。", "Use your own API key instead": "改用自己的 API key", "You can sign in later under Connections, for sync and your devices.": "之后可以在「连接」里登录,用于同步和你的设备。", + + // ── several OpenAI-compatible endpoints of one's own (#294) ──────────────────── + "Add an endpoint": "添加接口", + "Add endpoint": "添加接口", + "An endpoint joins your list with its own key and stays there; add as many as you use. Pick one as the chat model, or use its models for the hands, pictures and clips.": + "接口带着自己的密钥加入列表并一直保留;用几个就加几个。可以选一个作为对话模型,也可以把它的模型用于双手、图片和短片。", + "Name (optional)": "名字(可选)", + "How the endpoint reads in the lists; its host when left empty.": "接口在列表里显示的名字;留空则显示主机名。", + "for example: my gateway": "例如:我的网关", + "Stored encrypted in the vault under this endpoint's own name.": "加密保存在保险库里,以这个接口自己的名字命名。", + "Models (optional)": "模型(可选)", + "Leave empty when the endpoint lists its models at /models. Otherwise type their ids, separated by commas.": + "接口能在 /models 列出模型时留空;否则输入模型 id,用逗号分隔。", + "Endpoint added": "已添加接口", + "Endpoint renamed": "已给接口改名", + "Endpoint removed": "已移除接口", + "Key saved": "密钥已保存", + "Models saved": "模型已保存", + Models: "模型", + Rename: "改名", + "Change key": "换密钥", + "Edit models": "编辑模型", + "Ask for its models": "重新获取模型", + "{n} models": "{n} 个模型", + "{n} models saved with this endpoint": "这个接口保存了 {n} 个模型", + "Used by {slots}": "用于{slots}", + "the hands": "双手", + pictures: "图片", + clips: "短片", + "The ids of the models this endpoint serves, separated by commas; what it lists at /models is added after them.": + "这个接口提供的模型 id,用逗号分隔;它在 /models 列出的模型会接在后面。", + "The endpoint did not list its models; the saved list stands.": "接口没有列出模型;沿用已保存的列表。", + "The chat model answers through this endpoint; pick another chat model first.": "对话模型正通过这个接口回答;请先换一个对话模型。", + "Its key goes with it, and the hands, pictures or clips set on it go back to automatic.": "它的密钥会一起删除;设在它上面的双手、图片或短片会回到自动。", + "Uses the key saved with this endpoint.": "使用这个接口保存的密钥。", + "Your endpoints": "你的接口", + "The model that looks at screens when the hands run: a small, fast one that takes pictures. Pick one of this provider's, or one from another endpoint of your list, which then lends its address and key.": + "双手运行时看屏幕的模型:一个小而快、能看图的模型。可以选这个服务商的,也可以选你列表里另一个接口的,那个接口的地址和密钥会一并使用。", + // the runtime's sentences about the endpoint list + "the endpoint did not list its models (GET /models); type the ids of the models it serves, separated by commas": + "接口没有列出模型(GET /models);请输入它提供的模型 id,用逗号分隔", + "the chat model answers through this endpoint; pick another chat model first": "对话模型正通过这个接口回答;请先换一个对话模型", + "the address must start with http:// or https://": "地址必须以 http:// 或 https:// 开头", + "that is nanoMuse Cloud; it is the account, not an endpoint": "那是 nanoMuse Cloud;它是账号,不是接口", + "a key has no spaces in it": "密钥里不会有空格", }; export default zhCN; diff --git a/web/src/models.test.ts b/web/src/models.test.ts index 6708b708a..8659d45db 100644 --- a/web/src/models.test.ts +++ b/web/src/models.test.ts @@ -1,6 +1,6 @@ import { describe, expect, it } from "vitest"; -import { CLOUD_ID, currentChoice, entryFor, handsValue, mediaChoices, providerLabel, slotValue } from "./models"; -import type { MediaSlotData } from "./types"; +import { CLOUD_ID, currentChoice, endpointChoice, endpointGroups, endpointLabel, endpointOf, entryFor, handsValue, mediaChoices, providerLabel, slotValue } from "./models"; +import type { CustomEndpoint, MediaSlotData } from "./types"; const BAILIAN = "https://dashscope.aliyuncs.com/compatible-mode/v1"; @@ -93,3 +93,65 @@ describe("the model slots (the Models contract)", () => { expect(currentChoice(slot({ configured: true, provider: "openai", base_url: "https://images.example.com/v1" }), "")).toBe("custom"); }); }); + +describe("several endpoints of one's own (#294)", () => { + const gateway: CustomEndpoint = { + id: "ep-1a2b3c4d", + label: "my gateway", + base_url: "https://gateway.example/v1", + key_source: "vault", + models: ["ui-tars", "deepseek-chat", "qwen3-vl"], + slots: ["chat"], + }; + const local: CustomEndpoint = { id: "ep-9f9f9f9f", label: "", base_url: "http://127.0.0.1:8000/v1", key_source: "none", models: ["llava"], slots: [] }; + const endpoints = [gateway, local]; + + it("names a picker value after the endpoint and reads it back", () => { + expect(endpointChoice("ep-1a2b3c4d")).toBe("endpoint:ep-1a2b3c4d"); + expect(endpointOf("endpoint:ep-1a2b3c4d")).toBe("ep-1a2b3c4d"); + expect(endpointOf("endpoint:")).toBeNull(); + expect(endpointOf("bailian")).toBeNull(); + }); + + it("reads an endpoint by its name, else by its host with the port", () => { + expect(endpointLabel(gateway)).toBe("my gateway"); + expect(endpointLabel(local)).toBe("127.0.0.1:8000"); + expect(endpointLabel({ label: " ", base_url: "not a url" })).toBe("not a url"); + }); + + it("offers the endpoints to the media pickers between the chat provider and the catalogue", () => { + const chat = { provider: "openai", base_url: BAILIAN, cloud: false }; + const image = mediaChoices("image", { signedIn: false, chat, region: "cn", locale: "en", endpoints }); + expect(image.slice(0, 3).map((c) => [c.value, c.label, c.group, c.needsKey])).toEqual([ + ["bailian", "Alibaba Cloud Bailian", "chat", false], + ["endpoint:ep-1a2b3c4d", "my gateway", "endpoints", false], + ["endpoint:ep-9f9f9f9f", "127.0.0.1:8000", "endpoints", false], + ]); + expect(image[image.length - 1].value).toBe("custom"); + // a slot standing on one reads back as that endpoint, whatever its host + expect(currentChoice(slot({ configured: true, provider: "openai", base_url: gateway.base_url, endpoint: gateway.id }), "")).toBe("endpoint:ep-1a2b3c4d"); + expect(slotValue(slot({ effective_provider: "custom", effective_model: "flux-2", base_url: gateway.base_url, endpoint: gateway.id }), "en", undefined, endpoints)).toBe( + "my gateway · flux-2", + ); + // without the list (an older runtime) the host stands, as before + expect(slotValue(slot({ effective_provider: "custom", effective_model: "flux-2", base_url: gateway.base_url, endpoint: gateway.id }), "en")).toBe("gateway.example · flux-2"); + }); + + it("gives the hands picker one group per other endpoint, less the models known not to see", () => { + const groups = endpointGroups(endpoints, "ep-9f9f9f9f"); + expect(groups.map((g) => [g.key, g.label, g.rows.map((r) => r.id)])).toEqual([["endpoint:ep-1a2b3c4d", "my gateway", ["ui-tars", "qwen3-vl"]]]); + expect(endpointGroups([{ ...gateway, models: ["deepseek-chat"] }])).toEqual([]); + }); + + it("writes the hands row's value with the endpoint's name", () => { + const deepseek = { provider: "openai", base_url: "https://api.deepseek.com", cloud: false }; + const onGateway = { provider: "openai", provider_id: "", base_url: gateway.base_url, endpoint: gateway.id, effective_model: "ui-tars", effective_source: "gui" as const }; + expect(handsValue(onGateway, deepseek, "en", undefined, endpoints)).toBe("my gateway · ui-tars"); + expect(handsValue(onGateway, deepseek, "en")).toBe("gateway.example · ui-tars"); + // riding on a chat model that answers through an endpoint + const chatOnLocal = { provider: "openai", base_url: local.base_url, cloud: false, endpoint: local.id }; + expect(handsValue({ provider: "openai", provider_id: "", base_url: "", effective_model: "llava", effective_source: "chat" }, chatOnLocal, "en", undefined, endpoints)).toBe( + "127.0.0.1:8000 · llava", + ); + }); +}); diff --git a/web/src/models.ts b/web/src/models.ts index 18dff6c24..47cbd2352 100644 --- a/web/src/models.ts +++ b/web/src/models.ts @@ -5,8 +5,10 @@ * capability (its key serves), then every catalogue provider that has it (a key to add). * Pure functions; `models.test.ts` checks them. */ +import type { ModelGroup } from "./model-list"; import { CATALOGUE, providerName, providersFor, type Capability, type Region } from "./providers"; -import type { CatalogueProvider, MediaSlotData } from "./types"; +import { modelSees } from "./region"; +import type { CatalogueProvider, CustomEndpoint, MediaSlotData } from "./types"; /** what the account's model is called when it stands in a provider list (the runtime's id) */ export const CLOUD_ID = "nanomuse_cloud"; @@ -14,6 +16,8 @@ export const CLOUD_ID = "nanomuse_cloud"; export const CLOUD_KEY_REF = "{{vault:NANOMUSE_CLOUD_KEY}}"; /** the picker's entry for a host the catalogue does not list */ export const CUSTOM_ID = "custom"; +/** a picker value or provider tile that names a custom endpoint of the runtime's list: `endpoint:` (#294) */ +export const ENDPOINT_PREFIX = "endpoint:"; /** the protocols a slot's `provider` may be instead of a catalogue id */ const PROTOCOLS = ["openai", "openai_responses"]; @@ -25,6 +29,46 @@ function hostOf(url: string): string { } } +/** the picker value that stands for an endpoint of the list */ +export function endpointChoice(id: string): string { + return ENDPOINT_PREFIX + id; +} + +/** the endpoint id a picker value names; null for anything else */ +export function endpointOf(value: string): string | null { + return value.startsWith(ENDPOINT_PREFIX) && value.length > ENDPOINT_PREFIX.length ? value.slice(ENDPOINT_PREFIX.length) : null; +} + +/** what an endpoint is called in a row or a tile: its name, else its host (with the port when it has one) */ +export function endpointLabel(e: Pick): string { + if (e.label.trim()) return e.label.trim(); + try { + return new URL(e.base_url).host; + } catch { + return e.base_url; + } +} + +function endpointNamed(id: string | undefined, endpoints: readonly CustomEndpoint[]): CustomEndpoint | null { + return id ? (endpoints.find((e) => e.id === id) ?? null) : null; +} + +/** + * One picker group per endpoint of the list for the hands model: the endpoint's name and + * the models it serves, less those known not to see pictures. `except` leaves out the + * endpoint whose models the picker lists already (the chat model's own). + */ +export function endpointGroups(endpoints: readonly CustomEndpoint[], except = ""): ModelGroup[] { + return endpoints + .filter((e) => e.id !== except && e.models.length) + .map((e) => ({ + key: endpointChoice(e.id), + label: endpointLabel(e), + rows: e.models.filter((m) => modelSees(m) !== false).map((id) => ({ id, name: id })), + })) + .filter((g) => g.rows.length); +} + /** * The catalogue entry a slot stands on: the id `provider` names, else the entry whose host * `baseUrl` is (a regional subdomain counts); null for a protocol with an unlisted host. @@ -55,10 +99,16 @@ export function providerLabel(id: string, locale: string, baseUrl = "", list: Ca return hostOf(baseUrl) || id; } -/** A row's value, ` · `; "" when nothing draws. */ -export function slotValue(slot: Pick, locale: string, list: CatalogueProvider[] = CATALOGUE): string { +/** A row's value, ` · `; "" when nothing draws. A slot on an endpoint of the list reads its name. */ +export function slotValue( + slot: Pick, + locale: string, + list: CatalogueProvider[] = CATALOGUE, + endpoints: readonly CustomEndpoint[] = [], +): string { if (!slot.effective_provider) return ""; - const name = providerLabel(slot.effective_provider, locale, slot.base_url, list); + const own = endpointNamed(slot.endpoint, endpoints); + const name = own ? endpointLabel(own) : providerLabel(slot.effective_provider, locale, slot.base_url, list); return slot.effective_model ? `${name} · ${slot.effective_model}` : name; } @@ -69,18 +119,20 @@ export interface HandsSlot { base_url: string; effective_model?: string; effective_source?: "gui" | "chat" | "cloud"; + endpoint?: string; } /** * The hands row's value, ` · `, from the effective fields: nanoMuse Cloud * when the relay's hands model serves, the hands' own host when one is set, else the chat - * model's provider. "" while the runtime does not say. + * model's provider. An endpoint of the list reads its name. "" while the runtime does not say. */ export function handsValue( gui: HandsSlot, - llm: { provider: string; base_url: string; cloud?: boolean }, + llm: { provider: string; base_url: string; cloud?: boolean; endpoint?: string }, locale: string, list: CatalogueProvider[] = CATALOGUE, + endpoints: readonly CustomEndpoint[] = [], ): string { const model = gui.effective_model ?? ""; if (!model) return ""; @@ -88,18 +140,22 @@ export function handsValue( const labelOf = (provider: string, baseUrl: string) => providerLabel(entryFor(provider, baseUrl, list)?.id ?? (PROTOCOLS.includes(provider) ? CUSTOM_ID : provider), locale, baseUrl, list); let name: string; + const ownHands = endpointNamed(gui.endpoint, endpoints); + const ownChat = endpointNamed(llm.endpoint, endpoints); if (gui.effective_source === "cloud") name = "nanoMuse Cloud"; + else if (gui.effective_source === "gui" && ownHands) name = endpointLabel(ownHands); else if (gui.effective_source === "gui" && (gui.provider_id || gui.base_url || !PROTOCOLS.includes(gui.provider || "openai"))) name = gui.provider_id ? providerLabel(gui.provider_id, locale, gui.base_url, list) : labelOf(gui.provider, gui.base_url); - else name = llm.cloud ? "nanoMuse Cloud" : labelOf(llm.provider, llm.base_url); + else if (llm.cloud) name = "nanoMuse Cloud"; + else name = ownChat ? endpointLabel(ownChat) : labelOf(llm.provider, llm.base_url); return `${name} · ${model}`; } export interface MediaChoice { - /** `nanomuse_cloud`, a catalogue id, or `custom` */ + /** `nanomuse_cloud`, a catalogue id, `endpoint:` for an endpoint of the list, or `custom` */ value: string; label: string; - group: "cloud" | "chat" | "add"; + group: "cloud" | "chat" | "endpoints" | "add"; /** a key must be typed (the chat provider's key serves its own slot; the account needs none) */ needsKey: boolean; entry: CatalogueProvider | null; @@ -107,9 +163,10 @@ export interface MediaChoice { /** * What the picker of one slot offers, in order: nanoMuse Cloud when signed in; the chat - * model's provider when it is an own provider with the capability; then every catalogue - * provider with the capability for the region (the chat provider not twice), and a host of - * one's own last. A provider without the capability is not offered at all. + * model's provider when it is an own provider with the capability; the endpoints of the + * list (their own keys serve); then every catalogue provider with the capability for the + * region (the chat provider not twice), and a host of one's own last. A provider without + * the capability is not offered at all. */ export function mediaChoices( cap: Capability, @@ -120,6 +177,8 @@ export function mediaChoices( region: Region; locale: string; list?: CatalogueProvider[]; + /** the custom endpoints of the runtime's list (#294) */ + endpoints?: readonly CustomEndpoint[]; }, ): MediaChoice[] { const list = opts.list ?? CATALOGUE; @@ -129,6 +188,9 @@ export function mediaChoices( if (chat && chat.capabilities.includes(cap)) { out.push({ value: chat.id, label: providerName(chat, opts.locale), group: "chat", needsKey: false, entry: chat }); } + for (const e of opts.endpoints ?? []) { + out.push({ value: endpointChoice(e.id), label: endpointLabel(e), group: "endpoints", needsKey: false, entry: null }); + } for (const p of providersFor(opts.region, cap, list)) { if (p.id === chat?.id) continue; out.push({ value: p.id, label: providerName(p, opts.locale), group: "add", needsKey: true, entry: p }); @@ -139,10 +201,12 @@ export function mediaChoices( /** * The picker's value for a slot as the runtime reports it: "" for nothing chosen, the - * relay when the slot names its URL, the catalogue id, else `custom`. + * relay when the slot names its URL, an endpoint of the list by `endpoint:`, the + * catalogue id, else `custom`. */ export function currentChoice(slot: MediaSlotData, cloudBaseUrl: string): string { if (!slot.configured) return ""; if (cloudBaseUrl && slot.base_url && hostOf(slot.base_url) === hostOf(cloudBaseUrl)) return CLOUD_ID; + if (slot.endpoint) return endpointChoice(slot.endpoint); return slot.provider_id || CUSTOM_ID; } diff --git a/web/src/screens/ConnectionsScreen.tsx b/web/src/screens/ConnectionsScreen.tsx index a97869e88..c83465fd0 100644 --- a/web/src/screens/ConnectionsScreen.tsx +++ b/web/src/screens/ConnectionsScreen.tsx @@ -43,14 +43,29 @@ import { ModelPicker } from "../components/ModelPicker"; import { getLocale, useT } from "../i18n"; import type { ModelGroup } from "../model-list"; import { useStore } from "../store"; -import { CLOUD_ID, CLOUD_KEY_REF, CUSTOM_ID, currentChoice, handsValue, mediaChoices, slotValue, type MediaChoice } from "../models"; +import { + CLOUD_ID, + CLOUD_KEY_REF, + CUSTOM_ID, + currentChoice, + endpointChoice, + endpointGroups, + endpointLabel, + endpointOf, + handsValue, + mediaChoices, + slotValue, + type MediaChoice, +} from "../models"; import { CATALOGUE, catalogueIdFor, coversLine, editionFor, invalidateProviders, presetFor, providerName, regionOf, unavailableLine, type Capability } from "../providers"; import { modelSees, orderPresets } from "../region"; -import type { Contact, ConnectionsData, SharedConnector, TestResult } from "../types"; +import type { Contact, ConnectionsData, CustomEndpoint, ProviderPreset, SharedConnector, TestResult } from "../types"; import { cx, relativeTime } from "../util"; /** the runtime's preset for the account's model, present in `providers` while signed in */ const CLOUD_PRESET = "nanomuse_cloud"; +/** the provider tile that adds a custom endpoint to the runtime's list (#294); not a preset of the runtime's */ +const ADD_ENDPOINT = "add-endpoint"; /** * Connections: the model, your mailbox, your calendar, a browser, MCP servers — plugged in and out from the @@ -129,9 +144,15 @@ export function ModelCard({ const t = useT(); const [open, setOpen] = useState(!!compact); const presets = data.providers; + // the custom endpoints of the runtime's list (#294); a runtime without one offers the single + // "custom" slot as before + const endpoints = data.endpoints ?? []; + const hasList = data.endpoints !== undefined; + const currentEndpoint = endpoints.find((e) => e.id === data.llm.endpoint) ?? null; // a member of the relay may name any model of the provider's for its kind, not only the menu's const anyModel = !!state.hub?.account?.any_model; const currentPreset = + (currentEndpoint ? endpointChoice(currentEndpoint.id) : null) ?? Object.entries(presets).find( ([id, p]) => id !== "custom" && @@ -146,7 +167,18 @@ export function ModelCard({ data.llm.base_url.startsWith(p.base_url), )?.[0] ?? (data.llm.base_url ? "custom" : "deepseek"); + // a tile's preset: the runtime's, the one that adds an endpoint, or one standing for an + // endpoint of the list + const presetOf = (id: string): ProviderPreset | undefined => { + if (id === ADD_ENDPOINT) return { label: t("Add an endpoint"), subtitle: presets.custom?.subtitle, group: "local", provider: "openai", base_url: "", key_optional: true }; + const own = endpointOf(id); + if (!own) return presets[id]; + const e = endpoints.find((x) => x.id === own); + return e ? { label: endpointLabel(e), group: "local", provider: "openai", base_url: e.base_url, models: e.models, no_key: true } : undefined; + }; const [preset, setPreset] = useState(currentPreset); + // the endpoint tile just added: chosen as soon as the list arrives with it + const wantEndpoint = useRef(""); const [model, setModel] = useState(data.llm.model); const [baseUrl, setBaseUrl] = useState(data.llm.base_url); const [key, setKey] = useState(""); @@ -167,6 +199,8 @@ export function ModelCard({ // the hands model (contract C4): "" = the default — the relay's hands model with the // account, the chat model otherwise; set here, it goes to [gui] model const [guiModel, setGuiModel] = useState(data.gui?.model ?? ""); + // the endpoint of the list the hands model answers through, when not the chat model's (#294) + const [guiEndpoint, setGuiEndpoint] = useState(data.gui?.endpoint ?? ""); // the endpoint's own list of models, fetched when the provider, URL or key changes const [models, setModels] = useState<{ list: string[]; @@ -182,7 +216,7 @@ export function ModelCard({ gui: string[]; source: "live" | "catalogue" | "loading"; }>({ - list: presets[currentPreset]?.models ?? [], + list: presetOf(currentPreset)?.models ?? [], image: [], video: [], menu: [], @@ -205,27 +239,46 @@ export function ModelCard({ setProxy(data.llm.proxy ?? ""); setProxyTouched(false); setGuiModel(data.gui?.model ?? ""); + setGuiEndpoint(data.gui?.endpoint ?? ""); + const added = endpoints.find((e) => e.id === wantEndpoint.current); + if (added) { + // the endpoint just added stands selected, its first model in the field + wantEndpoint.current = ""; + setPreset(endpointChoice(added.id)); + setBaseUrl(added.base_url); + if (!added.models.includes(data.llm.model)) setModel(added.models[0] ?? ""); + setTyped(false); + return; + } setPreset(currentPreset); // eslint-disable-next-line react-hooks/exhaustive-deps - }, [data.llm, data.gui?.model]); + }, [data.llm, data.gui?.model, data.gui?.endpoint, data.endpoints]); - const p = presets[preset]; + const p = presetOf(preset); + // the endpoint of the list the chosen tile stands for, if any + const ep = endpoints.find((e) => endpointChoice(e.id) === preset) ?? null; + // the tile that adds an endpoint to the list: its form instead of the model fields + const adding = preset === ADD_ENDPOINT; const effectiveUrl = preset === "custom" || !p?.base_url ? baseUrl : p.base_url; // ask the endpoint what it serves; the typed model is never replaced by the answer useEffect(() => { - if (!open) return; + if (!open || adding) return; let alive = true; const handle = setTimeout( () => { setModels((m) => ({ ...m, source: "loading" })); api - .llmModels({ - preset, - base_url: effectiveUrl, - api_key: key || undefined, - }) + .llmModels( + ep + ? { endpoint: ep.id } + : { + preset, + base_url: effectiveUrl, + api_key: key || undefined, + }, + ) .then((r) => { if (!alive) return; setModels({ @@ -272,13 +325,13 @@ export function ModelCard({ const pick = (id: string) => { setPreset(id); - const next = presets[id]; + const next = presetOf(id); if (!next) return; if (next.base_url) setBaseUrl(next.base_url); - else if (presets[preset]?.base_url) setBaseUrl(""); + else if (p?.base_url) setBaseUrl(""); // a model typed by hand stays; an empty field or one from another preset's catalogue moves on const cameFromCatalogue = - !model || Object.values(presets).some((q) => q.models?.includes(model)); + !model || Object.values(presets).some((q) => q.models?.includes(model)) || endpoints.some((e) => e.models.includes(model)); if ( cameFromCatalogue && next.models?.length && @@ -318,6 +371,8 @@ export function ModelCard({ const keyless = !!p?.no_key || (noKey && !!p?.key_optional); const status = data.llm.cloud ? { text: t("Your account's model"), tone: "ok" } + : data.llm.key_source === "none" && currentEndpoint + ? { text: t("No key"), tone: "ok" } : data.llm.key_source === "none" && !presets[currentPreset]?.no_key && !presets[currentPreset]?.key_optional @@ -341,6 +396,14 @@ export function ModelCard({ if (p?.cloud) { // the account's key stays the key; only the model is chosen here await api.cloudUseAsModel(model.trim()); + } else if (ep) { + // an endpoint of the list: its address and key by id, never retyped here + await api.setLLM({ + endpoint: ep.id, + model: model.trim(), + tool_mode: toolMode, + proxy: proxyTouched && data.llm.proxy !== undefined ? proxy.trim() : null, + }); } else { await api.setLLM({ provider: p?.provider ?? "openai", @@ -352,8 +415,14 @@ export function ModelCard({ proxy: proxyTouched && data.llm.proxy !== undefined ? proxy.trim() : null, }); } - // the hands model rides on the chat model's endpoint and key (contract C4) - if (guiModel.trim() !== (data.gui?.model ?? "")) await api.setGui({ model: guiModel.trim() }); + // the hands model rides on the chat model's endpoint and key (contract C4), unless it + // was picked from another endpoint of the list, which then lends its address and key + const guiWas = { model: data.gui?.model ?? "", endpoint: data.gui?.endpoint ?? "" }; + if (guiModel.trim() !== guiWas.model || guiEndpoint !== guiWas.endpoint) { + if (guiEndpoint) await api.setGui({ endpoint: guiEndpoint, model: guiModel.trim() }); + else if (guiWas.endpoint) await api.setGui({ model: guiModel.trim(), provider: "", base_url: "", api_key: "" }); + else await api.setGui({ model: guiModel.trim() }); + } setKey(""); invalidateProviders(); toast(t("Model saved")); @@ -389,10 +458,18 @@ export function ModelCard({ ); // the region's own-key provider first (contract C5): Bailian on the mainland, OpenRouter elsewhere for (const g of groups) g.ids = orderPresets(g.ids, presets, state.hub?.account); - const needsUrl = preset === "custom" || !p?.base_url; + // the endpoints of the list stand first, the tile that adds one last (#294); the single + // "custom" slot stays only while the chat model is on an unlisted host outside the list + // (set in config.toml, say), or on a runtime without the list + const local = groups.find((g) => g.id === "local"); + if (local) { + const rest = local.ids.filter((id) => id !== "custom" || !hasList || currentPreset === "custom"); + local.ids = [...endpoints.map((e) => endpointChoice(e.id)), ...rest, ...(hasList ? [ADD_ENDPOINT] : [])]; + } + const needsUrl = !ep && !adding && (preset === "custom" || !p?.base_url); // what the chosen provider covers, from the catalogue (contract C11); the account's model // covers all four through the relay, "custom" is whatever the endpoint happens to serve - const catalogueEntry = p?.cloud ? null : CATALOGUE.find((c) => c.id === catalogueIdFor(preset)) ?? null; + const catalogueEntry = p?.cloud || ep || adding ? null : CATALOGUE.find((c) => c.id === catalogueIdFor(preset)) ?? null; const region = regionOf(state.hub?.account); const locale = getLocale(); const lacks = (cap: Capability) => !!catalogueEntry && !catalogueEntry.user_capabilities && !catalogueEntry.capabilities.includes(cap); @@ -409,7 +486,7 @@ export function ModelCard({ : model.trim(); const handsOnCloud = !p?.cloud && lacks("vision") && !!cloudPreset; // what the hands use right now, as the runtime resolved it (the saved state, not the form) - const handsNow = data.gui ? handsValue(data.gui, data.llm, locale) : ""; + const handsNow = data.gui ? handsValue(data.gui, data.llm, locale, CATALOGUE, endpoints) : ""; const handsOptions = Array.from( new Set([ ...(p?.cloud ? models.gui : []), @@ -419,9 +496,17 @@ export function ModelCard({ ).filter(Boolean); // the hands picker's one group: this provider's models that see, the catalogue's hands // default first (the relay's recommended one on nanoMuse Cloud), folded past eight - const handsProviderLabel = p?.cloud ? "nanoMuse Cloud" : catalogueEntry ? providerName(catalogueEntry, locale) : hostOf(effectiveUrl) || preset; + const handsProviderLabel = p?.cloud ? "nanoMuse Cloud" : ep ? endpointLabel(ep) : catalogueEntry ? providerName(catalogueEntry, locale) : hostOf(effectiveUrl) || preset; const handsPreset = p?.cloud ? (models.gui[0] ?? p.gui_model ?? "") : (catalogueEntry?.defaults.hands ?? p?.gui_model ?? ""); - const handsGroups: ModelGroup[] = [{ key: "hands", label: handsProviderLabel, rows: handsOptions.map((id) => ({ id, name: id })), ...(handsPreset ? { default: handsPreset } : {}) }]; + // ... and one group per other endpoint of the list, which lends the hands its address and key (#294) + const handsGroups: ModelGroup[] = [ + { key: "hands", label: handsProviderLabel, rows: handsOptions.map((id) => ({ id, name: id })), ...(handsPreset ? { default: handsPreset } : {}) }, + ...endpointGroups(endpoints, ep?.id ?? ""), + ]; + // the hands model picked from an endpoint that is the chat model's own stands in its group + const handsGroup = guiEndpoint && guiEndpoint !== ep?.id ? endpointChoice(guiEndpoint) : "hands"; + const handsEndpoint = endpoints.find((e) => e.id === guiEndpoint) ?? null; + const handsText = guiModel ? `${handsGroup === "hands" ? handsProviderLabel : handsEndpoint ? endpointLabel(handsEndpoint) : ""} · ${guiModel}` : t("Automatic"); const willAppendV1 = needsUrl && /^https?:\/\/[^/]+\/?$/.test(baseUrl.trim()); return ( @@ -431,7 +516,9 @@ export function ModelCard({ summary={ data.llm.cloud ? `nanoMuse Cloud · ${data.llm.model || "—"}` - : `${data.llm.model || "—"}${data.llm.base_url ? ` · ${hostOf(data.llm.base_url)}` : ""}` + : currentEndpoint + ? `${data.llm.model || "—"} · ${endpointLabel(currentEndpoint)}` + : `${data.llm.model || "—"}${data.llm.base_url ? ` · ${hostOf(data.llm.base_url)}` : ""}` } status={status} open={open} @@ -448,7 +535,11 @@ export function ModelCard({
{g.ids.map((id) => { - const q = presets[id]; + const q = presetOf(id); + if (!q) return null; + const own = endpoints.find((e) => endpointChoice(e.id) === id); + // an endpoint's tile reads its name over its host + const subtitle = own ? (hostOf(own.base_url) !== q.label ? hostOf(own.base_url) : undefined) : q.subtitle ? t(q.subtitle) : undefined; return ( @@ -504,6 +597,30 @@ export function ModelCard({
+ {adding && ( + { + wantEndpoint.current = e.id; + invalidateProviders(); + onChange(); + }} + /> + )} + {ep && ( + + { + invalidateProviders(); + onChange(); + }} + onModels={(list) => { + setModels((m) => ({ ...m, list, source: "live" })); + if (list.length && !typed && !list.includes(model)) setModel(list[0]); + }} + /> + + )} {needsUrl && ( )} + {!adding && ( )} + )} + {!adding && ( (ep ? 1 : 0) + ? t("The model that looks at screens when the hands run: a small, fast one that takes pictures. Pick one of this provider's, or one from another endpoint of your list, which then lends its address and key.") + : t("The model that looks at screens when the hands run: a small, fast one that takes pictures, on the same endpoint and key. Default: this provider's own hands model.") } > setGuiModel("")} - onPick={(_group, row) => setGuiModel(row.id)} + current={guiModel ? { group: handsGroup, id: guiModel } : undefined} + onHead={() => { + setGuiModel(""); + setGuiEndpoint(""); + }} + onPick={(group, row) => { + setGuiModel(row.id); + setGuiEndpoint(endpointOf(group) ?? ""); + }} /> {handsNow &&

{t("Currently {value}", { value: handsNow })}

} {!p?.cloud && model.trim() && !guiModel && modelSees(model.trim()) === false && ( @@ -665,7 +795,8 @@ export function ModelCard({ )}
- {!p?.no_key && ( + )} + {!p?.no_key && !adding && ( )} + {!adding && ( - {!p?.cloud && data.llm.proxy !== undefined && ( + )} + {!p?.cloud && !adding && data.llm.proxy !== undefined && ( )} + {!adding && (
+ )} {test && ( = { + chat: "the chat model", + hands: "the hands", + image: "pictures", + video: "clips", +}; + +/** + * The form that adds a custom OpenAI-compatible endpoint to the runtime's list: a name, the + * address, a key of its own (or none), and the ids of its models when it does not list them + * at /models. The runtime keeps the key in the vault under the endpoint's own name; the + * entry then stands in the provider tiles and in the hands, pictures and clips pickers. + */ +function AddEndpointForm({ onAdded }: { onAdded: (e: CustomEndpoint) => void }) { + const t = useT(); + const { toast } = useStore(); + const [label, setLabel] = useState(""); + const [baseUrl, setBaseUrl] = useState(""); + const [key, setKey] = useState(""); + const [showKey, setShowKey] = useState(false); + const [noKey, setNoKey] = useState(false); + const [typedModels, setTypedModels] = useState(""); + const [error, setError] = useState(null); + const [busy, setBusy] = useState(false); + const willAppendV1 = /^https?:\/\/[^/]+\/?$/.test(baseUrl.trim()); + + const add = async () => { + setBusy(true); + setError(null); + try { + const added = await api.addEndpoint({ + label: label.trim(), + base_url: baseUrl.trim(), + api_key: noKey ? "" : key, + models: typedModels, + }); + toast(t("Endpoint added")); + onAdded(added); + } catch (e) { + setError(t((e as Error).message)); + } finally { + setBusy(false); + } + }; + + return ( +
+

+ {t("An endpoint joins your list with its own key and stays there; add as many as you use. Pick one as the chat model, or use its models for the hands, pictures and clips.")} +

+ + setLabel(e.target.value)} className={inputCls} placeholder={t("for example: my gateway")} autoCapitalize="off" /> + + + setBaseUrl(e.target.value)} className={inputCls} placeholder="https://host/v1" inputMode="url" autoCapitalize="off" /> + + +
+ setKey(e.target.value)} + disabled={noKey} + className={cx(inputCls, "pr-10 disabled:opacity-50")} + placeholder="sk-…" + autoComplete="off" + autoCapitalize="off" + spellCheck={false} + /> + +
+ +
+ + setTypedModels(e.target.value)} className={inputCls} placeholder="model-a, model-b" autoCapitalize="off" autoCorrect="off" spellCheck={false} /> + + {error &&
{error}
} + +
+ ); +} + +/** + * One endpoint of the list, under its tile: name and host, where its key is, the models it + * serves and the slots that answer through it, with the ways to change it: rename, change + * the key, retype the models, ask it for its models again, remove it. The slots that use + * the endpoint follow a rename, a new key or a move; removing it needs the chat model + * elsewhere first, and sets the hands, pictures or clips on it back to automatic. + */ +function EndpointCard({ + endpoint, + onChange, + onModels, +}: { + endpoint: CustomEndpoint; + onChange: () => void; + /** the endpoint listed its models again: the chat model picker follows */ + onModels: (list: string[]) => void; +}) { + const t = useT(); + const { toast } = useStore(); + const [mode, setMode] = useState<"" | "rename" | "key" | "models" | "remove">(""); + const [label, setLabel] = useState(endpoint.label); + const [key, setKey] = useState(""); + const [showKey, setShowKey] = useState(false); + const [noKey, setNoKey] = useState(false); + const [typedModels, setTypedModels] = useState(endpoint.models.join(", ")); + const [busy, setBusy] = useState(false); + const [note, setNote] = useState(null); + const modelsText = endpoint.models.join(", "); + + useEffect(() => { + setLabel(endpoint.label); + setTypedModels(modelsText); + setMode(""); + setKey(""); + setNoKey(false); + setNote(null); + }, [endpoint.id, endpoint.label, modelsText]); + + const run = async (work: () => Promise, done: string) => { + setBusy(true); + setNote(null); + try { + await work(); + if (done) toast(done); + setMode(""); + onChange(); + } catch (e) { + setNote(t((e as Error).message)); + } finally { + setBusy(false); + } + }; + + const refresh = async () => { + setBusy(true); + setNote(null); + try { + const r = await api.refreshEndpointModels(endpoint.id); + if (r.source === "live") { + onModels(r.models); + toast(t("{n} models from the endpoint", { n: r.models.length })); + onChange(); + } else { + setNote(t("The endpoint did not list its models; the saved list stands.") + (r.error ? ` ${t(r.error)}` : "")); + } + } catch (e) { + setNote(t((e as Error).message)); + } finally { + setBusy(false); + } + }; + + const keyLine = + endpoint.key_source === "vault" + ? t("Key in vault") + : endpoint.key_source === "config" + ? t("Key from config") + : endpoint.key_source === "missing" + ? t("Key missing from vault") + : t("No key"); + const usedBy = endpoint.slots.map((s) => t(SLOT_NAMES[s])).join(getLocale() === "zh-CN" ? "、" : ", "); + const chatUsesIt = endpoint.slots.includes("chat"); + const linkCls = "text-[12.5px] text-accent disabled:opacity-50"; + + return ( +
+
+ {endpointLabel(endpoint)} + · {hostOf(endpoint.base_url)} +
+
+ {keyLine} · {t("{n} models", { n: endpoint.models.length })} + {usedBy ? ` · ${t("Used by {slots}", { slots: usedBy })}` : ""} +
+ {mode === "" && ( +
+ + + + + +
+ )} + {mode === "rename" && ( +
+ setLabel(e.target.value)} className={inputCls} placeholder={hostOf(endpoint.base_url)} autoCapitalize="off" aria-label={t("Name")} /> +
+ + +
+
+ )} + {mode === "key" && ( +
+
+ setKey(e.target.value)} + disabled={noKey} + className={cx(inputCls, "pr-10 disabled:opacity-50")} + placeholder={endpoint.key_source === "vault" ? "••••••••" : "sk-…"} + aria-label={t("API key")} + autoComplete="off" + autoCapitalize="off" + spellCheck={false} + /> + +
+ +
+ + +
+
+ )} + {mode === "models" && ( +
+ setTypedModels(e.target.value)} className={inputCls} placeholder="model-a, model-b" aria-label={t("Models")} autoCapitalize="off" autoCorrect="off" spellCheck={false} /> +
{t("The ids of the models this endpoint serves, separated by commas; what it lists at /models is added after them.")}
+
+ + +
+
+ )} + {mode === "remove" && ( +
+
+ {chatUsesIt + ? t("The chat model answers through this endpoint; pick another chat model first.") + : t("Its key goes with it, and the hands, pictures or clips set on it go back to automatic.")} +
+
+ + +
+
+ )} + {note &&
{note}
} +
+ ); +} + // ------------------------------------------------------------------ pictures and clips /** * One of the two media rows of the Models contract — *Making pictures* (`[image]`) and @@ -841,11 +1276,14 @@ export function MediaSlotCard({ const region = regionOf(account); const locale = getLocale(); const cloudBaseUrl = data.providers[CLOUD_PRESET]?.base_url ?? ""; + // the custom endpoints of the runtime's list (#294), each with its own key + const endpoints = data.endpoints ?? []; const choices = mediaChoices(cap, { signedIn, chat: { provider: data.llm.provider, base_url: data.llm.base_url, cloud: !!data.llm.cloud }, region, locale, + endpoints, }); const current = currentChoice(info, cloudBaseUrl); const [open, setOpen] = useState(false); @@ -868,7 +1306,9 @@ export function MediaSlotCard({ const chosen = choices.find((c) => c.value === choice) ?? null; const entry = chosen?.entry ?? null; const edition = entry ? editionFor(entry, region) : null; - const endpointUrl = choice === CLOUD_ID ? cloudBaseUrl : choice === CUSTOM_ID ? baseUrl.trim() : (edition?.base_url ?? ""); + // an endpoint of the list, chosen by id: its address and key are the runtime's to look up + const own = endpoints.find((e) => endpointChoice(e.id) === choice) ?? null; + const endpointUrl = choice === CLOUD_ID ? cloudBaseUrl : own ? own.base_url : choice === CUSTOM_ID ? baseUrl.trim() : (edition?.base_url ?? ""); // the key the slot would use: one typed here, the one saved for this very provider, the // chat model's on its own host, the account's on nanoMuse Cloud const keySaved = current === choice && current !== "" && (info.key_source === "vault" || info.key_source === "config"); @@ -886,7 +1326,13 @@ export function MediaSlotCard({ () => { setModels((m) => ({ ...m, source: "loading" })); api - .llmModels(choice === CLOUD_ID ? { preset: CLOUD_PRESET } : { preset: entry ? presetFor(entry.id) : "", base_url: endpointUrl, api_key: key || undefined }) + .llmModels( + choice === CLOUD_ID + ? { preset: CLOUD_PRESET } + : own + ? { endpoint: own.id } + : { preset: entry ? presetFor(entry.id) : "", base_url: endpointUrl, api_key: key || undefined }, + ) .then((r) => { if (!alive) return; const list = (slot === "image" ? r.image_models : r.video_models) ?? []; @@ -906,7 +1352,7 @@ export function MediaSlotCard({ const title = slot === "image" ? t("Making pictures") : t("Making clips"); const subtitle = slot === "image" ? t("Portraits of your Muse.") : t("Short clips of your Muse."); - const value = slotValue(info, locale); + const value = slotValue(info, locale, CATALOGUE, endpoints); const sentence = unavailableLine(t, cap, region, locale); const status = !info.effective_provider ? { text: t("Not set up"), tone: "warn" } @@ -922,6 +1368,9 @@ export function MediaSlotCard({ await api.setMedia(slot, { provider: "", model: "", base_url: "", api_key: "" }); } else if (choice === CLOUD_ID) { await api.setMedia(slot, { provider: "openai", base_url: cloudBaseUrl, model: model.trim(), api_key: CLOUD_KEY_REF }); + } else if (own) { + // an endpoint of the list lends the slot its address and key, by id + await api.setMedia(slot, { endpoint: own.id, model: model.trim() }); } else if (choice === CUSTOM_ID) { await api.setMedia(slot, { provider: "openai", base_url: baseUrl.trim(), model: model.trim(), api_key: key ? key : null }); } else { @@ -940,8 +1389,9 @@ export function MediaSlotCard({ } }; - const groupTitle = (g: MediaChoice["group"]) => (g === "cloud" ? t("Your account") : g === "chat" ? t("The chat model's provider") : t("Add a provider")); - const groups = (["cloud", "chat", "add"] as const).map((g) => ({ g, items: choices.filter((c) => c.group === g) })).filter((x) => x.items.length); + const groupTitle = (g: MediaChoice["group"]) => + g === "cloud" ? t("Your account") : g === "chat" ? t("The chat model's provider") : g === "endpoints" ? t("Your endpoints") : t("Add a provider"); + const groups = (["cloud", "chat", "endpoints", "add"] as const).map((g) => ({ g, items: choices.filter((c) => c.group === g) })).filter((x) => x.items.length); const vaultName = slot === "image" ? "IMAGE_API_KEY" : "VIDEO_API_KEY"; return ( @@ -1006,7 +1456,7 @@ export function MediaSlotCard({ placeholder={defaultModel || undefined} /> )} - {choice && choice !== CLOUD_ID && chosen?.group !== "chat" && ( + {choice && choice !== CLOUD_ID && chosen?.group !== "chat" && !own && ( )} {chosen?.group === "chat" &&

{t("Uses the chat model's key.")}

} + {own &&

{t("Uses the key saved with this endpoint.")}

}
diff --git a/web/src/components/BrowserViewer.tsx b/web/src/components/BrowserViewer.tsx index 60cdc9ba6..9b223e554 100644 --- a/web/src/components/BrowserViewer.tsx +++ b/web/src/components/BrowserViewer.tsx @@ -154,6 +154,7 @@ export function BrowserViewer({ thread, eventId, onClose }: { thread: string; ev value={text} onChange={(e) => setText(e.target.value)} placeholder={t("Type into the focused field…")} + aria-label={t("Type into the focused field…")} className="flex-1 rounded-2xl bg-surface-2 px-3.5 py-2.5 text-[14px] outline-none" autoComplete="off" autoCapitalize="off" @@ -192,6 +193,7 @@ export function BrowserViewer({ thread, eventId, onClose }: { thread: string; ev value={url} onChange={(e) => setUrl(e.target.value)} placeholder={t("Open a URL…")} + aria-label={t("Open a URL…")} inputMode="url" autoCapitalize="off" className="flex-1 min-w-0 rounded-2xl bg-surface-2 px-3.5 py-2 text-[13px] outline-none" diff --git a/web/src/components/Cards.tsx b/web/src/components/Cards.tsx index 7305718e4..b54a09477 100644 --- a/web/src/components/Cards.tsx +++ b/web/src/components/Cards.tsx @@ -269,7 +269,7 @@ export function ApprovalCard({
diff --git a/web/src/components/Sheet.tsx b/web/src/components/Sheet.tsx index 62ede711e..adb35fb31 100644 --- a/web/src/components/Sheet.tsx +++ b/web/src/components/Sheet.tsx @@ -1,6 +1,6 @@ import { X } from "lucide-react"; import type { ReactNode } from "react"; -import { useEffect, useRef } from "react"; +import { useEffect, useId, useRef } from "react"; import { useT } from "../i18n"; import { useFocusTrap } from "./useFocusTrap"; @@ -20,6 +20,8 @@ export function Sheet({ }) { const t = useT(); const panel = useRef(null); + // the title names the dialog for a screen reader when there is one + const titleId = useId(); useFocusTrap(panel, open); useEffect(() => { if (!open) return; @@ -36,11 +38,12 @@ export function Sheet({ ref={panel} role="dialog" aria-modal="true" + aria-labelledby={title ? titleId : undefined} className="sheet-in relative w-full sm:max-w-lg max-h-[92dvh] flex flex-col bg-surface rounded-t-3xl sm:rounded-3xl shadow-2xl border border-border" >
-
{title}
+
{title}
{s && (
- {t("Always asks before: {tools}.", { tools: s.sentinel.always_ask_tools.map((tool) => t(tool)).join(", ") || "—" })}{" "} + {t("Always asks before: {tools}.", { tools: s.sentinel.always_ask_tools.map((tool) => t(tool)).join(", ") || t("none") })}{" "} {s.sentinel.taint_tracking && t("After reading private data, new network destinations need approval.")}
)} @@ -275,7 +281,7 @@ export function SettingsScreen() {
void update({ profile: { proactivity: v } })} />
-
-
-
)}
diff --git a/web/src/store.tsx b/web/src/store.tsx index d335f27db..75b8ac6b9 100644 --- a/web/src/store.tsx +++ b/web/src/store.tsx @@ -361,7 +361,7 @@ function reducer(state: AppState, action: Action): AppState { return { ...state, events: { ...state.events, [action.thread]: state.events[action.thread] ?? [] }, - toast: t("Could not load the conversation. Pull to retry."), + toast: t("Could not load the conversation. Open the chat again to retry."), }; case "activeThread": return { ...state, activeThread: action.thread, tab: "chat" }; From acb11121cf8697576d786051e08c9e3467f727cd Mon Sep 17 00:00:00 2001 From: lgy0404 <2528379691@qq.com> Date: Mon, 12 Oct 2026 03:03:36 +0800 Subject: [PATCH 68/98] fix(desktop): run the shell's tests in CI, make them CRLF-safe, cover the clip parser The desktop shell's 59 tests under harness/desktop/tests ran in no workflow; desktop-app.yml now runs `npm test` before packaging on every platform. Two of them read checked-in files and split on a bare newline, so a Windows checkout with CRLF line ends failed them; both now normalise what they read. The own-clip probe took a version 1 movie header whose duration is all ones ("unknown") as a length of 1.8e19 units and refused the file as too long instead of reading the length from mvex/mehd; all ones now counts as unknown, like 0xffffffff in a version 0 header. Tests added for the parser paths that had none: a 64-bit box size, a QuickTime file opening with wide and free atoms, an mdat with size 0, a 64-bit size the file cannot hold, and fragmented files with and without mehd. The Chinese title of the connector sheet gets a space before the service's name. harness/README.md names the .tar.gz, the four bundles of the profile and Trajectory.tsx, and with docs/harness.md and its Chinese twin no longer says the shell pins Electron 44.0.0 (it pins one exact version, 44.6.0 today). A doubled comment marker in electron-builder.yml and the rail's description in cordis.patch.yml are corrected. Signed-off-by: lgy0404 <2528379691@qq.com> --- .github/workflows/desktop-app.yml | 6 +- docs/harness.md | 2 +- docs/zh/harness.md | 2 +- harness/README.md | 8 +-- harness/desktop/electron-builder.yml | 2 +- harness/desktop/tests/installer.test.mjs | 3 +- harness/desktop/tests/overlays.test.mjs | 6 +- harness/dsh-nanomuse/cordis.patch.yml | 4 +- harness/dsh-nanomuse/src/client/locales.ts | 2 +- harness/dsh-nanomuse/src/own-clip.ts | 4 +- harness/dsh-nanomuse/tests/own-clip.test.mjs | 58 ++++++++++++++++++++ 11 files changed, 81 insertions(+), 16 deletions(-) diff --git a/.github/workflows/desktop-app.yml b/.github/workflows/desktop-app.yml index 566c6ae26..4c2396be5 100644 --- a/.github/workflows/desktop-app.yml +++ b/.github/workflows/desktop-app.yml @@ -8,8 +8,8 @@ # Each platform builds the bundle (harness/dsh-nanomuse: pnpm build, test, pack), stages dsh # next to it with npm (scripts/prepare-dsh.mjs, the platform's own native prebuilds), builds # the runtime (scripts/desktop-app/build-runtime.py --target harness/desktop/runtime, a -# PyInstaller build), wraps it all with electron-builder, and -# then boots the unpacked app's harness once in Node mode (scripts/smoke.mjs) to see the Host +# PyInstaller build), runs the shell's own tests (harness/desktop: npm test), wraps it all +# with electron-builder, and then boots the unpacked app's harness once in Node mode (scripts/smoke.mjs) to see the Host # come up with the bundle's rows. On macOS the Swift helper that holds the hands' permissions # (harness/desktop/mac/computer-use/build.sh → "nanoMuse Computer Use.app") is built first and # electron-builder lays out the .app with it inside; @@ -144,6 +144,7 @@ jobs: run: | npm ci npm run typecheck + npm test npm run dist - name: The helper that holds the hands' permissions (macOS, nanoMuse Computer Use.app, Swift) if: runner.os == 'macOS' @@ -167,6 +168,7 @@ jobs: run: | npm ci npm run typecheck + npm test npm run dist:dir ../../scripts/desktop-app/package-mac.sh "${{ matrix.label == 'macos-arm64' && 'arm64' || 'x64' }}" - name: Boot the packaged harness once diff --git a/docs/harness.md b/docs/harness.md index 0b3bb7226..055a1cfb3 100644 --- a/docs/harness.md +++ b/docs/harness.md @@ -358,7 +358,7 @@ a community project with no affiliation) apply unchanged. project of its own), but a small Electron app that does what that one does at its core: starts the harness's Host as a child process with its own binary in Node mode (`ELECTRON_RUN_AS_NODE`, `--expose-internals`; the harness's `require-builtin` addon - fingerprints the Electron it was built for, so the shell pins `44.0.0`), from a `dsh` + fingerprints the Electron it was built for, so the shell pins one exact Electron version), from a `dsh` that npm installed under `resources/dsh` together with the bundle at build time, against a profile of its own under `~/.nanomuse/desktop` that names the bundle and links it from the copy inside the app. The runtime for the hands rides along as a diff --git a/docs/zh/harness.md b/docs/zh/harness.md index 1a73e667e..22cf89f0e 100644 --- a/docs/zh/harness.md +++ b/docs/zh/harness.md @@ -270,7 +270,7 @@ DeepSeek Harness 是 MIT 许可;它是依赖,不是内嵌的拷贝,它的 准备一个私有 Host、一个主运行时和硬件令牌签名,本身就是一个项目),而是一个小小的 Electron App, 做那个 App 核心上做的事:用自己的二进制以 Node 模式把 harness 的 Host 作为子进程启动 (`ELECTRON_RUN_AS_NODE`、`--expose-internals`;harness 的 `require-builtin` 原生扩展带着它构建时 - 所针对的 Electron 的指纹,所以外壳钉在 `44.0.0`),dsh 是构建时 npm 装到 `resources/dsh` 下的, + 所针对的 Electron 的指纹,所以外壳钉死一个确切的 Electron 版本),dsh 是构建时 npm 装到 `resources/dsh` 下的, bundle 也一起;用的是 `~/.nanomuse/desktop` 下它自己的 profile,里面写明 bundle,并链接到 App 内的 那份拷贝。负责手的运行时以 PyInstaller 构建随行,`NANOMUSE_PY` 把预设指向它。`desktop-app.yml` 在每个发布标签上构建 Windows 安装包、两种架构的 macOS dmg/zip 和 Linux AppImage/deb,把每个打包好 diff --git a/harness/README.md b/harness/README.md index 6d90c88fd..24493b207 100644 --- a/harness/README.md +++ b/harness/README.md @@ -119,17 +119,17 @@ needed on the machine: | --- | --- | | Windows | `nanoMuse-Desktop--win-x64.exe` (NSIS; no certificate, so SmartScreen asks for *Run anyway*) | | macOS | `nanoMuse-Desktop--mac-arm64.dmg`, `-mac-x64.dmg` (and `.zip`; ad-hoc signed unless the Apple secrets are set, then *Open Anyway* once in System Settings → Privacy & Security) | -| Linux | `nanoMuse-Desktop--linux-x64.AppImage`, `.deb` | +| Linux | `nanoMuse-Desktop--linux-x64.deb` (preferred), `.AppImage`, `.tar.gz` | How it runs, in one paragraph: the shell starts the harness's Host as a child process — its own Electron binary in Node mode (`ELECTRON_RUN_AS_NODE`, `--expose-internals`, the way DeepSeek Harness's desktop does; the harness's `require-builtin` addon accepts exactly the Electron the harness was built against, so [`package.json`](desktop/package.json) pins -`44.0.0`) running the `dsh` under `resources/dsh`, where npm installed `@deepseek-ai/dsh` +one exact Electron version, no range) running the `dsh` under `resources/dsh`, where npm installed `@deepseek-ai/dsh` and `dsh-nanomuse` side by side at build time. The profile the Host boots lives under `~/.nanomuse/desktop/profiles/nanomuse` (its own home; the CLI's `~/.dsh` is not touched; a home left by nanoMuse Harness 0.1.28–0.1.29 under `~/.nanomuse/harness` is taken over once): -a manifest naming the three bundles and a link `node_modules/dsh-nanomuse` to the copy +a manifest naming the four bundles (dsh's base and web app, the schedule bundle, ours) and a link `node_modules/dsh-nanomuse` to the copy under resources, refreshed every start, which is how the Loader finds a bundle that is not among the harness's own packages. The shell reads the Host's `dsh web: http://127.0.0.1:…` line and loads that URL; external links open in the browser; a Host that does not come up @@ -192,7 +192,7 @@ dsh-nanomuse/ MuseSidebar.tsx the rail (Chats, Search, Feed, Ideas, Goals, Library, Devices, hamburger) and the column that holds the chats FeedPanel.tsx, IdeasPanel.tsx, GoalsPanel.tsx, LibraryPanel.tsx the four rooms, Muse's layouts; rooms.ts is their SSE store and fetch helper - LiveStage.tsx the live stage: the latest frame, the caption, the cursor marker, expand and take over + Trajectory.tsx the trajectory of a hands run in the chat: each step's screenshot with the action drawn on it and the agent's words Memory.tsx the Memory tab's list, Muse's import-memory sheet, the Data controls rows (download, reset) AvatarStudio.tsx the avatar studio: describe, four candidates in a grid, pick, the poses, worn on the account Pages.tsx Settings → Connectors, Permissions, File system access, Dictation diff --git a/harness/desktop/electron-builder.yml b/harness/desktop/electron-builder.yml index 661d9c6c5..b5f55d1d1 100644 --- a/harness/desktop/electron-builder.yml +++ b/harness/desktop/electron-builder.yml @@ -5,7 +5,7 @@ # Nothing is signed by a developer certificate unless the Apple secrets are in the # environment: Windows asks for "Run anyway"; on macOS the workflow runs `--dir` and # scripts/desktop-app/package-mac.sh, which ad-hoc signs (or signs and notarizes) the -# # bundle and writes the zip and an APFS dmg (docs/desktop.md). +# bundle and writes the zip and an APFS dmg (docs/desktop.md). # The appId is the one the previous desktop app (desktop/app, retired in 0.1.30) carried, so # this one installs over it and keeps its place in the system's permission lists. appId: io.github.nanomuse.desktop diff --git a/harness/desktop/tests/installer.test.mjs b/harness/desktop/tests/installer.test.mjs index 5aa7e6f73..f2378e4fc 100644 --- a/harness/desktop/tests/installer.test.mjs +++ b/harness/desktop/tests/installer.test.mjs @@ -11,7 +11,8 @@ import { test } from "node:test"; import { fileURLToPath } from "node:url"; const here = new URL("..", import.meta.url); -const config = readFileSync(new URL("electron-builder.yml", here), "utf8"); +// read with LF line ends whatever the checkout wrote (a Windows runner with autocrlf writes CRLF) +const config = readFileSync(new URL("electron-builder.yml", here), "utf8").replace(/\r\n/g, "\n"); /** The lines of one top-level block of the YAML, by its key. */ function block(key) { diff --git a/harness/desktop/tests/overlays.test.mjs b/harness/desktop/tests/overlays.test.mjs index d97d1aa10..d84185e86 100644 --- a/harness/desktop/tests/overlays.test.mjs +++ b/harness/desktop/tests/overlays.test.mjs @@ -7,10 +7,12 @@ import { readFileSync } from "node:fs"; import { test } from "node:test"; import { fileURLToPath } from "node:url"; -const page = (name) => readFileSync(fileURLToPath(new URL(`../resources/${name}.html`, import.meta.url)), "utf8"); +// read with LF line ends whatever the checkout wrote (a Windows runner with autocrlf writes CRLF) +const text = (path) => readFileSync(fileURLToPath(new URL(path, import.meta.url)), "utf8").replace(/\r\n/g, "\n"); +const page = (name) => text(`../resources/${name}.html`); const glow = page("glow"); const capsule = page("capsule"); -const main = readFileSync(fileURLToPath(new URL("../src/main.ts", import.meta.url)), "utf8"); +const main = text("../src/main.ts"); test("the glow breathes along the four edges; nothing flows round the rim", () => { assert.match(glow, /\.on \.glow \{[^\n]*animation: breathe 4\.8s ease-in-out infinite/); diff --git a/harness/dsh-nanomuse/cordis.patch.yml b/harness/dsh-nanomuse/cordis.patch.yml index dab4cbc59..0a0907d82 100644 --- a/harness/dsh-nanomuse/cordis.patch.yml +++ b/harness/dsh-nanomuse/cordis.patch.yml @@ -33,8 +33,8 @@ - id: ui-brand-official disabled: true -# The left column is ours: an icon rail (face, Chats, Search, Schedules, -# Devices, a corner menu) beside the harness's own chats browser. The stock +# The left column is ours: an icon rail (Chats, Search, Feed, Ideas, Goals, +# Library, Devices, the hamburger) beside the harness's own chats browser. The stock # sidebar steps aside; our occupant declares the same seven child seats, so the # brand mark, panel glyphs, workspace browser, settings shell and footer # actions all mount exactly as before. diff --git a/harness/dsh-nanomuse/src/client/locales.ts b/harness/dsh-nanomuse/src/client/locales.ts index 0272dea40..65d41c435 100644 --- a/harness/dsh-nanomuse/src/client/locales.ts +++ b/harness/dsh-nanomuse/src/client/locales.ts @@ -2071,7 +2071,7 @@ export const zh: typeof en = { cnGateSentinelMail: '发信每次都会先问;一次性验证码和重置链接会在模型看到之前抹掉。', cnOwnPage: '打开它的设置页', cnDetailFine: '连接器只会在你看得见的聊天里被使用;个人资料里的活动记录列出每一次调用。', - cnConnectTitle: '连接{name}', + cnConnectTitle: '连接 {name}', cnConsentGets: '智能体会得到什么', cnConsentGetsSub: '只有这个连接器列出的那几个工具。除了工具本身发给该服务的内容,你的东西不会离开这台电脑。', cnConsentYou: '它能做什么由你定', diff --git a/harness/dsh-nanomuse/src/own-clip.ts b/harness/dsh-nanomuse/src/own-clip.ts index 66284a34d..25e3a334a 100644 --- a/harness/dsh-nanomuse/src/own-clip.ts +++ b/harness/dsh-nanomuse/src/own-clip.ts @@ -110,7 +110,9 @@ function lengthOf(buf: Buffer, moov: Box): number | undefined { if (version === 1) { if (mvhd.end - mvhd.start < 32) return undefined timescale = buf.readUInt32BE(mvhd.start + 20) - duration = Number(buf.readBigUInt64BE(mvhd.start + 24)) + const d = buf.readBigUInt64BE(mvhd.start + 24) + // all ones is "unknown" in a version 1 header, as 0xffffffff is in a version 0 one + duration = d === 0xffffffffffffffffn ? 0 : Number(d) } else { timescale = buf.readUInt32BE(mvhd.start + 12) duration = buf.readUInt32BE(mvhd.start + 16) diff --git a/harness/dsh-nanomuse/tests/own-clip.test.mjs b/harness/dsh-nanomuse/tests/own-clip.test.mjs index 4b97d496f..dc71630c2 100644 --- a/harness/dsh-nanomuse/tests/own-clip.test.mjs +++ b/harness/dsh-nanomuse/tests/own-clip.test.mjs @@ -21,6 +21,23 @@ function box(type, ...parts) { return Buffer.concat([head, body]) } +/** The same box with the 64-bit size field (`size` 1, then the length after the type). */ +function largeBox(type, ...parts) { + const body = Buffer.concat(parts.map((p) => (typeof p === 'string' ? Buffer.from(p, 'latin1') : p))) + const head = Buffer.alloc(16) + head.writeUInt32BE(1, 0) + head.write(type, 4, 'latin1') + head.writeBigUInt64BE(BigInt(body.length + 16), 8) + return Buffer.concat([head, body]) +} + +/** The same box with size 0: it runs to the end of the file, so it must be the last one. */ +function lastBox(type, ...parts) { + const out = box(type, ...parts) + out.writeUInt32BE(0, 0) + return out +} + function u32(n) { const b = Buffer.alloc(4) b.writeUInt32BE(n, 0) @@ -39,6 +56,13 @@ function mvhd(timescale, duration, version = 0) { return box('mvhd', u32(0), u32(0), u32(0), u32(timescale), u32(duration), Buffer.alloc(80)) } +/** `mvex` with a `mehd`, the length of a fragmented file; without `mehd` when `duration` is undefined. */ +function mvex(duration, version = 0) { + if (duration === undefined) return box('mvex', box('trex', Buffer.alloc(24))) + const mehd = version === 1 ? box('mehd', Buffer.from([1, 0, 0, 0]), u64(duration)) : box('mehd', u32(0), u32(duration)) + return box('mvex', mehd, box('trex', Buffer.alloc(24))) +} + function trak(handler, codec) { const stsd = box('stsd', u32(0), u32(1), box(codec, Buffer.alloc(78))) const hdlr = box('hdlr', u32(0), u32(0), handler, Buffer.alloc(13)) @@ -143,6 +167,40 @@ test('probe finds the video track behind an audio track, and reports other codec assert.equal(probeOwnClip(mp4({ codec: 'vp09' })).codec, 'vp09') }) +test('probe reads a moov with a 64-bit size, a file that opens with wide and free atoms, and an mdat that runs to the end', () => { + const ftyp = box('ftyp', 'isom', u32(0), 'isom', 'mp42') + const large = Buffer.concat([ftyp, largeBox('moov', mvhd(1000, 7000), trak('vide', 'avc1')), box('mdat', Buffer.alloc(64, 7))]) + assert.deepEqual(probeOwnClip(large), { container: true, bytes: large.length, durationMs: 7000, codec: 'avc1' }) + // an old QuickTime file: no ftyp, a wide and a free atom before the movie + const quicktime = Buffer.concat([box('wide'), box('free', Buffer.alloc(16)), box('mdat', Buffer.alloc(64, 7)), box('moov', mvhd(600, 1800), trak('vide', 'avc1'))]) + assert.deepEqual(probeOwnClip(quicktime), { container: true, bytes: quicktime.length, durationMs: 3000, codec: 'avc1' }) + // the media as the last box with size 0, which means "to the end of the file" + const open = Buffer.concat([ftyp, box('moov', mvhd(1000, 2000), trak('vide', 'avc3')), lastBox('mdat', Buffer.alloc(64, 7))]) + assert.deepEqual(probeOwnClip(open), { container: true, bytes: open.length, durationMs: 2000, codec: 'avc3' }) + // a 64-bit size the file cannot hold ends the look without a throw + const lying = Buffer.concat([ftyp, largeBox('moov', mvhd(1000, 2000), trak('vide', 'avc1'))]) + lying.writeBigUInt64BE(0xfffffffffffffn, ftyp.length + 8) + assert.equal(probeOwnClip(lying).container, true) + assert.equal(probeOwnClip(lying).codec, undefined) +}) + +test('probe takes the length of a fragmented file from mvex/mehd, and has none without it', () => { + const ftyp = box('ftyp', 'iso5', u32(0), 'iso5', 'dash') + const fragmented = (header, ex) => Buffer.concat([ftyp, box('moov', header, trak('vide', 'avc1'), ex), box('moof', Buffer.alloc(16)), box('mdat', Buffer.alloc(64, 7))]) + // the movie header says 0 (or all ones, "unknown"), the extends header has the length + assert.equal(probeOwnClip(fragmented(mvhd(1000, 0), mvex(9500))).durationMs, 9500) + assert.equal(probeOwnClip(fragmented(mvhd(1000, 0xffffffff), mvex(9500, 1))).durationMs, 9500) + const unknown64 = box('mvhd', Buffer.from([1, 0, 0, 0]), u64(0), u64(0), u32(1000), Buffer.alloc(8, 0xff), Buffer.alloc(80)) + assert.equal(probeOwnClip(fragmented(unknown64, mvex(12_000))).durationMs, 12_000) + // without mehd the length is not in the file, and the rule refuses it as a format problem + const open = probeOwnClip(fragmented(mvhd(1000, 0), mvex(undefined))) + assert.equal(open.codec, 'avc1') + assert.equal(open.durationMs, undefined) + assert.equal(checkOwnClip(open), 'format') + // a mehd that says 16 s is too long, as a mvhd would be + assert.equal(checkOwnClip(probeOwnClip(fragmented(mvhd(1000, 0), mvex(16_000)))), 'too_long') +}) + test('probe calls a WebM, a text file and an empty file no container at all', () => { const webm = Buffer.concat([Buffer.from([0x1a, 0x45, 0xdf, 0xa3]), Buffer.alloc(64, 1)]) assert.equal(probeOwnClip(webm).container, false) From 2a80277d7dc2ea48b38d50cfb3c40a2bca61979d Mon Sep 17 00:00:00 2001 From: lgy0404 <2528379691@qq.com> Date: Mon, 12 Oct 2026 03:03:50 +0800 Subject: [PATCH 69/98] fix(cloud): one hub device per console tab, consistent backups, a mail that rounds like the SMS The web console kept its hub device id in localStorage, so two tabs of one browser said hello with the same id and took turns replacing each other (close 4003) and reconnecting for as long as both stayed open. The id now lives in sessionStorage: a reload keeps it, a second tab gets its own. The self-hosting guide's backup line called a sqlite3 binary the image does not have and fell back to cp, which under WAL misses the newest writes; it now runs SQLite's backup API inside the container and streams the copy out, so nothing is written into the data directory that belongs to uid 10001. The production notes restore a backup with sudo and hand the file to that uid, as the relay cannot open a cloud.db left to the deploying user. The code mail rounded CODE_TTL_S down to whole minutes and could say zero; it now rounds like the SMS template (at least one). events(ip) gets the partial index ledger and api_keys already had, for the operator's accounts-at-this-address view. cloud/.dockerignore keeps .env, data/ and the tests out of the build context. self-host.sh --help no longer prints the set -euo pipefail line. The README's settings table names PASSWORD_MIN_LEN, PASSWORD_RESET_WINDOW_S, UPSTREAM_TIMEOUT_S and TRUSTED_PROXIES. Signed-off-by: lgy0404 <2528379691@qq.com> --- CHANGELOG.md | 3 +++ cloud/.dockerignore | 14 ++++++++++++++ cloud/README.md | 4 ++++ cloud/deploy/nanomuse-hk/README.md | 10 ++++++++-- cloud/nanomuse_cloud/console/app.js | 15 +++++++++++++-- cloud/nanomuse_cloud/db.py | 2 ++ cloud/nanomuse_cloud/senders.py | 3 ++- cloud/tests/test_cloud.py | 15 +++++++++++++++ cloud/tests/test_console.py | 12 ++++++++++++ cloud/tests/test_senders.py | 18 ++++++++++++++++++ docs/self-hosting.md | 14 ++++++++++++-- docs/zh/self-hosting.md | 14 ++++++++++++-- scripts/self-host.sh | 2 +- 13 files changed, 116 insertions(+), 10 deletions(-) create mode 100644 cloud/.dockerignore diff --git a/CHANGELOG.md b/CHANGELOG.md index 010d14dfa..75decf23c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,9 @@ All notable changes to nanoMuse. The format follows [Keep a Changelog](https://k ### Cloud +- **The web console open in two tabs no longer fights itself.** Every tab of one browser said hello to the hub with the same device id, so the two took turns replacing each other and reconnecting for as long as both stayed open, and a message sent from the tab that had just lost came back as disconnected. Each tab is now its own device on the hub; a reload keeps the tab's id. +- **A self-hosted relay's backup recipe takes a consistent copy.** The command in the self-hosting guide called a `sqlite3` binary the image does not have and fell back to copying `cloud.db`, which under WAL misses the newest writes; it now uses SQLite's backup API inside the running container and streams the copy out. The production notes restore a backup into the data directory as uid 10001, the user the relay runs as. A code mail composed with a `CODE_TTL_S` under a minute says the code is good for one minute, as the SMS template already did. + ### Runtime ### Web diff --git a/cloud/.dockerignore b/cloud/.dockerignore new file mode 100644 index 000000000..67d9d7e2c --- /dev/null +++ b/cloud/.dockerignore @@ -0,0 +1,14 @@ +# What the image build never needs. The Dockerfile copies pyproject.toml, README.md and +# nanomuse_cloud/ only, but without this file the whole directory, the database under +# data/ and .env included, is sent to the Docker daemon as the build context. +.env +*.env +data/ +tests/ +deploy/ +__pycache__/ +*.pyc +.pytest_cache/ +.ruff_cache/ +.mypy_cache/ +*.egg-info/ diff --git a/cloud/README.md b/cloud/README.md index d3411a8d9..db3cf7b26 100644 --- a/cloud/README.md +++ b/cloud/README.md @@ -181,7 +181,11 @@ for the full list. The ones that matter: | `DAILY_CAP_TOKENS` | 0 (off) | tokens per account per day | | `PER_MINUTE_REQUESTS` | 30 | per account — what stops a runaway loop | | `MAX_IN_FLIGHT` | 4 | requests of one account under way at the same time (0 = off); each holds a reservation against the allowance while it runs — see *Money* | +| `UPSTREAM_TIMEOUT_S` | 180 | how long one call to the provider may take (connecting has 20 s of its own); a reservation that outlives it by two minutes is dropped | +| `TRUSTED_PROXIES` | empty | whose `X-Forwarded-For` to believe, comma-separated addresses or networks; empty = every loopback, private, link-local and shared address (Caddy on this box or the compose network, a tailnet) | +| `PASSWORD_MIN_LEN` | 8 | the shortest password the relay accepts (`400 password_short` below it) | | `PASSWORD_MAX_ATTEMPTS`, `LOCKOUT_S` | 5, 900 | wrong passwords before an account is locked for that long (a code still works) | +| `PASSWORD_RESET_WINDOW_S` | 1800 | after a sign-in with a code, how long a new password may be set without the old one (the way back in when it is forgotten) | | `LOGIN_FAIL_PER_IP_HOUR` | 30 | wrong passwords from one network address per hour across all accounts — a list of numbers tried once each never trips the per-account lock, this does (0.12); 0 = off | | `CODE_TTL_S`, `CODE_MAX_ATTEMPTS` | 600, 5 | how long a sign-in code is good for, and how many wrong guesses it survives | | `CODE_PER_IDENTIFIER_10M`, `CODE_PER_IP_HOUR` | 3, 10 | codes one number or address may request per ten minutes, and one network address per hour; past either the request is answered `429 code_too_often` | diff --git a/cloud/deploy/nanomuse-hk/README.md b/cloud/deploy/nanomuse-hk/README.md index 3bd46fe4c..e7135feae 100644 --- a/cloud/deploy/nanomuse-hk/README.md +++ b/cloud/deploy/nanomuse-hk/README.md @@ -132,10 +132,16 @@ the *Free allowance* switch says it better to the apps. ```bash ssh nanomuse-hk 'cd /opt/nanomuse/relay && docker compose stop \ - && gunzip -c /opt/nanomuse/backups/cloud-YYYYMMDD-HHMMSS.db.gz > data/cloud.db \ - && rm -f data/cloud.db-wal data/cloud.db-shm && docker compose start' + && sudo sh -c "gunzip -c /opt/nanomuse/backups/cloud-YYYYMMDD-HHMMSS.db.gz > data/cloud.db \ + && rm -f data/cloud.db-wal data/cloud.db-shm && chown 10001:10001 data/cloud.db" \ + && docker compose start' ``` +`data/` belongs to uid 10001, the user the relay runs as, so the restored file +is written with `sudo` and handed to that uid; a `cloud.db` left to the +deploying user would stop the relay at start with the sentence about the +directory not being writable. + A backup is only readable with the `CLOUD_SECRET` it was written under; `backup.sh` keeps a copy of `.env` next to the database copies for that reason (`env.latest`, 0600). diff --git a/cloud/nanomuse_cloud/console/app.js b/cloud/nanomuse_cloud/console/app.js index 09709c7f6..69ae023eb 100644 --- a/cloud/nanomuse_cloud/console/app.js +++ b/cloud/nanomuse_cloud/console/app.js @@ -92,8 +92,19 @@ let ws = null, wsState = "off", hubPaused = false, backoff = 1000, devices = [], selected = params.get("device") || LS.getItem("nm.selected") || ""; const pending = new Map(); // call id → {onEvent, resolve, reject} const chats = new Map(); // device id → {messages:[], busy:false, callId:null} - const webId = LS.getItem("nm.webid") || ("web-" + Math.random().toString(36).slice(2, 12)); - LS.setItem("nm.webid", webId); + // One hub device per tab, not per browser: the id lives in sessionStorage, so a reload + // keeps it and a second tab gets its own. Two tabs sharing one id took turns replacing + // each other on the hub (close 4003) and reconnecting, for as long as both stayed open. + const webId = (() => { + let id = ""; + try { id = window.sessionStorage.getItem("nm.webid") || ""; } catch (_) { /* storage denied */ } + if (!id) { + id = "web-" + Math.random().toString(36).slice(2, 12); + try { window.sessionStorage.setItem("nm.webid", id); } catch (_) { /* this tab's life only */ } + } + return id; + })(); + LS.removeItem("nm.webid"); // the id of before, shared by every tab of this browser const app = document.getElementById("app"); const h = (tag, attrs = {}, ...kids) => { diff --git a/cloud/nanomuse_cloud/db.py b/cloud/nanomuse_cloud/db.py index d24742d89..57c0a5812 100644 --- a/cloud/nanomuse_cloud/db.py +++ b/cloud/nanomuse_cloud/db.py @@ -376,6 +376,8 @@ def add(table: str, col: str, ddl: str) -> None: add("devices", "ip", "TEXT NOT NULL DEFAULT ''") self._conn.execute("CREATE INDEX IF NOT EXISTS ledger_ip ON ledger(ip) WHERE ip<>''") self._conn.execute("CREATE INDEX IF NOT EXISTS api_keys_ip ON api_keys(ip) WHERE ip<>''") + # events is the largest of the three and accounts_at_address reads it by ip as well + self._conn.execute("CREATE INDEX IF NOT EXISTS events_ip ON events(ip) WHERE ip<>''") # 0.15: the allowance each account was given (the part of grant_uy that is neither # an invite nor the operator's credit), so a raised allowance can be applied to the # accounts that got less. -1 = from before the column; the service fills it with diff --git a/cloud/nanomuse_cloud/senders.py b/cloud/nanomuse_cloud/senders.py index 7913f48e2..89b2f4cf7 100644 --- a/cloud/nanomuse_cloud/senders.py +++ b/cloud/nanomuse_cloud/senders.py @@ -65,7 +65,8 @@ def accepts(self, ident: Identifier) -> bool: def send(self, ident: Identifier, code: str) -> None: if ident.channel != "email": raise SendError("this deployment sends codes by e-mail only") - msg = compose_code_mail(self.s.smtp_from, ident.value, code, self.s.code_ttl_s // 60) + # the same rounding as the SMS template: a lifetime under a minute still reads as one + msg = compose_code_mail(self.s.smtp_from, ident.value, code, max(1, self.s.code_ttl_s // 60)) smtp_send(self.s, msg) diff --git a/cloud/tests/test_cloud.py b/cloud/tests/test_cloud.py index 18a7930bc..7ea903ce6 100644 --- a/cloud/tests/test_cloud.py +++ b/cloud/tests/test_cloud.py @@ -1781,6 +1781,21 @@ def test_database_from_before_0_4_migrates(tmp_path): assert db._conn.execute("SELECT invite_code, contribute FROM accounts WHERE id='a1'").fetchone()[0] == "" +def test_the_three_tables_read_by_address_are_indexed_on_it(): + """The operator's "accounts seen from this address" reads ledger, api_keys and events by + ip (db.accounts_at_address); each has the partial index, events included, which is the + largest of the three. Opening the database twice creates nothing twice.""" + db = Database(":memory:") + + def indexes() -> list[str]: + return sorted(r["name"] for r in db._conn.execute("SELECT name FROM sqlite_master WHERE type='index'").fetchall()) + + before = indexes() + assert {"ledger_ip", "api_keys_ip", "events_ip"} <= set(before) + db._migrate() + assert indexes() == before # a second run neither fails nor adds anything + + def test_database_from_0_4_moves_to_the_lifetime_allowance(tmp_path): """0.4 kept a daily cap and credit beyond it; 0.5 has one pool. On the first open the service seeds every account with what it had spent plus the allowance, plus any 0.4 diff --git a/cloud/tests/test_console.py b/cloud/tests/test_console.py index d6a94e69c..ecfcc709a 100644 --- a/cloud/tests/test_console.py +++ b/cloud/tests/test_console.py @@ -68,6 +68,18 @@ def test_web_console_translates_every_refusal_in_both_languages(): assert "!" not in re.sub(r"[!=]==?|!\w", "", zh + en) and "!" not in zh +def test_web_console_is_one_hub_device_per_tab(): + """The id the console says hello with lives in sessionStorage, so two tabs of one + browser are two devices on the hub. Shared through localStorage, as before, the two + took turns replacing each other (close 4003) and reconnecting for as long as both + stayed open.""" + source = (CONSOLE / "app.js").read_text(encoding="utf-8") + assert 'sessionStorage.getItem("nm.webid")' in source and 'sessionStorage.setItem("nm.webid"' in source + assert 'LS.setItem("nm.webid"' not in source and 'LS.getItem("nm.webid")' not in source + # the hello carries that id; the hub keys its connections on it (hub.py _attach) + assert "device: { id: webId," in source + + def test_console_copy_has_no_dashes_in_sentences(): """The house rule: what a person reads carries no em dash. Checked on the two string tables (`const T = zh ? {...} : {...}`) of each console; the one-character placeholder diff --git a/cloud/tests/test_senders.py b/cloud/tests/test_senders.py index 86ec75d29..ce5f74d57 100644 --- a/cloud/tests/test_senders.py +++ b/cloud/tests/test_senders.py @@ -115,6 +115,24 @@ def test_make_sender_both_routes_phones_to_sms_and_addresses_to_mail(monkeypatch assert mailed == [("dev-a@example.com", "654321")] and len(fake.urls) == 1 +def test_the_code_mail_states_the_lifetime_in_whole_minutes_like_the_sms(monkeypatch): + """Both templates say how long the code is good for in minutes, rounded the same way: + CODE_TTL_S=600 reads as ten, and a lifetime under a minute still reads as one, never + as zero. The mail is composed with the settings' figure, in both languages.""" + sent = [] + monkeypatch.setattr(senders, "smtp_send", lambda s, msg: sent.append(msg)) + mail = SmtpSender(aliyun_settings(sender="smtp", smtp_host="smtp.test", smtp_from="nanoMuse ")) + mail.send(parse("dev-a@example.com"), "482913") + body = sent[-1].get_body(("plain",)).get_content() + assert "482913" in body and "10 分钟内有效" in body and "expires in 10 minutes" in body + short = SmtpSender(aliyun_settings(sender="smtp", smtp_host="smtp.test", smtp_from="nanoMuse ", code_ttl_s=30)) + short.send(parse("dev-a@example.com"), "482913") + body = sent[-1].get_body(("plain",)).get_content() + assert "1 分钟内有效" in body and "expires in 1 minutes" in body and "0 分钟" not in body + sms = AliyunSmsSender(aliyun_settings(code_ttl_s=30)) + assert json.loads(sms.params(parse("13800138000"), "482913")["TemplateParam"]) == {"code": "482913", "min": "1"} + + def test_unknown_api_and_missing_settings_are_refused_at_startup(): with pytest.raises(ValueError): AliyunSmsSender(aliyun_settings(aliyun_sms_api="carrier-pigeon")) diff --git a/docs/self-hosting.md b/docs/self-hosting.md index 2d943f7ff..1cf65dd3a 100644 --- a/docs/self-hosting.md +++ b/docs/self-hosting.md @@ -89,10 +89,20 @@ The database schema migrates forward on start. Read the release notes before a j Everything the relay keeps is `cloud/data/cloud.db` (SQLite) plus `CLOUD_SECRET` in `cloud/.env`. The database is useless without the secret (the identifiers are hashed and encrypted with it, and so is a sign-in code still waiting to be used, which is only six digits), and the secret is useless without the database; back them up together, and never rotate the secret unless you mean to start over: ```bash -cd cloud && docker compose exec relay sqlite3 /srv/nanomuse-cloud/data/cloud.db ".backup /srv/nanomuse-cloud/data/backup.db" \ - || cp data/cloud.db data/backup.db # when the container has no sqlite3: stop the relay first for a clean copy +cd cloud && docker compose exec -T relay python - > cloud-$(date -u +%Y%m%d).db <<'EOF' +import os, shutil, sqlite3, sys +src = sqlite3.connect("/srv/nanomuse-cloud/data/cloud.db") +dst = sqlite3.connect("/tmp/backup.db") +src.backup(dst) +dst.close(); src.close() +with open("/tmp/backup.db", "rb") as f: + shutil.copyfileobj(f, sys.stdout.buffer) +os.remove("/tmp/backup.db") +EOF ``` +The copy is taken with SQLite's own backup API inside the running container (the image has no `sqlite3` command) and streamed out, so it is consistent while the relay keeps writing and lands as a file of yours, outside the data directory that belongs to uid 10001. A plain `cp data/cloud.db` is not consistent: under WAL the newest writes sit in `cloud.db-wal`, and a copy of the main file alone misses them. + Caddy's certificates live in the `caddy_data` volume and are fetched again if lost. ### What your relay stores diff --git a/docs/zh/self-hosting.md b/docs/zh/self-hosting.md index 38d26daaa..b79bc6507 100644 --- a/docs/zh/self-hosting.md +++ b/docs/zh/self-hosting.md @@ -89,10 +89,20 @@ bash scripts/self-host.sh # Enter through the questions; secrets and acco 中继保存的一切就是 `cloud/data/cloud.db`(SQLite)加上 `cloud/.env` 里的 `CLOUD_SECRET`。没有这个密钥,数据库就没用(标识符是用它哈希和加密的,还在等待使用的登录验证码也是,那只有六位数字),没有数据库,密钥也没用;两样一起备份,而且除非你打算从头来过,否则绝不要更换密钥: ```bash -cd cloud && docker compose exec relay sqlite3 /srv/nanomuse-cloud/data/cloud.db ".backup /srv/nanomuse-cloud/data/backup.db" \ - || cp data/cloud.db data/backup.db # when the container has no sqlite3: stop the relay first for a clean copy +cd cloud && docker compose exec -T relay python - > cloud-$(date -u +%Y%m%d).db <<'EOF' +import os, shutil, sqlite3, sys +src = sqlite3.connect("/srv/nanomuse-cloud/data/cloud.db") +dst = sqlite3.connect("/tmp/backup.db") +src.backup(dst) +dst.close(); src.close() +with open("/tmp/backup.db", "rb") as f: + shutil.copyfileobj(f, sys.stdout.buffer) +os.remove("/tmp/backup.db") +EOF ``` +副本由运行中的容器里 SQLite 自带的备份接口生成(镜像里没有 `sqlite3` 命令),再流式输出到宿主机:中继一边写它也是一致的,落下来的文件归你所有,不在属于 uid 10001 的数据目录里。直接 `cp data/cloud.db` 做不到这一点:WAL 模式下最新的写入还在 `cloud.db-wal` 里,只复制主文件会漏掉它们。 + Caddy 的证书在 `caddy_data` 卷里,丢了会重新申请。 ### 你的中继存什么 {#what-your-relay-stores} diff --git a/scripts/self-host.sh b/scripts/self-host.sh index c21dcfc94..98dd831e9 100755 --- a/scripts/self-host.sh +++ b/scripts/self-host.sh @@ -29,7 +29,7 @@ while [ $# -gt 0 ]; do --bind) BIND="$2"; shift ;; --port) PORT="$2"; shift ;; --no-start) START=0 ;; - -h|--help) sed -n '2,19p' "$0" | sed 's/^# \{0,1\}//'; exit 0 ;; + -h|--help) sed -n '2,18p' "$0" | sed 's/^# \{0,1\}//'; exit 0 ;; *) echo "unknown option: $1 (try --help)" >&2; exit 2 ;; esac shift From cda83c9fe45ca9f89b7586c21de3295e543db7ea Mon Sep 17 00:00:00 2001 From: lgy0404 <2528379691@qq.com> Date: Mon, 12 Oct 2026 03:04:20 +0800 Subject: [PATCH 70/98] docs(changelog): name the pull request behind the web console bullet Signed-off-by: lgy0404 <2528379691@qq.com> --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 76feee10f..12811c38b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,7 +10,7 @@ All notable changes to nanoMuse. The format follows [Keep a Changelog](https://k ### Web -- **Adding an MCP server with its tools marked *high* no longer fails.** The risk chips under *Connections → MCP servers* offered *high*, a level the runtime does not have, so saving answered with a 400; the third chip is now *sensitive*, the level the Sentinel knows. The API key fields, the working hours and quiet hours times, the contacts search, the chat composer and the browser take-over fields are named for screen readers, the Settings selects are tied to their labels, a sheet's title names the dialog, the toast is announced, a pending sensitive approval keeps its red edge in the dark theme, sheets and drawers appear in place under *reduce motion*, and the places that showed a bare dash (the chat model summary without a model, a goal without a next step, a reminder without a time) say so in words. The docs' description of the chat now matches the screen (the ink pill, the chats drawer top left, the + button for attachments, the `conversation` grant scope). (#380) +- **Adding an MCP server with its tools marked *high* no longer fails.** The risk chips under *Connections → MCP servers* offered *high*, a level the runtime does not have, so saving answered with a 400; the third chip is now *sensitive*, the level the Sentinel knows. The API key fields, the working hours and quiet hours times, the contacts search, the chat composer and the browser take-over fields are named for screen readers, the Settings selects are tied to their labels, a sheet's title names the dialog, the toast is announced, a pending sensitive approval keeps its red edge in the dark theme, sheets and drawers appear in place under *reduce motion*, and the places that showed a bare dash (the chat model summary without a model, a goal without a next step, a reminder without a time) say so in words. The docs' description of the chat now matches the screen (the ink pill, the chats drawer top left, the + button for attachments, the `conversation` grant scope). (#382) ### Desktop From 6e5eb327b3026c97bfb296f4c28717bad6a32639 Mon Sep 17 00:00:00 2001 From: lgy0404 <2528379691@qq.com> Date: Mon, 12 Oct 2026 03:04:43 +0800 Subject: [PATCH 71/98] docs(changelog): the desktop fixes of #383 under Unreleased Signed-off-by: lgy0404 <2528379691@qq.com> --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 010d14dfa..f6a9dc9b0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,8 @@ All notable changes to nanoMuse. The format follows [Keep a Changelog](https://k ### Desktop +- **A clip of your own with a fragmented layout is read right, and the connector sheet's Chinese title has its space.** A fragmented MP4 whose 64-bit movie header says "unknown" for the length was refused as too long instead of being read from its `mehd` box; it is now read like the 32-bit case. The sheet that connects a service reads 连接 Notion rather than 连接Notion in Chinese. The desktop shell's own tests now run in the desktop workflow on every platform and pass on a Windows checkout with CRLF line ends ([#383](https://github.com/nano-muse/nanoMuse/pull/383)). + ### Android ### iOS From e63af0a006b317d54378b6c921b835990bffcaf1 Mon Sep 17 00:00:00 2001 From: lgy0404 <2528379691@qq.com> Date: Mon, 12 Oct 2026 03:05:38 +0800 Subject: [PATCH 72/98] chore(release): release-docs.py writes the roadmap rows; release-apk.sh checks the iOS version MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The 1.0.3 release left two edits to hand work that the scripts can do: - scripts/release-docs.py takes --roadmap "" and --roadmap-zh "<一句话>" (both or neither) and puts `| | | |` at the end of the past-releases table of docs/roadmap.md and docs/zh/roadmap.md; it refuses a page without the table, a second row for the same version and a line with `|` in it. Without the flags the by-hand reminder names the rows, as before. Covered by tests/test_release_docs.py; a --dry-run against the repository writes nothing. - scripts/release-apk.sh checks the iOS project's MARKETING_VERSION with the six version files it already compares, so an iPhone project left on the previous version stops the release before the tag. CONTRIBUTING.md's release recipe names the flags. Signed-off-by: lgy0404 <2528379691@qq.com> --- CHANGELOG.md | 1 + CONTRIBUTING.md | 2 +- scripts/release-apk.sh | 5 +-- scripts/release-docs.py | 63 +++++++++++++++++++++++++++++++--- tests/test_release_docs.py | 69 ++++++++++++++++++++++++++++++++++++++ 5 files changed, 133 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 010d14dfa..9bd272052 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,6 +19,7 @@ All notable changes to nanoMuse. The format follows [Keep a Changelog](https://k ### Project - **The READMEs' visitor counter runs on hits.sh.** The badge from komarev.com stopped showing now and then: GitHub's image proxy answers 404 for it at times, as its own tracker reports, and the badge was blank until a reload. The counter is now `hits.sh/github.com/nano-muse/nanoMuse.svg`, which also takes a starting number, so the 16,719 views counted so far are carried over; the same badge in the ten READMEs, twice each (the badge row and the end), one URL so a visit counts once. +- **The release scripts write the roadmap rows and check the iPhone's version.** `scripts/release-docs.py` takes `--roadmap "" --roadmap-zh "<一句话>"` and puts the version's row at the end of the past-releases tables of `docs/roadmap.md` and `docs/zh/roadmap.md`, two edits the 1.0.3 release still made by hand; `scripts/release-apk.sh` refuses to publish when the iOS project's `MARKETING_VERSION` is not the release's, beside the six files it already checked. ## [1.0.3] - 2026-10-12 · Helm diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 4280a3b49..8c50d3c97 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -153,7 +153,7 @@ A version is a plain number (`0.1.41`, `1.0.0`, …) because the apps' update ch A release goes out as soon as a fix people are waiting for is on `main` (a crash, a security issue, an app that will not install), and otherwise every few days, when the *Unreleased* block has something worth a version. What ships: the APK, the TestFlight build, the desktop installers for Windows, macOS and Linux, the harness tarball and the Docker image; no terminal builds and no pre-releases, every release is *Latest*. Before tagging, a maintainer installs the build that will ship on a phone and taps through the main flows. -1. **The release commit** `build(release): `, on its own branch and pull request. `scripts/release-bump.sh [ ]` moves every version file (`pyproject.toml`, `nanomuse/__init__.py`, `CITATION.cff`, `web/package.json`, the two `harness/*/package.json` and their lock files, the relay console's `VERSION`, the `VERSION_NAME`/`VERSION_CODE` in `scripts/rebrand.py`); then `python scripts/rebrand.py` writes the Android `versionName`/`versionCode` and the iOS `MARKETING_VERSION` (a second run must print `clean`). `scripts/release-docs.py ` opens the version's block in `CHANGELOG.md` under *Unreleased* and moves the download links of `README.md`, `docs/readme/*`, `docs/index.md` and `docs/zh/index.md` to the new tag, the example versions in the issue forms (`.github/ISSUE_TEMPLATE/*.yml`) to the new version and `versionCode`, and adds the codename to the list in the release-notes template; the *News* lists it leaves as written, since their lines are milestones and keep their date, version and words for good (`--dry-run` shows the first three lines of every list without writing, and the script says whether this release gets a News line). By hand: the lead paragraph of the `CHANGELOG.md` block and the empty `### Cloud / Runtime / Web / Desktop / Android / iOS / Project` headings for the next *Unreleased*; `docs/releases/v.md` from [docs/release-notes-template.md](docs/release-notes-template.md) (a short story, *Highlights*, *Upgrade Notes*, *Community*, English first and the same in Chinese in a collapsed block, every link checked); a new milestone line for the *News* lists when the release is one, which a major version (`x.0.0`) always is and a smaller one is not (one sentence of about a line, the date in inline code, one emoji, first in the list; the same line in the ten READMEs and on the homepage; the earlier versions' lines stay); the past-releases row in `docs/roadmap.md`; any "next release" cell in `docs/parity.md`; `scripts/readme-contributors.py`, so the *Community Contributors* avatars in the ten READMEs are current (`--check` says whether they are). Run the checks for what changed ([AGENTS.md](AGENTS.md); `scripts/rebrand.py` → `clean`, `connectors-json.mjs --check`, `providers-json.mjs --check`, `cd website && npm run docs:build`); the *iOS · build check* workflow runs on the pull request when `android/src/ios/` changed and can be started by hand from the Actions tab otherwise. Merge when green; `M` is the merge commit. +1. **The release commit** `build(release): `, on its own branch and pull request. `scripts/release-bump.sh [ ]` moves every version file (`pyproject.toml`, `nanomuse/__init__.py`, `CITATION.cff`, `web/package.json`, the two `harness/*/package.json` and their lock files, the relay console's `VERSION`, the `VERSION_NAME`/`VERSION_CODE` in `scripts/rebrand.py`); then `python scripts/rebrand.py` writes the Android `versionName`/`versionCode` and the iOS `MARKETING_VERSION` (a second run must print `clean`). `scripts/release-docs.py ` opens the version's block in `CHANGELOG.md` under *Unreleased* and moves the download links of `README.md`, `docs/readme/*`, `docs/index.md` and `docs/zh/index.md` to the new tag, the example versions in the issue forms (`.github/ISSUE_TEMPLATE/*.yml`) to the new version and `versionCode`, adds the codename to the list in the release-notes template and, with `--roadmap "" --roadmap-zh "<一句话>"`, puts the version's row at the end of the past-releases tables of `docs/roadmap.md` and `docs/zh/roadmap.md`; the *News* lists it leaves as written, since their lines are milestones and keep their date, version and words for good (`--dry-run` shows the first three lines of every list without writing, and the script says whether this release gets a News line). By hand: the lead paragraph of the `CHANGELOG.md` block and the empty `### Cloud / Runtime / Web / Desktop / Android / iOS / Project` headings for the next *Unreleased*; `docs/releases/v.md` from [docs/release-notes-template.md](docs/release-notes-template.md) (a short story, *Highlights*, *Upgrade Notes*, *Community*, English first and the same in Chinese in a collapsed block, every link checked); a new milestone line for the *News* lists when the release is one, which a major version (`x.0.0`) always is and a smaller one is not (one sentence of about a line, the date in inline code, one emoji, first in the list; the same line in the ten READMEs and on the homepage; the earlier versions' lines stay); the past-releases rows in `docs/roadmap.md` and `docs/zh/roadmap.md` when the script was run without `--roadmap`; any "next release" cell in `docs/parity.md`; `scripts/readme-contributors.py`, so the *Community Contributors* avatars in the ten READMEs are current (`--check` says whether they are). Run the checks for what changed ([AGENTS.md](AGENTS.md); `scripts/rebrand.py` → `clean`, `connectors-json.mjs --check`, `providers-json.mjs --check`, `cd website && npm run docs:build`); the *iOS · build check* workflow runs on the pull request when `android/src/ios/` changed and can be started by hand from the Actions tab otherwise. Merge when green; `M` is the merge commit. 2. **The APK and the GitHub release.** `scripts/release-apk.sh ` at `M` builds the release APK, verifies the signature and writes the sha256; `scripts/release-apk.sh --publish-only --target M` tags `v` on `M` and creates the release (marked Latest; the script also has `--prerelease`, which the project does not use) with `docs/releases/v.md` as the body. *What's Changed*, *New Contributors*, *Contributors* and the *Full Changelog* link are filled in from the pull requests merged since the previous tag by `scripts/release_notes.py` (`scripts/release_notes.py ` shows the body it would publish). The tag starts the desktop, harness, Docker and test workflows; the desktop installers, their `SHA256SUMS-desktop.txt`, the harness tarball and its `SHA256SUMS-harness.txt` are attached to the release by CI as they finish, the Docker image lands on `ghcr.io/nano-muse/nanomuse` as ``, `` and `latest`. Every workflow must end green before the release is announced. The signing key is one key for every version so an update installs over the previous one; it is not in the repository and not in CI. 3. **The relay**, when its version moved: `cloud/deploy/nanomuse-hk/deploy.sh` from the checkout at `M`; `/healthz` must answer with the new version. 4. **TestFlight.** The *iOS · TestFlight* workflow on `main` (or a tag `ios-*`) uploads the build; its number is the run number. Once App Store Connect shows it processed, the external group gets it after Apple's beta review; `docs/releases/v.md` names the build number. [docs/ios.md](docs/ios.md) has the details. diff --git a/scripts/release-apk.sh b/scripts/release-apk.sh index 7d88de003..e3a776401 100755 --- a/scripts/release-apk.sh +++ b/scripts/release-apk.sh @@ -45,8 +45,8 @@ command -v sha256sum >/dev/null 2>&1 || sha256sum() { shasum -a 256 "$@"; } out="$NM_ROOT/dist/nanoMuse-$version-arm64.apk" # Every part of the release carries the same version: the runtime, the desktop app, the web -# app (the APK is checked by badging below). Packages are named after -# these, so one left behind shows up as a wrong file name on the release. +# app, the iPhone app's MARKETING_VERSION (the APK is checked by badging below). Packages are +# named after these, so one left behind shows up as a wrong file name on the release. echo "== versions" versions_ok=1 check_version() { # file, what grep should find in it @@ -58,6 +58,7 @@ check_version web/package.json "\"version\": \"$version\"" check_version CITATION.cff "^version: $version$" check_version harness/dsh-nanomuse/package.json "\"version\": \"$version\"" check_version harness/desktop/package.json "\"version\": \"$version\"" +check_version android/src/ios/Minis.xcodeproj/project.pbxproj "MARKETING_VERSION = $version;" [ $versions_ok = 1 ] || { echo "the versions above disagree — bump them first" >&2; exit 1; } # Signature + badging of one APK; exits on the debug key unless allowed. diff --git a/scripts/release-docs.py b/scripts/release-docs.py index 2972bed4f..b80febfc1 100755 --- a/scripts/release-docs.py +++ b/scripts/release-docs.py @@ -2,6 +2,7 @@ """The release-day edits to the pages that name the current version. scripts/release-docs.py [--dry-run] + [--roadmap "" --roadmap-zh "<一句话>"] scripts/release-docs.py 0.1.40 0.1.41 Clear Still 2026-10-20 - ``CHANGELOG.md``: a ``## [] - · `` heading goes right under @@ -17,8 +18,10 @@ - ``docs/release-notes-template.md``: the new codename joins the list. - ``.github/ISSUE_TEMPLATE/*.yml``: the example versions (``1.0.0 (43)``, ``desktop 1.0.0``) move to the new version and the ``VERSION_CODE`` that ``scripts/rebrand.py`` carries. -- ``docs/roadmap.md`` (the past-releases table) and ``docs/parity.md`` (cells that said "next - release") are edited by hand. +- ``docs/roadmap.md`` and ``docs/zh/roadmap.md``: with ``--roadmap`` and ``--roadmap-zh`` (both + or neither) a row ``| | | |`` goes at the end of the past-releases + table of each; without them the row is written by hand, like the ``docs/parity.md`` cells + that said "next release". ``--dry-run`` writes nothing and prints, for every page with a News list, its first three News lines (unchanged by this script) so the reviewer sees what a new milestone line would go above. @@ -98,6 +101,28 @@ def edit_issue_form(text: str, old: str, new: str, code: str) -> tuple[str, int] return out, n1 + n2 +def add_roadmap_row(text: str, version: str, codename: str, line: str) -> str: + """The roadmap page with ``| version | codename | line |`` as the last row of its + past-releases table (the table whose separator is ``|---|---|---|``). + + Raises ``ValueError`` when the page has no such table or already has a row for the + version; the one line is taken as written, with ``|`` not allowed in it.""" + if "|" in line: + raise ValueError("the roadmap line cannot contain |") + lines = text.split("\n") + try: + start = next(i for i, text_line in enumerate(lines) if text_line.strip() == "|---|---|---|") + except StopIteration: + raise ValueError("no past-releases table (|---|---|---|)") from None + end = start + 1 + while end < len(lines) and lines[end].startswith("|"): + end += 1 + if any(text_line.startswith(f"| {version} |") for text_line in lines[start:end]): + raise ValueError(f"a row for {version} is already there") + lines.insert(end, f"| {version} | {codename} | {line.strip()} |") + return "\n".join(lines) + + def version_code() -> str: """The Android ``VERSION_CODE`` as ``scripts/rebrand.py`` carries it after the bump.""" m = re.search(r"^VERSION_CODE = (\d+)$", Path("scripts/rebrand.py").read_text("utf-8"), re.M) @@ -109,6 +134,18 @@ def version_code() -> str: def main(argv: list[str]) -> int: dry_run = "--dry-run" in argv argv = [a for a in argv if a != "--dry-run"] + roadmap: dict[str, str] = {} + for flag, page in (("--roadmap", "docs/roadmap.md"), ("--roadmap-zh", "docs/zh/roadmap.md")): + if flag in argv: + at = argv.index(flag) + if at + 1 >= len(argv): + print(f"{flag} needs the one line of the row", file=sys.stderr) + return 2 + roadmap[page] = argv[at + 1] + del argv[at : at + 2] + if len(roadmap) == 1: + print("--roadmap and --roadmap-zh go together (one row per language)", file=sys.stderr) + return 2 if len(argv) != 5: print(__doc__.strip().splitlines()[2].strip(), file=sys.stderr) return 2 @@ -154,6 +191,17 @@ def main(argv: list[str]) -> int: if moved: print(f"{name}: {moved} example version(s) now {new} ({code})") + for name, line in roadmap.items(): + p = Path(name) + try: + text = add_roadmap_row(p.read_text(encoding="utf-8"), new, newname, line) + except ValueError as exc: + print(f"{name}: {exc}", file=sys.stderr) + return 1 + if not dry_run: + p.write_text(text, encoding="utf-8") + print(f"{name}: a row for {new} {newname} at the end of the past-releases table") + template = Path("docs/release-notes-template.md") s = template.read_text(encoding="utf-8") if f", {oldname} (CHANGELOG" not in s: @@ -173,12 +221,19 @@ def main(argv: list[str]) -> int: if is_major(new) else "no News line (the News lists are milestones; this is not a major version), " ) + roadmap_note = ( + "" + if roadmap + else "docs/roadmap.md's and docs/zh/roadmap.md's past-releases rows (or run again with " + "--roadmap and --roadmap-zh), " + ) print( ("dry run, nothing written. " if dry_run else "") + "by hand now: " + news - + "the homepage's version line and download links, docs/roadmap.md's past-releases row, " - "docs/parity.md, the empty Unreleased headings in CHANGELOG.md" + + "the homepage's version line and download links, " + + roadmap_note + + "docs/parity.md, the empty Unreleased headings in CHANGELOG.md" ) return 0 diff --git a/tests/test_release_docs.py b/tests/test_release_docs.py index 511d005b6..b10d662ed 100644 --- a/tests/test_release_docs.py +++ b/tests/test_release_docs.py @@ -188,3 +188,72 @@ def test_main_moves_the_issue_forms_but_not_on_a_dry_run( assert release_docs.main(["1.0.0", "1.0.1", "Keel", "Still", "2026-10-20"]) == 0 assert "e.g. 1.0.1 (44)" in form.read_text(encoding="utf-8") + + +ROADMAP = """## Past releases + +| Version | Codename | In one line | +|---|---|---| +| 0.1.41 | Choice | Settings › Models with four rows | +| 1.0.0 | Keel | The first stable version | +""" + + +def test_a_roadmap_row_goes_at_the_end_of_the_past_releases_table( + release_docs: ModuleType, +) -> None: + text = release_docs.add_roadmap_row(ROADMAP, "1.0.1", "Ballast", "The phone app has a scheme") + assert text.endswith( + "| 1.0.0 | Keel | The first stable version |\n" + "| 1.0.1 | Ballast | The phone app has a scheme |\n" + ) + with pytest.raises(ValueError, match="already there"): + release_docs.add_roadmap_row(text, "1.0.1", "Ballast", "again") + with pytest.raises(ValueError, match="no past-releases table"): + release_docs.add_roadmap_row("# Roadmap\n", "1.0.1", "Ballast", "x") + with pytest.raises(ValueError, match="cannot contain"): + release_docs.add_roadmap_row(ROADMAP, "1.0.1", "Ballast", "a | b") + + +def test_main_writes_both_roadmap_rows_or_asks_for_them( + release_docs: ModuleType, + tmp_path: Path, + monkeypatch: pytest.MonkeyPatch, + capsys: pytest.CaptureFixture[str], +) -> None: + monkeypatch.chdir(tmp_path) + _tree(tmp_path) + (tmp_path / "docs" / "roadmap.md").write_text(ROADMAP, encoding="utf-8") + (tmp_path / "docs" / "zh" / "roadmap.md").write_text( + ROADMAP.replace("Version | Codename | In one line", "版本 | 代号 | 一句话"), + encoding="utf-8", + ) + args = ["1.0.0", "1.0.1", "Keel", "Still", "2026-10-20"] + + # one flag without the other is refused before anything is written + assert release_docs.main([*args, "--roadmap", "x"]) == 2 + assert "go together" in capsys.readouterr().err + assert "## [1.0.1]" not in (tmp_path / "CHANGELOG.md").read_text(encoding="utf-8") + + assert release_docs.main([*args, "--roadmap", "One line", "--roadmap-zh", "一句话"]) == 0 + out = capsys.readouterr().out + assert "docs/roadmap.md: a row for 1.0.1 Still" in out + assert "docs/roadmap.md's and docs/zh/roadmap.md's past-releases rows" not in out + assert ( + (tmp_path / "docs" / "roadmap.md") + .read_text(encoding="utf-8") + .endswith("| 1.0.1 | Still | One line |\n") + ) + assert ( + (tmp_path / "docs" / "zh" / "roadmap.md") + .read_text(encoding="utf-8") + .endswith("| 1.0.1 | Still | 一句话 |\n") + ) + + # without the flags the rows are left to hand work, and the message says so + again = tmp_path / "again" + again.mkdir() + monkeypatch.chdir(again) + _tree(again) + assert release_docs.main(["1.0.0", "1.0.2", "Keel", "Trim", "2026-10-21"]) == 0 + assert "run again with --roadmap and --roadmap-zh" in capsys.readouterr().out From 7d2592c98e9772eecaee549e24b308a14bd7a1e1 Mon Sep 17 00:00:00 2001 From: lgy0404 <2528379691@qq.com> Date: Mon, 12 Oct 2026 03:06:47 +0800 Subject: [PATCH 73/98] fix(android): bounded clip import, hub answers on a dropped socket, quotes in strings An own clip was copied in full into the avatar folder and only then measured, so a picker that gave no size could have a long video copied before the refusal; the copy now stops at the first byte over 30 MB, deletes the partial file and refuses, and the preview reads "> 30 MB" when the size is unknown. Picking a second clip no longer deletes the pending file it just imported (same path). A hub call's progress or answer sent after the socket had dropped threw on a worker thread and ended the process; such frames are now logged and dropped. A client stopped for a sign-out or key change no longer reports its own close as the new client's state. aapt drops a bare double quote inside a string, so seven English and eight Chinese strings lost their quotes on screen; escaped in English, typographic in Chinese, and a parity test refuses a bare quote in any locale from now on. The proxy prefs file joins the backup exclusions; docs/android.md no longer speaks of Reach pairing tokens that have not existed since 0.1.24. For #362 Signed-off-by: lgy0404 <2528379691@qq.com> --- CHANGELOG.md | 4 ++ .../java/io/github/nanomuse/avatar/OwnClip.kt | 36 ++++++++--- .../java/io/github/nanomuse/hub/HubClient.kt | 26 ++++++-- .../nanomuse/ui/avatar/OwnClipChooser.kt | 8 ++- .../app/src/main/res/values-zh/nm_strings.xml | 16 ++--- .../app/src/main/res/values/nm_strings.xml | 14 ++--- .../main/res/xml/nanomuse_backup_rules.xml | 2 + .../xml/nanomuse_data_extraction_rules.xml | 4 ++ .../io/github/nanomuse/avatar/OwnClipTest.kt | 56 +++++++++++++++++ .../io/github/nanomuse/hub/HubClientTest.kt | 62 +++++++++++++++++++ .../nanomuse/i18n/NmStringsParityTest.kt | 17 +++++ docs/android.md | 7 ++- docs/zh/android.md | 6 +- 13 files changed, 222 insertions(+), 36 deletions(-) create mode 100644 android/src/android/app/src/test/java/io/github/nanomuse/hub/HubClientTest.kt diff --git a/CHANGELOG.md b/CHANGELOG.md index ac788c4ae..f56120b77 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,10 @@ All notable changes to nanoMuse. The format follows [Keep a Changelog](https://k ### Android +- **A clip of your own stops copying at 30 MB.** The import copied the whole file into the avatar folder and only then checked its size, so a picker that gave no size up front could have a long video copied in full before it was refused; the copy now stops the moment the limit is passed, deletes the partial file and refuses with the usual sentence. The preview's refusal line reads *> 30 MB* when the true size is unknown (#362). +- **Quoted words show their quotes again.** aapt reads a bare `"` inside a string as quoting and drops it, so the empty Permissions and Routines pages read *answer always allow* and *something every morning*, and the avatar studio's lines lost the quotes around the description, in English and in 简体中文; the English strings now escape them and the Chinese ones use “ ”. A unit test refuses a bare quote in any of the seventeen locale files from now on. +- **The hub no longer takes the app down when the socket drops mid-task.** A task another device had running on the phone sent its progress and its answer through the hub socket; if the connection had dropped meanwhile the send threw on a worker thread, which Android treats as a crash. Such frames are now logged and lost (the relay fails the call to its caller on its own), and a client that was stopped for a sign-out or a key change no longer reports its own closing as the state of the new connection. + ### iOS ### Project diff --git a/android/src/android/app/src/main/java/io/github/nanomuse/avatar/OwnClip.kt b/android/src/android/app/src/main/java/io/github/nanomuse/avatar/OwnClip.kt index 267547922..4ec4e1a23 100644 --- a/android/src/android/app/src/main/java/io/github/nanomuse/avatar/OwnClip.kt +++ b/android/src/android/app/src/main/java/io/github/nanomuse/avatar/OwnClip.kt @@ -14,6 +14,7 @@ import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow import java.io.File import java.io.FileOutputStream +import java.io.InputStream /** * A clip of the person's own as the face (#324). One short video, picked from the phone's @@ -174,6 +175,28 @@ object OwnClip { return Probe(container, codec, durationMs, bytes) } + /** + * Copies [input] into [dst], but never more than [limit] bytes: the copy stops as soon as + * the limit is passed, the partial file is deleted and null comes back, so a provider that + * gave no size up front cannot fill the disk with a long clip. Otherwise the byte count. + */ + internal fun copyBounded(input: InputStream, dst: File, limit: Long = MAX_BYTES): Long? { + var copied = 0L + var over = false + val buffer = ByteArray(64 * 1024) + FileOutputStream(dst).use { out -> + while (true) { + val n = input.read(buffer) + if (n < 0) break + if (copied + n > limit) { over = true; break } + out.write(buffer, 0, n) + copied += n + } + } + if (over) { dst.delete(); return null } + return copied + } + /** * The whole import: a look first, and a clip the rule refuses never touches the disk; one it * takes is copied into the avatar directory as a pending file, its first frame decoded, and @@ -185,14 +208,11 @@ object OwnClip { val dst = pendingFile() try { dst.delete() - val copied = context.contentResolver.openInputStream(uri)?.use { input -> - FileOutputStream(dst).use { out -> input.copyTo(out) } - } ?: return Outcome.Failed("cannot open") - if (copied > MAX_BYTES) { - // the provider gave no size up front and the file turned out larger - dst.delete() - return Outcome.Refused(Refusal.TOO_LARGE, probe.copy(bytes = copied)) - } + val input = context.contentResolver.openInputStream(uri) ?: return Outcome.Failed("cannot open") + // The provider gave no size up front (or a wrong one) and the file turned out larger: + // the copy stopped at the limit, so the real size is unknown and stays null. + val copied = input.use { copyBounded(it, dst) } + ?: return Outcome.Refused(Refusal.TOO_LARGE, probe.copy(bytes = null)) val poster = runCatching { val r = MediaMetadataRetriever() try { diff --git a/android/src/android/app/src/main/java/io/github/nanomuse/hub/HubClient.kt b/android/src/android/app/src/main/java/io/github/nanomuse/hub/HubClient.kt index 27a76eee5..6509e406d 100644 --- a/android/src/android/app/src/main/java/io/github/nanomuse/hub/HubClient.kt +++ b/android/src/android/app/src/main/java/io/github/nanomuse/hub/HubClient.kt @@ -48,7 +48,12 @@ data class Device( class HubException(val code: String, message: String) : IOException(message) -/** A call another device made to this phone; answer it exactly once. */ +/** + * A call another device made to this phone; answer it exactly once. A frame that cannot be + * sent because the socket dropped meanwhile is logged and lost, never thrown: the handlers run + * on worker threads and in their own coroutines, where an exception would end the process, and + * the relay fails the call to its caller on its own when no answer arrives. + */ class IncomingCall internal constructor( val id: String, val from: JSONObject, @@ -63,19 +68,27 @@ class IncomingCall internal constructor( val senderKind: String get() = from.optString("kind") fun event(body: JSONObject) { - if (!answered) client.send(JSONObject().put("type", "event").put("id", id).put("body", body)) + if (!answered) trySend(JSONObject().put("type", "event").put("id", id).put("body", body)) } fun result(body: JSONObject) { if (answered) return answered = true - client.send(JSONObject().put("type", "result").put("id", id).put("ok", true).put("body", body)) + trySend(JSONObject().put("type", "result").put("id", id).put("ok", true).put("body", body)) } fun fail(code: String, message: String) { if (answered) return answered = true - client.send(JSONObject().put("type", "result").put("id", id).put("ok", false).put("error", code).put("message", message)) + trySend(JSONObject().put("type", "result").put("id", id).put("ok", false).put("error", code).put("message", message)) + } + + private fun trySend(frame: JSONObject) { + try { + client.send(frame) + } catch (e: HubException) { + AppLogger.info("HubClient", "$action for $senderName: ${frame.optString("type")} not sent, ${e.message}") + } } } @@ -160,8 +173,10 @@ class HubClient( connected = false ws = null failAll("disconnected", "the hub connection dropped") - onState(false, reason) + // A stopped client says nothing more: its own close arrives here a moment after + // stop(), when Hub may already run a new client whose state this would overwrite. if (stopped) return + onState(false, reason) retry?.cancel(false) val wait = maxOf(delayMs, atLeastMs) retry = timer.schedule({ connect() }, wait, TimeUnit.MILLISECONDS) @@ -185,6 +200,7 @@ class HubClient( } override fun onClosed(webSocket: WebSocket, code: Int, reason: String) { + if (stopped) return // our own close after stop(); see scheduleReconnect if (code == 4001 || code == 4002) { // Bad key or bad device: the relay will say the same thing next time. Stop here // and say why; a new sign-in makes a new client. diff --git a/android/src/android/app/src/main/java/io/github/nanomuse/ui/avatar/OwnClipChooser.kt b/android/src/android/app/src/main/java/io/github/nanomuse/ui/avatar/OwnClipChooser.kt index d0744eb75..24505fcd0 100644 --- a/android/src/android/app/src/main/java/io/github/nanomuse/ui/avatar/OwnClipChooser.kt +++ b/android/src/android/app/src/main/java/io/github/nanomuse/ui/avatar/OwnClipChooser.kt @@ -75,7 +75,9 @@ internal fun refusalText(context: Context, why: OwnClip.Refusal, probe: OwnClip. OwnClip.Refusal.TOO_LONG -> context.getString(R.string.nm_own_clip_refused_long, ((probe.durationMs ?: 0L) / 1000L).toInt()) OwnClip.Refusal.TOO_LARGE -> context.getString( R.string.nm_own_clip_refused_large, - android.text.format.Formatter.formatShortFileSize(context, probe.bytes ?: 0L), + // a null size: the copy stopped at the limit, so all that is known is "more than that" + probe.bytes?.let { android.text.format.Formatter.formatShortFileSize(context, it) } + ?: ("> " + android.text.format.Formatter.formatShortFileSize(context, OwnClip.MAX_BYTES)), ) } @@ -95,7 +97,9 @@ fun OwnClipChooserHost(state: OwnClipChooserState) { val outcome = withContext(Dispatchers.IO) { OwnClip.import(context, uri) } busy = false when (outcome) { - is OwnClip.Outcome.Ready -> { pending?.let { OwnClip.discard(it) }; pending = outcome.pending } + // Every pending copy lives at the same path, and the import just replaced it: + // discarding the old one here would delete the new file. + is OwnClip.Outcome.Ready -> pending = outcome.pending is OwnClip.Outcome.Refused -> message = refusalText(context, outcome.why, outcome.probe) is OwnClip.Outcome.Failed -> message = context.getString(R.string.nm_own_clip_unreadable) } diff --git a/android/src/android/app/src/main/res/values-zh/nm_strings.xml b/android/src/android/app/src/main/res/values-zh/nm_strings.xml index d0062d429..f25abaf79 100644 --- a/android/src/android/app/src/main/res/values-zh/nm_strings.xml +++ b/android/src/android/app/src/main/res/values-zh/nm_strings.xml @@ -400,7 +400,7 @@ 虚拟形象大小 - 首页顶部形象的大小。选择"已隐藏"时只显示名字。 + 首页顶部形象的大小。选择“已隐藏”时只显示名字。 小 中 大 @@ -421,11 +421,11 @@ 今天 昨天 今天还没有动态。你提的要求和它做的事会显示在这里。 - 还没有长期批准。对有风险的操作选择"始终允许"后,会列在这里,随时可以撤回。 + 还没有长期批准。对有风险的操作选择“始终允许”后,会列在这里,随时可以撤回。 已始终允许 已始终允许 · %1$s 管理权限 - 还没有每日任务。跟它说"每天早上……",就会出现在这里。 + 还没有每日任务。跟它说“每天早上……”,就会出现在这里。 管理每日任务 SOUL 记忆 @@ -433,21 +433,21 @@ 正在生成选项 正在完成形象 - 正在画四个"%1$s"的样子… - 点一个你喜欢的,或者直接告诉我"第二个"。 + 正在画四个“%1$s”的样子… + 点一个你喜欢的,或者直接告诉我“第二个”。 图片没有生成出来。到 ••• → 形象工坊检查一下图像模型,再试一次。 生图服务现在有点忙,请过一分钟再试。 再来一组 先不换了 第 %1$d 个 重试 - 几个"%1$s"的形象准备好了,选一个你最喜欢的。 - 我这就去画几版"%1$s"。出图需要一点时间,画好了我会告诉你。 + 几个“%1$s”的形象准备好了,选一个你最喜欢的。 + 我这就去画几版“%1$s”。出图需要一点时间,画好了我会告诉你。 再画一轮,稍等一下。 换好了,我的新形象是%1$s。 第 %1$d 个 现在还画不了新形象:%1$s - - %1$s:用户把我的虚拟形象换成了"%2$s"。 + - %1$s:用户把我的虚拟形象换成了“%2$s”。 我的新形象:%1$s,分享给朋友看看。 分享形象 以后再说 diff --git a/android/src/android/app/src/main/res/values/nm_strings.xml b/android/src/android/app/src/main/res/values/nm_strings.xml index 352e1b3a0..1fa03090c 100644 --- a/android/src/android/app/src/main/res/values/nm_strings.xml +++ b/android/src/android/app/src/main/res/values/nm_strings.xml @@ -425,11 +425,11 @@ Today Yesterday Nothing yet today. What you ask for and what the agent does about it shows up here. - No standing approvals. When you answer "always allow" to a risky step, it is listed here and can be revoked. + No standing approvals. When you answer \"always allow\" to a risky step, it is listed here and can be revoked. Always allowed Always allowed · %1$s Manage permissions - No routines yet. Ask the agent for something "every morning" and it will appear here. + No routines yet. Ask the agent for something \"every morning\" and it will appear here. Manage routines SOUL Memory @@ -437,21 +437,21 @@ Generating options Finalizing avatar - Drawing four takes on "%1$s"… - Tap the one you like, or tell me: "the second one". + Drawing four takes on \"%1$s\"… + Tap the one you like, or tell me: \"the second one\". The pictures did not come through. Check the image model under ••• → Avatar studio and try again. The image provider is busy right now; try again in a minute. Again Keep current Option %1$d Retry - Here are a few takes on "%1$s": pick the one you like best. - I\'m drawing a few takes on "%1$s" now. Pictures take a little while; I\'ll tell you when they\'re ready. + Here are a few takes on \"%1$s\": pick the one you like best. + I\'m drawing a few takes on \"%1$s\" now. Pictures take a little while; I\'ll tell you when they\'re ready. One more round, give me a moment. Done, my new look is on. I\'m %1$s now. Option %1$d I can\'t draw a new look yet: %1$s - - %1$s: the user changed my avatar to "%2$s". + - %1$s: the user changed my avatar to \"%2$s\". My new look: %1$s. Have a look. Share avatar Later diff --git a/android/src/android/app/src/main/res/xml/nanomuse_backup_rules.xml b/android/src/android/app/src/main/res/xml/nanomuse_backup_rules.xml index 2b5e441ce..1e50275c9 100644 --- a/android/src/android/app/src/main/res/xml/nanomuse_backup_rules.xml +++ b/android/src/android/app/src/main/res/xml/nanomuse_backup_rules.xml @@ -12,6 +12,8 @@ + + diff --git a/android/src/android/app/src/main/res/xml/nanomuse_data_extraction_rules.xml b/android/src/android/app/src/main/res/xml/nanomuse_data_extraction_rules.xml index 74ed29539..397bb9a30 100644 --- a/android/src/android/app/src/main/res/xml/nanomuse_data_extraction_rules.xml +++ b/android/src/android/app/src/main/res/xml/nanomuse_data_extraction_rules.xml @@ -10,6 +10,8 @@ + + @@ -19,6 +21,8 @@ + + diff --git a/android/src/android/app/src/test/java/io/github/nanomuse/avatar/OwnClipTest.kt b/android/src/android/app/src/test/java/io/github/nanomuse/avatar/OwnClipTest.kt index c302f56ae..8d0849482 100644 --- a/android/src/android/app/src/test/java/io/github/nanomuse/avatar/OwnClipTest.kt +++ b/android/src/android/app/src/test/java/io/github/nanomuse/avatar/OwnClipTest.kt @@ -33,11 +33,25 @@ class OwnClipTest { @Test fun `a clip that rounds down to 15 seconds is taken and 16 seconds is not`() { assertNull(OwnClip.check(ok(durationMs = 15_000L))) + assertNull(OwnClip.check(ok(durationMs = 15_500L))) assertNull(OwnClip.check(ok(durationMs = 15_999L))) assertEquals(Refusal.TOO_LONG, OwnClip.check(ok(durationMs = 16_000L))) assertEquals(Refusal.TOO_LONG, OwnClip.check(ok(durationMs = 60_000L))) } + @Test fun `a picture or a text file has no video track and is a format refusal`() { + // what probe() returns for a JPEG: the retriever gives a container and no length, the extractor no video track + assertEquals(Refusal.FORMAT, OwnClip.check(Probe("image/jpeg", null, null, 300_000L))) + // a text file: nothing can be read of it but its size + assertEquals(Refusal.FORMAT, OwnClip.check(Probe(null, null, null, 12L))) + // an audio-only MP4: a container and a length, but no video track + assertEquals(Refusal.FORMAT, OwnClip.check(Probe("video/mp4", null, 8_000L, 300_000L))) + } + + @Test fun `a HEVC MOV is refused for its codec, not its container`() { + assertEquals(Refusal.FORMAT, OwnClip.check(ok(container = "video/quicktime", codec = "video/hevc"))) + } + @Test fun `30 MB is the largest file taken`() { assertNull(OwnClip.check(ok(bytes = OwnClip.MAX_BYTES))) assertEquals(Refusal.TOO_LARGE, OwnClip.check(ok(bytes = OwnClip.MAX_BYTES + 1))) @@ -69,6 +83,48 @@ class OwnClipTest { assertEquals(Refusal.TOO_LONG, OwnClip.check(ok(durationMs = 60_000L, bytes = OwnClip.MAX_BYTES * 2))) } + // -- the copy ----------------------------------------------------------------------------- + + @Test fun `a file within the limit is copied whole and its size reported`() { + val dst = File(tmp.newFolder(), "pending.mp4") + val bytes = ByteArray(200_000) { (it % 251).toByte() } + assertEquals(200_000L, OwnClip.copyBounded(bytes.inputStream(), dst, limit = 1_000_000L)) + assertTrue(dst.readBytes().contentEquals(bytes)) + } + + @Test fun `a file exactly at the limit is taken`() { + val dst = File(tmp.newFolder(), "pending.mp4") + val bytes = ByteArray(70_000) + assertEquals(70_000L, OwnClip.copyBounded(bytes.inputStream(), dst, limit = 70_000L)) + assertEquals(70_000L, dst.length()) + } + + @Test fun `the copy stops at the limit, deletes the partial file and reads no further`() { + val dst = File(tmp.newFolder(), "pending.mp4") + var served = 0L + val endless = object : java.io.InputStream() { + override fun read(): Int { served++; return 7 } + override fun read(b: ByteArray, off: Int, len: Int): Int { served += len; return len } + } + assertNull(OwnClip.copyBounded(endless, dst, limit = 1_000_000L)) + assertFalse("the partial copy is gone", dst.exists()) + assertTrue("stopped soon after the limit, not at the end of the stream (read $served bytes)", served <= 1_000_000L + 2 * 64 * 1024) + } + + @Test fun `the default limit is the 30 MB rule`() { + val dst = File(tmp.newFolder(), "pending.mp4") + val overLimit = object : java.io.InputStream() { + var left = OwnClip.MAX_BYTES + 1 + override fun read(): Int = if (left-- > 0) 0 else -1 + override fun read(b: ByteArray, off: Int, len: Int): Int { + if (left <= 0) return -1 + val n = minOf(len.toLong(), left).toInt(); left -= n; return n + } + } + assertNull(OwnClip.copyBounded(overLimit, dst)) + assertFalse(dst.exists()) + } + // -- the files ---------------------------------------------------------------------------- private fun pending(root: File, content: String = "clip"): OwnClip.Pending { diff --git a/android/src/android/app/src/test/java/io/github/nanomuse/hub/HubClientTest.kt b/android/src/android/app/src/test/java/io/github/nanomuse/hub/HubClientTest.kt new file mode 100644 index 000000000..e8d79d00a --- /dev/null +++ b/android/src/android/app/src/test/java/io/github/nanomuse/hub/HubClientTest.kt @@ -0,0 +1,62 @@ +package io.github.nanomuse.hub + +import org.json.JSONObject +import org.junit.Assert.assertEquals +import org.junit.Assert.assertFalse +import org.junit.Assert.assertTrue +import org.junit.Test + +/** The client's behaviour apart from the socket: what a call does when the socket is gone. */ +class HubClientTest { + private fun client(onState: (Boolean, String) -> Unit = { _, _ -> }) = HubClient( + url = "wss://relay.example/v1/hub", + key = "nm_test", + hello = { JSONObject() }, + onCall = {}, + onDevices = {}, + onState = onState, + ) + + private fun call(client: HubClient) = IncomingCall( + id = "c1", + from = JSONObject().put("id", "pc-1").put("name", "Desk"), + action = "task", + args = JSONObject(), + client = client, + ) + + @Test fun `an answer on a dropped socket is lost quietly, not thrown`() { + val c = call(client()) + c.event(JSONObject().put("stage", "thinking")) + c.result(JSONObject().put("text", "done")) + assertTrue(c.answered) + c.fail("failed", "late") + assertTrue(c.answered) + } + + @Test fun `a call is answered once`() { + val c = call(client()) + assertFalse(c.answered) + c.fail("not_allowed", "no") + assertTrue(c.answered) + c.result(JSONObject()) + assertTrue(c.answered) + } + + @Test fun `our own call throws disconnected when there is no socket`() { + val states = mutableListOf() + val c = client { _, detail -> states += detail } + val e = runCatching { c.call("pc-1", "info", JSONObject(), timeoutMs = 1_000L) }.exceptionOrNull() + assertTrue(e is HubException) + assertEquals("disconnected", (e as HubException).code) + assertTrue("no state change was reported for a client that never started", states.isEmpty()) + } + + @Test fun `a stopped client reports no state`() { + val states = mutableListOf>() + val c = client { on, detail -> states += on to detail } + c.stop() + assertFalse(c.connected) + assertTrue(states.isEmpty()) + } +} diff --git a/android/src/android/app/src/test/java/io/github/nanomuse/i18n/NmStringsParityTest.kt b/android/src/android/app/src/test/java/io/github/nanomuse/i18n/NmStringsParityTest.kt index edcb8a903..736f9b02f 100644 --- a/android/src/android/app/src/test/java/io/github/nanomuse/i18n/NmStringsParityTest.kt +++ b/android/src/android/app/src/test/java/io/github/nanomuse/i18n/NmStringsParityTest.kt @@ -59,6 +59,23 @@ class NmStringsParityTest { } } + /** + * aapt strips a bare `"` from a string (it reads it as quoting, to keep whitespace), so + * *answer "always allow"* reaches the screen as *answer always allow*. A quote inside a + * string is written `\"`, or as the language's own marks (“” 「」 „“ «»); a string wrapped + * whole in quotes, to keep a trailing space, is the one allowed use. + */ + @Test fun `no bare double quote inside a string`() { + for (f in localeFiles() + File(res, "values/nm_strings.xml")) { + val bare = stringRx.findAll(f.readText()).filter { m -> + val body = m.groupValues[2] + val wrapped = body.length >= 2 && body.startsWith("\"") && body.endsWith("\"") && body.count { it == '"' } == 2 + !wrapped && Regex("""(?(), bare) + } + } + /** The house style: no em dashes in copy; a comma, colon or full stop instead. 非营利 is the word, not 非盈利. */ @Test fun `no em dashes and no 非盈利 in the strings`() { val commentRx = Regex("""""", RegexOption.DOT_MATCHES_ALL) diff --git a/docs/android.md b/docs/android.md index 28ff6045c..d632129ee 100644 --- a/docs/android.md +++ b/docs/android.md @@ -243,8 +243,9 @@ milliseconds. Unit tests: `ProviderReachTest`, `OwnProviderProxyTest`. The relay keeps an account id, a masked identifier, usage counts and the agent's name and look (so your devices match), and message content only as conversation sync, on by default when signed in and switched off under *Data controls* ([privacy.md](privacy.md), -[sync.md](sync.md)); the first conversation says so in its fourth line. On the phone, API keys, the account key and Reach -pairing tokens are in `EncryptedSharedPreferences`; since 0.1.40 the app takes no part in +[sync.md](sync.md)); the first conversation says so in its fourth line. On the phone, API keys and the account key +are in `EncryptedSharedPreferences` (the proxy password of *Settings → Network* is in plain +preferences, on this phone only); since 0.1.40 the app takes no part in the device backup at all (`allowBackup="false"`: chats, memory and keys never go to Google, a reinstall starts empty and the account's chats come back through sync; the two rule files under `res/xml/` are kept for the day the switch is turned on again). Hands needs the accessibility service @@ -319,7 +320,7 @@ like the Python package's version does. | `sync/` | Conversation sync (contracts C7–C10): `SyncEngine` (what goes up and comes down; `owner` per mapping, the account's only), `ConversationSync` (when; `hidden`: the chats of another account, left out of `ChatRepository.observeSessions()`), `LocalChats`, the Room store `nanomuse_sync.db` (with the `session_owners` table of C12) | | `account/` | Contract C12 (0.1.40, [sync.md](sync.md)): `AccountScope` (the rules: whose chat a session is, the account's key, what the lists leave out, what a refused key keeps (`keepOnRefusedKey`: everything, unless the relay says `account_deleted`); unit-tested), `AccountData` (applies them: every chat an owner row, `leave` puts the account's chats, memory, feed, goals, routines, face and preferences aside or deletes them, `enter` brings an account's back). The Library tab follows the same rule: it lists the workspaces of the sessions the chat list shows, so another account's files stay off a shared phone (`library/LibraryIndex.shows`, unit-tested) | | `hub/` | `Hub` (state, device identity, settings), `HubClient` (the socket with backoff; a refused key is retried once a minute and shown as such, a replaced connection waits 30 s, a hub the operator paused waits two minutes and is shown as such), `HubService` (the foreground service), `HubActions` (what other devices may ask this phone; `stop {call | conversation}` ends a task the asking device started here, bookkept in `HubTasks`, unit-tested), `HubErrors` (failures in words) | -| `reach/` | `Computers` (paired computers, tokens in the encrypted store), the offload handler that sends work to a computer | +| `reach/` | `Computers` (the account's devices as the hub lists them, and the calls to them; no pairing and no tokens of its own since 0.1.24), the offload handler that sends work to a computer | | `models/` | Settings → Models behind the screens: `ModelSlots` (the four slots, what each is set to and where that is kept, the groups a picker shows, `followPick` for the chat default, `applyProvider` for the *Use it for* card), `SlotOrder` (the resolution order and the catalogue default, pure Kotlin, unit-tested), `PickerList` (the picker's eight-row groups, their order and the search filter, pure Kotlin, unit-tested) | | `ui/models/` | The Models page, the picker behind each row, the *Use it for* card (`minis://settings/models`) | | `chat/CloudRetry.kt` | *Use nanoMuse Cloud this time*: whether the card offers it and the one-turn provider `ChatViewModel.retryLast` uses | diff --git a/docs/zh/android.md b/docs/zh/android.md index 2165ed482..8975513b8 100644 --- a/docs/zh/android.md +++ b/docs/zh/android.md @@ -192,8 +192,8 @@ base URL(从不包括中继的,从不包括局域网地址)它回答代理 中继保存账号 id、一个打码的标识、用量计数,以及智能体的名字和外观(让你的设备保持一致); 消息内容只以对话同步的形式保存:登录后默认开启,在*数据控制*里关掉([privacy.md](privacy.md)、 -[sync.md](sync.md));第一次对话的第四句话会这么说。在手机上,API key、账号 key 和 Reach 配对令牌放在 -`EncryptedSharedPreferences` 里;从 0.1.40 起 App 完全不参与设备备份(`allowBackup="false"`: +[sync.md](sync.md));第一次对话的第四句话会这么说。在手机上,API key 和账号 key 放在 +`EncryptedSharedPreferences` 里(*设置 → 网络* 的代理密码放在普通偏好里,只在这台手机上);从 0.1.40 起 App 完全不参与设备备份(`allowBackup="false"`: 聊天、记忆和 key 从不上传到 Google,重装后从空白开始,账号的聊天通过同步回来;`res/xml/` 下的 两个规则文件留着,等哪天开关再打开时用)。手需要无障碍服务和悬浮窗权限,两者都可选、都能在 同一屏撤销(首次运行的「手」那一页在 App 标志下面请求这两项,和登录页一样);会发送东西的步骤(点「发送」,或在聊天软件的消息框里按回车)一次一次地审批, @@ -256,7 +256,7 @@ keytool -genkeypair -keystore ~/.nanomuse-release/nanomuse.jks -alias nanomuse \ | `sync/` | 对话同步(契约 C7–C10):`SyncEngine`(什么上传、什么下载;每个映射带 `owner`,只有本账号的)、`ConversationSync`(何时同步;`hidden`:另一个账号的聊天,从 `ChatRepository.observeSessions()` 里排除)、`LocalChats`、Room 存储 `nanomuse_sync.db`(含 C12 的 `session_owners` 表) | | `account/` | 契约 C12(0.1.40,[sync.md](sync.md)):`AccountScope`(规则:一个会话是谁的聊天、账号的 key、列表排除什么、被拒绝的 key 保留什么(`keepOnRefusedKey`:全部保留,除非中继说 `account_deleted`);有单元测试)、`AccountData`(执行规则:每个聊天一行归属记录,`leave` 把账号的聊天、记忆、动态、目标、例程、形象和偏好收起来或删掉,`enter` 把一个账号的东西带回来)。「库」标签遵循同一条规则:只列出聊天列表会显示的那些会话的工作区,共用一台手机时另一个账号的文件不会出现(`library/LibraryIndex.shows`,有单元测试) | | `hub/` | `Hub`(状态、设备身份、设置)、`HubClient`(带退避的 socket;key 被拒绝时每分钟重试一次并如实显示,连接被替换时等 30 秒,运营者暂停 hub 时等两分钟并如实显示)、`HubService`(前台服务)、`HubActions`(其他设备可以让这台手机做什么;`stop {call | conversation}` 结束发起设备在这里启动的任务,由 `HubTasks` 记账,有单元测试)、`HubErrors`(用文字描述的失败) | -| `reach/` | `Computers`(已配对的电脑,令牌在加密存储里)、把工作转交给电脑的处理器 | +| `reach/` | `Computers`(账号的设备,按 hub 列出的样子,以及对它们的调用;0.1.24 起不再有配对,也没有自己的令牌)、把工作转交给电脑的处理器 | | `models/` | 「设置 → 模型」背后的逻辑:`ModelSlots`(四个槽位、各自设成了什么、存在哪里、选择页列出的分组、对话默认的 `followPick`、「用它来做什么」卡片的 `applyProvider`),`SlotOrder`(解析顺序和目录默认,纯 Kotlin,有单元测试),`PickerList`(选择页每组 8 行的折叠、排序和搜索过滤,纯 Kotlin,有单元测试) | | `ui/models/` | 「模型」页、每一行背后的选择页、「用它来做什么」卡片(`minis://settings/models`) | | `chat/CloudRetry.kt` | 「这次改用 nanoMuse Cloud」:卡片何时提供它,以及 `ChatViewModel.retryLast` 这一轮用的服务商 | From ce98e7d9bda7532d183064c3fda2b821ca1b0d74 Mon Sep 17 00:00:00 2001 From: lgy0404 <2528379691@qq.com> Date: Mon, 12 Oct 2026 03:06:47 +0800 Subject: [PATCH 74/98] ci: the phones' catalogue and Ideas copies keep LF too The new Windows job showed it at once: with harness/ checked out as LF and the Android copy of ideas.en.json as CRLF, the byte-for-byte comparison in tests/fences.test.mjs failed. The phones' copies of the desktop's JSON assets now carry the same attribute. No tracked file changes; the index holds LF for all of them. Signed-off-by: lgy0404 <2528379691@qq.com> --- .gitattributes | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.gitattributes b/.gitattributes index 866000e4a..8c3b624d7 100644 --- a/.gitattributes +++ b/.gitattributes @@ -15,3 +15,7 @@ harness/**/*.png binary harness/**/*.webp binary harness/**/*.icns binary harness/**/*.ico binary +# The phones' copies of the desktop's catalogues and Ideas lists: the desktop's tests compare +# them with its own byte for byte (tests/fences.test.mjs), so they keep LF the same way. +android/src/android/app/src/main/assets/nanomuse/*.json text eol=lf +android/src/ios/NanoMuse/Resources/*.json text eol=lf From fbe11486ad86e7bb60f53b89129dba0a60cc38fd Mon Sep 17 00:00:00 2001 From: lgy0404 <2528379691@qq.com> Date: Mon, 12 Oct 2026 03:07:15 +0800 Subject: [PATCH 75/98] fix(runtime): honest risk for standing work, a wider SSRF guard, no secrets in feed errors Findings of the runtime audit that are clearly right to fix: - the reminders, triggers and goals tools declared every action safe; create is moderate now (standing work the model takes up later), so strict mode asks; list, cancel and the goals' bookkeeping stay safe; the Sentinel page says so in English and Chinese - the private-host guard behind web_fetch and the browser lets 100.64.0.0/10 through; it now refuses every address that is not globally routable, with a test over each range - a failed calendar feed put httpx's message, the private link included, into the connections view and the log; it is "HTTP 404" now - app-settings.json is written through a temporary file with mode 0600 and a rename, and a file that cannot be read is named in the log instead of passing for a first start - the endpoints migration keeps a dangling vault reference on the endpoint, so it and the slot agree on "missing" and a key set later mends both; tests for that case, for a slot without a key, and for the atomic write - nanomuse config show masks *_KEY values under an MCP server's env, header values named Authorization or Cookie, and the password in a proxy URL - coding/agents.py reads meta.json as UTF-8 on every platform - the update-check comment, the example config and the configuration page said GitHub every six hours; it is the download index, then GitHub, daily - the Sentinel page named the wrong redaction marker; en dashes in three messages; a docstring that named another product's screen Signed-off-by: lgy0404 <2528379691@qq.com> --- CHANGELOG.md | 7 +++ config/config.example.toml | 2 +- docs/configuration.md | 7 +-- docs/sentinel.md | 8 ++-- docs/zh/configuration.md | 7 +-- docs/zh/sentinel.md | 8 ++-- nanomuse/calendar/feeds.py | 18 +++++++- nanomuse/cli.py | 19 ++++++--- nanomuse/coding/agents.py | 2 +- nanomuse/config.py | 20 ++++++--- nanomuse/server/connections.py | 6 +-- nanomuse/server/endpoints.py | 4 ++ nanomuse/tools/files.py | 2 +- nanomuse/tools/goal_tools.py | 3 ++ nanomuse/tools/reminder_tools.py | 3 ++ nanomuse/tools/trigger_tools.py | 3 ++ nanomuse/tools/web.py | 9 +++- nanomuse/vault/vault.py | 2 +- tests/test_calendar.py | 3 +- tests/test_cli.py | 11 +++++ tests/test_endpoints_api.py | 73 ++++++++++++++++++++++++++++++++ tests/test_memory_goals.py | 17 ++++++++ tests/test_reminders.py | 10 +++-- tests/test_server.py | 18 ++++++++ tests/test_tools.py | 34 +++++++++++++++ tests/test_triggers.py | 11 +++-- 26 files changed, 265 insertions(+), 42 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ac788c4ae..963fd1001 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,13 @@ All notable changes to nanoMuse. The format follows [Keep a Changelog](https://k ### Runtime +- **Creating a reminder, a trigger or a goal counts as a change, not a read.** The `reminders`, `triggers` and `goals` tools declared every action `safe`, the level for reads with no side effect, although each `create` sets up work the model takes up later on its own. `create` is now `moderate`, so `strict` mode asks before a routine, a mail trigger or a goal is set up; `list`, `cancel` and the goals' bookkeeping stay `safe`, and `ask` and `auto` mode behave as before. The risk table in the Sentinel page says so (#385). +- **`web_fetch` and the browser refuse every address that is not globally routable.** The carrier-grade NAT block 100.64.0.0/10, which a Tailscale network or an ISP uses, passed the guard; it is now refused with the loopback, link-local, private, multicast and reserved ranges, in IPv4 and IPv6 and through redirects, and a test pins each range (#385). +- **A calendar feed that fails no longer shows its link.** A private calendar link is a secret, and the status error for a feed that answered 404 or 401 carried the full URL into the connections view and the log; it now reads `HTTP 404`, and any other error has the address taken out (#385). +- **`app-settings.json` is written whole or not at all, and a broken file is reported.** The app's settings were written in place; a crash or a full disk mid-write left a truncated file that the next start read as a first start without a word, and the endpoint migration ran again. The file is now written beside the old one, with owner-only permissions before any content is in it, and renamed over it; a file that cannot be read is named in the log (#385). +- **The endpoints list keeps a chat slot's missing key reference.** On the first start with the list, a chat slot whose key named a vault entry nothing answered became an endpoint that said *no key* while the slot said *missing*, and choosing the endpoint again cleared the slot's reference. The endpoint now carries the same reference, both say *missing*, and a key typed on the endpoint mends both (#385). +- **`nanomuse config show` masks every kind of credential.** A value under an MCP server's `env` whose name ends in `_KEY`, an `Authorization` or `Cookie` header under `extra_headers`, and the password in a proxy URL were printed in full; they are shortened or taken out like the API keys (#385). + ### Web ### Desktop diff --git a/config/config.example.toml b/config/config.example.toml index 0ee315bc4..635cbdb24 100644 --- a/config/config.example.toml +++ b/config/config.example.toml @@ -319,7 +319,7 @@ token = "" # empty → generated once, kept in /server_t approval_timeout = 3600 # seconds an approval card waits before it counts as "deny" cors_origins = [] # only for the Vite dev server of the web app, e.g. ["http://localhost:5173"] max_upload_mb = 25 # largest file the app may attach to a message -update_check = true # say under Settings → About when a newer release is out (GitHub Releases, every 6 h; nothing is sent) +update_check = true # say under Settings → About when a newer release is out (the download index, then GitHub Releases; once a day; nothing is sent) start_grace = 4 # seconds the tools/MCP servers/cloud account may take before the app answers anyway (/api/health names the step still running) # ------------------------------------------------------------------------------ diff --git a/docs/configuration.md b/docs/configuration.md index 1a08b2f1b..93895c5eb 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -442,12 +442,13 @@ token = "" # empty → generated once, stored in /vault.key` (created on first use, mode 600) or `NANOMUSE_VAULT_KEY`. +Config values (the model's key, mail, calendar and contact links, the search key) reference secrets as `{{vault:NAME}}`; the placeholder is what the model sees, and the connector is built with the real value. Tool arguments do **not** carry secrets: no production tool opts in (`accepts_secrets`), so a `{{vault:NAME}}` in a `shell` or `python_execute` call is refused with the reason rather than run with the literal text (a tool of your own may opt in; Sentinel then substitutes immediately before execution). If a secret shows up in any tool's output it is replaced with `[REDACTED:NAME]` before the model reads it. The key is `/vault.key` (created on first use, mode 600) or `NANOMUSE_VAULT_KEY`. ## Audit log @@ -119,7 +119,7 @@ Meta Muse runs each user's agent in its own cloud VM with the Sentinel outside i **Covered** - *The model acting beyond what you asked.* Every tool call goes through the policy; sensitive and dangerous calls stop for a decision; permissions are scoped to a tool and a target and can be revoked. -- *Prompt injection that tries to exfiltrate.* Once private data has been read, egress to any host not on the allowlist asks first, with the destination on the card. `web_fetch` cannot be pointed at loopback, link-local, private or cloud-metadata addresses, including through redirects. +- *Prompt injection that tries to exfiltrate.* Once private data has been read, egress to any host not on the allowlist asks first, with the destination on the card. `web_fetch` cannot be pointed at loopback, link-local, private, carrier-grade NAT (100.64.0.0/10, a Tailscale network) or cloud-metadata addresses, in IPv4 or IPv6, including through redirects. - *The model seeing your secrets.* Keys and passwords live in the encrypted vault and enter tool calls as placeholders; they are substituted after approval and redacted from results. Subprocesses do not inherit credential-looking environment variables, and in the sandbox cannot read the vault, the data directory or anything else under your home. The model never sees the access token of the app. - *Not knowing what happened.* Everything is in `audit.jsonl` and the Activity view. diff --git a/docs/zh/configuration.md b/docs/zh/configuration.md index 633c9403a..d51db94b1 100644 --- a/docs/zh/configuration.md +++ b/docs/zh/configuration.md @@ -442,12 +442,13 @@ token = "" # empty → generated once, stored in /vault.key`(首次使用时创建,权限 600)或 `NANOMUSE_VAULT_KEY`。 +配置值(模型的 key、邮件、日历和联系人的链接、搜索的 key)用 `{{vault:NAME}}` 引用机密;模型看到的是占位符,连接器用真实值构建。工具参数**不**携带机密:没有任何正式工具选择接受(`accepts_secrets`),所以 `shell` 或 `python_execute` 调用里的 `{{vault:NAME}}` 会被拒绝并说明原因,而不是拿字面文本去跑(你自己的工具可以选择接受;哨兵会在执行前一刻替换)。如果某个机密出现在任何工具的输出里,模型读到之前它就被换成 `[REDACTED:NAME]`。密钥是 `/vault.key`(首次使用时创建,权限 600)或 `NANOMUSE_VAULT_KEY`。 ## 审计日志 {#audit-log} @@ -119,7 +119,7 @@ Meta Muse 把每个用户的智能体跑在各自的云端 VM 里,哨兵在 VM **覆盖到的** - *模型做了你没要求的事。* 每个工具调用都过策略;敏感和危险的调用停下来等决定;许可限定在一个工具和一个目标上,可以撤销。 -- *试图外泄数据的提示注入。* 私密数据一旦被读取,外发到白名单之外的任何主机都先询问,目的地写在卡片上。`web_fetch` 不能被指向回环、链路本地、私有或云元数据地址,经重定向也不行。 +- *试图外泄数据的提示注入。* 私密数据一旦被读取,外发到白名单之外的任何主机都先询问,目的地写在卡片上。`web_fetch` 不能被指向回环、链路本地、私有、运营商级 NAT(100.64.0.0/10,例如 Tailscale 网络)或云元数据地址,IPv4 和 IPv6 都一样,经重定向也不行。 - *模型看到你的机密。* key 和密码放在加密的保险库里,以占位符进入工具调用;审批之后才替换,结果里再抹掉。子进程不继承看起来像凭据的环境变量,在沙箱里也读不到保险库、数据目录或你家目录下的任何其他东西。模型永远看不到 App 的访问令牌。 - *不知道发生了什么。* 一切都在 `audit.jsonl` 和「活动」视图里。 diff --git a/nanomuse/calendar/feeds.py b/nanomuse/calendar/feeds.py index 52a30fd9f..e0ff77453 100644 --- a/nanomuse/calendar/feeds.py +++ b/nanomuse/calendar/feeds.py @@ -167,20 +167,34 @@ async def refresh(self, force: bool = False) -> dict[str, Any]: texts: dict[str, str] = {} for feed in self.settings.feeds: state = self.states.setdefault(feed.name, FeedState(feed.name)) + url = "" try: - text = await self._read(self._url(feed.url)) + url = self._url(feed.url) + text = await self._read(url) if "BEGIN:VCALENDAR" not in text[:2000]: raise ValueError("not an iCalendar file (no BEGIN:VCALENDAR)") state.events = parse_ics(text, self.tz, calendar=feed.name) state.error = "" texts[feed.name] = text except (httpx.HTTPError, OSError, ValueError) as exc: - state.error = f"{type(exc).__name__}: {exc}"[:200] + state.error = self._error_text(exc, url or feed.url) logger.warning("calendar feed '{}' failed: {}", feed.name, state.error) state.fetched_at = time.time() self._save_cache(texts) return self.status() + @staticmethod + def _error_text(exc: Exception, url: str) -> str: + """What the status and the log say about a failed feed. A private calendar link is + a secret (whoever has it reads the calendar), and httpx puts the full URL into its + status errors, so the status code stands alone and the address never appears.""" + if isinstance(exc, httpx.HTTPStatusError): + return f"HTTP {exc.response.status_code}" + text = f"{type(exc).__name__}: {exc}" + if url and url in text: + text = text.replace(url, "") + return text[:200] + def status(self) -> dict[str, Any]: return { "enabled": self.settings.enabled, diff --git a/nanomuse/cli.py b/nanomuse/cli.py index f1cf0cf57..7c82a160f 100644 --- a/nanomuse/cli.py +++ b/nanomuse/cli.py @@ -1421,7 +1421,7 @@ def config_init( 'api_key = "${DEEPSEEK_API_KEY}"\n\n[sentinel]\nmode = "ask"\n', "utf-8", ) - console.print(f"wrote [cyan]{path}[/cyan] – edit llm.api_key / model, then run `nanomuse chat`") + console.print(f"wrote [cyan]{path}[/cyan]; edit llm.api_key / model, then run `nanomuse chat`") @config_app.command("show") @@ -1433,19 +1433,28 @@ def config_show(config: ConfigOpt = None) -> None: ) -_SECRET_KEY_RE = re.compile(r"(api_key|password|secret|token|app_key|passwd)$", re.IGNORECASE) +_SECRET_KEY_RE = re.compile( + r"(api_key|password|passwd|secret|token|app_key|authorization|cookie|(^|_)key)$", + re.IGNORECASE, +) def mask_secrets(data: Any) -> Any: """The same structure with every value under a key that names a credential - (``api_key``, ``password``, ``secret``, ``token`` and the like) shortened to its first - and last characters, in every section: the image and video slots, the mail account, - the search connector and the chat channels hold keys too, not only ``[llm]``.""" + (``api_key``, ``password``, ``secret``, ``token``, any ``*_KEY`` an MCP server's ``env`` + carries, an ``Authorization`` header and the like) shortened to its first and last + characters, in every section: the image and video slots, the mail account, the search + connector and the chat channels hold keys too, not only ``[llm]``. A proxy URL keeps + its host and loses its password.""" + from nanomuse.server.connections import mask_proxy + if isinstance(data, dict): out: dict[str, Any] = {} for k, v in data.items(): if isinstance(v, str) and v and _SECRET_KEY_RE.search(str(k)): out[k] = v if v.startswith("{{vault:") else _masked(v) + elif isinstance(v, str) and str(k) == "proxy": + out[k] = mask_proxy(v) else: out[k] = mask_secrets(v) return out diff --git a/nanomuse/coding/agents.py b/nanomuse/coding/agents.py index d437ca7e8..eb8281f8e 100644 --- a/nanomuse/coding/agents.py +++ b/nanomuse/coding/agents.py @@ -420,7 +420,7 @@ def _cursor_cli_meta() -> dict[str, dict[str, Any]]: meta = c / "meta.json" if meta.is_file(): try: - out[c.name] = json.loads(meta.read_text()) + out[c.name] = json.loads(meta.read_text("utf-8")) except (OSError, ValueError): continue return out diff --git a/nanomuse/config.py b/nanomuse/config.py index 098184e74..72cfc9918 100644 --- a/nanomuse/config.py +++ b/nanomuse/config.py @@ -605,8 +605,9 @@ class ServerSettings(BaseModel): cors_origins: list[str] = Field(default_factory=list) # Largest file the app may attach to a message (photos from a phone run 3–12 MB). max_upload_mb: int = 25 - # Ask GitHub Releases (at most every six hours) whether a newer nanoMuse is out, and say so - # under Settings → About. Nothing is downloaded or reported. NANOMUSE_NO_UPDATE_CHECK=1 also turns it off. + # Ask the download mirror's index, then GitHub Releases (once a day, or on "Check now") + # whether a newer nanoMuse is out, and say so under Settings → About. Nothing is downloaded + # or reported. NANOMUSE_NO_UPDATE_CHECK=1 also turns it off. update_check: bool = True # How long the services (tools, MCP servers, the cloud account) may take before the # socket opens anyway; past it the app answers and /api/health names the step still running. @@ -854,19 +855,28 @@ def load_app_settings(data_dir: Path) -> dict[str, Any]: return {} try: data = json.loads(path.read_text("utf-8")) - except (OSError, json.JSONDecodeError): + except (OSError, json.JSONDecodeError) as exc: + # a file that cannot be read is not silently a first start: say so in the log, the + # defaults apply until the next save rewrites it + logger.warning("{} could not be read ({}); the app's settings are ignored", path, exc) return {} return data if isinstance(data, dict) else {} def save_app_settings(data_dir: Path, data: dict[str, Any]) -> None: + """Write the file whole or not at all: a temporary file next to it, mode 0600 before any + content is in it, then renamed over the old one, so a crash mid-write cannot leave a + truncated file that the next start reads as a first start.""" data_dir.mkdir(parents=True, exist_ok=True) path = data_dir / APP_SETTINGS_FILE - path.write_text(json.dumps({"version": 1, **data}, ensure_ascii=False, indent=1), "utf-8") + tmp = path.with_suffix(".tmp") + tmp.touch(mode=0o600, exist_ok=True) + tmp.write_text(json.dumps({"version": 1, **data}, ensure_ascii=False, indent=1), "utf-8") try: - path.chmod(0o600) + tmp.chmod(0o600) except OSError: # pragma: no cover pass + tmp.replace(path) def apply_app_settings(settings: Settings, data: dict[str, Any]) -> None: diff --git a/nanomuse/server/connections.py b/nanomuse/server/connections.py index 463a2bec2..9f9a28cfa 100644 --- a/nanomuse/server/connections.py +++ b/nanomuse/server/connections.py @@ -1,10 +1,10 @@ """Connections: the model, email, the browser and MCP servers, set up from the app. -Muse's Connections screen is where you plug things in and take them out again. Here that -means: non-secret settings go to ``/app-settings.json`` (layered over +The Connections screen is where a person plugs things in and takes them out again. Here +that means: non-secret settings go to ``/app-settings.json`` (layered over ``config.toml`` on every start, for the app and the CLI alike); secrets go straight into the encrypted vault and are referred to as ``{{vault:NAME}}``. Nothing here is ever shown -to the model — it only gets the tools that result. +to the model; it only gets the tools that result. """ from __future__ import annotations diff --git a/nanomuse/server/endpoints.py b/nanomuse/server/endpoints.py index e5b6ba9fc..5ccf86376 100644 --- a/nanomuse/server/endpoints.py +++ b/nanomuse/server/endpoints.py @@ -193,6 +193,10 @@ def migrate(self) -> None: llm["api_key"] = row["api_key"] self.conn.data["llm"] = llm self.conn.settings.llm.api_key = row["api_key"] + else: + # the slot names a vault entry nothing answers: the endpoint keeps the + # same reference, so both say "missing" and setting that entry mends both + row["api_key"] = ref rows.append(row) logger.info("the chat model's endpoint {} is now endpoint number one", base_url) self._write(rows) diff --git a/nanomuse/tools/files.py b/nanomuse/tools/files.py index 0da23ee07..459a83f43 100644 --- a/nanomuse/tools/files.py +++ b/nanomuse/tools/files.py @@ -208,7 +208,7 @@ async def execute( ) break return ToolResult(output=("\n".join(matches) or "(no matches)") + note) - return ToolResult.fail(f"unknown action '{action}' – use read/write/append/list/search") + return ToolResult.fail(f"unknown action '{action}'; use read/write/append/list/search") except (PermissionError, FileNotFoundError, IsADirectoryError, OSError) as exc: return ToolResult.fail(str(exc)) diff --git a/nanomuse/tools/goal_tools.py b/nanomuse/tools/goal_tools.py index 56ddab8ce..83edb197a 100644 --- a/nanomuse/tools/goal_tools.py +++ b/nanomuse/tools/goal_tools.py @@ -74,6 +74,9 @@ def assess(self, args: dict[str, Any]) -> CallAssessment: action = str(args.get("action") or "?") gid = args.get("goal_id") or "" if action == "create": + # a goal is work the model takes up again at every check-in: creating one + # changes state (strict mode asks); the bookkeeping actions stay safe + a.risk = RiskLevel.MODERATE detail = str(args.get("title") or "")[:80] elif action == "update_step": detail = f"{gid} step {args.get('step_index')} → {args.get('status') or 'note'}" diff --git a/nanomuse/tools/reminder_tools.py b/nanomuse/tools/reminder_tools.py index cf9a6365f..673113435 100644 --- a/nanomuse/tools/reminder_tools.py +++ b/nanomuse/tools/reminder_tools.py @@ -59,6 +59,9 @@ def assess(self, args: dict[str, Any]) -> CallAssessment: a = super().assess(args) action = str(args.get("action") or "?") if action == "create": + # a reminder, a routine above all, is work the model does later on its own: + # creating one changes state (strict mode asks); listing and cancelling stay safe + a.risk = RiskLevel.MODERATE when = args.get("repeat") or args.get("at") or "?" detail = f"{when}: {str(args.get('text') or '')[:60]}" elif action == "cancel": diff --git a/nanomuse/tools/trigger_tools.py b/nanomuse/tools/trigger_tools.py index 5eedea37f..0a683ca4e 100644 --- a/nanomuse/tools/trigger_tools.py +++ b/nanomuse/tools/trigger_tools.py @@ -63,6 +63,9 @@ def assess(self, args: dict[str, Any]) -> CallAssessment: a = super().assess(args) action = str(args.get("action") or "?") if action == "create": + # a trigger is standing work: the model acts on it later, in a thread nobody + # may be watching, so creating one changes state (strict mode asks) + a.risk = RiskLevel.MODERATE detail = f"{args.get('kind') or '?'} “{args.get('match') or '*'}”: {str(args.get('text') or '')[:60]}" elif action == "cancel": detail = str(args.get("trigger_id") or "") diff --git a/nanomuse/tools/web.py b/nanomuse/tools/web.py index 86f33b91b..15748138f 100644 --- a/nanomuse/tools/web.py +++ b/nanomuse/tools/web.py @@ -34,7 +34,11 @@ def host_of(url: str) -> str | None: def _is_private_host(host: str) -> bool: - """SSRF guard: refuse loopback / link-local / private ranges.""" + """SSRF guard: refuse every address that is not globally routable: loopback, link-local + (the cloud metadata address among them), the private ranges, the carrier-grade NAT + block 100.64.0.0/10 (a Tailscale or an ISP network), multicast, reserved and + unspecified addresses, in IPv4 and IPv6 alike (IPv4-mapped addresses included). A + name that does not resolve is left to the request, which reports the DNS error.""" if host in ("localhost",) or host.endswith((".local", ".internal", ".localhost")): return True try: @@ -44,7 +48,8 @@ def _is_private_host(host: str) -> bool: for info in infos: ip = ipaddress.ip_address(info[4][0]) if ( - ip.is_private + not ip.is_global + or ip.is_private or ip.is_loopback or ip.is_link_local or ip.is_reserved diff --git a/nanomuse/vault/vault.py b/nanomuse/vault/vault.py index f729e8fca..aca391b24 100644 --- a/nanomuse/vault/vault.py +++ b/nanomuse/vault/vault.py @@ -69,7 +69,7 @@ def _load(self) -> dict[str, str]: raw = self.fernet.decrypt(self.path.read_bytes()) except InvalidToken as exc: raise VaultError( - f"cannot decrypt {self.path} – wrong key? (key file: {self.key_path})" + f"cannot decrypt {self.path}: wrong key? (key file: {self.key_path})" ) from exc data = json.loads(raw.decode("utf-8")) self._cache = {str(k): str(v) for k, v in data.items()} diff --git a/tests/test_calendar.py b/tests/test_calendar.py index 0c0bb24be..af1b5f095 100644 --- a/tests/test_calendar.py +++ b/tests/test_calendar.py @@ -215,7 +215,8 @@ def client(**kwargs: object) -> httpx.AsyncClient: status = await feeds.refresh() good, bad = status["feeds"] assert good["events"] == 6 and not good["error"] - assert bad["events"] == 0 and "404" in bad["error"] + assert bad["events"] == 0 and bad["error"] == "HTTP 404" + assert "missing.ics" not in bad["error"], "a private link never shows in the status" assert len(feeds.agenda(date(2026, 9, 21))) == 1, "the good feed still answers" assert seen[0] == "https://cal.example/good.ics", "a webcal:// link is fetched over https" diff --git a/tests/test_cli.py b/tests/test_cli.py index ade256b0d..5b13434a3 100644 --- a/tests/test_cli.py +++ b/tests/test_cli.py @@ -247,3 +247,14 @@ def test_config_show_masks_every_credential(tmp_path, monkeypatch): "a": {"token": "***"}, "b": [{"client_secret": "xxxx…xx"}], } + # an MCP server's env, a custom header and a proxy with a password hold secrets too + masked = mask_secrets( + { + "env": {"AMAP_KEY": "amap-0123456789", "HOME": "/home/me"}, + "extra_headers": {"Authorization": "Bearer abcdefghijkl"}, + "proxy": "http://user:hunter2@proxy.example:3128", + } + ) + assert masked["env"] == {"AMAP_KEY": "amap…89", "HOME": "/home/me"} + assert masked["extra_headers"] == {"Authorization": "Bear…kl"} + assert "hunter2" not in masked["proxy"] and "proxy.example:3128" in masked["proxy"] diff --git a/tests/test_endpoints_api.py b/tests/test_endpoints_api.py index 4a1637486..5fdf6129d 100644 --- a/tests/test_endpoints_api.py +++ b/tests/test_endpoints_api.py @@ -8,6 +8,7 @@ from __future__ import annotations import json +import sys from collections.abc import Iterator from pathlib import Path @@ -290,6 +291,78 @@ def test_the_single_custom_slot_is_migrated_once(settings: Settings, listed): assert [e["id"] for e in _endpoints(client2)] == [one["id"]] +def test_migration_keeps_a_dangling_key_reference_and_takes_a_slot_without_a_key( + settings: Settings, listed +): + """Two edges of the first start: a chat slot whose key names a vault entry nothing + answers (the vault was lost, or the key never set) becomes an endpoint that says + ``missing`` just as the slot does, and a key set on the endpoint later mends both; a slot + with no key at all becomes an endpoint with none.""" + _app_settings( + settings, + { + "provider": "openai", + "model": "my-model", + "base_url": GATEWAY, + "api_key": "{{vault:LLM_API_KEY}}", + }, + ) + client, service = _make(settings) + with client: + (one,) = _endpoints(client) + assert one["key_source"] == "missing" and one["slots"] == ["chat"] + assert client.get("/api/connections").json()["llm"]["key_source"] == "missing" + assert service.app.vault.get(key_name(one["id"])) is None + saved = load_app_settings(settings.data_dir) + assert saved["endpoints"][0]["api_key"] == "{{vault:LLM_API_KEY}}" + assert saved["llm"]["api_key"] == "{{vault:LLM_API_KEY}}" + # a key typed on the endpoint goes to its own entry and the chat slot follows + mended = client.put( + f"/api/connections/endpoints/{one['id']}", json={"api_key": "sk-found-again"} + ) + assert mended.status_code == 200 and mended.json()["key_source"] == "vault" + assert service.app.vault.get(key_name(one["id"])) == "sk-found-again" + assert settings.llm.api_key == "{{vault:" + key_name(one["id"]) + "}}" + assert client.get("/api/connections").json()["llm"]["key_source"] == "vault" + # taking the key away again: the endpoint and the slot both have none + cleared = client.put(f"/api/connections/endpoints/{one['id']}", json={"api_key": ""}) + assert cleared.status_code == 200 and cleared.json()["key_source"] == "none" + assert service.app.vault.get(key_name(one["id"])) is None + assert settings.llm.api_key == "" + assert client.get("/api/connections").json()["llm"]["key_source"] == "none" + + other = Settings() + other.data_dir = settings.data_dir.parent / "no-key" + other.agent.workspace = settings.data_dir.parent / "no-key-ws" + other.llm.stream = False + other.ensure_dirs() + _app_settings(other, {"provider": "openai", "model": "local-model", "base_url": SECOND}) + client2, service2 = _make(other) + with client2: + (row,) = _endpoints(client2) + assert row["base_url"] == SECOND and row["key_source"] == "none" + assert row["models"] == ["local-model"] and row["slots"] == ["chat"] + assert [n for n in service2.app.vault.names() if n.startswith("ENDPOINT_")] == [] + + +def test_app_settings_are_written_whole_and_private(settings: Settings, listed): + """``app-settings.json`` is written whole or not at all: after a save the file parses, + no temporary file is left next to it, and it is readable by its owner only (where the + platform keeps modes).""" + client, _ = _make(settings) + with client: + added = client.post( + "/api/connections/endpoints", + json={"base_url": GATEWAY, "api_key": "sk-gateway-1"}, + ) + assert added.status_code == 200 + path = settings.data_dir / "app-settings.json" + assert json.loads(path.read_text("utf-8"))["endpoints"][0]["base_url"] == GATEWAY + assert not path.with_suffix(".tmp").exists() + if sys.platform != "win32": + assert path.stat().st_mode & 0o777 == 0o600 + + def test_a_catalogue_slot_or_a_config_slot_is_not_migrated(settings: Settings, tmp_path: Path): _app_settings( settings, diff --git a/tests/test_memory_goals.py b/tests/test_memory_goals.py index 1e66deef8..edac97cfe 100644 --- a/tests/test_memory_goals.py +++ b/tests/test_memory_goals.py @@ -163,6 +163,23 @@ def test_goals_lifecycle(tmp_path: Path): assert store.delete(goal.id) and store.get(goal.id) is None +def test_goals_tool_rates_creating_a_goal_as_a_change(tmp_path: Path): + """A goal is work the model takes up again at every check-in, so creating one is + ``moderate`` (strict mode asks); reading and bookkeeping stay ``safe``.""" + from nanomuse.schema import RiskLevel + from nanomuse.tools import Goals + + tool = Goals(store=GoalStore(tmp_path / "g.db")) + assert tool.assess({"action": "create", "title": "Sell my old car"}).risk == RiskLevel.MODERATE + for args in ( + {"action": "list"}, + {"action": "get", "goal_id": "g_1"}, + {"action": "update_step", "goal_id": "g_1", "step_index": 1, "status": "done"}, + {"action": "note", "goal_id": "g_1", "note": "buyer asked"}, + ): + assert tool.assess(args).risk == RiskLevel.SAFE, args + + def test_goal_categories_due_dates_and_check_ins(tmp_path: Path): from datetime import UTC, datetime, timedelta diff --git a/tests/test_reminders.py b/tests/test_reminders.py index 9d95261d4..fd4c37aa7 100644 --- a/tests/test_reminders.py +++ b/tests/test_reminders.py @@ -7,6 +7,7 @@ import pytest from nanomuse.reminders import ReminderStore, parse_when +from nanomuse.schema import RiskLevel from nanomuse.tools import Reminders @@ -99,7 +100,10 @@ def test_reminders_tool(tmp_path: Path): assert r.ok and r.output.startswith("Cancelled.") and len(changes) == 3 r = run(tool.execute(action="cancel", reminder_id=item.id)) assert not r.ok - assert tool.assess({"action": "create", "text": "call mum", "at": soon}).summary.startswith( - f"reminders create: {soon}" - ) + create = tool.assess({"action": "create", "text": "call mum", "at": soon}) + assert create.summary.startswith(f"reminders create: {soon}") + # creating standing work is a change of state; listing and cancelling are not + assert create.risk == RiskLevel.MODERATE + assert tool.assess({"action": "list"}).risk == RiskLevel.SAFE + assert tool.assess({"action": "cancel", "reminder_id": "r_x"}).risk == RiskLevel.SAFE store.close() diff --git a/tests/test_server.py b/tests/test_server.py index 164092140..e870113b2 100644 --- a/tests/test_server.py +++ b/tests/test_server.py @@ -1321,6 +1321,24 @@ def test_app_settings_are_layered_on_config(server, settings: Settings): assert fresh.connectors.email.imap_host == "imap.x" and fresh.browser.enabled is True +def test_a_broken_app_settings_file_is_reported_not_silently_a_first_start(tmp_path: Path): + from loguru import logger + + from nanomuse.config import load_app_settings + + data_dir = tmp_path / "data" + data_dir.mkdir() + (data_dir / "app-settings.json").write_text('{"version": 1, "llm": {"model": "m2"', "utf-8") + lines: list[str] = [] + sink = logger.add(lambda m: lines.append(str(m)), level="WARNING") + try: + assert load_app_settings(data_dir) == {} + assert load_app_settings(tmp_path / "nowhere") == {}, "no file is a quiet first start" + finally: + logger.remove(sink) + assert len(lines) == 1 and "app-settings.json" in lines[0], lines + + def test_files_are_scoped_to_workspace(server, settings: Settings): client, _, _ = server (settings.agent.workspace / "notes").mkdir() diff --git a/tests/test_tools.py b/tests/test_tools.py index 9978a51df..5b4c36325 100644 --- a/tests/test_tools.py +++ b/tests/test_tools.py @@ -1,5 +1,6 @@ from __future__ import annotations +import contextlib import socket import sys from pathlib import Path @@ -305,6 +306,39 @@ def handler(request: httpx.Request) -> httpx.Response: await fetch_public(url, timeout=5, transport=transport) +def test_private_host_guard_refuses_every_non_global_address(): + """Numeric literals go to the resolver as they are, so the guard's answer depends on the + address alone: every range that is not globally routable is refused, the carrier-grade + NAT block (a Tailscale network) and IPv4-mapped IPv6 addresses among them; decimal and + IPv6 spellings of loopback count as loopback.""" + from nanomuse.tools.web import _is_private_host + + refused = [ + "127.0.0.1", + "10.1.2.3", + "172.16.0.9", + "192.168.1.1", + "169.254.169.254", + "100.64.0.1", + "0.0.0.0", + "224.0.0.1", + "240.0.0.1", + "::1", + "::ffff:127.0.0.1", + "::ffff:10.0.0.1", + "fe80::1", + "fd00::1", + ] + for host in refused: + assert _is_private_host(host), host + # 127.0.0.1 written as one number: loopback where the platform's resolver reads it so + with contextlib.suppress(socket.gaierror): + socket.getaddrinfo("2130706433", None) + assert _is_private_host("2130706433") + assert not _is_private_host("93.184.216.34") + assert not _is_private_host("2606:2800:220:1:248:1893:25c8:1946") + + async def test_web_fetch_stops_reading_at_the_body_cap(monkeypatch: pytest.MonkeyPatch): from nanomuse.tools import web as web_mod diff --git a/tests/test_triggers.py b/tests/test_triggers.py index f47e63e92..98570d528 100644 --- a/tests/test_triggers.py +++ b/tests/test_triggers.py @@ -8,6 +8,7 @@ import pytest +from nanomuse.schema import RiskLevel from nanomuse.tools import Triggers from nanomuse.triggers import TriggerStore, matches @@ -113,10 +114,14 @@ def test_triggers_tool(tmp_path: Path): assert store.active("hook") == [] and changes == [1, 1, 1] assert run(tool.execute(action="rename")).error - summary = tool.assess( + create = tool.assess( {"action": "create", "kind": "mail", "match": "landlord", "text": "draft a reply"} - ).summary - assert summary == "triggers create: mail “landlord”: draft a reply" + ) + assert create.summary == "triggers create: mail “landlord”: draft a reply" + # creating standing work is a change of state; listing and cancelling are not + assert create.risk == RiskLevel.MODERATE + assert tool.assess({"action": "list"}).risk == RiskLevel.SAFE + assert tool.assess({"action": "cancel", "trigger_id": "t_x"}).risk == RiskLevel.SAFE store.close() From ba49887d76b7c01884d4b6a8b9ee6f4bdefcb704 Mon Sep 17 00:00:00 2001 From: lgy0404 <2528379691@qq.com> Date: Mon, 12 Oct 2026 03:07:22 +0800 Subject: [PATCH 76/98] docs(own-key): the Hands model row is a picker of the endpoint's models, not a typed id The web console paragraph under Local models said to type the model id on the Hands model row; that row is a ModelPicker fed by the endpoint's /models list and has no typed-id row. Both languages say to pick it there. Signed-off-by: lgy0404 <2528379691@qq.com> --- docs/own-key.md | 3 ++- docs/zh/own-key.md | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/docs/own-key.md b/docs/own-key.md index b49a2af53..559313461 100644 --- a/docs/own-key.md +++ b/docs/own-key.md @@ -267,7 +267,8 @@ Ollama, LM Studio and vLLM on your own computer work too: pick the preset (`http://127.0.0.1:11434/v1`, `:1234`, `:8000`) and no key is needed. They count as *chat*; the hands need a model that sees, so run a multimodal one locally (Ollama's `qwen3-vl`, say) and pick it under *Operating the screen* -(web console: type its id on the *Hands model* row). Pictures and clips need +(web console: the *Hands model* row under *Chat model* lists what the endpoint +serves; pick it there). Pictures and clips need one of the providers in the table. ## Any other OpenAI-compatible endpoint diff --git a/docs/zh/own-key.md b/docs/zh/own-key.md index 910257cf6..3f0b02d11 100644 --- a/docs/zh/own-key.md +++ b/docs/zh/own-key.md @@ -123,7 +123,7 @@ ChatGPT 登录走的是 OpenAI 自家 Codex 的授权流程(网页控制台: ## 本机模型 {#local-models} -Ollama、LM Studio、vLLM 跑在自己电脑上的模型也能用:选对应的预设(网页控制台:「连接」;桌面版:设置 → nanoMuse Cloud;手机:设置 → 服务商),地址默认是本机端口(`http://127.0.0.1:11434/v1`、`:1234`、`:8000`),不需要 key。它们算「对话」;手的模型要能看图,本机跑一个多模态模型(例如 Ollama 的 `qwen3-vl`)再在「操作屏幕」里选它(网页控制台:在「手的模型」里手填 id)。画图和视频需要上面表里的一家。 +Ollama、LM Studio、vLLM 跑在自己电脑上的模型也能用:选对应的预设(网页控制台:「连接」;桌面版:设置 → nanoMuse Cloud;手机:设置 → 服务商),地址默认是本机端口(`http://127.0.0.1:11434/v1`、`:1234`、`:8000`),不需要 key。它们算「对话」;手的模型要能看图,本机跑一个多模态模型(例如 Ollama 的 `qwen3-vl`)再在「操作屏幕」里选它(网页控制台:「对话模型」下面的「动手模型」一行列出这个端点提供的模型,在那里选它)。画图和视频需要上面表里的一家。 ## 其他 OpenAI 兼容服务 {#any-other-openai-compatible-endpoint} From 2ffe313fa3bfe98b6f8f26c3768ff78f2f4ede8f Mon Sep 17 00:00:00 2001 From: lgy0404 <2528379691@qq.com> Date: Mon, 12 Oct 2026 03:07:24 +0800 Subject: [PATCH 77/98] ci: a change to config/ runs the Python checks config/config.example.toml is read by tests/test_voice.py and nanomuse/cli.py and copied into the Docker image, but the "what changed" filter of ci.yml did not list config/, so a pull request that only edited the example configuration skipped the Python matrix and the image build. Signed-off-by: lgy0404 <2528379691@qq.com> --- .github/workflows/ci.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 5aa75a8d6..3c6e4029c 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -35,6 +35,7 @@ jobs: - "nanomuse/**" - "tests/**" - "scripts/**" + - "config/**" # config.example.toml: the tests read it, the image carries it - "pyproject.toml" - "Dockerfile" - ".dockerignore" From 5f38c690a8cc05be5241b1214ecb544d750232cd Mon Sep 17 00:00:00 2001 From: lgy0404 <2528379691@qq.com> Date: Mon, 12 Oct 2026 03:08:08 +0800 Subject: [PATCH 78/98] docs(changelog): the audit bullets carry their pull request number Signed-off-by: lgy0404 <2528379691@qq.com> --- CHANGELOG.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0d8c5d8af..2d72d1bf6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,12 +8,12 @@ All notable changes to nanoMuse. The format follows [Keep a Changelog](https://k ### Runtime -- **Creating a reminder, a trigger or a goal counts as a change, not a read.** The `reminders`, `triggers` and `goals` tools declared every action `safe`, the level for reads with no side effect, although each `create` sets up work the model takes up later on its own. `create` is now `moderate`, so `strict` mode asks before a routine, a mail trigger or a goal is set up; `list`, `cancel` and the goals' bookkeeping stay `safe`, and `ask` and `auto` mode behave as before. The risk table in the Sentinel page says so (#385). -- **`web_fetch` and the browser refuse every address that is not globally routable.** The carrier-grade NAT block 100.64.0.0/10, which a Tailscale network or an ISP uses, passed the guard; it is now refused with the loopback, link-local, private, multicast and reserved ranges, in IPv4 and IPv6 and through redirects, and a test pins each range (#385). -- **A calendar feed that fails no longer shows its link.** A private calendar link is a secret, and the status error for a feed that answered 404 or 401 carried the full URL into the connections view and the log; it now reads `HTTP 404`, and any other error has the address taken out (#385). -- **`app-settings.json` is written whole or not at all, and a broken file is reported.** The app's settings were written in place; a crash or a full disk mid-write left a truncated file that the next start read as a first start without a word, and the endpoint migration ran again. The file is now written beside the old one, with owner-only permissions before any content is in it, and renamed over it; a file that cannot be read is named in the log (#385). -- **The endpoints list keeps a chat slot's missing key reference.** On the first start with the list, a chat slot whose key named a vault entry nothing answered became an endpoint that said *no key* while the slot said *missing*, and choosing the endpoint again cleared the slot's reference. The endpoint now carries the same reference, both say *missing*, and a key typed on the endpoint mends both (#385). -- **`nanomuse config show` masks every kind of credential.** A value under an MCP server's `env` whose name ends in `_KEY`, an `Authorization` or `Cookie` header under `extra_headers`, and the password in a proxy URL were printed in full; they are shortened or taken out like the API keys (#385). +- **Creating a reminder, a trigger or a goal counts as a change, not a read.** The `reminders`, `triggers` and `goals` tools declared every action `safe`, the level for reads with no side effect, although each `create` sets up work the model takes up later on its own. `create` is now `moderate`, so `strict` mode asks before a routine, a mail trigger or a goal is set up; `list`, `cancel` and the goals' bookkeeping stay `safe`, and `ask` and `auto` mode behave as before. The risk table in the Sentinel page says so (#387). +- **`web_fetch` and the browser refuse every address that is not globally routable.** The carrier-grade NAT block 100.64.0.0/10, which a Tailscale network or an ISP uses, passed the guard; it is now refused with the loopback, link-local, private, multicast and reserved ranges, in IPv4 and IPv6 and through redirects, and a test pins each range (#387). +- **A calendar feed that fails no longer shows its link.** A private calendar link is a secret, and the status error for a feed that answered 404 or 401 carried the full URL into the connections view and the log; it now reads `HTTP 404`, and any other error has the address taken out (#387). +- **`app-settings.json` is written whole or not at all, and a broken file is reported.** The app's settings were written in place; a crash or a full disk mid-write left a truncated file that the next start read as a first start without a word, and the endpoint migration ran again. The file is now written beside the old one, with owner-only permissions before any content is in it, and renamed over it; a file that cannot be read is named in the log (#387). +- **The endpoints list keeps a chat slot's missing key reference.** On the first start with the list, a chat slot whose key named a vault entry nothing answered became an endpoint that said *no key* while the slot said *missing*, and choosing the endpoint again cleared the slot's reference. The endpoint now carries the same reference, both say *missing*, and a key typed on the endpoint mends both (#387). +- **`nanomuse config show` masks every kind of credential.** A value under an MCP server's `env` whose name ends in `_KEY`, an `Authorization` or `Cookie` header under `extra_headers`, and the password in a proxy URL were printed in full; they are shortened or taken out like the API keys (#387). ### Web From af3b8649bce045bac0ac2d3eeee903cfa4ab5343 Mon Sep 17 00:00:00 2001 From: lgy0404 <2528379691@qq.com> Date: Mon, 12 Oct 2026 03:10:47 +0800 Subject: [PATCH 79/98] docs(app): the account, hub, hands and bridge routes in the API table Twenty-one routes of nanomuse serve were on no page: the nanoMuse Cloud account (/api/cloud and its sign-in, password, sessions, events, data controls and model switch), this device on the hub (/api/hub, join, leave, refresh, forget a device, ask a device), this computer's hands (/api/hands, PUT /api/connections/hands, /api/hands/stop) and GET /api/bridge/tools. Each gets a row with its body, its answer and its error codes, read from the handlers, in the English table and the Chinese one. Signed-off-by: lgy0404 <2528379691@qq.com> --- docs/app.md | 22 ++++++++++++++++++++++ docs/zh/app.md | 22 ++++++++++++++++++++++ 2 files changed, 44 insertions(+) diff --git a/docs/app.md b/docs/app.md index 03da2c449..36ce8432e 100644 --- a/docs/app.md +++ b/docs/app.md @@ -194,6 +194,9 @@ Everything the app does goes through this API, so another front-end (a Telegram | PUT | `/api/connections/gui` `{enabled, provider, model, base_url, api_key}` | operating the phone ([gui.md](gui.md)): the switch adds or removes the phone tools at once; the model fields are the operator's own model (`""` → the main model's); `api_key` set → vault (`GUI_API_KEY`), `""` → the main key, omitted → unchanged. `endpoint` instead of `provider` / `base_url` / `api_key` names an endpoint of the list, as for the chat model; so do `PUT /api/connections/image` and `/video` | | POST | `/api/connections/gui/test` | one short round trip to the operator's model: `{ok, reply, ms}` or `{ok: false, error}` | | GET | `/api/phone` | `{connected, device{id, name, platform, gui, apps, width, height}, gui_enabled, last_screen, screen}`: which phone is connected and the last screen it sent | +| GET | `/api/hands` | this computer's own screen and hands ([gui.md](gui.md)): `{enabled, available, backend, reason, mode, coords, screen_size, picture_size, window{available, reason, active, app, title, frame}, device, task_active, task_text, last_screen}`; on a phone `{enabled: false, available: false, reason}` | +| PUT | `/api/connections/hands` `{enabled, backend (auto · desktop · pyautogui · xdotool), mode (auto · screen · window)}` | the switch for this computer's hands and which backend drives them; omitted fields stay; 400 for an unknown backend or mode. Answers the view above | +| POST | `/api/hands/stop` | *Stop* on the Hands card: the task on this computer's screen ends at its next step; `{stopped}` | | POST · DELETE | `/api/connections/mcp` `{name, command, args[], env{}, url, risk}` · `/api/connections/mcp/{name}` | connect a server now (502 if it does not come up) / disconnect and remove one added from the app | | GET | `/api/skills` | `{count, built_in, yours, dir, errors{}, skills[{name, description, source (built-in · yours), enabled, path, files[], metadata{}, channel, updated_at}]}` | | GET / PUT / DELETE | `/api/skills/{name}` | one skill with `body` and `content` (the whole `SKILL.md`) / write it from `{content}` (a built-in name creates your copy) / delete one of yours | @@ -210,6 +213,25 @@ Everything the app does goes through this API, so another front-end (a Telegram | GET / PUT | `/api/sync/state` · `{enabled}` | conversations synced between the account's devices ([every-device.md](every-device.md#the-same-conversations-everywhere)): `{enabled, available, paused, cursor, last_pull_at, last_push_at, error, relay}`; `available` is "signed in and the setting allows it", `paused` is set after a 401 until the next sign-in, `relay` is the relay's own `{enabled, cursor, counts{conversations, messages}, limits}` or `null` when it could not be asked. `PUT {enabled: false}` turns it off here and deletes what the relay holds for the account (the other devices' switches follow at their next push or pull, which the relay refuses with `sync_off`); `PUT {enabled: true}` turns it on again and pushes the chats here. A relay refusal comes back as its status and code (`409 sync_off`). Since 0.1.38 the state also carries `side_chats` (this device's *Also sync side chats*, off by default: only the main conversation is pushed and pulled) and `working` (`[{thread, cid, device, device_name, at}]`: the other devices answering right now, from the hub's `working` frames, each entry dropped after ten minutes); `PUT {side_chats: true}` sends this device's side chats up and pulls the account's once from the start, `false` keeps them local from then on | | POST | `/api/sync/delete` | delete every synced conversation on the relay, switch left as it is; returns the state | | POST | `/api/sync/pull` | fetch and apply the other devices' changes now: `{applied, …state}` | +| GET | `/api/cloud` | the nanoMuse Cloud account as the app shows it: `{base_url, signed_in, required, models, hint, channel, signed_in_at, has_password, account_id, member, any_model, region, is_model}` ([cloud.md](cloud.md)). Every `/api/cloud/*` route below answers a relay refusal with the relay's status, its sentence, and the code in the `X-Nanomuse-Code` header; 401 `bad_key` when no account is signed in | +| GET | `/api/cloud/config` | the relay's public figures (the allowance a new account gets, the invite bonus, whether sign-up is open, the repository to star); `{}` from an older relay or none | +| POST | `/api/cloud/code` `{identifier}` | send a sign-in code to an e-mail address or a phone number; `{ok}` | +| POST | `/api/cloud/verify` `{identifier, code, invite?}` | sign in with the code (an invite code on a first sign-up); answers the relay's `/v1/me` and refreshes the nudges policy | +| POST | `/api/cloud/login` `{identifier, password}` | sign in with the account's password; answers as `verify` does | +| POST | `/api/cloud/password` `{password, current?}` | set or change the password (`current` when one is set, unless the key came from a code sign-in just now; an empty `password` with `current` removes it) | +| GET | `/api/cloud/me` | the account as the relay sees it now (`/v1/me`), nudges policy refreshed on the way | +| GET · DELETE | `/api/cloud/sessions` · `/api/cloud/sessions/{prefix}` | the account's sign-ins on every device / revoke one by the prefix the list shows; both answer `{sessions}` | +| POST | `/api/cloud/sign-out` · `/api/cloud/sign-out-all` `{all}` | sign this device out / revoke every other device's sign-in (`all: true` this one too, `{signed_out}` with the account view) | +| GET | `/api/cloud/events?limit=` | the account's activity log from the relay: `{events}` | +| POST | `/api/cloud/models` `{on}` | *Use nanoMuse Cloud models*: off, the account's models leave the automatic order of the hands, pictures and clips and the providers' listing; the sign-in stays. 409 `chat_on_cloud` while the chat model is the account's | +| POST | `/api/cloud/use-as-model` `{model?}` | make the account the chat model: the recommended model unless one is named, the Cloud key from the vault; switches the account's models back on. Answers the connections view's `llm` | +| POST · DELETE | `/api/cloud/contribute` `{on}` · `/api/cloud/samples` | data controls: *Help improve nanoMuse's AI models* on or off (the relay keeps chat turns only while it is on) / delete what it kept, `{deleted}` | +| POST | `/api/cloud/delete` | delete the account on the relay and sign out here; answers the account view | +| GET / PUT | `/api/hub` · `{enabled, remote_control, name}` | this device on the account's hub ([hub.md](hub.md)): `{enabled, remote_control, state, detail, device{id, name, kind, actions}, devices[], account}` / join or leave, allow or refuse remote control, rename this device (60 characters at most) | +| POST | `/api/hub/join` · `/api/hub/leave` · `/api/hub/refresh` | join (401 when no account is signed in) / leave / ask the relay for the device list again; each answers the hub view | +| DELETE | `/api/hub/devices/{device_id}` | forget a device of the account; 502 when the hub is not connected | +| POST | `/api/hub/ask` `{device, text?}` | the side chat addressed to a device (by id or name; created if needed) and, with `text`, the first message in it, which runs on that device: `{thread, event}`; 404 for no such device | +| GET | `/api/bridge/tools` | for a command the agent runs, not the app: the device tools `nanomuse-device list` prints, `{ok, tools[{name, description}]}`. No app token; the call token the shell tool minted comes in `X-Nanomuse-Bridge` (401 otherwise), as for `POST /api/bridge/{kind}` ([local-runtime.md](local-runtime.md)) | | GET | `/api/browser/{thread}/frames/{id}.jpg` | a browser frame (JPEG, in memory for the current session) | | POST | `/api/browser/{thread}/control` `{action: click(x,y as 0–1 fractions) · type(text) · key(key) · scroll(dy) · navigate(url) · look · handed_back}` | you drive the agent's browser; `handed_back` is what the Android app sends when you close its take-over sheet (a fresh frame, the agent told); `409` when the browser is not open (open a URL first) | | GET | `/api/push` | `{available, public_key, subscriptions, devices[]}`: the VAPID public key to subscribe with | diff --git a/docs/zh/app.md b/docs/zh/app.md index 96a64bd0e..176039cda 100644 --- a/docs/zh/app.md +++ b/docs/zh/app.md @@ -192,6 +192,9 @@ Meta 的 Muse「自己会做事,但不会做太多」。「设置」里的*主 | PUT | `/api/connections/gui` `{enabled, provider, model, base_url, api_key}` | 操作手机([gui.md](gui.md)):这个开关立刻添加或移除手机工具;模型字段是操作器自己的模型(`""` → 用主模型的);`api_key` 给了 → 保险库(`GUI_API_KEY`),`""` → 用主 key,没给 → 不变。用 `endpoint` 代替 `provider` / `base_url` / `api_key` 时指向列表里的一个接口,和对话模型一样;`PUT /api/connections/image` 和 `/video` 也是 | | POST | `/api/connections/gui/test` | 和操作器的模型来一次简短往返:`{ok, reply, ms}` 或 `{ok: false, error}` | | GET | `/api/phone` | `{connected, device{id, name, platform, gui, apps, width, height}, gui_enabled, last_screen, screen}`:哪台手机连着,以及它最后发来的屏幕 | +| GET | `/api/hands` | 这台电脑自己的屏幕和双手([gui.md](gui.md)):`{enabled, available, backend, reason, mode, coords, screen_size, picture_size, window{available, reason, active, app, title, frame}, device, task_active, task_text, last_screen}`;在手机上是 `{enabled: false, available: false, reason}` | +| PUT | `/api/connections/hands` `{enabled, backend (auto · desktop · pyautogui · xdotool), mode (auto · screen · window)}` | 这台电脑双手的开关,以及由哪个后端驱动;省略的字段不变;未知的后端或模式返回 400。回答上面的视图 | +| POST | `/api/hands/stop` | 双手卡片上的「停止」:这台电脑屏幕上的任务在下一步结束;`{stopped}` | | POST · DELETE | `/api/connections/mcp` `{name, command, args[], env{}, url, risk}` · `/api/connections/mcp/{name}` | 现在就连接一个服务器(起不来返回 502)/ 断开并移除一个从应用里添加的 | | GET | `/api/skills` | `{count, built_in, yours, dir, errors{}, skills[{name, description, source (built-in · yours), enabled, path, files[], metadata{}, channel, updated_at}]}` | | GET / PUT / DELETE | `/api/skills/{name}` | 一个技能,带 `body` 和 `content`(整个 `SKILL.md`)/ 从 `{content}` 写入(用内置技能的名字会创建你的副本)/ 删除你自己的一个 | @@ -208,6 +211,25 @@ Meta 的 Muse「自己会做事,但不会做太多」。「设置」里的*主 | GET / PUT | `/api/sync/state` · `{enabled}` | 账号各设备之间同步的对话([every-device.md](every-device.md#the-same-conversations-everywhere)):`{enabled, available, paused, cursor, last_pull_at, last_push_at, error, relay}`;`available` 是「已登录且设置允许」,`paused` 在收到 401 后置上,直到下一次登录,`relay` 是中继自己的 `{enabled, cursor, counts{conversations, messages}, limits}`,问不到时为 `null`。`PUT {enabled: false}` 在这里关掉同步,并删掉中继为这个账号保存的内容(其他设备的开关会在它们下一次推送或拉取时跟着关,中继会以 `sync_off` 拒绝);`PUT {enabled: true}` 重新打开,并把这里的聊天推上去。中继的拒绝会以它的状态码和代码原样返回(`409 sync_off`)。从 0.1.38 起,状态里还带 `side_chats`(这台设备的*同时同步旁聊*,默认关闭:只推送和拉取主要聊天)和 `working`(`[{thread, cid, device, device_name, at}]`:此刻正在回答的其他设备,来自 hub 的 `working` 帧,每条十分钟后丢弃);`PUT {side_chats: true}` 把这台设备的旁聊发上去,并从头把账号的旁聊拉一次,`false` 则从此留在本地 | | POST | `/api/sync/delete` | 删掉中继上每一段已同步的对话,开关保持原样;返回状态 | | POST | `/api/sync/pull` | 现在就抓取并应用其他设备的改动:`{applied, …state}` | +| GET | `/api/cloud` | 应用所显示的 nanoMuse Cloud 账号:`{base_url, signed_in, required, models, hint, channel, signed_in_at, has_password, account_id, member, any_model, region, is_model}`([cloud.md](cloud.md))。下面每条 `/api/cloud/*` 路由遇到中继拒绝时,都以中继的状态码、它的那句话作答,代码放在 `X-Nanomuse-Code` 头里;没有登录账号时是 401 `bad_key` | +| GET | `/api/cloud/config` | 中继的公开数字(新账号的额度、邀请奖励、是否开放注册、要加星的仓库);旧中继或没有中继时是 `{}` | +| POST | `/api/cloud/code` `{identifier}` | 向一个邮箱地址或手机号发送登录验证码;`{ok}` | +| POST | `/api/cloud/verify` `{identifier, code, invite?}` | 用验证码登录(首次注册可带邀请码);回答中继的 `/v1/me`,顺带刷新提示策略 | +| POST | `/api/cloud/login` `{identifier, password}` | 用账号密码登录;回答与 `verify` 相同 | +| POST | `/api/cloud/password` `{password, current?}` | 设置或更改密码(已有密码时要带 `current`,刚用验证码登录的除外;空的 `password` 加 `current` 表示取消密码) | +| GET | `/api/cloud/me` | 中继此刻看到的账号(`/v1/me`),顺带刷新提示策略 | +| GET · DELETE | `/api/cloud/sessions` · `/api/cloud/sessions/{prefix}` | 账号在各设备上的登录 / 按列表显示的前缀撤销一个;两者都回答 `{sessions}` | +| POST | `/api/cloud/sign-out` · `/api/cloud/sign-out-all` `{all}` | 退出这台设备 / 撤销其他所有设备的登录(`all: true` 时连这台一起,`{signed_out}` 加账号视图) | +| GET | `/api/cloud/events?limit=` | 中继上这个账号的活动记录:`{events}` | +| POST | `/api/cloud/models` `{on}` | 「使用 nanoMuse Cloud 模型」:关掉后,账号的模型退出双手、图片和短片的自动顺序以及提供方列表;登录保留。聊天模型正在用账号时返回 409 `chat_on_cloud` | +| POST | `/api/cloud/use-as-model` `{model?}` | 让账号当聊天模型:不点名就用推荐模型,Cloud 的 key 来自保险库;同时把账号的模型重新打开。回答连接视图里的 `llm` | +| POST · DELETE | `/api/cloud/contribute` `{on}` · `/api/cloud/samples` | 数据控制:「帮助改进 nanoMuse 的 AI 模型」开或关(只有开着时中继才保留聊天回合)/ 删除它保留的内容,`{deleted}` | +| POST | `/api/cloud/delete` | 在中继上删除账号并在这里退出;回答账号视图 | +| GET / PUT | `/api/hub` · `{enabled, remote_control, name}` | 这台设备在账号枢纽上的状态([hub.md](hub.md)):`{enabled, remote_control, state, detail, device{id, name, kind, actions}, devices[], account}` / 加入或离开、允许或拒绝远程控制、给这台设备改名(最多 60 个字符) | +| POST | `/api/hub/join` · `/api/hub/leave` · `/api/hub/refresh` | 加入(没有登录账号时 401)/ 离开 / 再向中继要一次设备列表;各自回答枢纽视图 | +| DELETE | `/api/hub/devices/{device_id}` | 忘掉账号下的一台设备;枢纽没连上时 502 | +| POST | `/api/hub/ask` `{device, text?}` | 对着某台设备(按 id 或名字;没有就新建)的侧聊,带 `text` 时作为其中第一条消息,在那台设备上运行:`{thread, event}`;没有这台设备时 404 | +| GET | `/api/bridge/tools` | 给代理运行的命令用,不是给应用用:`nanomuse-device list` 打印的设备工具,`{ok, tools[{name, description}]}`。不走应用令牌;shell 工具签发的调用令牌放在 `X-Nanomuse-Bridge` 头里(否则 401),与 `POST /api/bridge/{kind}` 相同([local-runtime.md](local-runtime.md)) | | GET | `/api/browser/{thread}/frames/{id}.jpg` | 一帧浏览器画面(JPEG,当前会话期间留在内存里) | | POST | `/api/browser/{thread}/control` `{action: click(x,y as 0–1 fractions) · type(text) · key(key) · scroll(dy) · navigate(url) · look · handed_back}` | 你来开智能体的浏览器;`handed_back` 是 Android 应用在你关掉它的接管面板时发的(取一帧新画面,告知智能体);浏览器没打开时返回 `409`(先打开一个 URL) | | GET | `/api/push` | `{available, public_key, subscriptions, devices[]}`:用来订阅的 VAPID 公钥 | From bf7259fb3de9f031aa387d5425cc05dc0480e1cb Mon Sep 17 00:00:00 2001 From: lgy0404 <2528379691@qq.com> Date: Mon, 12 Oct 2026 03:12:40 +0800 Subject: [PATCH 80/98] fix(cloud): close a device's hub socket when its key is signed out Sign out everywhere, a sign-in revoked on the account page and a device's own sign-out revoked the key at once, but a hub socket that device had open stayed open until it next reconnected: a lost phone kept a live line to the account's other devices for a while. After each of the three the hub now closes every socket of the account whose key no longer opens with 4001 bad_key, takes it off the account's list so the other devices see it offline and a call it was carrying out fails as device_offline. The device that asked keeps its socket. docs/hub.md and its Chinese twin name the new moment under 4001; one CHANGELOG bullet under Cloud; a test with two keys of one account for the three ways out. Signed-off-by: lgy0404 <2528379691@qq.com> --- CHANGELOG.md | 1 + cloud/nanomuse_cloud/api.py | 10 +++++++ cloud/nanomuse_cloud/hub.py | 16 +++++++++++ cloud/nanomuse_cloud/service.py | 5 ++++ cloud/tests/test_hub.py | 50 +++++++++++++++++++++++++++++++++ docs/hub.md | 6 +++- docs/zh/hub.md | 2 +- 7 files changed, 88 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 75decf23c..1254030df 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ All notable changes to nanoMuse. The format follows [Keep a Changelog](https://k ### Cloud +- **Signing a device out also drops its line to the hub.** *Sign out everywhere*, a sign-in revoked on the account page and a device's own sign-out revoked the key at once, but a hub socket that device had open stayed open until it next reconnected, so a lost phone could still reach the account's other devices for a while. The relay now closes such a socket with `4001 bad_key` the moment the key is revoked, and the other devices see the device offline. - **The web console open in two tabs no longer fights itself.** Every tab of one browser said hello to the hub with the same device id, so the two took turns replacing each other and reconnecting for as long as both stayed open, and a message sent from the tab that had just lost came back as disconnected. Each tab is now its own device on the hub; a reload keeps the tab's id. - **A self-hosted relay's backup recipe takes a consistent copy.** The command in the self-hosting guide called a `sqlite3` binary the image does not have and fell back to copying `cloud.db`, which under WAL misses the newest writes; it now uses SQLite's backup API inside the running container and streams the copy out. The production notes restore a backup into the data directory as uid 10001, the user the relay runs as. A code mail composed with a `CODE_TTL_S` under a minute says the code is good for one minute, as the SMS template already did. diff --git a/cloud/nanomuse_cloud/api.py b/cloud/nanomuse_cloud/api.py index 3bd024be1..33b1d9d77 100644 --- a/cloud/nanomuse_cloud/api.py +++ b/cloud/nanomuse_cloud/api.py @@ -534,6 +534,7 @@ async def me_sessions(caller: Caller = Depends(caller_dep)) -> dict: @app.delete("/v1/me/sessions/{prefix}", status_code=204) async def me_revoke_session(prefix: str, caller: Caller = Depends(caller_dep)) -> Response: cloud.revoke_session(caller, prefix) + await _drop_signed_out(caller.account_id) return Response(status_code=204) @app.get("/v1/me/events") @@ -543,8 +544,16 @@ async def me_events(limit: int = 50, caller: Caller = Depends(caller_dep)) -> di @app.post("/v1/auth/sign-out", status_code=204) async def sign_out(caller: Caller = Depends(caller_dep)) -> Response: cloud.sign_out(caller) + await _drop_signed_out(caller.account_id) return Response(status_code=204) + async def _drop_signed_out(account_id: str) -> None: + # a key that was just revoked may still hold a hub socket (the device signed out + # from elsewhere); the hub closes it with 4001 now rather than at the next reconnect + hub = getattr(app.state, "hub", None) + if hub is not None: + await hub.drop_signed_out(account_id) + @app.post("/v1/auth/session-key") async def session_key(request: Request, caller: Caller = Depends(caller_dep)) -> dict: """A key for this account that expires on its own: {"device", "ttl_s"} → {"api_key", @@ -563,6 +572,7 @@ async def sign_out_all(request: Request, caller: Caller = Depends(caller_dep)) - """Every other device; {"all": true} takes this one too.""" body = await _json(request) n = cloud.sign_out_all(caller, keep_current=not bool(body.get("all"))) + await _drop_signed_out(caller.account_id) return {"signed_out": n} @app.post("/v1/auth/delete", status_code=204) diff --git a/cloud/nanomuse_cloud/hub.py b/cloud/nanomuse_cloud/hub.py index 64b2794d2..2eb171207 100644 --- a/cloud/nanomuse_cloud/hub.py +++ b/cloud/nanomuse_cloud/hub.py @@ -319,6 +319,22 @@ async def drop_account(self, account_id: str) -> None: c.stop() await c._close(4001, "account_gone") + async def drop_signed_out(self, account_id: str) -> int: + """After a sign-out (this device, every other device, one session revoked on the + account page): every socket of the account whose key no longer opens is closed with + 4001 bad_key, so a device signed out from elsewhere, a lost phone say, loses its live + line now and not at its next reconnect. Returns how many were closed.""" + n = 0 + for c in list(self.online.get(account_id, {}).values()): + if self.cloud.key_live(c.key_hash): + continue + await c._close(4001, "bad_key") + # off the account's list now, not when its receive loop notices the close: the + # other devices hear it left and a call it was carrying out fails as offline + await self._detach(c) + n += 1 + return n + async def drop_all(self, reason: str = "hub_paused") -> int: """0.22: the operator turned the hub (or the whole service) off — every socket is closed with 4003 and the reason; the apps reconnect with backoff and are refused diff --git a/cloud/nanomuse_cloud/service.py b/cloud/nanomuse_cloud/service.py index 9a9f23875..b8fae2621 100644 --- a/cloud/nanomuse_cloud/service.py +++ b/cloud/nanomuse_cloud/service.py @@ -1028,6 +1028,11 @@ def authenticate(self, bearer: str | None) -> Caller: self.db.daily_add("active", caller.account_id) return caller + def key_live(self, key_hash: str) -> bool: + """Whether a key still opens: not revoked, not past its time. What the hub asks after + a sign-out to find the sockets whose key just stopped working.""" + return self._caller(key_hash) is not None + def sign_out(self, caller: Caller) -> None: self.db.revoke_key(caller.key_hash) self.db.add_event(caller.account_id, "sign_out") diff --git a/cloud/tests/test_hub.py b/cloud/tests/test_hub.py index 0f60a15b6..ba74fc264 100644 --- a/cloud/tests/test_hub.py +++ b/cloud/tests/test_hub.py @@ -352,6 +352,56 @@ def test_reconnect_replaces_the_older_socket(client): assert all(len(f["devices"]) == 1 for f in frames) +def test_a_sign_out_closes_the_hub_socket_of_the_key_it_revoked(client): + """Sign out everywhere is what to do after losing a phone. The lost phone's key stops + opening at once; its hub socket, open before the sign-out, must go too (4001 bad_key, + docs/hub.md), or the phone keeps a live line to the other devices until it next + reconnects. The device that asked keeps its socket; a session revoked by prefix from + the account page and a device's own sign-out close the same way.""" + phone_key = sign_up(client, "13800138000") + pc_key = sign_up(client, "13800138000") + with connect(client, phone_key) as phone, connect(client, pc_key) as pc: + phone.send_json(hello("phone", "phone-1", "Pixel")) + phone.receive_json() + phone.receive_json() + pc.send_json(hello("computer", "pc-1", "desk")) + pc.receive_json() + pc.receive_json() + phone.receive_json() # the pc arrived + # every other device: the phone's key is revoked, its socket closed; the pc stays + r = client.post("/v1/auth/sign-out-all", headers={"Authorization": f"Bearer {pc_key}"}, json={}) + assert r.status_code == 200 and r.json()["signed_out"] == 1 + with pytest.raises(WebSocketDisconnect) as closed: + phone.receive_json() + assert closed.value.code == 4001 and closed.value.reason == "bad_key" + pc.send_json({"type": "devices"}) + assert pc.receive_json()["type"] == "devices" # the pc's line is still open + r = client.get("/v1/devices", headers={"Authorization": f"Bearer {pc_key}"}) + assert {d["id"]: d["online"] for d in r.json()["devices"]} == {"phone-1": False, "pc-1": True} + # a session revoked by prefix from the account page + key_a = sign_up(client, "dev-a@example.com") + key_b = sign_up(client, "dev-a@example.com") + with connect(client, key_b) as other: + other.send_json(hello("computer", "pc-2", "laptop")) + other.receive_json() + other.receive_json() + sessions = client.get("/v1/me/sessions", headers={"Authorization": f"Bearer {key_a}"}).json()["sessions"] + prefix = next(s["prefix"] for s in sessions if not s["current"]) + assert client.delete(f"/v1/me/sessions/{prefix}", headers={"Authorization": f"Bearer {key_a}"}).status_code == 204 + with pytest.raises(WebSocketDisconnect) as closed: + other.receive_json() + assert closed.value.code == 4001 + # a device's own sign-out + with connect(client, key_a) as own: + own.send_json(hello("computer", "pc-3", "desk")) + own.receive_json() + own.receive_json() + assert client.post("/v1/auth/sign-out", headers={"Authorization": f"Bearer {key_a}"}).status_code == 204 + with pytest.raises(WebSocketDisconnect) as closed: + own.receive_json() + assert closed.value.code == 4001 + + def test_the_profile_is_shared_and_announced(client): """The agent's name and look live on the relay so every device of the account wears the same one: a PUT from one device is a ``profile`` frame on the other's socket, and diff --git a/docs/hub.md b/docs/hub.md index 7017aec08..b4658212d 100644 --- a/docs/hub.md +++ b/docs/hub.md @@ -175,7 +175,11 @@ the key in `hello` instead). Close codes: `4000` hello expected (no hello within 15 s, or a frame that is not a hello first; a binary frame counts), `4001` bad key (reason `bad_key` or `account_deleted`; `account_gone` when the account was deleted or disabled -under a live socket), `4002` bad device, `4003` replaced +under a live socket; after relay 0.24.2 also `bad_key` under a live socket +whose key was just revoked, by *Sign out everywhere* from another device, a +session revoked on the account page or the device's own sign-out, so a lost +phone loses its line at once and the other devices see it offline), `4002` +bad device, `4003` replaced by a newer connection of the same device id, or, with the reason `hub_paused` (relay 0.22), the operator switched the hub or the whole service off: a client waits and reconnects later instead of retrying at once diff --git a/docs/zh/hub.md b/docs/zh/hub.md index ae80f6a0c..2ed6b1893 100644 --- a/docs/zh/hub.md +++ b/docs/zh/hub.md @@ -82,7 +82,7 @@ hub 上传递两类请求: ← working {cid, from, device_name, working, at} another device started (true) or finished (false) a turn in that synced conversation ``` -关闭码:`4000` 期待 hello(15 秒内没有 hello,或第一帧不是 hello,二进制帧也算)、`4001` key 无效(原因 `bad_key` 或 `account_deleted`;账号在连接期间被删除或停用时为 `account_gone`)、`4002` 设备无效、`4003` 被同一设备 id 的更新连接顶替,或者,带原因 `hub_paused`(中继 0.22)时,是运营者关掉了 hub 或整个服务:客户端应等一会儿再重连,而不是立刻重试([cloud.md › 控制](cloud.md#controls));`4008` 帧太多(无视了下面的限速),以及 `4009` 读得太慢(这条连接上已经积压了 512 帧或 32 MB 而对方一直不读;客户端像遇到任何网络断开一样退避重连)。发往某台设备的帧从不等那台设备:每条连接各有一个队列,按顺序随 socket 排空写出;一部卡住的手机不会拖住正在呼叫它的电脑。 +关闭码:`4000` 期待 hello(15 秒内没有 hello,或第一帧不是 hello,二进制帧也算)、`4001` key 无效(原因 `bad_key` 或 `account_deleted`;账号在连接期间被删除或停用时为 `account_gone`;中继 0.24.2 之后,连接期间 key 刚被吊销时也会收到 `bad_key`:另一台设备点了「在所有设备上退出」、在账号页退出了这个登录,或这台设备自己退出登录,这样丢失的手机会立刻断线,其他设备看到它离线)、`4002` 设备无效、`4003` 被同一设备 id 的更新连接顶替,或者,带原因 `hub_paused`(中继 0.22)时,是运营者关掉了 hub 或整个服务:客户端应等一会儿再重连,而不是立刻重试([cloud.md › 控制](cloud.md#controls));`4008` 帧太多(无视了下面的限速),以及 `4009` 读得太慢(这条连接上已经积压了 512 帧或 32 MB 而对方一直不读;客户端像遇到任何网络断开一样退避重连)。发往某台设备的帧从不等那台设备:每条连接各有一个队列,按顺序随 socket 排空写出;一部卡住的手机不会拖住正在呼叫它的电脑。 `Authorization` 头里的 key 被拒时,处理方式与 `hello` 里的 key 被拒一致:握手完成,先发一个带 code 的 `error` 帧,再以 `4001` 关闭。客户端看到 `4001` 或 `4002` 就离开退避重连,把 hub 显示为「被拒绝」并请人重新登录(运行时仍每分钟试一次,这样在中继上恢复的 key 不用重启也能接回来);其他关闭都视为网络问题,按退避重试。 From 6bcb282a4eddd4fb0fbc0c07512067fe68fa0d11 Mon Sep 17 00:00:00 2001 From: lgy0404 <2528379691@qq.com> Date: Mon, 12 Oct 2026 03:14:37 +0800 Subject: [PATCH 81/98] fix(ios): password refusals, the Cloud row's allowance line, the relay key's keychain, Reduce Motion The sign-in and account pages name the relay's password refusals (bad_credentials, locked, password_short, password_long, password_required); a wrong password read as an expired sign-in and the lock-out as too many requests. The nanoMuse Cloud row under Providers shows the yuan left or who is signed in instead of "0% of the allowance left" on a relay without a token ceiling; the Settings card shares the rule (NanoMuseCloudAccount.leftLine). The relay's key is rewritten device-only right after upstream's synchronizable write, not after the model fetch. The pill bar's indicator and the face honour Reduce Motion. The Chinese "n of m moods drawn" lines and the Korean "nearly used up" line put their two numbers back in order. The Devices footer says a step that needs permission is approved on that device, which is what the phone does. A stale palette comment is gone. Strings in all nine languages; docs and CHANGELOG. Signed-off-by: lgy0404 <2528379691@qq.com> --- CHANGELOG.md | 7 + android/src/ios/Localizable.xcstrings | 320 ++++++++++++++---- android/src/ios/NanoMuse/NanoMuseCloud.swift | 41 ++- .../src/ios/NanoMuse/NanoMuseCloudView.swift | 7 +- android/src/ios/NanoMuse/NanoMuseFaces.swift | 14 +- android/src/ios/NanoMuse/NanoMuseReach.swift | 4 +- .../src/ios/NanoMuse/NanoMuseSettings.swift | 10 +- android/src/ios/NanoMuse/NanoMuseShell.swift | 4 +- docs/ios.md | 6 +- docs/zh/ios.md | 5 +- 10 files changed, 316 insertions(+), 102 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ac788c4ae..65b0c8fff 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,6 +16,13 @@ All notable changes to nanoMuse. The format follows [Keep a Changelog](https://k ### iOS +- **A wrong password says so.** The sign-in and account pages name the relay's password refusals: a wrong address or password, too many wrong attempts in a row, a password that is too short or too long, the current password left out. Before, a wrong password read as a sign-in that had expired, and the lock-out read as too many requests. In all nine languages. +- **The nanoMuse Cloud row under Providers stops saying *0% of the allowance left*.** On a relay without a token ceiling it shows who is signed in; on one that prices in money it shows the yuan left, the same figure as the Settings card. +- **The relay's key is written to this phone's keychain only, from the first moment.** Signing in wrote the key as an iCloud-synchronizable item first and replaced it with a device-only one after the model list arrived; the device-only write now follows at once. +- **Reduce Motion is honoured.** With it on, the pill bar's indicator moves to the tapped tab without the spring, and the face keeps still: no breath, bob, tilt, pop or shake; the mood still changes with its crossfade, and a clip of your own still plays. +- **Three translations put their numbers back in order.** The avatar studio's *n of m moods drawn* line in Chinese and Traditional Chinese, and the Korean *nearly used up* line above the composer, had the two figures swapped. +- **The Devices footer tells the truth about approvals.** A step a computer must ask about is approved on that computer, not on the phone; the footer said approvals would show here. + ### Project ## [1.0.3] - 2026-10-12 · Helm diff --git a/android/src/ios/Localizable.xcstrings b/android/src/ios/Localizable.xcstrings index 07016f3f9..60b877b61 100644 --- a/android/src/ios/Localizable.xcstrings +++ b/android/src/ios/Localizable.xcstrings @@ -7877,7 +7877,7 @@ "ko" : { "stringUnit" : { "state" : "translated", - "value" : "거의 다 썼습니다: 무료 사용량 ¥%@ 중 ¥%@ 남았습니다. 직접 추가한 키나 이미 결제 중인 요금제로 계속 쓸 수 있습니다. 설정 → nanoMuse Cloud에서." + "value" : "거의 다 썼습니다: 무료 사용량 ¥%2$@ 중 ¥%1$@ 남았습니다. 직접 추가한 키나 이미 결제 중인 요금제로 계속 쓸 수 있습니다. 설정 → nanoMuse Cloud에서." } }, "ru" : { @@ -115003,64 +115003,6 @@ } } }, - "%@ · %@ of the allowance left" : { - "localizations" : { - "de" : { - "stringUnit" : { - "state" : "translated", - "value" : "%@ · %@ des Guthabens übrig" - } - }, - "en" : { - "stringUnit" : { - "state" : "translated", - "value" : "%@ · %@ of the allowance left" - } - }, - "es" : { - "stringUnit" : { - "state" : "translated", - "value" : "%@ · queda %@ del saldo" - } - }, - "fr" : { - "stringUnit" : { - "state" : "translated", - "value" : "%@ · %@ du crédit restants" - } - }, - "ja" : { - "stringUnit" : { - "state" : "translated", - "value" : "%@ · 無料枠の残り %@" - } - }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "%@ · 사용량 %@ 남음" - } - }, - "ru" : { - "stringUnit" : { - "state" : "translated", - "value" : "%@ · осталось %@ лимита" - } - }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "%1$@ · 额度还剩 %2$@" - } - }, - "zh-Hant" : { - "stringUnit" : { - "state" : "translated", - "value" : "%1$@ · 額度還剩 %2$@" - } - } - } - }, "Signed in" : { "localizations" : { "de" : { @@ -119521,6 +119463,242 @@ } } }, + "That password is too long." : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Dieses Passwort ist zu lang." + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "That password is too long." + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Esa contraseña es demasiado larga." + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ce mot de passe est trop long." + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "パスワードが長すぎます。" + } + }, + "ko" : { + "stringUnit" : { + "state" : "translated", + "value" : "비밀번호가 너무 깁니다." + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "Этот пароль слишком длинный." + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "密码太长了。" + } + }, + "zh-Hant" : { + "stringUnit" : { + "state" : "translated", + "value" : "密碼太長了。" + } + } + } + }, + "Enter the current password first." : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Gib zuerst das aktuelle Passwort ein." + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Enter the current password first." + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Escribe primero la contraseña actual." + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Saisissez d’abord le mot de passe actuel." + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "まず現在のパスワードを入力してください。" + } + }, + "ko" : { + "stringUnit" : { + "state" : "translated", + "value" : "먼저 현재 비밀번호를 입력하세요." + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "Сначала введите текущий пароль." + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "请先输入当前密码。" + } + }, + "zh-Hant" : { + "stringUnit" : { + "state" : "translated", + "value" : "請先輸入目前的密碼。" + } + } + } + }, + "Too many wrong attempts. Wait a few minutes, or sign in with a code." : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Zu viele falsche Versuche. Warte ein paar Minuten oder melde dich mit einem Code an." + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Too many wrong attempts. Wait a few minutes, or sign in with a code." + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Demasiados intentos fallidos. Espera unos minutos o inicia sesión con un código." + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Trop de tentatives incorrectes. Attendez quelques minutes ou connectez-vous avec un code." + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "間違いが続きました。数分待つか、コードでサインインしてください。" + } + }, + "ko" : { + "stringUnit" : { + "state" : "translated", + "value" : "틀린 시도가 너무 많습니다. 몇 분 기다리거나 코드로 로그인하세요." + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "Слишком много неверных попыток. Подождите несколько минут или войдите по коду." + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "错误次数太多。请过几分钟再试,或改用验证码登录。" + } + }, + "zh-Hant" : { + "stringUnit" : { + "state" : "translated", + "value" : "錯誤次數太多。請過幾分鐘再試,或改用驗證碼登入。" + } + } + } + }, + "Wrong phone number, e-mail or password." : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Telefonnummer, E-Mail oder Passwort falsch." + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Wrong phone number, e-mail or password." + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Teléfono, correo o contraseña incorrectos." + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Numéro de téléphone, e-mail ou mot de passe incorrect." + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "電話番号、メールアドレスまたはパスワードが違います。" + } + }, + "ko" : { + "stringUnit" : { + "state" : "translated", + "value" : "전화번호, 이메일 또는 비밀번호가 틀렸습니다." + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "Неверный номер телефона, e-mail или пароль." + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "手机号、邮箱或密码不对。" + } + }, + "zh-Hant" : { + "stringUnit" : { + "state" : "translated", + "value" : "手機號碼、信箱或密碼不對。" + } + } + } + }, "This account has no password yet. Sign in with a code and set one under nanoMuse Cloud." : { "extractionState" : "manual", "localizations" : { @@ -120454,13 +120632,13 @@ "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "画好了 %d 个状态里的 %d 个,其余先用主图。" + "value" : "画好了 %2$d 个状态里的 %1$d 个,其余先用主图。" } }, "zh-Hant" : { "stringUnit" : { "state" : "translated", - "value" : "畫好了 %d 個狀態裡的 %d 個,其餘先用主圖。" + "value" : "畫好了 %2$d 個狀態裡的 %1$d 個,其餘先用主圖。" } } } @@ -122766,61 +122944,61 @@ } } }, - "In a chat, just ask: “on my Mac, list the downloads folder”, “tell my PC to build the project and send me the log”. Approvals show on this phone." : { + "In a chat, just ask: “on my Mac, list the downloads folder”, “tell my PC to build the project and send me the log”. A step that needs permission is approved on that device, not here." : { "extractionState" : "manual", "localizations" : { "de" : { "stringUnit" : { "state" : "translated", - "value" : "Bitte einfach im Chat: „auf meinem Mac den Downloads-Ordner auflisten“, „sag meinem PC, er soll das Projekt bauen und mir das Log schicken“. Freigaben erscheinen auf diesem Telefon." + "value" : "Bitte einfach im Chat: „auf meinem Mac den Downloads-Ordner auflisten“, „sag meinem PC, er soll das Projekt bauen und mir das Log schicken“. Ein Schritt, der eine Freigabe braucht, wird auf dem jeweiligen Gerät freigegeben, nicht hier." } }, "en" : { "stringUnit" : { "state" : "translated", - "value" : "In a chat, just ask: “on my Mac, list the downloads folder”, “tell my PC to build the project and send me the log”. Approvals show on this phone." + "value" : "In a chat, just ask: “on my Mac, list the downloads folder”, “tell my PC to build the project and send me the log”. A step that needs permission is approved on that device, not here." } }, "es" : { "stringUnit" : { "state" : "translated", - "value" : "En un chat, solo pídelo: “en mi Mac, lista la carpeta de descargas”, “dile a mi PC que compile el proyecto y me mande el registro”. Las aprobaciones se muestran en este teléfono." + "value" : "En un chat, solo pídelo: “en mi Mac, lista la carpeta de descargas”, “dile a mi PC que compile el proyecto y me mande el registro”. Un paso que necesita permiso se aprueba en ese dispositivo, no aquí." } }, "fr" : { "stringUnit" : { "state" : "translated", - "value" : "Dans une discussion, demandez simplement : « sur mon Mac, liste le dossier Téléchargements », « dis à mon PC de compiler le projet et de m’envoyer le journal ». Les approbations s’affichent sur ce téléphone." + "value" : "Dans une discussion, demandez simplement : « sur mon Mac, liste le dossier Téléchargements », « dis à mon PC de compiler le projet et de m’envoyer le journal ». Une étape qui demande une autorisation s’approuve sur cet appareil-là, pas ici." } }, "ja" : { "stringUnit" : { "state" : "translated", - "value" : "チャットでこう頼むだけです: 「Mac でダウンロードフォルダの一覧を出して」「PC にプロジェクトをビルドさせてログを送って」。承認はこの端末に表示されます。" + "value" : "チャットでこう頼むだけです: 「Mac でダウンロードフォルダの一覧を出して」「PC にプロジェクトをビルドさせてログを送って」。許可が要る手順はその端末側で承認します。この端末には表示されません。" } }, "ko" : { "stringUnit" : { "state" : "translated", - "value" : "채팅에서 그냥 말하세요. “내 Mac에서 다운로드 폴더 목록 보여 줘”, “내 PC에 프로젝트를 빌드하고 로그를 보내라고 해 줘”. 승인은 이 휴대전화에 표시됩니다." + "value" : "채팅에서 그냥 말하세요. “내 Mac에서 다운로드 폴더 목록 보여 줘”, “내 PC에 프로젝트를 빌드하고 로그를 보내라고 해 줘”. 허가가 필요한 단계는 그 기기에서 승인합니다. 여기에는 표시되지 않습니다." } }, "ru" : { "stringUnit" : { "state" : "translated", - "value" : "В чате просто попросите: «на моём Mac покажи папку загрузок», «скажи моему ПК собрать проект и прислать мне лог». Подтверждения показываются на этом телефоне." + "value" : "В чате просто попросите: «на моём Mac покажи папку загрузок», «скажи моему ПК собрать проект и прислать мне лог». Шаг, которому нужно разрешение, подтверждается на том устройстве, а не здесь." } }, "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "在聊天里直接说就行:「在我 Mac 上列一下下载文件夹」「让电脑把项目编译一遍,把日志发给我」。需要确认的事会在这台手机上弹卡片。" + "value" : "在聊天里直接说就行:「在我 Mac 上列一下下载文件夹」「让电脑把项目编译一遍,把日志发给我」。需要确认的步骤要在那台设备上批准,这里不会弹卡片。" } }, "zh-Hant" : { "stringUnit" : { "state" : "translated", - "value" : "在聊天裡直接說就好:「在我的 Mac 上列出下載資料夾」「讓電腦把專案編譯一遍,把日誌傳給我」。需要確認的事會在這支手機上跳出卡片。" + "value" : "在聊天裡直接說就好:「在我的 Mac 上列出下載資料夾」「讓電腦把專案編譯一遍,把日誌傳給我」。需要確認的步驟要在那台裝置上核准,這裡不會跳出卡片。" } } } diff --git a/android/src/ios/NanoMuse/NanoMuseCloud.swift b/android/src/ios/NanoMuse/NanoMuseCloud.swift index b516b6cbb..89a7d4f8c 100644 --- a/android/src/ios/NanoMuse/NanoMuseCloud.swift +++ b/android/src/ios/NanoMuse/NanoMuseCloud.swift @@ -48,6 +48,21 @@ struct NanoMuseCloudAccount: Codable, Equatable, Sendable { return min(max(Double(remaining) / Double(granted), 0), 1) } + /// What is left, as the Settings card and the providers row say it: in yuan on a relay that + /// prices in money (the account page's headline figure), in tokens on an older relay; nil + /// when the relay runs without a ceiling, where there is nothing to count down. + var leftLine: String? { + if unlimited { return nil } + if let left = poolLeftCny { + let whole = left.rounded() == left + return String(format: AppLocalized("%@ left"), "¥" + left.formatted(.number.precision(.fractionLength(whole ? 0 : 2)))) + } + let formatter = NumberFormatter() + formatter.numberStyle = .decimal + let left = formatter.string(from: NSNumber(value: remaining)) ?? "\(remaining)" + return String(format: AppLocalized("%@ left"), left) + } + init(channel: String, hint: String, granted: Int64, used: Int64, usedToday: Int64, dailyCap: Int64, checkedAt: Date, unlimited: Bool = false, id: String = "", grantCny: Double? = nil, leftCny: Double? = nil) { self.channel = channel self.hint = hint @@ -343,6 +358,10 @@ enum NanoMuseCloud { store.updateInstance(existing) } ProviderKeychainHelper.saveAPIKey(apiKey, instanceId: existing.id) + // C12: the relay's key is this phone's alone, never in iCloud Keychain; upstream's + // helper writes a synchronizable item, so it is rewritten device-only at once, + // before the model fetch below gives iCloud time to pick it up. + NanoMuseAccountData.saveRelayKey(apiKey, instanceId: existing.id) inst = existing } else { let fresh = ProviderInstance( @@ -354,6 +373,7 @@ enum NanoMuseCloud { ) // Key first: addInstance fetches the model list on its own right away. ProviderKeychainHelper.saveAPIKey(apiKey, instanceId: fresh.id) + NanoMuseAccountData.saveRelayKey(apiKey, instanceId: fresh.id) // C12, as above store.addInstance(fresh) inst = fresh } @@ -372,8 +392,6 @@ enum NanoMuseCloud { let parsed = parseAccount(reply) account = parsed - // C12: the relay's key is this phone's alone — never in iCloud Keychain - NanoMuseAccountData.saveRelayKey(apiKey, instanceId: inst.id) NanoMuseNudges.shared.absorb(me: reply) // nanoMuse: contract C1 — the star policy rides along // C12: whoever was here is put aside, and this account's own set comes back (or starts empty) let after = NanoMuseAccountData.shared.current @@ -484,7 +502,8 @@ enum NanoMuseCloud { } return AppLocalized("The model provider is busy right now. Try again in a moment.") case "locked": - return AppLocalized("Too many requests at once. Try again shortly.") + // the password endpoints: too many wrong passwords in a row, not too many requests + return AppLocalized("Too many wrong attempts. Wait a few minutes, or sign in with a code.") case "model_not_offered": return AppLocalized("nanoMuse Cloud no longer offers that model. Pick another under Settings → nanoMuse Cloud.") case "service_paused": @@ -495,12 +514,20 @@ enum NanoMuseCloud { return AppLocalized("The device hub is paused on this relay for now; each device keeps working on its own.") case "upstream": return AppLocalized("nanoMuse Cloud did not answer. Try again in a moment.") - case "password_wrong": - return AppLocalized("That password is not right.") - case "password_required", "no_password": + // The relay's password codes (cloud/nanomuse_cloud/service.py): a 401 `bad_credentials` + // for a wrong address or password, `no_password` for an account that has none yet, + // `password_required` when the current one was left out, `password_short` and + // `password_long` from the rules; the two names after them are kept for older relays. + case "bad_credentials", "password_wrong": + return AppLocalized("Wrong phone number, e-mail or password.") + case "no_password": return AppLocalized("This account has no password yet. Sign in with a code and set one under nanoMuse Cloud.") - case "password_weak": + case "password_required": + return AppLocalized("Enter the current password first.") + case "password_short", "password_weak": return AppLocalized("Use eight characters or more.") + case "password_long": + return AppLocalized("That password is too long.") case "invite_bad": return AppLocalized("That invite code is not one we know. Check it, or leave it empty.") case "signup_closed": diff --git a/android/src/ios/NanoMuse/NanoMuseCloudView.swift b/android/src/ios/NanoMuse/NanoMuseCloudView.swift index 0ca62eeed..d49836d2d 100644 --- a/android/src/ios/NanoMuse/NanoMuseCloudView.swift +++ b/android/src/ios/NanoMuse/NanoMuseCloudView.swift @@ -479,9 +479,10 @@ struct NanoMuseCloudRow: View { VStack(alignment: .leading, spacing: 2) { Text(NanoMuseCloud.label) if let account { - let hint = account.hint - let left = account.fraction.formatted(.percent.precision(.fractionLength(0))) - Text(String(format: AppLocalized("%@ · %@ of the allowance left"), hint, left)) + // Who is signed in, and what is left by the same rule as the Settings card: the + // yuan on a relay that prices in money, tokens on an older one, nothing to count + // on a relay without a ceiling (where a token fraction would read 0 percent). + Text(account.leftLine.map { "\(account.hint) · \($0)" } ?? account.hint) .font(.caption) .foregroundStyle(.secondary) } else if NanoMuseCloud.isSignedIn { diff --git a/android/src/ios/NanoMuse/NanoMuseFaces.swift b/android/src/ios/NanoMuse/NanoMuseFaces.swift index ed54e1244..b7016281a 100644 --- a/android/src/ios/NanoMuse/NanoMuseFaces.swift +++ b/android/src/ios/NanoMuse/NanoMuseFaces.swift @@ -259,6 +259,9 @@ struct NanoMuseFaceView: View { @ObservedObject private var motion = NanoMuseAvatarMotion.shared @ObservedObject private var own = NanoMuseOwnClip.shared @Environment(\.scenePhase) private var scenePhase + /// Reduce Motion on: the still keeps still (no breath, bob, tilt, pop or shake); the mood + /// still changes with its crossfade, and a clip the person chose still plays. + @Environment(\.accessibilityReduceMotion) private var reduceMotion @State private var breath = false @State private var popped = false @State private var shake: CGFloat = 0 @@ -318,13 +321,14 @@ struct NanoMuseFaceView: View { .offset(x: shake, y: bob) .animation(.easeInOut(duration: 0.35), value: mood) .onAppear { - startBreathing() + if !reduceMotion { startBreathing() } NanoMuseClipPlayers.shared.setSuspended(scenePhase != .active) } .nmOnChange(of: scenePhase) { phase in NanoMuseClipPlayers.shared.setSuspended(phase != .active) } .nmOnChange(of: mood) { newMood in + guard !reduceMotion else { return } if newMood == .happy { popped = true withAnimation(.spring(response: 0.35, dampingFraction: 0.45)) { popped = false } @@ -338,8 +342,9 @@ struct NanoMuseFaceView: View { .accessibilityLabel(Text(AppLocalized("Agent face"))) } - /// The still's own motion; a clip brings its own and stays at rest. - private var animatesStill: Bool { clip == nil } + /// The still's own motion; a clip brings its own and stays at rest, and so does the still + /// under Reduce Motion. + private var animatesStill: Bool { clip == nil && !reduceMotion } private var scale: CGFloat { if popped { return 1.12 } @@ -489,9 +494,6 @@ enum NanoMuseTones { /// The agent's message pill, a shade off the canvas (Android's `ChatColors.assistantBubble`: /// #F2F2F7 in light, #1C1C1E in dark). The composer pill keeps `bubble`. static let agentPill = Color(uiColor: UIColor { $0.userInterfaceStyle == .dark ? UIColor(red: 0.11, green: 0.11, blue: 0.118, alpha: 1) : UIColor(red: 0.949, green: 0.949, blue: 0.969, alpha: 1) }) - /// The bottom bar's indicator capsule under the current tab, and the glyph on it: Android's - /// primaryContainer and onPrimaryContainer (#E5F0FF with #012F80 in light, #1A2B4A with - /// #E5F0FF in dark). /// The pill bar's indicator disc and the glyph on it: the same ink as the chat, black with /// a white glyph in light and white with a black glyph in dark, as Android's MuseBottomBar. static let tabIndicator = ink diff --git a/android/src/ios/NanoMuse/NanoMuseReach.swift b/android/src/ios/NanoMuse/NanoMuseReach.swift index 6f05ebb48..7b1c56d45 100644 --- a/android/src/ios/NanoMuse/NanoMuseReach.swift +++ b/android/src/ios/NanoMuse/NanoMuseReach.swift @@ -38,7 +38,9 @@ struct NanoMuseReachSection: View { } header: { Text(AppLocalized("Reach a device")) } footer: { - Text(AppLocalized("In a chat, just ask: “on my Mac, list the downloads folder”, “tell my PC to build the project and send me the log”. Approvals show on this phone.")) + // A step the other Muse must ask about is declined from here and left to that device + // (NanoMuseDeviceMention); the footer says so rather than promising a card. + Text(AppLocalized("In a chat, just ask: “on my Mac, list the downloads folder”, “tell my PC to build the project and send me the log”. A step that needs permission is approved on that device, not here.")) } .sheet(item: $target) { device in NanoMuseReachSheet(device: device) diff --git a/android/src/ios/NanoMuse/NanoMuseSettings.swift b/android/src/ios/NanoMuse/NanoMuseSettings.swift index be16bfac7..ab1bfe776 100644 --- a/android/src/ios/NanoMuse/NanoMuseSettings.swift +++ b/android/src/ios/NanoMuse/NanoMuseSettings.swift @@ -92,15 +92,7 @@ struct NanoMuseSettingsHomeView: View { private var cloudLine: String { _ = store.instances guard NanoMuseCloud.isSignedIn, let account = NanoMuseCloud.account else { return AppLocalized("Sign in") } - if account.unlimited { return account.hint } - if let left = account.poolLeftCny { - let whole = left.rounded() == left - return String(format: AppLocalized("%@ left"), "¥" + left.formatted(.number.precision(.fractionLength(whole ? 0 : 2)))) - } - let formatter = NumberFormatter() - formatter.numberStyle = .decimal - let left = formatter.string(from: NSNumber(value: account.remaining)) ?? "\(account.remaining)" - return String(format: AppLocalized("%@ left"), left) + return account.leftLine ?? account.hint } // MARK: Card 2 — the agent diff --git a/android/src/ios/NanoMuse/NanoMuseShell.swift b/android/src/ios/NanoMuse/NanoMuseShell.swift index 76a739bc4..453e1f53c 100644 --- a/android/src/ios/NanoMuse/NanoMuseShell.swift +++ b/android/src/ios/NanoMuse/NanoMuseShell.swift @@ -816,6 +816,8 @@ struct NanoMuseBottomBar: View { @Binding var selected: NanoMuseTab var onPick: (NanoMuseTab) -> Void @Namespace private var indicator + /// Reduce Motion on: the indicator moves to the tapped tab without the spring. + @Environment(\.accessibilityReduceMotion) private var reduceMotion /// The indicator capsule behind the selected glyph, centred in its slot; the five slots share /// the pill's width equally. @@ -869,7 +871,7 @@ struct NanoMuseBottomBar: View { Capsule().fill(NanoMuseTones.surface.opacity(0.55)) } .overlay(Capsule().strokeBorder(NanoMuseTones.hairline, lineWidth: 1)) - .animation(.spring(response: 0.35, dampingFraction: 0.8), value: selected) + .animation(reduceMotion ? nil : Animation.spring(response: 0.35, dampingFraction: 0.8), value: selected) .frame(maxWidth: Self.maxWidth) .frame(maxWidth: .infinity) .padding(.horizontal, Self.inset) diff --git a/docs/ios.md b/docs/ios.md index 8c63d8561..779a8fb70 100644 --- a/docs/ios.md +++ b/docs/ios.md @@ -92,7 +92,8 @@ Ours, in `NanoMuse/`: then *On it: 〈brief〉*, and the model's name when idle; while a new face is being drawn it reads the avatar flow's line. The face (`NanoMuseFaces.swift`, the drawn face from Application Support or the dragon from the bundle, five moods with the breath, bob, tilt, pop and shake of - the other clients) is tapped into **the agent's page**. A short clip of your own can play as the + the other clients; with Reduce Motion on the still keeps still and only the mood's crossfade + remains) is tapped into **the agent's page**. A short clip of your own can play as the face instead (`NanoMuseOwnClip.swift`: *Your own clip…* under the pen on the agent's page and in the avatar studio; MP4 or MOV with H.264 or HEVC video, up to 15 seconds and 30 MB, previewed before it is used, kept on that phone only under `Application Support/nanomuse/avatar/own-clip.mp4`, @@ -536,7 +537,8 @@ Ours, in `NanoMuse/`: current one shows the filled symbol in `tabIndicatorGlyph` on a 60 by 46 pt capsule of `tabIndicator` (the chat's ink: black with a white symbol in light, white with a black symbol in dark, as Android's `MuseBottomBar`) that slides to the tab tapped next with a spring - (`matchedGeometryEffect`); the others show the outlined symbol in the secondary colour. The bar + (`matchedGeometryEffect`; with Reduce Motion on it moves without the spring); the others show + the outlined symbol in the secondary colour. The bar still leaves while the keyboard or the chat's voice panel is up. Layout: the pill lies over the rooms and the chat in a `ZStack` aligned to the bottom. The chat keeps the 0.1.40 rule above (bottom padding of the bar's height, 70 pt: 46 plus 6 above and below plus the 12 pt gap, so the diff --git a/docs/zh/ios.md b/docs/zh/ios.md index 5a212a3ce..00ac3a9c3 100644 --- a/docs/zh/ios.md +++ b/docs/zh/ios.md @@ -83,7 +83,8 @@ scripts/gen-ios-icons.py the app icon and the four alternates, from asse `tool_title`(模型自己对这一步的描述,比如 *打开携程网站*),然后是 *正在写回复*,然后是 *正在处理:〈简述〉*,空闲时是模型的名字;正在画新形象时,显示的是形象流程那边的那行字。 形象(`NanoMuseFaces.swift`:Application Support 里画出来的脸,或者 bundle 里的小龙,五种 - 状态,带着其他客户端那样的呼吸、浮动、歪头、弹出和抖动)点一下进入**智能体的页面**。 + 状态,带着其他客户端那样的呼吸、浮动、歪头、弹出和抖动;开了「减弱动态效果」静态图就不动了, + 只剩状态切换时的淡入淡出)点一下进入**智能体的页面**。 也可以换成一段你自己的短视频来当形象(`NanoMuseOwnClip.swift`:智能体页面钢笔菜单和形象 工作室里的 *你自己的视频…*;MP4 或 MOV,H.264 或 HEVC 视频,最长 15 秒、最大 30 MB,用之前 先预览,只保存在这台手机的 `Application Support/nanomuse/avatar/own-clip.mp4`,*默认形象* @@ -445,7 +446,7 @@ scripts/gen-ios-icons.py the app icon and the four alternates, from asse 五个标签平分胶囊的宽度,每一格整格可点;当前这个用 `tabIndicatorGlyph` 色显示实心符号,底下一个 60 × 46 pt 的 `tabIndicator` 色胶囊(聊天的墨色:浅色黑底白符号,深色白底黑符号,和 Android 的 `MuseBottomBar` 一样),点下一个标签时它带着弹簧滑过去 - (`matchedGeometryEffect`);其他标签用次要颜色显示线框符号。键盘弹起或聊天的语音面板打开时, + (`matchedGeometryEffect`;开了「减弱动态效果」就不带弹簧,直接过去);其他标签用次要颜色显示线框符号。键盘弹起或聊天的语音面板打开时, 底栏仍然离开。布局:胶囊在一个贴底对齐的 `ZStack` 里盖在房间和聊天上面。聊天沿用上面 0.1.40 的规矩(聊天层加一段底栏高度、70 pt 的底部 padding:46 加上下各 6,再加 12 pt 的间隙,所以输入区在胶囊上面, `NavigationStack` 的祖先上没有任何 inset);房间是普通的 SwiftUI 滚动视图,同样的高度用 From 1831667315032a9f14fb765fced81a67f8f24054 Mon Sep 17 00:00:00 2001 From: lgy0404 <2528379691@qq.com> Date: Mon, 12 Oct 2026 03:18:13 +0800 Subject: [PATCH 82/98] =?UTF-8?q?docs(zh):=20the=20showcase=20page's=20?= =?UTF-8?q?=E8=BD=A8=E8=BF=B9=20labels=20render=20as=20bold?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A bold run that closes right after a Chinese full-width colon is not right-flanking under CommonMark, so `**轨迹:**` showed its asterisks on the site (seven lines, the one this branch adds included). The colon now sits outside the run, `**轨迹**:`, which markdown-it renders as bold; checked with markdown-it-py on the page. Signed-off-by: lgy0404 <2528379691@qq.com> --- CHANGELOG.md | 2 +- docs/zh/showcase.md | 14 +++++++------- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2c4bb4c8d..af40f7211 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -22,7 +22,7 @@ All notable changes to nanoMuse. The format follows [Keep a Changelog](https://k - **The showcase page no longer takes the phone's address from the link.** MobileGym's page reads `?sim=` to point its frame at a separate dev server; on the public site that let a crafted link put any page, a `javascript:` one included, inside the phone on the site's own origin, where a visitor's sign-in ticket is kept. The composed page now loads `/phone.html` and nothing else. - **The showcase gateway lets DeepSeek Flash see screenshots.** A visitor's own key with `deepseek-flash` or `deepseek-v4-flash` (the names DeepSeek serves with V4.1 Flash, and the key page's default) was marked text-only, so the chat model in that session ran with vision off; the gateway now follows the runtime's rule (`nanomuse/llm/vision.py`). The DeepSeek V4 Pro, V4 and chat ids stay text-only. - **The showcase's containers roll their logs.** The gateway, Caddy and the Docker proxy keep five 20 MB files each (`docker compose logs`) instead of one file that grows for as long as the box runs. -- **The showcase pages say what the showcase does.** Case 4 of `docs/showcase.md` pointed at a note "at the end of this page" that was never there; the line now says what the 2026-09-24 attempt found and where it is tracked. The *Never in public material* section says which 微信 it means (the real app; the simulator's re-creation is what the hosted demo's Chinese lines use, as `demo/showcase/README.md` already said). The Chinese *every device* page described the embedded phone as waiting for a tap, which the English page and the code had stopped doing. +- **The showcase pages say what the showcase does.** Case 4 of `docs/showcase.md` pointed at a note "at the end of this page" that was never there; the line now says what the 2026-09-24 attempt found and where it is tracked. The *Never in public material* section says which 微信 it means (the real app; the simulator's re-creation is what the hosted demo's Chinese lines use, as `demo/showcase/README.md` already said). The Chinese *every device* page described the embedded phone as waiting for a tap, which the English page and the code had stopped doing. The Chinese showcase page's 轨迹 labels showed their asterisks on the site (a bold run that closes right after a Chinese colon is not bold under CommonMark); the colon now sits outside the run. - **The showcase workflow lints what it tests.** `showcase.yml` runs `ruff check` and `ruff format --check` on `demo/` before the gateway's tests, the lint the runtime already gets; and a `*.env` file anywhere in the checkout (the production box's `gateway.env` has that shape) is ignored by git like `.env`. ## [1.0.3] - 2026-10-12 · Helm diff --git a/docs/zh/showcase.md b/docs/zh/showcase.md index 73642330f..a48d05f24 100644 --- a/docs/zh/showcase.md +++ b/docs/zh/showcase.md @@ -21,7 +21,7 @@ nanoMuse 是一个智能体,有好几只手。它读写文件、搜网页、 全程没碰屏幕。哨兵(Sentinel)只问一次,为了那条消息;其余的要么只读,要么在你自己的工作区里。 -**轨迹:**[火车那一半](../traces/case-1-train.md),2026-09-24 在网页版用 12306 服务器录的;模型发现 13:00 前的二等座全卖完了,如实说了,并给出最接近的替代车次,而不是装作有票。高德路线、日历草稿和飞书消息*待跑*:测试机上需要一把高德 key 和一个飞书登录。 +**轨迹**:[火车那一半](../traces/case-1-train.md),2026-09-24 在网页版用 12306 服务器录的;模型发现 13:00 前的二等座全卖完了,如实说了,并给出最接近的替代车次,而不是装作有票。高德路线、日历草稿和飞书消息*待跑*:测试机上需要一把高德 key 和一个飞书登录。 ## 2. 早间简报 {#_2-the-morning-brief} @@ -35,7 +35,7 @@ nanoMuse 是一个智能体,有好几只手。它读写文件、搜网页、 | `shell: tmeet meeting list --compact` | 今天的会议,带会议号和链接 | | 通知 | 一张卡片;点开进入聊天,看到完整简报 | -**轨迹:***待跑*:高德 key、飞书和腾讯会议登录。例程和通知这条路本身已经由 App 的测试和模拟器验证过([archive/android-python-line.md](../archive/android-python-line.md#keeping-it-running) 里*让它一直跑*那部分的工作)。 +**轨迹**:*待跑*:高德 key、飞书和腾讯会议登录。例程和通知这条路本身已经由 App 的测试和模拟器验证过([archive/android-python-line.md](../archive/android-python-line.md#keeping-it-running) 里*让它一直跑*那部分的工作)。 ## 3. 我的京东订单到哪了 {#_3-where-is-my-京东-order} @@ -51,7 +51,7 @@ nanoMuse 是一个智能体,有好几只手。它读写文件、搜网页、 第二级(App 里一个带着你登录态的页面)排在任何屏幕之前:京东没有个人 API,但它的网页版不用 App 也能用。配置好快递100,查物流就成了一次工具调用。 -**轨迹:***待跑*:一台装了本地版的手机上的京东登录。浏览器后端、接管面板和登录态的保留已经在模拟器上验证过,见 [browser.md](browser.md)。 +**轨迹**:*待跑*:一台装了本地版的手机上的京东登录。浏览器后端、接管面板和登录态的保留已经在模拟器上验证过,见 [browser.md](browser.md)。 ## 4. 国庆成都行的预算表 {#_4-a-budget-table-for-成都-over-the-holiday} @@ -65,7 +65,7 @@ nanoMuse 是一个智能体,有好几只手。它读写文件、搜网页、 第三级:公开网站,不用登录,在后台浏览,你可以去忙别的。智能体不下单;「只看不订」也正是 `browser` 工具的哨兵规则对下单和付款按钮的要求。 -**轨迹:***待跑*:2026-09-24 在电脑上试过,去哪儿把无头的桌面 Chromium 送回首页,只渲染出页脚(机器人检测);21 次工具调用后停下。要改走手机的 WebView,那才是为它准备的后端;[发布清单](../launch-checklist.md#9-chinese-services-and-the-showcase-p0)在跟踪它。 +**轨迹**:*待跑*:2026-09-24 在电脑上试过,去哪儿把无头的桌面 Chromium 送回首页,只渲染出页脚(机器人检测);21 次工具调用后停下。要改走手机的 WebView,那才是为它准备的后端;[发布清单](../launch-checklist.md#9-chinese-services-and-the-showcase-p0)在跟踪它。 ## 5. 约一个会,告诉群里 {#_5-book-a-meeting-and-tell-the-group} @@ -78,7 +78,7 @@ nanoMuse 是一个智能体,有好几只手。它读写文件、搜网页、 | `shell: lark-cli im +messages-send --chat-id oc_… --text "…"` | 群消息,带会议号和链接;正文在第二张卡片上 | | `reminders` | 提前十分钟 | -两个 CLI,两次审批,没打开任何 App。**轨迹:***待跑*:测试机上的腾讯会议和飞书登录(`tmeet auth login`、`lark-cli auth login`)。 +两个 CLI,两次审批,没打开任何 App。**轨迹**:*待跑*:测试机上的腾讯会议和飞书登录(`tmeet auth login`、`lark-cli auth login`)。 ## 6. 剪贴板 → 日历 + 闹钟 {#_6-clipboard-→-calendar-alarm} @@ -91,7 +91,7 @@ nanoMuse 是一个智能体,有好几只手。它读写文件、搜网页、 | `device__alarm_set` | 周五 09:00,通过时钟 App | | `amap__maps_geo`(可选) | 核对地址,把路上时间加进备注 | -手机自己的能力作为 MCP 工具([device.md](device.md));除了可选的那次地理编码,什么都不离开手机。**轨迹:***待跑*:Android 手机上的本地版(设备服务器只在那里跑)。 +手机自己的能力作为 MCP 工具([device.md](device.md));除了可选的那次地理编码,什么都不离开手机。**轨迹**:*待跑*:Android 手机上的本地版(设备服务器只在那里跑)。 ## 7. 一单美团,停在付款前 {#_7-a-美团-order-that-stops-before-payment} @@ -105,7 +105,7 @@ nanoMuse 是一个智能体,有好几只手。它读写文件、搜网页、 唯一一个在屏幕上做的案例,因为美团没有个人 API,它的网页版又需要 App 的登录。操作器看到和做过的一切都在轨迹里,每次点按都画在对应的截图上。两个模型分工:聊天模型负责计划和汇报(展示站机器 `.env` 里的 `MAIN_MODEL`;留空时是 `deepseek-v4.1-flash`),手的模型读每张截图、决定点哪里(`qwen3.8-27b`,`GUI_MODEL`);访客用自己的 OpenRouter key 时,手用的是 `qwen/qwen3.8-27b`。 -**轨迹:***待跑*:一台装了美团的 Android 手机(x86 模拟器跑不了它)。执行器、胶囊和「停止」已经在模拟器上验证过,见 [gui.md](gui.md)。 +**轨迹**:*待跑*:一台装了美团的 Android 手机(x86 模拟器跑不了它)。执行器、胶囊和「停止」已经在模拟器上验证过,见 [gui.md](gui.md)。 ## 写下来了,没有演示 {#documented-not-shown} From a24a6ff135c506ae828bcc00d1f1982154895005 Mon Sep 17 00:00:00 2001 From: lgy0404 <2528379691@qq.com> Date: Mon, 12 Oct 2026 03:21:48 +0800 Subject: [PATCH 83/98] docs: bring the docs up to the code after the docs audit The update check: the privacy page and the configuration page said the runtime asked the GitHub API every six hours. Every client asks nanomuse.cn/dl/index.json first and GitHub only when that does not answer, once a day, with a User-Agent naming the app and its version. The look: app.md still described grey and light-blue bubbles after Meta Muse; design.md's table named the red panda, the plush dolls, RedPanda.tsx and RedPanda.css; brand.md kept "rust orange from the red panda". All three now describe the monochrome chat and the bundled dragon, and name the files that exist (Avatar.tsx, screens/MuseSheet.tsx). browser.md gets the same design-record note that device.md and local-runtime.md carry: the phone half was the Python-line app; the current Android browser is OpenMinis's browser_use with hand_over. Smaller corrections: the own-relay suffix list in android.md gains .localdomain (LanOnly.kt has it); ChatColors.kt is named with its upstream path; cli.md lists /forget-approvals and /exit; trial.md says only the main conversation follows you unless "Also sync side chats" is on; the Chinese cloud.md says the hash covers a phone number too and the video-task row keeps the price and goes after three days; the Chinese every-device.md describes the embedded phone as the English does; the release-notes template says nanoMuse Desktop, not nanoMuse Harness. THIRD_PARTY_NOTICES.md lists DeepSeek Harness (MIT, carried unmodified) and Electron, and its heading covers harness/. The pull request template asks for "For #123" as CONTRIBUTING.md does. The ten READMEs' footer ends with a full stop. Signed-off-by: lgy0404 <2528379691@qq.com> --- .github/PULL_REQUEST_TEMPLATE.md | 2 +- CHANGELOG.md | 2 ++ README.md | 2 +- THIRD_PARTY_NOTICES.md | 6 +++++- docs/android.md | 4 ++-- docs/app.md | 2 +- docs/brand.md | 4 ++-- docs/browser.md | 7 +++++++ docs/cli.md | 2 ++ docs/configuration.md | 9 +++++---- docs/design.md | 8 ++++---- docs/privacy.md | 2 +- docs/readme/README_es.md | 2 +- docs/readme/README_fr.md | 2 +- docs/readme/README_id.md | 2 +- docs/readme/README_ja.md | 2 +- docs/readme/README_ko.md | 2 +- docs/readme/README_ru.md | 2 +- docs/readme/README_vi.md | 2 +- docs/readme/README_zh-TW.md | 2 +- docs/readme/README_zh.md | 2 +- docs/release-notes-template.md | 4 ++-- docs/trial.md | 5 +++-- docs/zh/android.md | 4 ++-- docs/zh/app.md | 2 +- docs/zh/brand.md | 2 +- docs/zh/browser.md | 5 +++++ docs/zh/cli.md | 2 ++ docs/zh/cloud.md | 4 ++-- docs/zh/configuration.md | 7 ++++--- docs/zh/design.md | 8 ++++---- docs/zh/every-device.md | 2 +- docs/zh/privacy.md | 2 +- docs/zh/trial.md | 2 +- 34 files changed, 71 insertions(+), 46 deletions(-) diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index f095b4199..aba3f6265 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -2,7 +2,7 @@ ## What - + ## Why diff --git a/CHANGELOG.md b/CHANGELOG.md index ac788c4ae..0f5c5fb0f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,6 +18,8 @@ All notable changes to nanoMuse. The format follows [Keep a Changelog](https://k ### Project +- **The docs say what the update check does.** The privacy page and the configuration page said the runtime asked the GitHub API every six hours; every client asks the project's download index at `nanomuse.cn/dl/index.json` first and GitHub only when that does not answer, once a day, and the request's `User-Agent` names the app and its version. The same pass brought the design, brand and app pages up to the monochrome chat and the bundled dragon (the red panda and the plush dolls were still described as the current face), added `/forget-approvals` and `/exit` to the CLI page, put DeepSeek Harness and Electron in `THIRD_PARTY_NOTICES.md`, and made the pull request template ask for `For #N` as CONTRIBUTING.md does. + ## [1.0.3] - 2026-10-12 · Helm Helm: the day after 1.0.2, with the pull requests and reports that came in that day. @Ichiro786's redesign of the Android app landed in three pull requests ([#329](https://github.com/nano-muse/nanoMuse/pull/329), [#330](https://github.com/nano-muse/nanoMuse/pull/330), [#331](https://github.com/nano-muse/nanoMuse/pull/331)): a floating frosted-glass bottom bar, the drawer and the chat on the theme's own canvas with black and white pills, a scrim for a header; the iPhone, the web console and the desktop follow it, so the chat reads the same on every device. A clip of your own can be the face on Android, the iPhone and the desktop ([#324](https://github.com/nano-muse/nanoMuse/issues/324)), and the desktop and the web console keep several custom OpenAI-compatible endpoints at once instead of one ([#294](https://github.com/nano-muse/nanoMuse/issues/294)). @Mola-maker's ten reports on the Android app ([#332](https://github.com/nano-muse/nanoMuse/issues/332) to [#340](https://github.com/nano-muse/nanoMuse/issues/340), [#347](https://github.com/nano-muse/nanoMuse/issues/347)) are all fixed, from an own Anthropic key that could not send to a debug log that kept raw keys; the iPhone gets a voice prompt from the Action Button ([#298](https://github.com/nano-muse/nanoMuse/pull/298) by @cypggs) and OpenCode Go works on every client ([#325](https://github.com/nano-muse/nanoMuse/pull/325) by @PovedaAqui). The relay is 0.24.2: its image runs as an unprivileged user and its guidance lists Go apart; nothing changes on the wire. diff --git a/README.md b/README.md index 5b3c4906d..60d4d6105 100644 --- a/README.md +++ b/README.md @@ -177,6 +177,6 @@ nanoMuse is an independent community project, not affiliated with or endorsed by [GPL-3.0-or-later](LICENSE). The phone app is based on OpenMinis 1.13 (GPL-3.0), modified since 2026-09-24; see [NOTICE](NOTICE). Earlier versions of the Python line were MIT (tag `pre-openminis`).

- Thanks for visiting ✨ nanoMuse!

+ Thanks for visiting ✨ nanoMuse.

Visitors

diff --git a/THIRD_PARTY_NOTICES.md b/THIRD_PARTY_NOTICES.md index ed4bd11f2..ae7dd5475 100644 --- a/THIRD_PARTY_NOTICES.md +++ b/THIRD_PARTY_NOTICES.md @@ -61,10 +61,14 @@ Test-only: JUnit 4.13.2 (**EPL-1.0**), MockWebServer 4.12.0 (**Apache-2.0**), ko The name nanoMuse and the mark in `assets/brand/` are the project's own. Use them to refer to this project; do not use them to suggest that something else is nanoMuse or endorsed by it. -## The runtime, the relay, the web console and the showcase (`nanomuse/`, `cloud/`, `web/`, `demo/`) +## The runtime, the relay, the web console, the desktop app and the showcase (`nanomuse/`, `cloud/`, `web/`, `harness/`, `demo/`) Our own code, GPL-3.0-or-later like the rest. Third-party code inside it keeps its own licence and notice; the ports named below say where they come from. +### DeepSeek Harness (MIT) + +The desktop app is a plugin for [DeepSeek Harness](https://www.npmjs.com/package/@deepseek-ai/dsh) (`@deepseek-ai/dsh` and the `@deepseek-ai/dsh-*` packages, 0.2.0-rc.2, MIT), carried inside nanoMuse Desktop unmodified with every package's licence file; it is not vendored in this repository (`harness/dsh-nanomuse/package.json`, `harness/desktop/scripts/prepare-dsh.mjs`). "DeepSeek Harness" and "DSH" are DeepSeek's names; *harness* in `harness/` is the word ([harness/README.md](harness/README.md#licence-and-names)). The shell is [Electron](https://github.com/electron/electron) (MIT), installed by npm at build time. + ### MemGUI-Bench (MIT) The phone operator (`nanomuse/phone/operator.py`) is a port of the `mobile_use` operator in [MemGUI-Bench](https://github.com/lgy0404/MemGUI-Bench) (`src/mobile_world/agents/implementations/qwen3vl.py` and its prompt): the tool schema, the system prompt's wording, the `Thought` / `Action` / `` reply shape, the 999-grid coordinates and the step history. Rewritten in nanoMuse's own structure, with rules added (passwords, payments, `ask_user`), Sentinel labels and traces. diff --git a/docs/android.md b/docs/android.md index 28ff6045c..0a2a4ec82 100644 --- a/docs/android.md +++ b/docs/android.md @@ -102,7 +102,7 @@ you run yourself ([cloud.md](cloud.md), `cloud/docker-compose.yml`), *Check* ask across launches. `https://` is required for anything outside your own network; plain `http://` is accepted for an address on your own network, judged by the same rule as a model server's (below: the private ranges as parsed addresses, `localhost`, a name without -a dot, a `.local`, `.lan`, `.home`, `.internal`, `.home.arpa` or `.ts.net` name). Settings → Account shows *Server: ``* with *Change*, which signs the phone out first: the key it holds belongs to the +a dot, a `.local`, `.lan`, `.home`, `.internal`, `.home.arpa`, `.localdomain` or `.ts.net` name). Settings → Account shows *Server: ``* with *Change*, which signs the phone out first: the key it holds belongs to the server that issued it. Everything the app does with the account (sign-in, the hub, sync, usage, the model menu) goes to that address. @@ -127,7 +127,7 @@ pills with white text in light), the agent's replies sit in a pill a shade off t black arrow (inverted in light); there is no blue in the conversation apart from links. The header is not a bar but a scrim: the conversation scrolls under it and dissolves into the canvas, and a second fade appears at the top edge while you read older messages. The palette -is `ui/theme/ChatColors.kt`, written by `scripts/rebrand.py`. +is upstream's `com/openminis/app/ui/theme/ChatColors.kt`, written by `scripts/rebrand.py`. The message composer stays above the floating navigation pill, and the pill is as wide as the composer (the same 16 dp margins; 420 dp at most, centred on a wider screen), so the two diff --git a/docs/app.md b/docs/app.md index 03da2c449..632398ca3 100644 --- a/docs/app.md +++ b/docs/app.md @@ -24,7 +24,7 @@ nanomuse serve --port 9000 --no-qr Library: pages with live previews

-The look follows Meta Muse: near-white and near-black surfaces, one blue accent, grey bubbles for the agent and light blue for you (on the phone, white on the black canvas and black on the white one, see [android.md](android.md)), a small dragon at the top of the chat that changes pose with what the agent is doing, and a floating frosted-glass pill with five icons. The font is [Figtree](https://github.com/erikdkennedy/figtree) (OFL), bundled. The study behind these choices is in [design.md](design.md). +The look is monochrome: near-white and near-black surfaces, blue for links only, a light grey pill for the agent's messages and, for yours, a pill in the chat's own ink (white on the black canvas, black on the white one, see [android.md](android.md)), a small dragon at the top of the chat that changes pose with what the agent is doing, and a floating frosted-glass pill with five icons. The font is [Figtree](https://github.com/erikdkennedy/figtree) (OFL), bundled. The study behind these choices is in [design.md](design.md). ## Getting it onto your phone diff --git a/docs/brand.md b/docs/brand.md index ee9c1c13c..c27fa3268 100644 --- a/docs/brand.md +++ b/docs/brand.md @@ -68,8 +68,8 @@ Rules: one accent hue only. Code blocks, thinking text and links that OpenMinis iOS blue, orange and green become `primary` plus neutrals. The conversation itself is monochrome: your pill, the send button and the selected tab are the ink colour on the canvas, and the blue is left to links and the status line (`ChatColors.kt`, written by -`scripts/rebrand.py`). Rust orange from the red panda stays -inside the avatar; it is not a UI colour. +`scripts/rebrand.py`). The dragon's own colours stay inside the avatar; they are not UI +colours. ## Android mapping (done in S1) diff --git a/docs/browser.md b/docs/browser.md index 3f64b6207..439700cf9 100644 --- a/docs/browser.md +++ b/docs/browser.md @@ -1,5 +1,12 @@ # The browser +> **Partly a design record of the Python line.** The Playwright backend, the actions, the +> logged-in `fetch` and the testing below are the Python runtime's and still hold on a +> computer. The phone half (the `device` backend, the virtual display, the protocol under +> *How the phone's browser works*) belonged to the Python-line Android app; in the current +> Android app the browser is OpenMinis's `browser_use` tool, and a page that needs you is +> handed over through its `hand_over` action ([android.md](android.md#what-the-phone-does)). + The agent has one browser tool and two browsers to run it in: Chromium through Playwright on the computer the server runs on, and the phone's own WebView inside the nanoMuse app. The tool is the same either way (the same actions, the same numbered elements on the page, the same pictures in the chat, the same take-over), so a skill written against one works on the other, and a task can move from the desk to the phone without changing a line. Where the browser sits in the order of things: the agent reaches a service through its API, MCP server or command-line tool first; then through a **logged-in `fetch`** (a request that carries the browser's cookies, no page rendered); then through the browser page itself; and only last through the screen of an app on the phone ([gui.md](gui.md)). The browser is rung two and three of that ladder. diff --git a/docs/cli.md b/docs/cli.md index c1358e094..c44df9c27 100644 --- a/docs/cli.md +++ b/docs/cli.md @@ -26,6 +26,8 @@ Interactive session in the terminal with approvals inline. Slash commands: | `/tainted` | whether the conversation has read private data | | `/permissions` | standing permissions you granted (key and lifetime) | | `/revoke ` | take one back, e.g. `/revoke shell:git` | +| `/forget-approvals` | clear every granted permission | +| `/exit` | quit (also `/quit`, `/q`) | `--resume` continues the most recent session (`/sessions/`). diff --git a/docs/configuration.md b/docs/configuration.md index 1a08b2f1b..30db1c1e8 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -442,13 +442,14 @@ token = "" # empty → generated once, stored in - ¡Gracias por visitar ✨ nanoMuse!

+ Gracias por visitar ✨ nanoMuse.

Visitors

diff --git a/docs/readme/README_fr.md b/docs/readme/README_fr.md index 09f882cce..6d7367638 100644 --- a/docs/readme/README_fr.md +++ b/docs/readme/README_fr.md @@ -177,6 +177,6 @@ nanoMuse est un projet communautaire indépendant, sans lien avec Meta Platforms [GPL-3.0-or-later](../../LICENSE). L'app du téléphone est basée sur OpenMinis 1.13 (GPL-3.0), modifiée depuis le 2026-09-24 ; voir [NOTICE](../../NOTICE). Les versions antérieures de la ligne Python étaient sous MIT (tag `pre-openminis`).

- Merci de votre visite ✨ nanoMuse !

+ Merci de votre visite ✨ nanoMuse.

Visitors

diff --git a/docs/readme/README_id.md b/docs/readme/README_id.md index 40552d11c..5051f7f04 100644 --- a/docs/readme/README_id.md +++ b/docs/readme/README_id.md @@ -177,6 +177,6 @@ nanoMuse adalah proyek komunitas independen, tidak berafiliasi dengan atau diduk [GPL-3.0-or-later](../../LICENSE). Aplikasi ponsel berbasis OpenMinis 1.13 (GPL-3.0), dimodifikasi sejak 2026-09-24; lihat [NOTICE](../../NOTICE). Versi lebih awal dari jalur Python berlisensi MIT (tag `pre-openminis`).

- Terima kasih sudah berkunjung ✨ nanoMuse!

+ Terima kasih sudah berkunjung ✨ nanoMuse.

Visitors

diff --git a/docs/readme/README_ja.md b/docs/readme/README_ja.md index de07d883c..b87647787 100644 --- a/docs/readme/README_ja.md +++ b/docs/readme/README_ja.md @@ -177,6 +177,6 @@ nanoMuse は独立したコミュニティプロジェクトで、Meta Platforms [GPL-3.0-or-later](../../LICENSE)。スマホアプリは OpenMinis 1.13(GPL-3.0)をもとに 2026-09-24 以降改変しています。[NOTICE](../../NOTICE) を参照。それ以前の Python 系統のバージョンは MIT でした(タグ `pre-openminis`)。

- ご覧いただきありがとうございます ✨ nanoMuse!

+ ご覧いただきありがとうございます ✨ nanoMuse。

Visitors

diff --git a/docs/readme/README_ko.md b/docs/readme/README_ko.md index 609b9fdb9..68738511f 100644 --- a/docs/readme/README_ko.md +++ b/docs/readme/README_ko.md @@ -177,6 +177,6 @@ nanoMuse는 독립적인 커뮤니티 프로젝트로, Meta Platforms, Inc.와 [GPL-3.0-or-later](../../LICENSE). 휴대폰 앱은 OpenMinis 1.13(GPL-3.0)을 바탕으로 2026-09-24부터 수정했습니다. [NOTICE](../../NOTICE) 참고. 그 이전 Python 계열 버전은 MIT였습니다(태그 `pre-openminis`).

- 방문해 주셔서 감사합니다 ✨ nanoMuse!

+ 방문해 주셔서 감사합니다 ✨ nanoMuse.

Visitors

diff --git a/docs/readme/README_ru.md b/docs/readme/README_ru.md index bf55541a0..3246f8fc8 100644 --- a/docs/readme/README_ru.md +++ b/docs/readme/README_ru.md @@ -177,6 +177,6 @@ nanoMuse — независимый проект сообщества, не св [GPL-3.0-or-later](../../LICENSE). Приложение для телефона основано на OpenMinis 1.13 (GPL-3.0) и изменяется с 2026-09-24; см. [NOTICE](../../NOTICE). Более ранние версии линии Python были под MIT (тег `pre-openminis`).

- Спасибо, что заглянули ✨ nanoMuse!

+ Спасибо, что заглянули ✨ nanoMuse.

Visitors

diff --git a/docs/readme/README_vi.md b/docs/readme/README_vi.md index e6aab0542..79de60a0d 100644 --- a/docs/readme/README_vi.md +++ b/docs/readme/README_vi.md @@ -177,6 +177,6 @@ nanoMuse là dự án cộng đồng độc lập, không liên kết với Meta [GPL-3.0-or-later](../../LICENSE). Ứng dụng điện thoại dựa trên OpenMinis 1.13 (GPL-3.0), được sửa đổi từ ngày 2026-09-24; xem [NOTICE](../../NOTICE). Các phiên bản trước đó của nhánh Python theo giấy phép MIT (tag `pre-openminis`).

- Cảm ơn bạn đã ghé thăm ✨ nanoMuse!

+ Cảm ơn bạn đã ghé thăm ✨ nanoMuse.

Visitors

diff --git a/docs/readme/README_zh-TW.md b/docs/readme/README_zh-TW.md index 2a6af7ca0..bf0f1f5e0 100644 --- a/docs/readme/README_zh-TW.md +++ b/docs/readme/README_zh-TW.md @@ -177,6 +177,6 @@ nanoMuse 是獨立的社群專案,與 Meta Platforms, Inc. 無關,也未獲 [GPL-3.0-or-later](../../LICENSE)。手機 App 基於 OpenMinis 1.13(GPL-3.0),自 2026-09-24 起修改,見 [NOTICE](../../NOTICE)。Python 這一支更早的版本採 MIT 授權(tag `pre-openminis`)。

- 感謝來訪 ✨ nanoMuse!

+ 感謝來訪 ✨ nanoMuse。

Visitors

diff --git a/docs/readme/README_zh.md b/docs/readme/README_zh.md index 614326925..a865f5bcb 100644 --- a/docs/readme/README_zh.md +++ b/docs/readme/README_zh.md @@ -177,6 +177,6 @@ nanoMuse 是独立的社区项目,与 Meta Platforms, Inc. 无关,也未获 [GPL-3.0-or-later](../../LICENSE)。手机 App 基于 OpenMinis 1.13(GPL-3.0),自 2026-09-24 起修改,见 [NOTICE](../../NOTICE)。Python 线更早的版本是 MIT(tag `pre-openminis`)。

- 感谢来访 ✨ nanoMuse!

+ 感谢来访 ✨ nanoMuse。

Visitors

diff --git a/docs/release-notes-template.md b/docs/release-notes-template.md index b3322df8d..c12fcff79 100644 --- a/docs/release-notes-template.md +++ b/docs/release-notes-template.md @@ -50,7 +50,7 @@ nanoMuse is open source, free and non-profit. Sign in with a phone number or an A stable version is not the last word: nanoMuse keeps evolving, and the [roadmap](https://github.com/nano-muse/nanoMuse/blob/main/docs/roadmap.md) says what comes next. We use it every day and know where it is rough; tell us where it broke for you and what you want it to do. Thanks to everyone who tried a build and reported what broke. [Open an issue](https://github.com/nano-muse/nanoMuse/issues/new/choose) · [send a pull request](https://github.com/nano-muse/nanoMuse/blob/main/CONTRIBUTING.md) · [Discussions](https://github.com/nano-muse/nanoMuse/discussions) · [Discord](https://discord.gg/bkTySmm28X) · [star the repo](https://github.com/nano-muse/nanoMuse); if it is useful to you, a star helps others find it. -Based on [OpenMinis](https://github.com/OpenMinis/OpenMinis) 1.13 (GPL-3.0), modified since 2026-09-24. The complete corresponding source of this build is tag `v` plus the `android/deps/proot` submodule ([nano-muse/proot](https://github.com/nano-muse/proot)). The whole repository is GPL-3.0-or-later. nanoMuse Harness carries DeepSeek Harness unmodified, with its licence files inside; *harness* in the name is the word, not DeepSeek's. nanoMuse is not affiliated with Meta; Muse is a trademark of Meta Platforms, Inc. The desktop follows what Muse's app looks like and does, written down from using it; none of Meta's assets, code or content is in it. +Based on [OpenMinis](https://github.com/OpenMinis/OpenMinis) 1.13 (GPL-3.0), modified since 2026-09-24. The complete corresponding source of this build is tag `v` plus the `android/deps/proot` submodule ([nano-muse/proot](https://github.com/nano-muse/proot)). The whole repository is GPL-3.0-or-later. nanoMuse Desktop carries DeepSeek Harness unmodified, with its licence files inside; *harness* in the name is the word, not DeepSeek's. nanoMuse is not affiliated with Meta; Muse is a trademark of Meta Platforms, Inc. The desktop follows what Muse's app looks like and does, written down from using it; none of Meta's assets, code or content is in it. @@ -91,6 +91,6 @@ nanoMuse 开源、免费、非营利。手机号或邮箱登录后有一份起 稳定版也不是最后一句话:nanoMuse 在持续进化,接下来做什么写在[路线图](https://github.com/nano-muse/nanoMuse/blob/main/docs/zh/roadmap.md)里。我们自己每天在用,知道哪些地方还糙;哪里坏了、想要什么,直接提 issue。谢谢每一位装过、试过、报过问题的人。[提 issue](https://github.com/nano-muse/nanoMuse/issues/new/choose) · [发 PR](https://github.com/nano-muse/nanoMuse/blob/main/CONTRIBUTING.md) · [Discussions](https://github.com/nano-muse/nanoMuse/discussions) · [Discord](https://discord.gg/bkTySmm28X) · [点个 Star](https://github.com/nano-muse/nanoMuse);觉得有用,点个 Star,让更多人看到。 -基于 [OpenMinis](https://github.com/OpenMinis/OpenMinis) 1.13(GPL-3.0),自 2026-09-24 起修改;本版本的完整对应源码是 tag `v` 加子模块 `android/deps/proot`([nano-muse/proot](https://github.com/nano-muse/proot))。整个仓库以 GPL-3.0-or-later 发布。nanoMuse Harness 原样携带 DeepSeek Harness 及其许可证文件;名字里的 *harness* 是普通词,不是 DeepSeek 的名字。nanoMuse 与 Meta 无关,Muse 是 Meta Platforms, Inc. 的商标。桌面端照着 Muse 应用用起来的样子做,是用过之后写下来的;里面没有 Meta 的任何素材、代码或内容。 +基于 [OpenMinis](https://github.com/OpenMinis/OpenMinis) 1.13(GPL-3.0),自 2026-09-24 起修改;本版本的完整对应源码是 tag `v` 加子模块 `android/deps/proot`([nano-muse/proot](https://github.com/nano-muse/proot))。整个仓库以 GPL-3.0-or-later 发布。nanoMuse 桌面版原样携带 DeepSeek Harness 及其许可证文件;名字里的 *harness* 是普通词,不是 DeepSeek 的名字。nanoMuse 与 Meta 无关,Muse 是 Meta Platforms, Inc. 的商标。桌面端照着 Muse 应用用起来的样子做,是用过之后写下来的;里面没有 Meta 的任何素材、代码或内容。 diff --git a/docs/trial.md b/docs/trial.md index 3d062eefe..dd303708c 100644 --- a/docs/trial.md +++ b/docs/trial.md @@ -69,8 +69,9 @@ device (section 1 and 2 above). Nobody there, and the caller hears that it was n ## 6. What follows you -Signed in, the main conversation and the side chats follow you to your other devices; *Data -controls* on each device switches that off ([sync.md](sync.md)). The agent's name and face +Signed in, the main conversation follows you to your other devices, and the side chats too +once *Also sync side chats* is on; *Data controls* on each device holds both switches +([sync.md](sync.md)). The agent's name and face are the account's. A connector signed in on one device shows on the others as *Connected on 〈device〉*, one tap to sign in there too ([hub.md](hub.md)). Models are chosen per device: each one's *Settings → Models* is its own. diff --git a/docs/zh/android.md b/docs/zh/android.md index 2165ed482..f13f3a8b9 100644 --- a/docs/zh/android.md +++ b/docs/zh/android.md @@ -80,7 +80,7 @@ Play 商店:「设置 → 版本」把已安装的构建和最新版本并排 `/healthz` 并显示它回答的版本,「使用这个服务器」把地址记住,下次启动仍然有效。自己网络之外的 地址必须是 `https://`;自己网络内的地址可以用明文 `http://`,判断规则与模型服务器地址相同 (见下文:按解析后的地址判断私有网段,`localhost`、不带点的名字,以及 `.local`、`.lan`、`.home`、 -`.internal`、`.home.arpa`、`.ts.net` 后缀)。「设置 → 账号」显示「服务器:``」和「更改」,更改会先把 +`.internal`、`.home.arpa`、`.localdomain`、`.ts.net` 后缀)。「设置 → 账号」显示「服务器:``」和「更改」,更改会先把 手机退出登录:它持有的 key 属于签发它的那台服务器。App 对账号做的一切(登录、hub、同步、 用量、模型菜单)都发往这个地址。 @@ -101,7 +101,7 @@ Play 商店:「设置 → 版本」把已安装的构建和最新版本并排 聊天和胶囊栏、菜单、抽屉在同一块底色上:深色主题是纯黑,浅色主题是纯白。你的消息是白色胶囊、黑色文字(浅色主题下反过来,黑色胶囊、白色文字), 智能体的回复放在比底色略浅一级的胶囊里(`#1C1C1E` / `#F2F2F7`),发送按钮和「回到最新」圆盘是白底黑箭头(浅色主题下反过来); 除了链接,对话里没有蓝色。顶栏不是一条横条,而是一层渐隐:对话从它下面滚过去,渐渐融进底色;往回翻旧消息时,顶边还会多出一层渐隐。 -调色板在 `ui/theme/ChatColors.kt`,由 `scripts/rebrand.py` 写入。 +调色板在上游的 `com/openminis/app/ui/theme/ChatColors.kt`,由 `scripts/rebrand.py` 写入。 消息输入框始终位于浮动导航胶囊上方,胶囊栏和输入框一样宽(同样的 16 dp 边距;最宽 420 dp,更宽的屏幕上居中),两枚胶囊的边缘对齐。智能体使用工具时,步骤条在输入框上方; 最新消息和工具小标签都可以完整滚动到它们上方。对话仍会滚过导航胶囊背后, diff --git a/docs/zh/app.md b/docs/zh/app.md index 96a64bd0e..0ab05c52e 100644 --- a/docs/zh/app.md +++ b/docs/zh/app.md @@ -22,7 +22,7 @@ nanomuse serve --port 9000 --no-qr 资源库:带实时预览的页面

-外观跟着 Meta 的 Muse 走:接近纯白和接近纯黑的底色,一种蓝色作强调,智能体的气泡是灰色、你的是浅蓝色(手机上是黑底上的白色、白底上的黑色,见 [android.md](android.md)),聊天顶部有一只小龙,姿势跟着智能体正在做的事变,底下是一枚带五个图标的毛玻璃悬浮胶囊栏。字体是 [Figtree](https://github.com/erikdkennedy/figtree)(OFL),已内置。这些选择背后的研究在 [design.md](design.md)。 +外观是单色的:接近纯白和接近纯黑的底色,蓝色只用于链接,智能体的消息是浅灰色胶囊,你的消息是对话墨色的胶囊(黑底上是白色、白底上是黑色,见 [android.md](android.md)),聊天顶部有一只小龙,姿势跟着智能体正在做的事变,底下是一枚带五个图标的毛玻璃悬浮胶囊栏。字体是 [Figtree](https://github.com/erikdkennedy/figtree)(OFL),已内置。这些选择背后的研究在 [design.md](design.md)。 ## 装到手机上 {#getting-it-onto-your-phone} diff --git a/docs/zh/brand.md b/docs/zh/brand.md index 0d88acc76..fca622ea7 100644 --- a/docs/zh/brand.md +++ b/docs/zh/brand.md @@ -61,7 +61,7 @@ OpenManus 和 Manus 押韵,却是另一个手势。标志刻意做得抽象: | `bg` / `surface` / `surface.2` | `#000000` / `#1C1C1E` / `#2C2C2E` | — | 沿用 OpenMinis,没有改 | 规则:强调色只有一个色相。OpenMinis 用 iOS 的蓝、橙、绿着色的代码块、思考文字和链接,一律改成 -`primary` 加中性色。对话本身是单色的:你的胶囊、发送按钮和当前标签都是底色上的墨色,蓝色只留给链接和状态行(`ChatColors.kt`,由 `scripts/rebrand.py` 写入)。小熊猫身上的铁锈橙留在形象里;它不是界面颜色。 +`primary` 加中性色。对话本身是单色的:你的胶囊、发送按钮和当前标签都是底色上的墨色,蓝色只留给链接和状态行(`ChatColors.kt`,由 `scripts/rebrand.py` 写入)。小龙自己的颜色留在形象里;它们不是界面颜色。 ## Android 映射(S1 已完成) {#android-mapping-done-in-s1} diff --git a/docs/zh/browser.md b/docs/zh/browser.md index 255b69e85..860aaa6f8 100644 --- a/docs/zh/browser.md +++ b/docs/zh/browser.md @@ -1,5 +1,10 @@ # 浏览器 +> **部分是 Python 线路的设计记录。** 下文的 Playwright 后端、动作、带登录态的 `fetch` 和测试都是 +> Python 运行时的,在电脑上仍然成立。手机那一半(`device` 后端、虚拟显示、「手机浏览器是怎么工作的」 +> 下面的协议)属于 Python 线路的 Android 应用;在当前的 Android 应用里,浏览器是 OpenMinis 的 +> `browser_use` 工具,需要你的页面通过它的 `hand_over` 动作交到你手上([android.md](android.md#what-the-phone-does))。 + 智能体有一个浏览器工具,和两个可以跑它的浏览器:服务器所在电脑上经 Playwright 驱动的 Chromium,以及 nanoMuse 手机 App 里手机自己的 WebView。两边的工具是同一个(同样的动作、页面上同样编号的元素、聊天里同样的画面、同样的接管方式),所以针对一边写的技能在另一边也能用,一项任务从书桌挪到手机上,一行都不用改。 浏览器在整个顺序里的位置:智能体先通过服务的 API、MCP 服务器或命令行工具去够它;然后是**带登录态的 `fetch`**(带着浏览器 cookie 的一次请求,不渲染页面);再然后才是浏览器页面本身;最后才是手机上某个 App 的屏幕([gui.md](gui.md))。浏览器是这条阶梯的第二级和第三级。 diff --git a/docs/zh/cli.md b/docs/zh/cli.md index a3c412e3d..5d765d1de 100644 --- a/docs/zh/cli.md +++ b/docs/zh/cli.md @@ -26,6 +26,8 @@ nanomuse chat [--resume] [--show-thinking] [--auto] | `/tainted` | 这段对话有没有读过私密数据 | | `/permissions` | 你授予的长期权限(键和有效期) | | `/revoke ` | 收回一项,例如 `/revoke shell:git` | +| `/forget-approvals` | 清掉所有已授予的权限 | +| `/exit` | 退出(`/quit`、`/q` 也可以) | `--resume` 接着最近一次会话继续(`/sessions/`)。 diff --git a/docs/zh/cloud.md b/docs/zh/cloud.md index 3ce63b421..d215ea43f 100644 --- a/docs/zh/cloud.md +++ b/docs/zh/cloud.md @@ -19,12 +19,12 @@ 中继就是 [`cloud/`](../../cloud/README.md) 里的代码。它存: -- 邮箱地址的加盐哈希(HMAC-SHA256)(0.1.18–0.1.21 的手机号账号继续可用)、一个打码的提示如 `so***@example.com`,以及地址本身的加密副本(AES-GCM,密钥由中继的 secret 派生),让运营者能在管理页上看到账号属于谁(单看数据库文件什么也看不出来); +- 邮箱地址或中国大陆手机号的加盐哈希(HMAC-SHA256)、一个打码的提示如 `so***@example.com`,以及地址本身的加密副本(AES-GCM,密钥由中继的 secret 派生),让运营者能在管理页上看到账号属于谁(单看数据库文件什么也看不出来); - 每个已发 key 的哈希,连同你登录时的设备名、方式(验证码还是密码)和最后使用时间;吊销的 key 保留它那一行,登录记录列表才能说明这一点; - 密码,如果你设了,以 scrypt 哈希保存,从不保存密码本身; - 每次请求:类型(聊天、图片、视频)、模型、token 数和扣费金额; - 一条账号事件时间线(登录、登录失败、设置或修改密码、退出登录、因预算被拒、上游错误),细节是设备名、模型或错误码,从不是消息内容; -- 每个视频任务的 id,这样只有发起它的账号能轮询它; +- 每个视频任务的 id,连同它的价格和服务商的最终答复,这样只有发起它的账号能轮询它,短片也只收一次费(这些行三天后删除); - 智能体的名字和形象(`/v1/me/profile`):它用的是哪一张(小龙、某个颜色底上的 emoji,或者形象工作室里画的一张,连同那张形象的五张小 WebP 图),好让账号的每台设备显示同一个。0.1.34 起,同一份 profile 还列出账号的**连接器**:哪台设备连接了哪个服务(一个标签;登录方式:OAuth、key 或开放;以及时间),这样另一台设备能说「已在你的 Mac 上连接」。凭据本身留在持有它的设备上;中继拒绝任何带着像凭据一样命名的字段的项。从不存 key 或设置。 - 中继 0.19 起,**同步的对话**(「在我的设备之间同步对话」,默认开):账号聊天的文本(每个对话的标题、类型和由哪台设备发起,每条消息的角色、文本、时间和设备,以及附件的名字和大小,从不存文件本身),好让每台设备显示同样的对话。关掉开关会删掉全部;删除账号也一样。下面的[对话同步](#conversation-sync)一节有它的形状。 diff --git a/docs/zh/configuration.md b/docs/zh/configuration.md index 633c9403a..3d6ecd77f 100644 --- a/docs/zh/configuration.md +++ b/docs/zh/configuration.md @@ -442,12 +442,13 @@ token = "" # empty → generated once, stored in Date: Mon, 12 Oct 2026 03:26:58 +0800 Subject: [PATCH 84/98] docs(hub): the 4001 note names the release after 0.24.2 The close-code paragraph said "after relay 0.24.2", which reads as 0.24.2 itself; the behaviour ships with the next relay version, so the sentence says so in both languages. Signed-off-by: lgy0404 <2528379691@qq.com> --- docs/hub.md | 5 +++-- docs/zh/hub.md | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/docs/hub.md b/docs/hub.md index b4658212d..6b8999773 100644 --- a/docs/hub.md +++ b/docs/hub.md @@ -175,8 +175,9 @@ the key in `hello` instead). Close codes: `4000` hello expected (no hello within 15 s, or a frame that is not a hello first; a binary frame counts), `4001` bad key (reason `bad_key` or `account_deleted`; `account_gone` when the account was deleted or disabled -under a live socket; after relay 0.24.2 also `bad_key` under a live socket -whose key was just revoked, by *Sign out everywhere* from another device, a +under a live socket; from the relay release after 0.24.2 also `bad_key` +under a live socket whose key was just revoked, by *Sign out everywhere* +from another device, a session revoked on the account page or the device's own sign-out, so a lost phone loses its line at once and the other devices see it offline), `4002` bad device, `4003` replaced diff --git a/docs/zh/hub.md b/docs/zh/hub.md index 2ed6b1893..b767eb486 100644 --- a/docs/zh/hub.md +++ b/docs/zh/hub.md @@ -82,7 +82,7 @@ hub 上传递两类请求: ← working {cid, from, device_name, working, at} another device started (true) or finished (false) a turn in that synced conversation ``` -关闭码:`4000` 期待 hello(15 秒内没有 hello,或第一帧不是 hello,二进制帧也算)、`4001` key 无效(原因 `bad_key` 或 `account_deleted`;账号在连接期间被删除或停用时为 `account_gone`;中继 0.24.2 之后,连接期间 key 刚被吊销时也会收到 `bad_key`:另一台设备点了「在所有设备上退出」、在账号页退出了这个登录,或这台设备自己退出登录,这样丢失的手机会立刻断线,其他设备看到它离线)、`4002` 设备无效、`4003` 被同一设备 id 的更新连接顶替,或者,带原因 `hub_paused`(中继 0.22)时,是运营者关掉了 hub 或整个服务:客户端应等一会儿再重连,而不是立刻重试([cloud.md › 控制](cloud.md#controls));`4008` 帧太多(无视了下面的限速),以及 `4009` 读得太慢(这条连接上已经积压了 512 帧或 32 MB 而对方一直不读;客户端像遇到任何网络断开一样退避重连)。发往某台设备的帧从不等那台设备:每条连接各有一个队列,按顺序随 socket 排空写出;一部卡住的手机不会拖住正在呼叫它的电脑。 +关闭码:`4000` 期待 hello(15 秒内没有 hello,或第一帧不是 hello,二进制帧也算)、`4001` key 无效(原因 `bad_key` 或 `account_deleted`;账号在连接期间被删除或停用时为 `account_gone`;从 0.24.2 之后的那个中继版本起,连接期间 key 刚被吊销时也会收到 `bad_key`:另一台设备点了「在所有设备上退出」、在账号页退出了这个登录,或这台设备自己退出登录,这样丢失的手机会立刻断线,其他设备看到它离线)、`4002` 设备无效、`4003` 被同一设备 id 的更新连接顶替,或者,带原因 `hub_paused`(中继 0.22)时,是运营者关掉了 hub 或整个服务:客户端应等一会儿再重连,而不是立刻重试([cloud.md › 控制](cloud.md#controls));`4008` 帧太多(无视了下面的限速),以及 `4009` 读得太慢(这条连接上已经积压了 512 帧或 32 MB 而对方一直不读;客户端像遇到任何网络断开一样退避重连)。发往某台设备的帧从不等那台设备:每条连接各有一个队列,按顺序随 socket 排空写出;一部卡住的手机不会拖住正在呼叫它的电脑。 `Authorization` 头里的 key 被拒时,处理方式与 `hello` 里的 key 被拒一致:握手完成,先发一个带 code 的 `error` 帧,再以 `4001` 关闭。客户端看到 `4001` 或 `4002` 就离开退避重连,把 hub 显示为「被拒绝」并请人重新登录(运行时仍每分钟试一次,这样在中继上恢复的 key 不用重启也能接回来);其他关闭都视为网络问题,按退避重试。 From 5e47ba4b7ebc6a931653200f761d7eb62dc99117 Mon Sep 17 00:00:00 2001 From: lgy0404 <2528379691@qq.com> Date: Mon, 12 Oct 2026 03:43:04 +0800 Subject: [PATCH 85/98] ci(harness): the desktop shell's tests run on Windows too The new Windows job hung for half an hour in the shell's tests: the helper test reads the token file's mode bits back (0600, 0700), Windows has none, the assertion failed before stop() and the fake helper's HTTP server kept the test process alive. The mode check is now skipped on win32, every fake server is closed in after() so a failed assertion cannot hang the run again, and both harness jobs carry a 30 minute limit. Signed-off-by: lgy0404 <2528379691@qq.com> --- .github/workflows/harness.yml | 3 +++ harness/desktop/tests/mac-helper.test.mjs | 14 +++++++++++--- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/.github/workflows/harness.yml b/.github/workflows/harness.yml index 70e7dc4bf..671e41c5c 100644 --- a/.github/workflows/harness.yml +++ b/.github/workflows/harness.yml @@ -44,6 +44,7 @@ jobs: bundle: name: build · test · pack runs-on: ubuntu-latest + timeout-minutes: 30 steps: - uses: actions/checkout@v7 - uses: pnpm/action-setup@v6 @@ -119,6 +120,8 @@ jobs: windows: name: build · test (Windows) runs-on: windows-latest + # a test that leaves a handle open hangs the process; the limit turns that into a failure + timeout-minutes: 30 steps: - uses: actions/checkout@v7 - uses: pnpm/action-setup@v6 diff --git a/harness/desktop/tests/mac-helper.test.mjs b/harness/desktop/tests/mac-helper.test.mjs index 5fe7c5ad2..52cf95764 100644 --- a/harness/desktop/tests/mac-helper.test.mjs +++ b/harness/desktop/tests/mac-helper.test.mjs @@ -15,7 +15,11 @@ import { after, test } from "node:test"; import { MacHelper, MacHelperError, HELPER_NAME, HELPER_SCREEN_PERMISSION_TEXT, QUARANTINE_KEPT_TEXT, clearQuarantine, defaultHelperPath, describeAction, translocated } from "../out/mac-helper.js"; const roots = []; +// every fake helper's server, so a failed assertion between launch and stop() cannot leave +// one listening: an open server keeps the test process alive and the run hangs instead of failing +const servers = []; after(() => { + for (const server of servers) server.close(); for (const dir of roots) rmSync(dir, { recursive: true, force: true }); }); @@ -148,6 +152,7 @@ function fakeHelper(mode = "ok") { }); }); state.servers.push(server); + servers.push(server); await new Promise((resolve) => server.listen(0, "127.0.0.1", resolve)); state.port = server.address().port; // the real helper writes it atomically; a short delay stands for its start-up @@ -186,9 +191,12 @@ test("start: token file 0600 before the launch, open's arguments, port discovery assert.ok(fake.args.includes("--port-file")); assert.equal(fake.parentPid, process.pid); assert.equal(fake.token.length, 48); - // the token file is the person's alone while the helper runs - assert.equal(statSync(fake.args[1]).mode & 0o777, 0o600); - assert.equal(statSync(join(dir, "data")).mode & 0o777, 0o700); + // the token file is the person's alone while the helper runs (Windows has no POSIX mode + // bits to read back; the helper itself only ever runs on a Mac) + if (process.platform !== "win32") { + assert.equal(statSync(fake.args[1]).mode & 0o777, 0o600); + assert.equal(statSync(join(dir, "data")).mode & 0o777, 0o700); + } // the token the fake read is the one the client sends: /status was answered 200 const status = helper.cachedStatus(); assert.equal(status.screen, "granted"); From eb0d49b1cc0af315fd4c69dbe346bdf1a662d65c Mon Sep 17 00:00:00 2001 From: lgy0404 <2528379691@qq.com> Date: Mon, 12 Oct 2026 03:48:46 +0800 Subject: [PATCH 86/98] fix(ios): password_wrong and password_weak keep their own sentences The relay still sends both: `password_wrong` when the current password given while changing or removing one is not the one set (service.py set_password, clear_password), `password_weak` for a new password with fewer than three different characters or equal to the address. The audit's commit folded the first into the sign-in sentence and the second into the eight-characters rule; each gets its own line again, the second a new one in nine languages. Signed-off-by: lgy0404 <2528379691@qq.com> --- CHANGELOG.md | 2 +- android/src/ios/Localizable.xcstrings | 59 ++++++++++++++++++++ android/src/ios/NanoMuse/NanoMuseCloud.swift | 15 +++-- 3 files changed, 70 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 63bf445f2..0e48221b5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,7 +16,7 @@ All notable changes to nanoMuse. The format follows [Keep a Changelog](https://k ### iOS -- **A wrong password says so.** The sign-in and account pages name the relay's password refusals: a wrong address or password, too many wrong attempts in a row, a password that is too short or too long, the current password left out. Before, a wrong password read as a sign-in that had expired, and the lock-out read as too many requests. In all nine languages. +- **A wrong password says so.** The sign-in and account pages name the relay's password refusals: a wrong address or password, too many wrong attempts in a row, a password that is too short, too long or too plain, the current password left out. Before, a wrong password read as a sign-in that had expired, the lock-out read as too many requests, and a password with too few different characters was told to use eight or more. In all nine languages. - **The nanoMuse Cloud row under Providers stops saying *0% of the allowance left*.** On a relay without a token ceiling it shows who is signed in; on one that prices in money it shows the yuan left, the same figure as the Settings card. - **The relay's key is written to this phone's keychain only, from the first moment.** Signing in wrote the key as an iCloud-synchronizable item first and replaced it with a device-only one after the model list arrived; the device-only write now follows at once. - **Reduce Motion is honoured.** With it on, the pill bar's indicator moves to the tapped tab without the spring, and the face keeps still: no breath, bob, tilt, pop or shake; the mood still changes with its crossfade, and a clip of your own still plays. diff --git a/android/src/ios/Localizable.xcstrings b/android/src/ios/Localizable.xcstrings index 60b877b61..e8477ff73 100644 --- a/android/src/ios/Localizable.xcstrings +++ b/android/src/ios/Localizable.xcstrings @@ -119876,6 +119876,65 @@ } } }, + "Use a few different characters, not the address itself." : { + "extractionState" : "manual", + "localizations" : { + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Verwende ein paar verschiedene Zeichen; die Adresse selbst geht nicht als Passwort." + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Use a few different characters, not the address itself." + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Usa varios caracteres distintos; la propia dirección no vale como contraseña." + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Utilisez quelques caractères différents ; l’adresse elle-même ne peut pas servir de mot de passe." + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "いくつか異なる文字を使ってください。アドレスそのものはパスワードにできません。" + } + }, + "ko" : { + "stringUnit" : { + "state" : "translated", + "value" : "서로 다른 문자를 몇 가지 섞어 주세요. 주소 자체는 비밀번호로 쓸 수 없습니다." + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "Используйте несколько разных символов; сам адрес паролем быть не может." + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "密码要含几种不同的字符,也不能是手机号或邮箱本身。" + } + }, + "zh-Hant" : { + "stringUnit" : { + "state" : "translated", + "value" : "密碼要含幾種不同的字元,也不能是手機號碼或信箱本身。" + } + } + } + }, "Use eight characters or more." : { "extractionState" : "manual", "localizations" : { diff --git a/android/src/ios/NanoMuse/NanoMuseCloud.swift b/android/src/ios/NanoMuse/NanoMuseCloud.swift index 89a7d4f8c..caef09fe2 100644 --- a/android/src/ios/NanoMuse/NanoMuseCloud.swift +++ b/android/src/ios/NanoMuse/NanoMuseCloud.swift @@ -515,17 +515,22 @@ enum NanoMuseCloud { case "upstream": return AppLocalized("nanoMuse Cloud did not answer. Try again in a moment.") // The relay's password codes (cloud/nanomuse_cloud/service.py): a 401 `bad_credentials` - // for a wrong address or password, `no_password` for an account that has none yet, - // `password_required` when the current one was left out, `password_short` and - // `password_long` from the rules; the two names after them are kept for older relays. - case "bad_credentials", "password_wrong": + // at sign-in for a wrong address or password, `password_wrong` when the current password + // given while changing or removing it is not the one set, `no_password` for an account + // that has none yet, `password_required` when the current one was left out, and + // `password_short`, `password_long`, `password_weak` from the rules for a new one. + case "bad_credentials": return AppLocalized("Wrong phone number, e-mail or password.") + case "password_wrong": + return AppLocalized("That password is not right.") case "no_password": return AppLocalized("This account has no password yet. Sign in with a code and set one under nanoMuse Cloud.") case "password_required": return AppLocalized("Enter the current password first.") - case "password_short", "password_weak": + case "password_short": return AppLocalized("Use eight characters or more.") + case "password_weak": + return AppLocalized("Use a few different characters, not the address itself.") case "password_long": return AppLocalized("That password is too long.") case "invite_bad": From 61e8f6cf8c90464fe72404d11dc07240166688ec Mon Sep 17 00:00:00 2001 From: lgy0404 <2528379691@qq.com> Date: Mon, 12 Oct 2026 03:54:06 +0800 Subject: [PATCH 87/98] docs(zh): punctuation outside emphasis runs on four pages; a test renders every page Eleven spots on docs/zh/{desktop-muse,every-device,ios,parity}.md closed a bold or italic run right after a Chinese colon, a full stop or a closing bracket and went on with a character, which CommonMark does not read as a closer; the site showed the asterisks (checked with markdown-it-py and the built site). The design page's dragon row says the error state has a still only, as web/src/avatars.ts has it. CONTRIBUTING.md states the rule and tests/test_docs_markup.py renders README.md and every page under docs/ and fails on a literal marker. Signed-off-by: lgy0404 <2528379691@qq.com> --- CHANGELOG.md | 2 +- CONTRIBUTING.md | 1 + docs/design.md | 2 +- docs/zh/design.md | 2 +- docs/zh/desktop-muse.md | 2 +- docs/zh/every-device.md | 4 ++-- docs/zh/ios.md | 4 ++-- docs/zh/parity.md | 14 ++++++------- tests/test_docs_markup.py | 43 +++++++++++++++++++++++++++++++++++++++ 9 files changed, 59 insertions(+), 15 deletions(-) create mode 100644 tests/test_docs_markup.py diff --git a/CHANGELOG.md b/CHANGELOG.md index d491fceb0..13484f502 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -24,7 +24,7 @@ All notable changes to nanoMuse. The format follows [Keep a Changelog](https://k - **The showcase's containers roll their logs.** The gateway, Caddy and the Docker proxy keep five 20 MB files each (`docker compose logs`) instead of one file that grows for as long as the box runs. - **The showcase pages say what the showcase does.** Case 4 of `docs/showcase.md` pointed at a note "at the end of this page" that was never there; the line now says what the 2026-09-24 attempt found and where it is tracked. The *Never in public material* section says which 微信 it means (the real app; the simulator's re-creation is what the hosted demo's Chinese lines use, as `demo/showcase/README.md` already said). The Chinese *every device* page described the embedded phone as waiting for a tap, which the English page and the code had stopped doing. The Chinese showcase page's 轨迹 labels showed their asterisks on the site (a bold run that closes right after a Chinese colon is not bold under CommonMark); the colon now sits outside the run. - **The showcase workflow lints what it tests.** `showcase.yml` runs `ruff check` and `ruff format --check` on `demo/` before the gateway's tests, the lint the runtime already gets; and a `*.env` file anywhere in the checkout (the production box's `gateway.env` has that shape) is ignored by git like `.env`. -- **The docs say what the update check does.** The privacy page and the configuration page said the runtime asked the GitHub API every six hours; every client asks the project's download index at `nanomuse.cn/dl/index.json` first and GitHub only when that does not answer, once a day, and the request's `User-Agent` names the app and its version. The same pass brought the design, brand and app pages up to the monochrome chat and the bundled dragon (the red panda and the plush dolls were still described as the current face), added `/forget-approvals` and `/exit` to the CLI page, put DeepSeek Harness and Electron in `THIRD_PARTY_NOTICES.md`, and made the pull request template ask for `For #N` as CONTRIBUTING.md does. +- **The docs say what the update check does.** The privacy page and the configuration page said the runtime asked the GitHub API every six hours; every client asks the project's download index at `nanomuse.cn/dl/index.json` first and GitHub only when that does not answer, once a day, and the request's `User-Agent` names the app and its version. The same pass brought the design, brand and app pages up to the monochrome chat and the bundled dragon (the red panda and the plush dolls were still described as the current face), added `/forget-approvals` and `/exit` to the CLI page, put DeepSeek Harness and Electron in `THIRD_PARTY_NOTICES.md`, and made the pull request template ask for `For #N` as CONTRIBUTING.md does. Eleven more spots on the Chinese pages (desktop-muse, every-device, ios, parity) showed their asterisks on the site for the reason the showcase page did; they are rewritten, CONTRIBUTING.md states the rule, and a test now renders every page and fails on a literal marker. ## [1.0.3] - 2026-10-12 · Helm diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 812e819d6..5c5c593c3 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -84,6 +84,7 @@ Rules for a Chinese page: - Paths: pages link to pages by bare name (`android.md`); images and other files under `docs/` are one level up (`../screenshots/feed.png`); the repository is two levels up (`../../nanomuse/config.py`). - Voice as everywhere else: plain, specific, human; Chinese idiom, never a word-for-word rendering of the English sentence; no exclamation marks, no marketing words. Second person 你, the agent is 它; menu paths as 设置 → 账号 → 设备, button and switch names in 「」. - Things are called what the apps' Chinese screens call them. The glossary below is derived from `res/values-zh/nm_strings.xml`, the `zh` block of `locales.ts`, `Localizable.xcstrings` (zh-Hans), `web/src/i18n/zh-CN.ts` and the relay console; when a screen and the glossary disagree, the screen wins and the glossary is corrected. +- Punctuation stays outside a bold or italic run: `**轨迹**:` and `*提议*:`, not `**轨迹:**` or `*提议:*`. Under CommonMark a run that closes right after a colon or a bracket and is followed by a character is not closed, and the asterisks show on the site; `tests/test_docs_markup.py` renders every page and fails on one. | English | 简体中文 | English | 简体中文 | |---|---|---|---| diff --git a/docs/design.md b/docs/design.md index b34b5debc..aa1ab23a4 100644 --- a/docs/design.md +++ b/docs/design.md @@ -25,7 +25,7 @@ A study of Muse's screens (the announcement, the walkthrough and sizzle videos, | Near-white / near-black, one blue | The same palette: `bg`, `surface-2`, `fg`, `muted`, accent `#0064d4`; dark mode by `prefers-color-scheme`. The conversation goes further on the phone and the web alike: the chat sits on pure white in light (on the phone the pill bar, the menus and the drawer too) and on black in dark on the phone, near-black on the web, and the blue stays with links and the status line | `web/src/index.css`, `android/…/values/colors.xml`, `android/…/ui/theme/ChatColors.kt` | | Optimistic | [Figtree](https://github.com/erikdkennedy/figtree) (OFL), bundled; close in proportions and warmth | `web/public/fonts/` | | Grey / light-blue bubbles, chips for tool use, cards for approvals | Monochrome pills on the phone and the web alike: your messages are white pills with black text on the dark canvas (black on white in light), the agent's a shade off the canvas, the send button and the scroll-to-latest control the same ink, and the header a scrim the conversation scrolls under and dissolves into; chips open to the tool call, cards carry the summary the Sentinel wrote and the scope buttons (once, this conversation, always; on the phone once, this chat, always) | `web/src/screens/ChatScreen.tsx`, `web/src/components/`, `android/…/ui/chat/ChatScreen.kt` | -| The plush doll that changes pose | The bundled **dragon**, a still and a short looping clip per state (idle, working, waiting, happy, error); a face drawn in the avatar studio or an emoji on a colour as alternatives (the red panda of the early releases is the history below) | `web/src/components/Avatar.tsx`, `web/public/avatars/` | +| The plush doll that changes pose | The bundled **dragon**, a still per state (idle, working, waiting, happy, error) and a short looping clip for every state but error; a face drawn in the avatar studio or an emoji on a colour as alternatives (the red panda of the early releases is the history below) | `web/src/components/Avatar.tsx`, `web/public/avatars/` | | Name and status under the avatar; tap for the sheet | The same header; the sheet has the avatar large, the status, *Stop*, four buttons (approvals, activity, permissions, upcoming) and rows for memory, skills, connections, settings | `web/src/screens/MuseSheet.tsx` | | Five-icon floating bar | The same five: Chat, Feed, Ideas, Goals, Library, in a frosted-glass pill 12 px above the bottom edge, translucent over a blur with a hairline edge; the current tab's filled glyph sits on an ink indicator (`ink`, with the glyph in `ink-fg`), the others are outlined in `muted`. The sidebar replaces it on a wide window | `web/src/App.tsx` | | Little motion | The dragon's and a studio face's clips, breathing / sway / hop for an emoji; everything off under `prefers-reduced-motion` | `web/src/index.css`, `web/src/components/Avatar.tsx` | diff --git a/docs/zh/design.md b/docs/zh/design.md index 68e394d93..6d5a8e0bb 100644 --- a/docs/zh/design.md +++ b/docs/zh/design.md @@ -25,7 +25,7 @@ | 接近纯白 / 接近纯黑,一种蓝 | 同一套调色板:`bg`、`surface-2`、`fg`、`muted`,强调色 `#0064d4`;深色模式跟 `prefers-color-scheme`。手机和网页版的对话都更进一步:聊天浅色下是纯白(手机上胶囊栏、菜单和抽屉也是),深色下手机是纯黑、网页版接近纯黑,蓝色只留给链接和状态行 | `web/src/index.css`、`android/…/values/colors.xml`、`android/…/ui/theme/ChatColors.kt` | | Optimistic | [Figtree](https://github.com/erikdkennedy/figtree)(OFL),已内置;比例和温度都接近 | `web/public/fonts/` | | 灰色 / 浅蓝色气泡,工具用小标签,审批用卡片 | 手机和网页版都是单色胶囊:你的消息是深色底上的白色胶囊、黑色文字(浅色下白底黑胶囊),智能体的胶囊比底色略浅或略深一级,发送按钮和回到最新的按钮用同一种墨色,顶栏是一层渐隐,对话从它下面滚过去、融进底色;小标签点开是工具调用,卡片上是哨兵(Sentinel)写的摘要和范围按钮(一次、本次对话、总是;手机上是一次、本聊天、总是) | `web/src/screens/ChatScreen.tsx`、`web/src/components/`、`android/…/ui/chat/ChatScreen.kt` | -| 会换姿势的毛绒玩偶 | 内置的**小龙**,每种状态(空闲、工作中、等待、开心、出错)一张静态图和一段短循环短片;在形象工作室里画的一张脸,或色块上的一个 emoji 作为备选(早期版本的小熊猫见下文的历史) | `web/src/components/Avatar.tsx`、`web/public/avatars/` | +| 会换姿势的毛绒玩偶 | 内置的**小龙**,每种状态(空闲、工作中、等待、开心、出错)一张静态图,除出错以外每种状态还有一段短循环短片;在形象工作室里画的一张脸,或色块上的一个 emoji 作为备选(早期版本的小熊猫见下文的历史) | `web/src/components/Avatar.tsx`、`web/public/avatars/` | | 形象下面是名字和状态;点开面板 | 同样的头部;面板里是大图的形象、状态、*停止*、四个按钮(审批、活动、权限、日程)以及记忆、技能、连接、设置几行 | `web/src/screens/MuseSheet.tsx` | | 五图标悬浮栏 | 同样的五个:聊天、动态、点子、目标、资源库,放在底边上方 12 px 的一枚毛玻璃胶囊里,半透明、带模糊和一圈细线边;当前标签页的填充图形垫在一块墨色指示块上(`ink`,图形用 `ink-fg`),其余的用 `muted` 描边。宽窗口下由侧栏代替 | `web/src/App.tsx` | | 很少的动效 | 小龙和工作室脸的短片,emoji 的呼吸 / 摇摆 / 蹦跳;`prefers-reduced-motion` 下全部关闭 | `web/src/index.css`、`web/src/components/Avatar.tsx` | diff --git a/docs/zh/desktop-muse.md b/docs/zh/desktop-muse.md index 0b69f195e..588c4ff41 100644 --- a/docs/zh/desktop-muse.md +++ b/docs/zh/desktop-muse.md @@ -417,7 +417,7 @@ nanoMuse 不替智能体保存任何密码,消息通过手机 App 的通知到 创建,去设定时间和细节」)或**开始这个目标**(目标对话,用这条点子起头);试过的点子得到一个绿色 对勾,⋯ 可以隐藏一条。 - **目标**:「● 追踪」列表,带分类(健康、人际关系、金融、职业、兴趣、效率提升)、智能体的一行 - 状态、它汇报过进度之后出现的进度条,以及一个「需要留意」标记。**创建目标 › <分类>**是手机的流程: + 状态、它汇报过进度之后出现的进度条,以及一个「需要留意」标记。「创建目标 › <分类>」是手机的流程: 「我想创建一个健康方面的目标。」进入你所在的聊天(它忙着时就开一个新的),带着手机的塑形提示; 智能体最多问三个简短的问题,一次一个(做什么、为什么、什么时候之前,多久检查一次),然后写一个 `nanomuse-goal` 围栏,聊天把它显示成一张「目标已创建」卡片(标题、为什么、步骤、「每天 09:00 diff --git a/docs/zh/every-device.md b/docs/zh/every-device.md index d3aa0a6f4..352105531 100644 --- a/docs/zh/every-device.md +++ b/docs/zh/every-device.md @@ -53,9 +53,9 @@ you, on the phone ──"编译一下项目,把日志发我"──▶ phone's 从 0.1.37 起是**一条线程**。主要聊天是跨所有设备的同一场对话:你在手机上对 Muse 说的话,会出现在电脑和网页版的主要聊天里,按时间顺序排在那边说过的话中间,是一个只读气泡,下面标着「来自 Pixel 8」;而 Muse 无论接下来在哪里回答,都已经读过它。另一台设备的旁聊从被拉取的那一刻起就是这台设备上的一场聊天,带着标题,在这里以同一场对话继续;聊天列表里不会标明一场聊天是在哪里写的,气泡会。人的消息一发出就到了其他设备上,回复在回合结束时到;登录会把这台设备的全部历史发上去,最早的在前。在任何地方给 Muse 改名(包括第一场对话里的起名),下次拉取时名字就跟过来。 -从 0.1.38 起是**主要聊天优先**。除非设备另外要求,否则只有主要对话在设备间流动:旁聊留在创建它的设备上,别的设备的旁聊也不会过来。「数据控制」里同步开关下面的「同时同步旁聊」按设备设置,默认关。*关:旁聊只留在这台设备。开:这台设备的旁聊进入账号,其他设备的旁聊到这里来。*打开它会把这台设备的旁聊发上去,并从头把其他设备的拉下来一次。新登录先拉最新的 300 条消息,这样很长的历史一下子就能读,而不是从最早的开始慢慢到。另一台设备正在回答时,聊天最后一条消息下面显示「kwai 正在处理…」,一条在场提示,中继只转发、从不存储;回复到了、设备说做完了、或者过了十分钟,它就消失。从另一台设备来的消息永远不会显示为被打断,也永远不提供「继续」:只有跑那个回合的设备知道它是怎么结束的。 +从 0.1.38 起是**主要聊天优先**。除非设备另外要求,否则只有主要对话在设备间流动:旁聊留在创建它的设备上,别的设备的旁聊也不会过来。「数据控制」里同步开关下面的「同时同步旁聊」按设备设置,默认关。*关:旁聊只留在这台设备。开:这台设备的旁聊进入账号,其他设备的旁聊到这里来*。打开它会把这台设备的旁聊发上去,并从头把其他设备的拉下来一次。新登录先拉最新的 300 条消息,这样很长的历史一下子就能读,而不是从最早的开始慢慢到。另一台设备正在回答时,聊天最后一条消息下面显示「kwai 正在处理…」,一条在场提示,中继只转发、从不存储;回复到了、设备说做完了、或者过了十分钟,它就消失。从另一台设备来的消息永远不会显示为被打断,也永远不提供「继续」:只有跑那个回合的设备知道它是怎么结束的。 -开关在「设置 → 数据控制 → 在我的设备之间同步对话」,默认开;关掉会让中继删除这个账号的存储,其他每台设备的开关也跟着关。「删除已同步的对话」清空存储,但保留开关。手机和网页版把每一场本地聊天映射到一个对话 id,把其他设备的改动直接套进自己的聊天列表。**nanoMuse 桌面版(dsh 插件)**把另一台设备的回合放在自己的存储里(`$DSH_HOME/nanomuse/sync-remote.json`,按会话;dsh 的会话日志只能追加,归它的智能体循环所有,在回合之外写进去的一行既不会显示也不安全),在浏览器里显示为另一台设备的气泡(`client/RemoteBubbles.ts`),按时间排在这里打的回合之间,并在模型下一步之前把到达的内容作为一条备注交给它(`agent.inject`;这条备注只是上下文,不是一行记录,也永远不会被推回去)。从中继拉下来的旁聊会立刻得到自己的 dsh 会话(列在「旁聊」里,尽管这里还没跑过回合);主要聊天就是账号的主要对话所在的那个会话,账号已经有主要对话时,第一场对话就在它里面开始。harness 没有删除功能,日志什么都不忘:在别处删掉的消息在这里隐藏,在别处删掉的聊天在这里归档。从 0.1.38 起,插件自己保存「同时同步旁聊」的状态(默认关;关着时,这里的旁聊既不列出也不读来推送,仍然到达的旁聊行也不会生成会话),向中继请求 `scope=main`,并在第一次拉取和旁聊开关打开时请求尾部;另一台设备的「kwai 正在处理…」那一行,根据 hub 的 `working` 帧画在它最后一个气泡下面,由它的回复、`working: false` 或十分钟后清掉;远端的行从不进会话日志,所以 harness 不会把它误当成一个没结束的回合。宿主每次变化只读一遍会话日志(标题、行和提示位置一直保留到该会话的下一个事件),并把一连串 `sync` 帧合并成每秒一次拉取,所以一个大账号在空闲时对聊天没有任何开销。代码:运行时的 [`nanomuse/sync/`](../../nanomuse/sync/)(`ConversationSync`,`/api/sync/*` 见 [app.md](app.md#api)),网页版的 `SyncControls` 和 `web/src/` 里的消息说明文字,插件的 `src/sync.ts`、`client/RemoteBubbles.ts` 和 `tests/sync.test.mjs`,中继的 [`cloud/nanomuse_cloud/sync.py`](../../cloud/nanomuse_cloud/sync.py)。 +开关在「设置 → 数据控制 → 在我的设备之间同步对话」,默认开;关掉会让中继删除这个账号的存储,其他每台设备的开关也跟着关。「删除已同步的对话」清空存储,但保留开关。手机和网页版把每一场本地聊天映射到一个对话 id,把其他设备的改动直接套进自己的聊天列表。**nanoMuse 桌面版**(dsh 插件)把另一台设备的回合放在自己的存储里(`$DSH_HOME/nanomuse/sync-remote.json`,按会话;dsh 的会话日志只能追加,归它的智能体循环所有,在回合之外写进去的一行既不会显示也不安全),在浏览器里显示为另一台设备的气泡(`client/RemoteBubbles.ts`),按时间排在这里打的回合之间,并在模型下一步之前把到达的内容作为一条备注交给它(`agent.inject`;这条备注只是上下文,不是一行记录,也永远不会被推回去)。从中继拉下来的旁聊会立刻得到自己的 dsh 会话(列在「旁聊」里,尽管这里还没跑过回合);主要聊天就是账号的主要对话所在的那个会话,账号已经有主要对话时,第一场对话就在它里面开始。harness 没有删除功能,日志什么都不忘:在别处删掉的消息在这里隐藏,在别处删掉的聊天在这里归档。从 0.1.38 起,插件自己保存「同时同步旁聊」的状态(默认关;关着时,这里的旁聊既不列出也不读来推送,仍然到达的旁聊行也不会生成会话),向中继请求 `scope=main`,并在第一次拉取和旁聊开关打开时请求尾部;另一台设备的「kwai 正在处理…」那一行,根据 hub 的 `working` 帧画在它最后一个气泡下面,由它的回复、`working: false` 或十分钟后清掉;远端的行从不进会话日志,所以 harness 不会把它误当成一个没结束的回合。宿主每次变化只读一遍会话日志(标题、行和提示位置一直保留到该会话的下一个事件),并把一连串 `sync` 帧合并成每秒一次拉取,所以一个大账号在空闲时对聊天没有任何开销。代码:运行时的 [`nanomuse/sync/`](../../nanomuse/sync/)(`ConversationSync`,`/api/sync/*` 见 [app.md](app.md#api)),网页版的 `SyncControls` 和 `web/src/` 里的消息说明文字,插件的 `src/sync.ts`、`client/RemoteBubbles.ts` 和 `tests/sync.test.mjs`,中继的 [`cloud/nanomuse_cloud/sync.py`](../../cloud/nanomuse_cloud/sync.py)。 **在另一台设备上干活。** 默认永远是你正在打字的这台设备。想把某一条消息发去别处,就以 `@` 加上 hub 列出的设备名开头(`@Desk compile the project and send me the log`),前缀匹配,不分大小写;输入框会在你打字时提示这些名字,提及词从正文里摘掉,气泡上写「发给 Desk」,回合前面加一行备注,告诉这台设备的智能体用 `delegate`(手机上是 `nanomuse-pc task … --on`)把它交给那台设备,并汇报它做了什么;设备页上的「交给这台设备」做的是同一件事。iPhone 没有 delegate 工具,提及词直接发到 hub(给那台设备发 `task`,它的答复作为聊天里的一个回合显示),而且只匹配在线的设备。哪些设备可以作为目标:**电脑**(nanoMuse 桌面版、运行时)只要在线就行,因为它们的 hub 连接一直保持着;**手机**(Android 和 iPhone)只在 nanoMuse App 打开时可以,因为连接活在 App 里,两个平台都不在后台保持它。不在线的设备在网页版和桌面版上照样作为目标提供,回答 `device_offline`;网页控制台永远不是目标。一台设备替另一台跑的会话保存在那台设备上,不同步。 diff --git a/docs/zh/ios.md b/docs/zh/ios.md index 5a212a3ce..9f398b3b3 100644 --- a/docs/zh/ios.md +++ b/docs/zh/ios.md @@ -366,7 +366,7 @@ scripts/gen-ios-icons.py the app icon and the four alternates, from asse 等级;文件在但读不出来时(手机锁着、App 在后台被唤醒),存储等下一次调用再读,而不是从 空表开始并把空表写回去覆盖每个账号的记录。图片和视频生成和同一服务商的聊天一样走 「网络」里的代理(`NanoMuseProxy.SessionSlot`),失败时是每种语言都有的整句,*服务商拒绝了 - 这把密钥(HTTP 401)*、*视频超过 12 分钟仍未完成*,服务商自己的话跟在*服务商说:*后面。 + 这把密钥(HTTP 401)*、*视频超过 12 分钟仍未完成*,服务商自己的话跟在「服务商说:」后面。 - **审计第三遍(第 11 轮)**(`NanoMuseHubTasks.swift`、`NanoMuseHub.swift`):其他设备发来的 `stop` 既能按任务帧的 id 找到这次运行(`stop {call}`,桌面端发的就是这个),也能按会话找; 只有发起任务的设备能停它;停下之后任务按 [hub.md](hub.md) 的约定答 `cancelled`。socket @@ -397,7 +397,7 @@ scripts/gen-ios-icons.py the app icon and the four alternates, from asse 源码,我们的 key 里出现破折号、感叹号或翻译过的中继名就失败。服务商表单在保存 key 之前先拿它 去取服务商的模型列表:401 或 403 时手机保持原样,并在输入框下面说明原因;之前上游的回退会 填入一份目录里的模型列表,表单像 key 正确一样关闭。订阅的 429 带的 `Retry-After` 现在会传到 - 可达性卡片,ChatGPT 或 Claude 订阅也能看到*……后重置*。动态详情的几行是一个 `Grid`,标签列 + 可达性卡片,ChatGPT 或 Claude 订阅也能看到「……后重置」。动态详情的几行是一个 `Grid`,标签列 按最长的标签取宽;形象大小改成菜单,不再是五段分段控件。 - **第三轮审计:版本行(1.0.x)**(`NanoMuseUpdateCheck.swift`、 `MinisTests/NanoMuseLogicTests.swift`):`nanomuse.cn/dl/index.json` 的形状是 diff --git a/docs/zh/parity.md b/docs/zh/parity.md index 16183f401..e5942db21 100644 --- a/docs/zh/parity.md +++ b/docs/zh/parity.md @@ -140,14 +140,14 @@ nanoMuse 是同一个智能体,在每台设备上都是它:手机(Android 30. **iOS · 输入框、气泡、页眉。** 0.1.36 照手机定下:单行药丸形输入框、这个人的消息是扁平的灰色气泡、悬浮的半透明页眉。还剩的:iOS 16–18 上,对话从页眉边缘下方开始,而不是滚到它下面去(UIKit 列表需要把内边距传下去;要在真机上试,因为盲改有盖住第一条消息的风险,不值得)。 31. **桌面 · Mac 和 Windows 上的操作器。** 从 UI-TARS-desktop 移植,在 Linux X11 上验证过;原生插件、坐标空间(Mac 上是 point,Windows 上是物理像素)、滚动单位、`ctrl` 对应 ⌘、光晕的内容保护都在 Mac 任务单上(`docs/tasks/mac-check-0.1.36.md`,F)。Wayland 仍是第 21 条。 32. **iOS · 基于目录的办法卡片。** 0.1.39 给了 iPhone 按账号区分的对话(约定 C10,`NanoMuseSync`)和内置的 `providers.json`,但额度卡片仍然提供 0.1.34 的预设,也没有套餐登录;Android 的 `AllowanceWaysCard` 是样板(本地区的首选、「更多服务商」、套餐、选择器为空时的一句话)。*0.1.40 定下:* `NanoMuseCatalogue` 读内置的 `providers.json`(或中继的 guidance),`NanoMuseWaysList` 是置顶卡片、账号页和自己的 key 面板上共用的那一个列表,`NanoMuseVendorSheet` 收 key 或跑套餐登录(ChatGPT 走上游的 Codex OAuth,Claude、OpenRouter,Kimi 的设备码),以及本地服务器的地址。选择器(图片、短视频)为空时的那一句话随 0.1.41 的模型页到了:空的一行写明缺什么,并给「添加服务商」。 -33. **iOS · 额度卡片和聊天里的提醒。** 中继以 `allowance_exhausted` 拒绝的一轮,在 iOS 上以上游的错误文字结束;办法只在账号页上,`spend.warn` 只给那里的进度条上色,聊天里没有一行。*提议:*流以这个代码结束时,像 Star 卡片(3)那样在页眉下钉一张卡片,办法取自 `spend.guidance`(和 32 一起);80 % 时输入框上方一行,每个额度池一次,和其他三个客户端一样。*0.1.40 定下:* `NanoMuseAllowance` 两者都管;外壳钉上 `NanoMuseAllowanceCard`(带「再试一次」),`NanoMuseChatCardsHost` 显示提醒;`AIChatView.body` 上没有新的链接。 -34. **Android · 从中继的 guidance 取办法。** `AllowanceWaysCard` 读内置的 `providers.json`;`/v1/me` 带着 `spend.guidance`(本地区的服务商、套餐、注意事项),卡片却不理它。*提议:*中继给了 `guidance` 就优先用,没有再退回目录,网页和桌面已经这么做了;`AllowanceWaysCard.kt` 和 `NanoMuseCloud.kt` 里几十行。*0.1.40 定下:* `Guidance.kt` 解析它,`Ways.resolve` 优先用它,卡片和设置 → nanoMuse Cloud 都读它。 -35. **手机 · 413、其余的拒绝和运营者的开关。** 手机的 `describe` 认得额度、每日上限、限流、坏 key、停用的账号和上游出问题,但不认得 `too_large`(413)、`not_invited`、`too_many_in_flight` 或 `provider_busy`,也不认得中继 0.22 的 `service_paused`、`sync_paused`、`hub_paused`、`signup_closed` 和带 `paused: true` 的 `allowance_exhausted`(中继说*已暂停*,额度卡片却说*已用完*);这些到人眼前时是上游的文字或中继的英文句子。网页和桌面在 0.1.40 定下(`nanomuse/server/failures.py`、`harness/dsh-nanomuse/src/refusals.ts`:参考句子,en 和 zh)。*提议:*两个 `describe` 都加上这九个代码和那些句子,413 那条指向「新对话」,暂停的额度在同一张卡片上换一个开头;iOS 上被拒的聊天轮次也经过 `describe`。手机上每种语言都要有字符串。*0.1.40 定下*,两台手机都做了:`RelayRefusal` / `NanoMuseRelayRefusal` 给回复分类,`describe` 认得每一个代码,聊天里的卡片带着按钮(「新对话」·「登录」·「打开设置」·「再试一次」)。 -36. **桌面和网页上的语音。** 听写靠 Web Speech API,而 Electron 外壳不带它(那是 Chrome 里 Google 的服务),所以桌面打开听写页,网页只在有它的浏览器里能用;两者都不朗读回复。*提议:*语音进出都走运行时(`/api/speech`),用已配置服务商的模型(百炼的 `paraformer` / `cosyvoice`,OpenAI 的 `whisper` / `tts`),用这个人自己的 key 或中继,两个客户端一份实现;手机继续用系统的引擎。 -37. **网页 · 数据导出。** 桌面的房间宿主把智能体数据的 zip(`/data/export`)写到「下载」;网页版能分享形象卡片,也有数据控制,但没有文件。*提议:*运行时里加 `GET /api/data/export` 写同一个 zip,数据控制下加一行「下载你的智能体数据」。 -38. **界面语言。** 手机跟随系统(17 和 9 种语言),网页有应用内切换(自动 · en · zh-CN),桌面通过 harness 的语言行有英文和中文。*提议:*桌面的 `locales.ts` 随着大家的要求加上手机的那些语言,de 和 ja 先;手机上的应用内覆盖由上游决定。 +33. **iOS · 额度卡片和聊天里的提醒。** 中继以 `allowance_exhausted` 拒绝的一轮,在 iOS 上以上游的错误文字结束;办法只在账号页上,`spend.warn` 只给那里的进度条上色,聊天里没有一行。*提议*:流以这个代码结束时,像 Star 卡片(3)那样在页眉下钉一张卡片,办法取自 `spend.guidance`(和 32 一起);80 % 时输入框上方一行,每个额度池一次,和其他三个客户端一样。*0.1.40 定下:* `NanoMuseAllowance` 两者都管;外壳钉上 `NanoMuseAllowanceCard`(带「再试一次」),`NanoMuseChatCardsHost` 显示提醒;`AIChatView.body` 上没有新的链接。 +34. **Android · 从中继的 guidance 取办法。** `AllowanceWaysCard` 读内置的 `providers.json`;`/v1/me` 带着 `spend.guidance`(本地区的服务商、套餐、注意事项),卡片却不理它。*提议*:中继给了 `guidance` 就优先用,没有再退回目录,网页和桌面已经这么做了;`AllowanceWaysCard.kt` 和 `NanoMuseCloud.kt` 里几十行。*0.1.40 定下:* `Guidance.kt` 解析它,`Ways.resolve` 优先用它,卡片和设置 → nanoMuse Cloud 都读它。 +35. **手机 · 413、其余的拒绝和运营者的开关。** 手机的 `describe` 认得额度、每日上限、限流、坏 key、停用的账号和上游出问题,但不认得 `too_large`(413)、`not_invited`、`too_many_in_flight` 或 `provider_busy`,也不认得中继 0.22 的 `service_paused`、`sync_paused`、`hub_paused`、`signup_closed` 和带 `paused: true` 的 `allowance_exhausted`(中继说*已暂停*,额度卡片却说*已用完*);这些到人眼前时是上游的文字或中继的英文句子。网页和桌面在 0.1.40 定下(`nanomuse/server/failures.py`、`harness/dsh-nanomuse/src/refusals.ts`:参考句子,en 和 zh)。*提议*:两个 `describe` 都加上这九个代码和那些句子,413 那条指向「新对话」,暂停的额度在同一张卡片上换一个开头;iOS 上被拒的聊天轮次也经过 `describe`。手机上每种语言都要有字符串。*0.1.40 定下*,两台手机都做了:`RelayRefusal` / `NanoMuseRelayRefusal` 给回复分类,`describe` 认得每一个代码,聊天里的卡片带着按钮(「新对话」·「登录」·「打开设置」·「再试一次」)。 +36. **桌面和网页上的语音。** 听写靠 Web Speech API,而 Electron 外壳不带它(那是 Chrome 里 Google 的服务),所以桌面打开听写页,网页只在有它的浏览器里能用;两者都不朗读回复。*提议*:语音进出都走运行时(`/api/speech`),用已配置服务商的模型(百炼的 `paraformer` / `cosyvoice`,OpenAI 的 `whisper` / `tts`),用这个人自己的 key 或中继,两个客户端一份实现;手机继续用系统的引擎。 +37. **网页 · 数据导出。** 桌面的房间宿主把智能体数据的 zip(`/data/export`)写到「下载」;网页版能分享形象卡片,也有数据控制,但没有文件。*提议*:运行时里加 `GET /api/data/export` 写同一个 zip,数据控制下加一行「下载你的智能体数据」。 +38. **界面语言。** 手机跟随系统(17 和 9 种语言),网页有应用内切换(自动 · en · zh-CN),桌面通过 harness 的语言行有英文和中文。*提议*:桌面的 `locales.ts` 随着大家的要求加上手机的那些语言,de 和 ja 先;手机上的应用内覆盖由上游决定。 39. **网页 · 第一次对话。** 已按手机的做法做完,状态由运行时掌握:阶段机、提示词附加段和保存都在 `nanomuse/server/firstrun.py`(状态存在资料旁边的 `firstrun.json`),围栏的解析在 `nanomuse/fences.py`,路由是 `/api/firstrun*`,socket 帧是 `firstrun`;聊天说出那三句并画起名卡片(`web/src/components/FirstConversation.tsx`),首次运行的清单去掉了「认识你的 nanoMuse」那一页。称呼写进资料,也作为「Call them: …」写进记忆(运行时没有 USER.md)。身份表单留在「设置」里供以后修改。对约定的一处补充:运行时记下按「开始」时的语言(`lang`),附加段里引用的开场就是这个人看到的那几句。[web.md](web.md#the-first-run-and-the-chat-s-opening) 有完整的流程。 -40. **模型页,四个槽位(0.1.41)。** Android、iOS 和桌面版已定为同一个页面,加上保存 key 之后的「用它来做什么」卡片和自有模型失败时的「这次改用 nanoMuse Cloud」;网页控制台在「连接」页上有同样的四个槽位(运行时的 `PUT /api/connections/gui`、`/image`、`/video`,每个都有「自动」),但没有「用它来做什么」卡片,也没有只这一轮走账号的重试:自有 key 表单设的是对话服务商,失败的一轮显示失败。iOS 上还剩:图片和视频的选择器除了 nanoMuse Cloud 只列 DashScope 主机上的自有服务商(阿里云百炼),因为 iPhone 的图片和视频代码只说 DashScope 的接口。*提议:*有人要时,网页加上卡片和按钮,iPhone 加上 OpenAI 的图片接口形状。 +40. **模型页,四个槽位(0.1.41)。** Android、iOS 和桌面版已定为同一个页面,加上保存 key 之后的「用它来做什么」卡片和自有模型失败时的「这次改用 nanoMuse Cloud」;网页控制台在「连接」页上有同样的四个槽位(运行时的 `PUT /api/connections/gui`、`/image`、`/video`,每个都有「自动」),但没有「用它来做什么」卡片,也没有只这一轮走账号的重试:自有 key 表单设的是对话服务商,失败的一轮显示失败。iOS 上还剩:图片和视频的选择器除了 nanoMuse Cloud 只列 DashScope 主机上的自有服务商(阿里云百炼),因为 iPhone 的图片和视频代码只说 DashScope 的接口。*提议*:有人要时,网页加上卡片和按钮,iPhone 加上 OpenAI 的图片接口形状。 ## 让这页保持真实 {#keeping-this-true} diff --git a/tests/test_docs_markup.py b/tests/test_docs_markup.py new file mode 100644 index 000000000..47a26e99f --- /dev/null +++ b/tests/test_docs_markup.py @@ -0,0 +1,43 @@ +"""Every page under docs/ renders without a literal emphasis marker. + +CommonMark's flanking rules: a ``**…**`` or ``*…*`` run that closes right after a punctuation +mark (a full-width colon, a closing bracket) and is followed by a letter has no closer, so the +asterisks show on the site; the same when a run opens on punctuation after a letter. Chinese +prose runs into this where English, with its spaces, does not. markdown-it-py follows the +same rules as the markdown-it VitePress renders with, so a hit here is a hit on the site. +""" + +from __future__ import annotations + +import re +from pathlib import Path + +import pytest +from markdown_it import MarkdownIt + +ROOT = Path(__file__).resolve().parents[1] +DOCS = ROOT / "docs" +SKIP = {"releases", "archive", "tasks", "traces", "briefs"} +CJK = "\u3000-\u303f\u4e00-\u9fff\uff00-\uffef" +# A doubled asterisk anywhere, or a single one touching a Chinese character or punctuation. +STRAY = re.compile(rf"\*\*|(?<=[{CJK}])\*|\*(?=[\u4e00-\u9fff])") + + +def pages() -> list[Path]: + under_docs = (p for p in DOCS.rglob("*.md") if not set(p.relative_to(DOCS).parts[:-1]) & SKIP) + return sorted([ROOT / "README.md", *under_docs]) + + +def rendered_text(source: str) -> str: + """The page's text as the site shows it: HTML rendered, code left out, tags stripped.""" + source = re.sub(r"\A---\n[\s\S]*?\n---\n", "", source) + html = MarkdownIt("commonmark").enable("table").enable("strikethrough").render(source) + html = re.sub(r"|", "", html) + return re.sub(r"<[^>]+>", "", html) + + +@pytest.mark.parametrize("page", pages(), ids=lambda p: str(p.relative_to(ROOT))) +def test_no_literal_emphasis_marker(page: Path) -> None: + text = rendered_text(page.read_text(encoding="utf-8")) + hits = [text[max(0, m.start() - 20) : m.end() + 20] for m in STRAY.finditer(text)] + assert not hits, hits From aa944d48fa42f74be63e349e7d3e44301068ae43 Mon Sep 17 00:00:00 2001 From: lgy0404 <2528379691@qq.com> Date: Mon, 12 Oct 2026 03:59:36 +0800 Subject: [PATCH 88/98] test(desktop): two Mac path assertions read the same on Windows The translocation and defaultHelperPath tests built or compared macOS paths through node:path's join, which uses the backslash on Windows; the first joins with "/" on purpose and the second compares with the separators normalised, so the Windows job runs the shell's 59 tests green. Signed-off-by: lgy0404 <2528379691@qq.com> --- harness/desktop/tests/mac-helper.test.mjs | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/harness/desktop/tests/mac-helper.test.mjs b/harness/desktop/tests/mac-helper.test.mjs index 52cf95764..f15e90d8a 100644 --- a/harness/desktop/tests/mac-helper.test.mjs +++ b/harness/desktop/tests/mac-helper.test.mjs @@ -10,7 +10,7 @@ import { createServer } from "node:http"; import { existsSync, mkdirSync, mkdtempSync, readFileSync, rmSync, statSync, writeFileSync } from "node:fs"; import Module, { createRequire } from "node:module"; import { tmpdir } from "node:os"; -import { join } from "node:path"; +import { join, sep } from "node:path"; import { after, test } from "node:test"; import { MacHelper, MacHelperError, HELPER_NAME, HELPER_SCREEN_PERMISSION_TEXT, QUARANTINE_KEPT_TEXT, clearQuarantine, defaultHelperPath, describeAction, translocated } from "../out/mac-helper.js"; @@ -504,9 +504,14 @@ test("clearQuarantine: xattr's answers → none, removed, kept (with what it sai assert.equal(calls.length, before); }); +// macOS paths from a function that joins with the platform's separator, so the assertions +// read the same on a Windows checkout (the helper never runs there; its path logic is tested) +const posix = (path) => path.split(sep).join("/"); + test("an app under App Translocation does not start its helper, and says why", async () => { const dir = scratch(); - const app = join(dir, "AppTranslocation", "4F1C", "d", "nanoMuse.app", "Contents", "Helpers", `${HELPER_NAME}.app`); + // joined with "/" on purpose: translocation is a macOS path, and Windows accepts the slash + const app = [dir, "AppTranslocation", "4F1C", "d", "nanoMuse.app", "Contents", "Helpers", `${HELPER_NAME}.app`].join("/"); mkdirSync(app, { recursive: true }); assert.equal(translocated(app), true); assert.equal(translocated("/Applications/nanoMuse.app/Contents/Helpers/x.app"), false); @@ -520,8 +525,8 @@ test("an app under App Translocation does not start its helper, and says why", a test("defaultHelperPath: the env override, Contents/Helpers when packaged, the build dir in development", () => { assert.equal(defaultHelperPath("/x/nanoMuse.app/Contents/MacOS/nanomuse-desktop", true, "/proj", { NANOMUSE_COMPUTER_USE_APP: "/elsewhere/Helper.app" }), "/elsewhere/Helper.app"); - assert.equal(defaultHelperPath("/x/nanoMuse.app/Contents/MacOS/nanomuse-desktop", true, "/proj", {}), "/x/nanoMuse.app/Contents/Helpers/nanoMuse Computer Use.app"); - assert.equal(defaultHelperPath("/usr/bin/electron", false, "/proj", {}), "/proj/mac/computer-use/build/nanoMuse Computer Use.app"); + assert.equal(posix(defaultHelperPath("/x/nanoMuse.app/Contents/MacOS/nanomuse-desktop", true, "/proj", {})), "/x/nanoMuse.app/Contents/Helpers/nanoMuse Computer Use.app"); + assert.equal(posix(defaultHelperPath("/usr/bin/electron", false, "/proj", {})), "/proj/mac/computer-use/build/nanoMuse Computer Use.app"); }); test("describeAction: the glow's words, as the operator phrases them", () => { From e4989128ffeb963c92c4ac4de86cfff0b1670d45 Mon Sep 17 00:00:00 2001 From: lgy0404 <2528379691@qq.com> Date: Mon, 12 Oct 2026 04:19:08 +0800 Subject: [PATCH 89/98] chore(release): release-docs.py works out the roadmap rows before it writes A page without the past-releases table, or with the version's row already there, refused the run after CHANGELOG.md, the READMEs and the issue forms had been rewritten. The rows are now computed right after the arguments are checked and written in their old place, so a refusal leaves every file as it was; the test covers it. Signed-off-by: lgy0404 <2528379691@qq.com> --- scripts/release-docs.py | 21 +++++++++++++-------- tests/test_release_docs.py | 11 +++++++++++ 2 files changed, 24 insertions(+), 8 deletions(-) diff --git a/scripts/release-docs.py b/scripts/release-docs.py index b80febfc1..dbe859e3c 100755 --- a/scripts/release-docs.py +++ b/scripts/release-docs.py @@ -153,6 +153,17 @@ def main(argv: list[str]) -> int: if not Path("pyproject.toml").is_file(): print("run from the repository root", file=sys.stderr) return 2 + # The roadmap rows are worked out before anything is written, so a page without the table + # or with the row already there refuses the run while every file is still as it was. + roadmap_texts: dict[str, str] = {} + for name, line in roadmap.items(): + try: + roadmap_texts[name] = add_roadmap_row( + Path(name).read_text(encoding="utf-8"), new, newname, line + ) + except ValueError as exc: + print(f"{name}: {exc}", file=sys.stderr) + return 1 changelog = Path("CHANGELOG.md") s = changelog.read_text(encoding="utf-8") @@ -191,15 +202,9 @@ def main(argv: list[str]) -> int: if moved: print(f"{name}: {moved} example version(s) now {new} ({code})") - for name, line in roadmap.items(): - p = Path(name) - try: - text = add_roadmap_row(p.read_text(encoding="utf-8"), new, newname, line) - except ValueError as exc: - print(f"{name}: {exc}", file=sys.stderr) - return 1 + for name, text in roadmap_texts.items(): if not dry_run: - p.write_text(text, encoding="utf-8") + Path(name).write_text(text, encoding="utf-8") print(f"{name}: a row for {new} {newname} at the end of the past-releases table") template = Path("docs/release-notes-template.md") diff --git a/tests/test_release_docs.py b/tests/test_release_docs.py index b10d662ed..858aa5149 100644 --- a/tests/test_release_docs.py +++ b/tests/test_release_docs.py @@ -250,6 +250,17 @@ def test_main_writes_both_roadmap_rows_or_asks_for_them( .endswith("| 1.0.1 | Still | 一句话 |\n") ) + # a page without the table refuses the run before anything is written + bare = tmp_path / "bare" + bare.mkdir() + monkeypatch.chdir(bare) + _tree(bare) + (bare / "docs" / "roadmap.md").write_text("# Roadmap\n", encoding="utf-8") + (bare / "docs" / "zh" / "roadmap.md").write_text("# 路线图\n", encoding="utf-8") + assert release_docs.main([*args, "--roadmap", "One line", "--roadmap-zh", "一句话"]) == 1 + assert "no past-releases table" in capsys.readouterr().err + assert "## [1.0.1]" not in (bare / "CHANGELOG.md").read_text(encoding="utf-8") + # without the flags the rows are left to hand work, and the message says so again = tmp_path / "again" again.mkdir() From ecb28006aef95bfc32e588cb194bb32caf009c45 Mon Sep 17 00:00:00 2001 From: lgy0404 <2528379691@qq.com> Date: Mon, 12 Oct 2026 08:49:08 +0800 Subject: [PATCH 90/98] feat(relay): show who invited whom on the admin page MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The admin page's funnel line said how many people had made a code, brought someone and come through one, and nothing more; the relay has held who signed up with whose code since invites began, but no view showed it. A new Invites view (GET /v1/admin/invites) ranks the inviters by the accounts their code brought, with how many of those ever made a request, how many were seen from one of the inviter's own addresses, what they spent, what the inviter earned from them and when the first and the last signed up; a row unfolds to the newest of the people it brought. An account's page names its inviter by identifier with a link and lists everyone it brought with when they joined, whether they used anything and from where; the accounts table marks an inviter with the count and can sort by it. English and 简体中文; the route is in the api docstring, cloud/README.md and docs/cloud.md with its twin. The invitee list is ordered newest first with the row id as the tie break, so two sign-ups in one second keep a stable order. Signed-off-by: lgy0404 <2528379691@qq.com> --- CHANGELOG.md | 1 + cloud/README.md | 9 ++ cloud/nanomuse_cloud/api.py | 8 ++ cloud/nanomuse_cloud/console/admin/admin.js | 115 ++++++++++++++++++-- cloud/nanomuse_cloud/db.py | 53 ++++++++- cloud/nanomuse_cloud/service.py | 64 ++++++++++- cloud/tests/test_accounts.py | 73 +++++++++++++ cloud/tests/test_console.py | 49 +++++++++ docs/cloud.md | 6 +- docs/zh/cloud.md | 2 +- 10 files changed, 366 insertions(+), 14 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 22f74b5a6..eeff5a956 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,7 @@ All notable changes to nanoMuse. The format follows [Keep a Changelog](https://k - **Signing a device out also drops its line to the hub.** *Sign out everywhere*, a sign-in revoked on the account page and a device's own sign-out revoked the key at once, but a hub socket that device had open stayed open until it next reconnected, so a lost phone could still reach the account's other devices for a while. The relay now closes such a socket with `4001 bad_key` the moment the key is revoked, and the other devices see the device offline. - **The web console open in two tabs no longer fights itself.** Every tab of one browser said hello to the hub with the same device id, so the two took turns replacing each other and reconnecting for as long as both stayed open, and a message sent from the tab that had just lost came back as disconnected. Each tab is now its own device on the hub; a reload keeps the tab's id. - **A self-hosted relay's backup recipe takes a consistent copy.** The command in the self-hosting guide called a `sqlite3` binary the image does not have and fell back to copying `cloud.db`, which under WAL misses the newest writes; it now uses SQLite's backup API inside the running container and streams the copy out. The production notes restore a backup into the data directory as uid 10001, the user the relay runs as. A code mail composed with a `CODE_TTL_S` under a minute says the code is good for one minute, as the SMS template already did. +- **The admin page shows who invited whom.** The funnel line said how many people had made a code, brought someone and come through one, and nothing more. A new *Invites* view (`GET /v1/admin/invites`) ranks the inviters by the accounts their code brought, with how many of those ever made a request, how many were seen from one of the inviter's own addresses, what they spent, what the inviter earned from them and when the first and the last signed up; a row unfolds to the people it brought. An account's page names its inviter by identifier, with a link, and lists everyone it brought with when they joined, whether they used anything and from where; the accounts table marks an inviter with the count and can sort by it. In English and 简体中文. ### Runtime diff --git a/cloud/README.md b/cloud/README.md index db3cf7b26..0a417699d 100644 --- a/cloud/README.md +++ b/cloud/README.md @@ -537,6 +537,15 @@ Identifiers are kept AES-GCM-encrypted with a key derived from `CLOUD_SECRET`. A person can also remove themselves: `POST /v1/auth/delete` with their key deletes the account, its keys, ledger and devices. +The *Invites* view (`/v1/admin/invites`) shows who invited whom: the +inviters in order of the accounts their code brought, each with how many of +those ever made a request, how many were seen from one of the inviter's own +addresses (what one person padding their own pool looks like), what they +spent, what the inviter's pool got from them and when the first and the last +signed up; a row unfolds to the newest of the people it brought, and the +account drawer names an account's inviter and lists everyone it brought. The +accounts table marks an inviter with the count and sorts by it. + Two more panels come from `/v1/admin/series` and `/v1/admin/traffic`: the relay's own numbers by day (sign-ins, new and active accounts, sign-ups through an invite, data switches turned on, calls, refusals, upstream errors, and the diff --git a/cloud/nanomuse_cloud/api.py b/cloud/nanomuse_cloud/api.py index 33b1d9d77..786547258 100644 --- a/cloud/nanomuse_cloud/api.py +++ b/cloud/nanomuse_cloud/api.py @@ -51,6 +51,7 @@ GET /v1/admin/accounts/{id}/ledger X-Admin-Token ?limit=&before= → the account's statement, every line, page by page (before = last id shown) GET /v1/admin/accounts/{id}/events X-Admin-Token ?limit=&before= → the account's timeline, every entry, page by page GET /v1/admin/address X-Admin-Token ?ip=… → the accounts seen from one address + GET /v1/admin/invites X-Admin-Token ?limit=200&per=20 → who invited whom: the funnel and the inviters ranked by the accounts their code brought, with the newest `per` of them GET /v1/admin/usage X-Admin-Token ?days=14 → charged tokens and yuan per day and kind GET /v1/admin/overview X-Admin-Token ?days=30 → the dashboard: accounts, today / week / period by kind and model, signals, events GET /v1/admin/events X-Admin-Token ?limit=200&kind=… → the timeline across accounts (never message content) @@ -1413,6 +1414,13 @@ async def admin_address(ip: str = "") -> dict: out["place"] = place.as_dict() if place is not None else None return with_places(out) + @app.get("/v1/admin/invites", dependencies=[Depends(admin_dep)]) + async def admin_invites(limit: int = 200, per: int = 20) -> dict: + """The inviters in order of how many accounts their code brought, with what those + accounts did and the newest `per` of them, and the funnel; an account's detail + page lists its invitees in full.""" + return with_places(cloud.admin_invites(max(1, min(limit, 1000)), max(0, min(per, 100)))) + @app.get("/v1/admin/events", dependencies=[Depends(admin_dep)]) async def admin_events(limit: int = 200, kind: str = "") -> dict: kinds = tuple(k.strip() for k in kind.split(",") if k.strip()) or None diff --git a/cloud/nanomuse_cloud/console/admin/admin.js b/cloud/nanomuse_cloud/console/admin/admin.js index ec270bebb..2cba1641a 100644 --- a/cloud/nanomuse_cloud/console/admin/admin.js +++ b/cloud/nanomuse_cloud/console/admin/admin.js @@ -96,7 +96,7 @@ catalog: "模型目录", catalogNote: "key 下能用的模型(菜单之外):relay 向每个模型各问一句话、再给一张品红色小图,确认它能回答、能不能看图;答案保存 7 天。客户端拿到的「能看图」就是这里的结果。", catalogOff: "模型目录未开启(CLOUD_CATALOG=0)。", catalogNames: "按名字推断,未逐个验证(CLOUD_CATALOG_PROBE=0)。", catalogProbing: "正在验证…", catalogPending: (n) => `${fmt(n)} 个待验证`, catalogFetched: (t) => `列表更新于 ${t}`, catalogError: (e) => `读取列表失败:${e}`, cModel: "模型", cKind: "类型", cSees: "看图", cVerified: "已验证", cYes: "是", cNo: "否", cUnusable: "服务商拒绝的模型(不出现在客户端)", cNoUnusable: "没有被拒绝的模型。", cCount: (n, v) => `${fmt(n)} 个对话模型 · ${fmt(v)} 个能看图`, // 0.14: the page in pages - nav: { overview: "总览", people: "用户", places: "地区", money: "花费", activity: "动态", demo: "在线体验", data: "数据控制", site: "官网", models: "模型", health: "服务状态", stats: "统计", controls: "控制", settings: "配置" }, + nav: { overview: "总览", people: "用户", invites: "邀请", places: "地区", money: "花费", activity: "动态", demo: "在线体验", data: "数据控制", site: "官网", models: "模型", health: "服务状态", stats: "统计", controls: "控制", settings: "配置" }, // 0.22: the Controls page, the Stats page, the GitHub series ctl: { title: "控制", note: "每个开关立刻生效、重启后保持;谁在何时改了什么记在下面的日志里。关闭前会先说明确切后果。", @@ -135,7 +135,15 @@ stat: { member: "成员", disabled: "已停用", locked: "已锁定", password: "设了密码", nopassword: "未设密码", contributes: "开启「帮助改进」", exhausted: "额度用光", online: "有设备在线", new: "本期新注册" }, act: { today: "24 小时内", "7d": "7 天内", "30d": "30 天内", older: "更早", never: "从未使用" }, bucket: { 0: "¥0", lt1: "<¥1", "1to5": "¥1–5", "5to10": "¥5–10", ge10: "≥¥10" }, - sortBy: { active: "最近活跃", joined: "注册时间", spent: "累计花费", today: "今天花费", tokens: "tokens", requests: "请求数", left: "剩余额度", region: "地区" }, + sortBy: { active: "最近活跃", joined: "注册时间", spent: "累计花费", today: "今天花费", tokens: "tokens", requests: "请求数", left: "剩余额度", region: "地区", invites: "邀请人数" }, + // who invited whom: the Invites view and the account drawer's list + invNote: "谁邀请了谁。按邀请到的账号数排序;点一行展开被邀请的人,点名字打开账号页。", invSearch: "搜索邀请人…", invNone: "还没有人经邀请注册。", invNoMatch: "没有匹配的邀请人。", + invKpiCode: "生成过邀请码", invKpiInviters: "邀请成功的人", invKpiInvited: "经邀请注册", invKpiActive: "其中用过的", invKpiSameIp: "与邀请人同地址", + invThWho: "邀请人", invThInvited: "邀请到", invThActive: "其中用过", invThSameIp: "同一地址", invThSpent: "他们花了", invThEarned: "获得奖励", invThLast: "最近一次", + invSort: { invited: "邀请到", active: "其中用过", same_ip: "同一地址", spent: "他们花了", earned: "获得奖励", latest: "最近一次" }, + invRecorded: (n) => `记录为 ${fmt(n)}`, invSameIp: "同地址", invGone: "已注销", invSeeRanking: "查看谁邀请了谁", invMore: (n) => `还有 ${fmt(n)} 个,打开账号页看全部`, + invSameIpNote: "「同一地址」指被邀请人的首次或最近地址与邀请人的相同,一个人给自己刷额度时常是这样;「记录为」是邀请计数器的值,被邀请人注销账号后计数不减。", + invitedList: (n) => `邀请的人 · ${fmt(n)}`, invPill: (n) => `邀请了 ${fmt(n)} 人`, invEarnedLine: (m) => `邀请奖励共 ${m}`, invNewest: (n, total) => `只列出最新 ${fmt(n)} 个,共 ${fmt(total)} 个`, cSignups: "注册", cRegions: "地区分布", cRegionsIn: (c) => `${c} · 分布`, cSpend: "花费分布", cActivity: "活跃度", cChannel: "渠道", cClients: "客户端", cClickNote: "图上的每一块都是筛选条件:点一下只看它,再点一下取消。", up: "上一级", thRegion: "地区", moreRows: (n) => `再显示 ${fmt(n)} 个`, exportCsv: "导出 CSV", csvNote: "导出的是当前筛选结果,和表格一样含完整的手机号 / 邮箱,文件只留在你手里。", byDayLabel: "按天", byWeekLabel: "按周", @@ -213,7 +221,7 @@ pCountry: "Country / region", pProvince: "Province / state", pAccounts: "Accounts", pNew: "New", pSignins: "Sign-ins", pRequests: "Requests", pDemo: "Demo visitors", pUnknown: "unknown", pLocal: "local network", pNone: "No visits recorded yet.", pAccountsNote: "accounts by their latest address", catalog: "Model catalog", catalogNote: "The models under the key beyond the menu: the relay asks each one a one-word question and then shows it a small magenta picture, to learn whether it answers and whether it sees; the answers stand for seven days. The “sees pictures” the apps show is what is here.", catalogOff: "The catalog is off (CLOUD_CATALOG=0).", catalogNames: "Guessed from names, not checked one by one (CLOUD_CATALOG_PROBE=0).", catalogProbing: "Checking…", catalogPending: (n) => `${fmt(n)} to check`, catalogFetched: (t) => `list read ${t}`, catalogError: (e) => `The list could not be read: ${e}`, cModel: "Model", cKind: "Kind", cSees: "Sees pictures", cVerified: "Checked", cYes: "yes", cNo: "no", cUnusable: "Models the provider refuses (not offered to the apps)", cNoUnusable: "None refused.", cCount: (n, v) => `${fmt(n)} chat models · ${fmt(v)} see pictures`, - nav: { overview: "Overview", people: "People", places: "Places", money: "Spend", activity: "Activity", demo: "Demo", data: "Data", site: "Site", models: "Models", health: "Health", stats: "Stats", controls: "Controls", settings: "Settings" }, + nav: { overview: "Overview", people: "People", invites: "Invites", places: "Places", money: "Spend", activity: "Activity", demo: "Demo", data: "Data", site: "Site", models: "Models", health: "Health", stats: "Stats", controls: "Controls", settings: "Settings" }, ctl: { title: "Controls", note: "Each switch applies at once and survives a restart; who changed what, and when, is in the log below. A switch says exactly what turning it off does before it flips.", names: { free_allowance: "Free allowance", signups: "Sign-ups", cloud_service: "Cloud service", sync: "Conversation sync", hub: "Device hub" }, @@ -251,7 +259,15 @@ stat: { member: "members", disabled: "disabled", locked: "locked", password: "with a password", nopassword: "without a password", contributes: "“help improve” on", exhausted: "allowance used up", online: "a device online", new: "new this period" }, act: { today: "last 24 h", "7d": "last 7 days", "30d": "last 30 days", older: "longer ago", never: "never used" }, bucket: { 0: "¥0", lt1: "<¥1", "1to5": "¥1–5", "5to10": "¥5–10", ge10: "≥¥10" }, - sortBy: { active: "last active", joined: "joined", spent: "spent", today: "spent today", tokens: "tokens", requests: "requests", left: "left", region: "region" }, + sortBy: { active: "last active", joined: "joined", spent: "spent", today: "spent today", tokens: "tokens", requests: "requests", left: "left", region: "region", invites: "invites" }, + // who invited whom: the Invites view and the account drawer's list + invNote: "Who brought whom. Inviters in order of the accounts their code brought; open a row for the people it brought, a name for the account page.", invSearch: "Search inviters…", invNone: "Nobody has come through an invite yet.", invNoMatch: "No inviter matches.", + invKpiCode: "made a code", invKpiInviters: "brought someone", invKpiInvited: "came through a code", invKpiActive: "of them used it", invKpiSameIp: "same address as the inviter", + invThWho: "Inviter", invThInvited: "Brought", invThActive: "Used it", invThSameIp: "Same address", invThSpent: "They spent", invThEarned: "Earned", invThLast: "Latest", + invSort: { invited: "brought", active: "used it", same_ip: "same address", spent: "they spent", earned: "earned", latest: "latest" }, + invRecorded: (n) => `recorded ${fmt(n)}`, invSameIp: "same address", invGone: "deleted", invSeeRanking: "see who brought whom", invMore: (n) => `${fmt(n)} more; the account page lists them all`, + invSameIpNote: "“Same address” means an invitee's first or latest address is one of the inviter's own, which is what one person padding their own pool looks like; “recorded” is the invite counter, which does not go down when an invitee deletes their account.", + invitedList: (n) => `Brought · ${fmt(n)}`, invPill: (n) => `${fmt(n)} invited`, invEarnedLine: (m) => `${m} earned from invites`, invNewest: (n, total) => `the newest ${fmt(n)} of ${fmt(total)}`, cSignups: "Sign-ups", cRegions: "By region", cRegionsIn: (c) => `${c} · by region`, cSpend: "By spend", cActivity: "By activity", cChannel: "By channel", cClients: "By client", cClickNote: "Every piece of a chart is a filter: click it to see only that, click again to let go.", up: "Up a level", thRegion: "Region", moreRows: (n) => `Show ${fmt(n)} more`, exportCsv: "Export CSV", csvNote: "The current selection as the table shows it, phone numbers and addresses included; keep the file to yourself.", byDayLabel: "by day", byWeekLabel: "by week", @@ -300,6 +316,7 @@ const NAV_ICON = { overview: svg(''), people: ICON.person, + invites: svg(''), places: svg(''), money: svg(''), activity: svg(''), @@ -319,7 +336,7 @@ "control.switch": ["warn", ICON.warn], "control.rule": ["warn", ICON.warn], }; const FILTERS = [["", "all"], ["sign_in.code,sign_in.password,sign_in.session,sign_in.failed,account.created", "signIns"], ["budget.refused", "refusals"], ["upstream.error", "errors"], ["content.rejected", "contentChecks"], ["call.ended", "calls"], ["password.set,password.changed,password.cleared", "passwords"]]; - const VIEWS = ["overview", "people", "places", "money", "activity", "demo", "data", "site", "models", "health", "stats", "controls", "settings"]; + const VIEWS = ["overview", "people", "invites", "places", "money", "activity", "demo", "data", "site", "models", "health", "stats", "controls", "settings"]; const PAGE = 50; // ── state ────────────────────────────────────────────────────── @@ -385,6 +402,7 @@ data: (d) => `/v1/admin/data?days=${d}`, demo: (d) => `/v1/admin/demo?days=${d}`, places: (d) => `/v1/admin/places?days=${d}`, + invites: () => "/v1/admin/invites?limit=500&per=20", catalog: () => "/v1/admin/catalog", health: () => "/v1/admin/health", nudges: () => "/v1/admin/nudges", @@ -394,7 +412,7 @@ stats: (d) => `/v1/admin/stats?days=${d}`, github: (d) => `/v1/admin/github?days=${d}`, }; - const TIMELESS = new Set(["catalog", "health", "nudges", "sync", "controls"]); + const TIMELESS = new Set(["catalog", "health", "nudges", "sync", "controls", "invites"]); const CACHE = new Map(); const cacheKey = (key) => `${key}:${TIMELESS.has(key) ? 0 : days}`; /** The view's data, or null while it is on its way (the view draws again when it lands); @@ -696,7 +714,7 @@ sparkRow(T.mRefused, rows, "budget_refusals", "warn", dayOf), sparkRow(T.mErrors, rows, "upstream_errors", "warn", dayOf), sparkRow(T.mContentRejected, rows, "content_rejected", "grey", dayOf)), h("div", { class: "kv" }, h("b", {}, T.devices), h("span", {}, Object.keys(byKind).length ? Object.entries(byKind).map(([k, v]) => h("div", {}, h("span", { class: "pill", style: "margin-right:6px" }, `${T.devKinds[k] || k} ${fmt(v.n)}`), h("span", { class: "fine" }, v.os.join(" · ")))) : T.none), - h("b", {}, T.invitesTitle), h("span", {}, T.invitesLine({ with_code: 0, inviters: 0, invited: 0, ...(sr.invites || {}) })), + h("b", {}, T.invitesTitle), h("span", {}, T.invitesLine({ with_code: 0, inviters: 0, invited: 0, ...(sr.invites || {}) }), " · ", h("a", { class: "more-link", href: "#invites" }, T.invSeeRanking)), h("b", {}, T.webTitle), h("span", {}, sr.web && sr.web.enabled === false ? T.webOff : T.webLine(sr.web)))); } function eventRow(e, withWho, accountId) { @@ -897,7 +915,8 @@ h("div", {}, h("div", { class: "k" }, T.spendToday), h("div", { class: "v", title: usd(sp.today_cny, rate) }, money(sp.today_cny)), h("div", { class: "k", style: "margin-top:4px" }, T.tokens(a.used))), h("div", {}, h("div", { class: "k" }, T.requests), h("div", { class: "v" }, fmt(sp.requests_total)), h("div", { class: "k", style: "margin-top:4px" }, s.unlimited ? T.noCap : `${T.grant}: ${fmt(a.granted)}`))), h("div", { class: "fine", style: "padding:0 16px 10px" }, T.poolLine(money(a.grant_cny || 0), a.left_cny === null || a.left_cny === undefined ? null : money(a.left_cny), a.invites || 0, !!a.contribute_bonus_at), - a.invited_by ? [" · ", T.invitedBy, " ", h("code", {}, String(a.invited_by).slice(0, 8))] : null), + // the inviter by name when the account is still there, the id's start when it is gone + a.invited_by ? [" · ", T.invitedBy, " ", a.inviter ? h("a", { class: "more-link", href: "#", onclick: (e) => { e.preventDefault(); openAccount(a.inviter.id); } }, who(a.inviter)) : [h("code", {}, String(a.invited_by).slice(0, 8)), ` (${T.invGone})`]] : null), h("div", { class: "acts" }, s.unlimited ? null : h("button", { class: "btn quiet", onclick: () => doGrant(a) }, T.grant), h("button", { class: "btn quiet", onclick: () => doCredit(a) }, T.credit), @@ -905,6 +924,10 @@ a.listed ? null : h("button", { class: "btn quiet", onclick: () => doMember(a) }, a.unlimited ? T.unmakeMember : T.makeMember), h("button", { class: "btn quiet", onclick: () => doDisable(a) }, a.disabled ? T.enable : T.disable), h("button", { class: "btn danger", onclick: () => doDelete(a) }, T.remove))), + // the people this account's code brought, newest first; shown once there is one to show + ...((a.invited || []).length || a.invites ? [h("div", { class: "label" }, T.invitedList(a.invited_total || (a.invited || []).length), a.invite_earned_cny ? ` · ${T.invEarnedLine(money(a.invite_earned_cny))}` : ""), + h("div", { class: "card" }, ...(a.invited || []).map((i) => inviteeRow(i, a)), !(a.invited || []).length ? h("div", { class: "empty" }, T.none) : null, + (a.invited_total || 0) > (a.invited || []).length ? h("div", { class: "fine", style: "padding:6px 16px 10px" }, T.invNewest((a.invited || []).length, a.invited_total)) : null)] : []), h("div", { class: "label" }, T.byKind), h("div", { class: "card" }, h("div", { class: "label", style: "margin:12px 16px 4px" }, T.usageToday), kindRows(u.today && u.today.by_kind, rate), h("div", { class: "label", style: "margin:12px 16px 4px" }, T.usagePeriod(p.days || days)), kindRows(p.by_kind, rate), @@ -993,6 +1016,7 @@ const SORTS = { active: (a) => a.last_active_at || 0, joined: (a) => a.created_at || 0, spent: (a) => Number(a.spent_cny || 0), today: (a) => Number(a.spent_today_cny || 0), tokens: (a) => Number(a.used || 0), requests: (a) => Number(a.requests || 0), left: (a) => (a.left_cny === null || a.left_cny === undefined ? -1 : Number(a.left_cny)), region: (a) => regionName(placeOfAccount(a)), + invites: (a) => Number(a.invites || 0), }; const peopleFilters = () => { const g = (k) => params.get(k) || ""; @@ -1095,7 +1119,8 @@ a.review ? h("span", { class: "pill", title: T.reviewNote }, T.review) : null, a.has_password ? h("span", { class: "pill violet" }, T.password) : null, a.disabled ? h("span", { class: "pill bad" }, T.disabled) : null, - a.locked ? h("span", { class: "pill warn" }, T.locked) : null)))), + a.locked ? h("span", { class: "pill warn" }, T.locked) : null, + a.invites ? h("span", { class: "pill violet", title: T.invSeeRanking, onclick: (e) => { e.stopPropagation(); go("invites", { q: a.identifier || a.hint }); } }, T.invPill(a.invites)) : null)))), h("td", { class: "hide-sm" }, dateOf(a.created_at)), h("td", { class: "hide-sm" }, p ? h("span", { class: "place", title: p.isp || "" }, placeText(p)) : h("span", { class: "fine" }, T.pUnknown)), h("td", { class: "num" }, money(a.spent_cny), h("span", { class: "sub" }, money(a.spent_today_cny)), cap > 0 ? h("div", { class: "meter sm", title: `${T.cap} ${money(cap)} · ${T.left} ${money(a.left_cny || 0)}` }, h("i", { class: frac >= 1 ? "bad" : frac >= 0.8 ? "warn" : "", style: `width:${Math.round(frac * 100)}%` })) : null), @@ -1124,6 +1149,76 @@ download(new Blob(["\ufeff" + text], { type: "text/csv;charset=utf-8" }), `nanomuse-accounts-${new Date().toISOString().slice(0, 10)}.csv`); } + // ── invites: who brought whom, the inviters that brought most first ── + const INV_SORTS = { + invited: (x) => x.invited || 0, active: (x) => x.invited_active || 0, same_ip: (x) => x.invited_same_ip || 0, + spent: (x) => Number(x.invited_spent_cny || 0), earned: (x) => Number(x.earned_cny || 0), latest: (x) => x.last_invite_at || 0, + }; + const INV_OPEN = new Set(); // the inviters whose people are unfolded in the table + const inviteeLabel = (i) => identOf(i.id, i.hint); + /** One account that came through a code, as a row: who, when, whether it was used, from where. */ + function inviteeRow(i, inviter, cls) { + const same = !!(inviter && [i.first_ip, i.last_ip].some((ip) => ip && (ip === inviter.first_ip || ip === inviter.last_ip))); + return h("div", { class: "row tap" + (cls ? " " + cls : ""), onclick: (e) => { e.stopPropagation(); openAccount(i.id); } }, + h("span", { class: "tile" + (i.requests > 0 ? "" : " grey"), html: ICON.person }), + h("div", { class: "txt" }, h("div", { class: "t" }, inviteeLabel(i), " ", h("span", { class: "pill" }, i.channel === "phone" ? T.phone : T.email), + same ? [" ", h("span", { class: "pill warn" }, T.invSameIp)] : null, i.disabled ? [" ", h("span", { class: "pill bad" }, T.disabled)] : null), + h("div", { class: "s" }, `${T.thJoined} ${dateOf(i.created_at)} · ${T.lastSeenAt} ${i.last_seen_at ? ago(i.last_seen_at) : T.never} · ${T.thReqs} ${fmt(i.requests)} · ${money(i.spent_cny)}`, + i.last_ip ? [" · ", ipChip(i.last_ip, i.id)] : null))); + } + function invitesView() { + const iv = need("invites"); + if (!iv) return loadingPanel(T.nav.invites); + if (iv._error) return failedPanel(T.nav.invites, "invites", iv._error); + const f = { q: params.get("q") || "", sort: INV_SORTS[params.get("sort")] ? params.get("sort") : "invited", dir: params.get("dir") || "desc", n: Number(params.get("n")) || PAGE }; + const q = f.q.trim().toLowerCase(); + const all = iv.leaders || [], fun = { with_code: 0, inviters: 0, invited: 0, ...(iv.funnel || {}) }; + const shown = all.filter((x) => !q || (x.hint || "").toLowerCase().includes(q) || (x.identifier || "").toLowerCase().includes(q) || (x.id || "").startsWith(q) || (x.last_ip || "").includes(q)); + const key = INV_SORTS[f.sort], sign = f.dir === "asc" ? 1 : -1; + shown.sort((a, b) => (key(a) - key(b)) * sign || (b.invited || 0) - (a.invited || 0) || (b.last_invite_at || 0) - (a.last_invite_at || 0)); + const page = shown.slice(0, f.n); + const sum = (k) => all.reduce((t, x) => t + Number(x[k] || 0), 0); + const kpis = h("div", { class: "kpis in-panel" }, + flatKpi(T.invKpiCode, fmt(fun.with_code)), flatKpi(T.invKpiInviters, fmt(fun.inviters)), flatKpi(T.invKpiInvited, fmt(fun.invited)), + flatKpi(T.invKpiActive, fmt(sum("invited_active"))), flatKpi(T.invKpiSameIp, fmt(sum("invited_same_ip")))); + const toolbar = h("div", { class: "toolbar" }, + h("span", { class: "search" }, h("input", { type: "search", "data-focus": "invites-q", placeholder: T.invSearch, value: f.q, oninput: (e) => setParams({ q: e.target.value, n: "" }) })), + select(T.fSort, f.sort, Object.entries(T.invSort), (v) => setParams({ sort: v, n: "" })), + h("span", { class: "cnt" }, T.fCount(shown.length, all.length))); + const th = (label, key, cls) => h("th", { class: (cls || "") + (key ? " sort" : "") + (key === f.sort ? " on" : ""), onclick: key ? () => setParams({ sort: key, dir: f.sort === key && f.dir === "desc" ? "asc" : "desc", n: "" }) : null }, label, key === f.sort ? (f.dir === "asc" ? " ↑" : " ↓") : ""); + const rows = []; + page.forEach((x, i) => { + const open = INV_OPEN.has(x.id), rank = shown.indexOf(x) + 1; + rows.push(h("tr", { class: open ? "country" : "", onclick: () => { if (open) INV_OPEN.delete(x.id); else INV_OPEN.add(x.id); draw(); } }, + h("td", { class: "num fine" }, String(rank)), + h("td", {}, h("div", { class: "who" }, h("div", { class: "disc" }, initial(x)), + h("div", { style: "min-width:0" }, h("div", { class: "n", title: x.hint }, h("a", { class: "more-link", href: "#", onclick: (e) => { e.preventDefault(); e.stopPropagation(); openAccount(x.id); } }, who(x))), + h("div", { class: "tags" }, h("span", { class: "pill" }, x.channel === "phone" ? T.phone : T.email), x.disabled ? h("span", { class: "pill bad" }, T.disabled) : null, + h("span", { class: "fine" }, `${T.thJoined} ${dateOf(x.created_at)}`))))), + h("td", { class: "num" + (f.sort === "invited" ? " on" : "") }, fmt(x.invited), x.invites !== x.invited ? h("span", { class: "sub" }, T.invRecorded(x.invites)) : null), + h("td", { class: "num hide-sm" + (f.sort === "active" ? " on" : "") }, fmt(x.invited_active), x.invited ? h("span", { class: "sub" }, `${Math.round(100 * x.invited_active / x.invited)}%`) : null), + h("td", { class: "num hide-sm" + (f.sort === "same_ip" ? " on" : "") }, x.invited_same_ip ? h("span", { class: "pill warn" }, fmt(x.invited_same_ip)) : "0"), + h("td", { class: "num hide-sm" + (f.sort === "spent" ? " on" : "") }, money(x.invited_spent_cny)), + h("td", { class: "num hide-sm" + (f.sort === "earned" ? " on" : "") }, money(x.earned_cny)), + h("td", { class: "hide-sm" + (f.sort === "latest" ? " on" : "") }, x.last_invite_at ? ago(x.last_invite_at) : T.never, h("span", { class: "sub" }, `${T.firstSeen} ${dateOf(x.first_invite_at)}`)), + h("td", { class: "num fine" }, open ? "▾" : "▸"))); + if (open) { + const list = x.invitees || []; + rows.push(h("tr", { class: "province" }, h("td", {}, ""), h("td", { colspan: 8, style: "padding:0" }, + h("div", { class: "list" }, ...list.map((it) => inviteeRow(it, x)), !list.length ? h("div", { class: "empty sm" }, T.none) : null, + x.invited > list.length ? h("div", { class: "row tap", onclick: (e) => { e.stopPropagation(); openAccount(x.id); } }, h("span", { class: "tile grey", html: ICON.person }), h("div", { class: "txt" }, h("div", { class: "s" }, T.invMore(x.invited - list.length)))) : null)))); + } + }); + const table = rows.length ? h("table", { class: "places" }, + h("thead", {}, h("tr", {}, th("#"), th(T.invThWho), th(T.invThInvited, "invited", "num"), th(T.invThActive, "active", "num hide-sm"), th(T.invThSameIp, "same_ip", "num hide-sm"), + th(T.invThSpent, "spent", "num hide-sm"), th(T.invThEarned, "earned", "num hide-sm"), th(T.invThLast, "latest", "hide-sm"), th(""))), + h("tbody", {}, ...rows)) : h("div", { class: "empty" }, all.length ? T.invNoMatch : T.invNone); + return [h("div", { class: "panel" }, h("h2", {}, T.nav.invites, h("span", { class: "pill" }, fmt(fun.inviters)), h("span", { class: "sp" }), h("span", { class: "fine" }, T.invNote)), kpis, toolbar), + h("div", { class: "panel" }, table, + shown.length > page.length ? h("div", { class: "more" }, h("button", { class: "btn quiet sm", onclick: () => setParams({ n: f.n + PAGE }) }, T.moreRows(Math.min(PAGE, shown.length - page.length))), h("span", { class: "fine" }, T.shown(page.length, shown.length))) : null, + h("div", { class: "fine", style: "padding:10px 16px 12px" }, T.invSameIpNote))]; + } + // ── places: where people are, and a way into them ────────────── const PLACE_METRICS = [["accounts", "pAccounts"], ["new_accounts", "pNew"], ["signins", "pSignins"], ["requests", "pRequests"], ["demo_visitors", "pDemo"]]; /** The places answer as a tree: countries with their provinces, every metric summed. */ @@ -1637,7 +1732,7 @@ h("div", {}, h("h3", {}, T.gh.releases), rankRows((latest.releases || []).map((r) => ({ name: r.tag, hits: r.downloads }))))), h("div", { class: "fine", style: "padding:0 16px 12px" }, T.gh.note)); } - const RENDER = { overview: overviewView, people: peopleView, places: placesView, money: moneyView, activity: activityView, demo: demoView, data: dataView, site: siteView, models: modelsView, health: healthView, stats: statsView, controls: controlsView, settings: settingsView }; + const RENDER = { overview: overviewView, people: peopleView, invites: invitesView, places: placesView, money: moneyView, activity: activityView, demo: demoView, data: dataView, site: siteView, models: modelsView, health: healthView, stats: statsView, controls: controlsView, settings: settingsView }; // ── the shell: bar, nav, one view ────────────────────────────── function drawMain() { diff --git a/cloud/nanomuse_cloud/db.py b/cloud/nanomuse_cloud/db.py index 57c0a5812..d1b1052ba 100644 --- a/cloud/nanomuse_cloud/db.py +++ b/cloud/nanomuse_cloud/db.py @@ -269,6 +269,13 @@ # account to come back online and hear the answer; short enough that a deletion is a deletion. DELETED_KEYS_TTL_S = 90 * 24 * 3600 +# The per-account figures the invite views join in, requests made and money spent, in one +# pass over the ledger (the same set of kinds as admin_accounts counts). +USAGE_BY_ACCOUNT = """(SELECT account_id, + SUM(CASE WHEN kind IN ('chat','image','video','realtime') THEN 1 ELSE 0 END) AS requests, + SUM(CASE WHEN cost_uy>0 THEN cost_uy ELSE 0 END) AS spent_uy + FROM ledger GROUP BY account_id)""" + def utc_day(ts: int) -> int: """The UNIX time the UTC day of `ts` starts — the key of the `daily` table.""" @@ -986,12 +993,56 @@ def invite_earned_uy(self, inviter_id: str) -> int: return int(r[0] or 0) def invitees(self, inviter_id: str, limit: int = 50) -> list[sqlite3.Row]: + """The accounts that signed up with this one's code, newest first, each with when it + came, whether it ever made a request and what it spent, where it was seen from and + when it was last seen. The person's own view keeps the hint and the date of these; + the operator's page shows the rest.""" with self._lock: return self._conn.execute( - "SELECT id, hint, created_at FROM accounts WHERE invited_by=? ORDER BY created_at DESC LIMIT ?", + f"""SELECT i.id, i.hint, i.channel, i.created_at, i.disabled, i.first_ip, i.last_ip, i.last_seen_at, + COALESCE(l.requests, 0) AS requests, COALESCE(l.spent_uy, 0) AS spent_uy + FROM accounts i + LEFT JOIN {USAGE_BY_ACCOUNT} l ON l.account_id=i.id + WHERE i.invited_by=? ORDER BY i.created_at DESC, i.rowid DESC LIMIT ?""", (inviter_id, limit), ).fetchall() + def invitee_count(self, inviter_id: str) -> int: + """How many accounts here now signed up with this one's code (the ``invites`` column + is the counter as it was recorded; an invitee who deleted their account leaves it).""" + with self._lock: + r = self._conn.execute("SELECT COUNT(*) FROM accounts WHERE invited_by=?", (inviter_id,)).fetchone() + return int(r[0] or 0) + + def invite_leaders(self, limit: int = 200) -> list[sqlite3.Row]: + """The accounts whose code brought someone, the ones that brought most first: how + many came (``invited``, the accounts here now; ``invites`` is the recorded counter), + how many of those ever made a request, how many were seen from one of the inviter's + own addresses, what they spent, what the inviter's pool got from them, and when the + first and the last of them signed up.""" + with self._lock: + return self._conn.execute( + f"""SELECT a.id, a.hint, a.channel, a.created_at, a.disabled, a.invites, a.first_ip, a.last_ip, a.identifier_enc, + COUNT(i.id) AS invited, + SUM(CASE WHEN COALESCE(l.requests, 0) > 0 THEN 1 ELSE 0 END) AS invited_active, + SUM(CASE WHEN (i.first_ip<>'' AND i.first_ip IN (a.first_ip, a.last_ip)) + OR (i.last_ip<>'' AND i.last_ip IN (a.first_ip, a.last_ip)) THEN 1 ELSE 0 END) AS invited_same_ip, + COALESCE(SUM(l.spent_uy), 0) AS invited_spent_uy, + COALESCE(e.earned_uy, 0) AS earned_uy, + MIN(i.created_at) AS first_invite_at, + MAX(i.created_at) AS last_invite_at + FROM accounts a + JOIN accounts i ON i.invited_by=a.id + LEFT JOIN {USAGE_BY_ACCOUNT} l ON l.account_id=i.id + LEFT JOIN (SELECT account_id, SUM(json_extract(extra, '$.credit_uy')) AS earned_uy + FROM ledger WHERE kind='credit' AND json_extract(extra, '$.from')='invite' + GROUP BY account_id) e ON e.account_id=a.id + GROUP BY a.id + ORDER BY invited DESC, last_invite_at DESC + LIMIT ?""", + (limit,), + ).fetchall() + # -- passwords ----------------------------------------------------------------- def set_password(self, account_id: str, password_hash: str) -> None: diff --git a/cloud/nanomuse_cloud/service.py b/cloud/nanomuse_cloud/service.py index b8fae2621..8bc20f228 100644 --- a/cloud/nanomuse_cloud/service.py +++ b/cloud/nanomuse_cloud/service.py @@ -2369,7 +2369,12 @@ def admin_account(self, account_id: str, days: int = 30) -> dict: a["locked"] = bool(row["locked_until"] and int(row["locked_until"]) > t) spent_total = self.db.spent_since(account_id, 0) self._pool_fields(a, spent_cny=self.s.uy_to_cny(spent_total)) - a["invited"] = [{"id": r["id"], "hint": r["hint"], "created_at": int(r["created_at"])} for r in self.db.invitees(account_id)] + # who this account brought (the newest 500, with the count of all of them), and who + # brought this account: the operator can follow an invite chain either way + a["invited"] = [self._invitee_fields(r) for r in self.db.invitees(account_id, limit=500)] + a["invited_total"] = self.db.invitee_count(account_id) + a["inviter"] = self._account_label(str(a.get("invited_by") or "")) + a["invite_earned_cny"] = self.s.uy_to_cny(self.db.invite_earned_uy(account_id)) a["contribute"] = bool(a.get("contribute")) # turns kept while the switch was on stay until the person deletes them: count them # whether or not it is on now, so the operator sees what is there @@ -2433,6 +2438,63 @@ def admin_account(self, account_id: str, days: int = 30) -> dict: "events": events["rows"], } + def _account_label(self, account_id: str) -> dict | None: + """`id`, `hint` and the identifier in clear for one account, or None when there is + no such account (an inviter who has since deleted theirs, say).""" + rows = self.db.accounts_brief([account_id]) if account_id else [] + if not rows: + return None + r = rows[0] + return {"id": r["id"], "hint": r["hint"], "identifier": self.crypto.decrypt(r["id"], r["identifier_enc"] or "") or ""} + + def _invitee_fields(self, r: sqlite3.Row) -> dict: + """One account that came through an invite, as the operator's page lists it.""" + return { + "id": r["id"], + "hint": r["hint"], + "channel": r["channel"], + "created_at": int(r["created_at"]), + "disabled": bool(r["disabled"]), + "first_ip": r["first_ip"] or "", + "last_ip": r["last_ip"] or "", + "last_seen_at": int(r["last_seen_at"]) if r["last_seen_at"] else None, + "requests": int(r["requests"] or 0), + "spent_cny": self.s.uy_to_cny(int(r["spent_uy"] or 0)), + } + + def admin_invites(self, limit: int = 200, per: int = 20) -> dict: + """Who invited whom, for the operator: the funnel as it stands and the inviters in + order of how many accounts their code brought, each with how many of those ever + made a request, how many were seen from one of the inviter's own addresses, what + they spent and what the inviter's pool got from them, and the newest `per` of the + accounts themselves (the account page lists up to 500). An inviter with many + sign-ups from one address and nobody using anything is a pool being farmed; one + whose invitees go on to make requests brought people.""" + leaders = [] + for r in self.db.invite_leaders(limit): + leaders.append( + { + "invitees": [self._invitee_fields(i) for i in self.db.invitees(r["id"], limit=per)] if per > 0 else [], + "id": r["id"], + "hint": r["hint"], + "identifier": self.crypto.decrypt(r["id"], r["identifier_enc"] or "") or "", + "channel": r["channel"], + "created_at": int(r["created_at"]), + "disabled": bool(r["disabled"]), + "first_ip": r["first_ip"] or "", + "last_ip": r["last_ip"] or "", + "invites": int(r["invites"] or 0), + "invited": int(r["invited"] or 0), + "invited_active": int(r["invited_active"] or 0), + "invited_same_ip": int(r["invited_same_ip"] or 0), + "invited_spent_cny": self.s.uy_to_cny(int(r["invited_spent_uy"] or 0)), + "earned_cny": self.s.uy_to_cny(int(r["earned_uy"] or 0)), + "first_invite_at": int(r["first_invite_at"] or 0), + "last_invite_at": int(r["last_invite_at"] or 0), + } + ) + return {"generated_at": now(), "funnel": self.db.invite_funnel(), "leaders": leaders} + def ledger_page(self, account_id: str, limit: int = 100, before_id: int = 0) -> dict: """One page of an account's statement, newest first, with the count of the whole — the operator's page reads it to the first line, page by page.""" diff --git a/cloud/tests/test_accounts.py b/cloud/tests/test_accounts.py index 32fc3c83a..b7429ede7 100644 --- a/cloud/tests/test_accounts.py +++ b/cloud/tests/test_accounts.py @@ -522,3 +522,76 @@ async def join(identifier: str) -> None: inv = (await client.get("/v1/me/invite", headers=auth(a["api_key"]))).json() assert inv["invites"] == 2 and inv["bonus_cny"] == 1 assert inv["earned_cny"] == 4, "3 for the first friend plus 1 for the second, as the ledger has it" + + +async def test_operator_sees_who_invited_whom_and_the_ranking(): + """`GET /v1/admin/invites` ranks the inviters by the accounts their code brought, says how + many of those ever made a request and how many came from one of the inviter's own + addresses (a pool being farmed looks like many of the second and none of the first), + and the account page names the inviter and lists the people brought.""" + app, client, sender, up, cloud, settings = make(allowance_cny=5, invite_bonus_cny=2) + admin = {"X-Admin-Token": "admin"} + a = await sign_up(client, sender, "dev-a@example.com", "pixel", headers={"X-Forwarded-For": "203.0.113.7"}) + b = await sign_up(client, sender, "dev-b@example.com", "mac", headers={"X-Forwarded-For": "198.51.100.2"}) + # every request says where it comes from: a request without the header would be seen from + # the test client's own address and make two unrelated accounts share one + from_ip = lambda key, ip: {**auth(key), "X-Forwarded-For": ip} # noqa: E731 + code_a = (await client.get("/v1/me/invite", headers=from_ip(a["api_key"], "203.0.113.7"))).json()["code"] + code_b = (await client.get("/v1/me/invite", headers=from_ip(b["api_key"], "198.51.100.2"))).json()["code"] + + async def join(identifier: str, code: str, ip: str) -> dict: + return await sign_up(client, sender, identifier, "mac", invite=code, headers={"X-Forwarded-For": ip}) + + # A's code brings three: two from A's own address that never use anything, one elsewhere who chats + await join("13900000001", code_a, "203.0.113.7") + await join("13900000002", code_a, "203.0.113.7") + c3 = await join("dev-c3@example.com", code_a, "192.0.2.9") + r = await client.post( + "/v1/chat/completions", + json={"model": "qwen3.8-flash", "messages": [{"role": "user", "content": "hi"}]}, + headers=from_ip(c3["api_key"], "192.0.2.9"), + ) + assert r.status_code == 200 + # B's code brings one, from somewhere else + d = await join("dev-d@example.com", code_b, "192.0.2.10") + + # nobody but the operator + assert (await client.get("/v1/admin/invites")).status_code == 401 + view = (await client.get("/v1/admin/invites", headers=admin)).json() + # every account is given its code at sign-up, so six have one; two have brought someone + assert view["funnel"] == {"with_code": 6, "inviters": 2, "invited": 4, "contribute_bonuses": 0} + assert [x["identifier"] for x in view["leaders"]] == ["dev-a@example.com", "dev-b@example.com"] + top = view["leaders"][0] + assert top["invites"] == 3 and top["invited"] == 3 and top["invited_active"] == 1 and top["invited_same_ip"] == 2 + assert top["earned_cny"] == 6 and top["invited_spent_cny"] > 0 and top["last_ip"] == "203.0.113.7" + assert top["first_invite_at"] <= top["last_invite_at"] + assert [i["hint"] for i in top["invitees"]][-1] == "139****0001", "newest first, with the hint and no identifier" + assert "identifier" not in top["invitees"][0] and top["invitees"][0]["requests"] == 1 and top["invitees"][0]["last_ip"] == "192.0.2.9" + second = view["leaders"][1] + assert second["invited"] == 1 and second["invited_same_ip"] == 0 and second["invitees"][0]["id"] == d["account"]["id"] + assert "places" in view + # the newest `per` of each inviter's people, and none when asked for none + few = (await client.get("/v1/admin/invites", params={"per": 1}, headers=admin)).json() + assert len(few["leaders"][0]["invitees"]) == 1 and few["leaders"][0]["invited"] == 3 + assert (await client.get("/v1/admin/invites", params={"per": 0}, headers=admin)).json()["leaders"][0]["invitees"] == [] + assert len((await client.get("/v1/admin/invites", params={"limit": 1}, headers=admin)).json()["leaders"]) == 1 + + # the account page: who brought this one, and whom this one brought + detail = (await client.get(f"/v1/admin/accounts/{c3['account']['id']}", headers=admin)).json()["account"] + assert detail["inviter"] == {"id": a["account"]["id"], "hint": "de***@example.com", "identifier": "dev-a@example.com"} + assert detail["invited"] == [] and detail["invited_total"] == 0 and detail["invite_earned_cny"] == 0 + detail = (await client.get(f"/v1/admin/accounts/{a['account']['id']}", headers=admin)).json()["account"] + assert detail["inviter"] is None and detail["invited_total"] == 3 and detail["invite_earned_cny"] == 6 + assert [i["hint"] for i in detail["invited"]] == ["de***@example.com", "139****0002", "139****0001"] + assert ( + detail["invited"][0]["requests"] == 1 + and detail["invited"][1]["requests"] == 0 + and detail["invited"][1]["first_ip"] == "203.0.113.7" + ) + + # an inviter who deleted their account: the invitee still says who, by id, and the ranking lets them go + r = await client.post("/v1/admin/delete", headers=admin, json={"account_id": b["account"]["id"]}) + assert r.status_code == 204, r.text + detail = (await client.get(f"/v1/admin/accounts/{d['account']['id']}", headers=admin)).json()["account"] + assert detail["invited_by"] == b["account"]["id"] and detail["inviter"] is None + assert [x["identifier"] for x in (await client.get("/v1/admin/invites", headers=admin)).json()["leaders"]] == ["dev-a@example.com"] diff --git a/cloud/tests/test_console.py b/cloud/tests/test_console.py index ecfcc709a..6aa59d1a0 100644 --- a/cloud/tests/test_console.py +++ b/cloud/tests/test_console.py @@ -105,3 +105,52 @@ def test_admin_console_names_the_star_card_text_in_both_languages(): assert "Empty: each app shows its own sentence. At most 200 characters." in source panel = source[source.index("function nudgesPanel()") : source.index("function settingsView()")] assert 'cardText("text")' in panel and 'cardText("text_zh"' in panel + + +def test_admin_console_has_the_invites_view_in_both_languages(): + """The Invites view (who brought whom, the inviters that brought most first) is in the + side navigation, reads `/v1/admin/invites`, and every string it draws is in the 简体中文 + table and in the English one; the account drawer names the inviter and lists the people + brought.""" + source = (CONSOLE / "admin" / "admin.js").read_text(encoding="utf-8") + assert '"invites"' in source[source.index("const VIEWS = ") : source.index("const PAGE = ")] + assert "invites: invitesView" in source and 'invites: () => "/v1/admin/invites?' in source + keys = ( + "invNote", + "invSearch", + "invNone", + "invNoMatch", + "invKpiCode", + "invKpiInviters", + "invKpiInvited", + "invKpiActive", + "invKpiSameIp", + "invThWho", + "invThInvited", + "invThActive", + "invThSameIp", + "invThSpent", + "invThEarned", + "invThLast", + "invSort", + "invRecorded", + "invSameIp", + "invGone", + "invSeeRanking", + "invMore", + "invSameIpNote", + "invitedList", + "invEarnedLine", + "invNewest", + "invPill", + ) + for key in keys: + assert source.count(f"{key}:") == 2, f"{key} is in one table only" + assert 'invites: "邀请"' in source and 'invites: "Invites"' in source + assert 'invThWho: "邀请人"' in source and 'invThWho: "Inviter"' in source + for key in keys: + assert f"T.{key}" in source, f"nothing draws {key}" + view = source[source.index("function invitesView()") : source.index("function placesView()")] + assert 'need("invites")' in view and "T.invSameIpNote" in view and "INV_OPEN" in view + drawer = source[source.index("function drawDrawer()") : source.index("function ledgerLine(")] + assert "a.inviter" in drawer and "T.invitedList(" in drawer and "inviteeRow(i, a)" in drawer diff --git a/docs/cloud.md b/docs/cloud.md index 8e8353bef..51f392154 100644 --- a/docs/cloud.md +++ b/docs/cloud.md @@ -336,7 +336,11 @@ list to `providers`. Other relays may set other rules (`ALLOWANCE_CNY`, `INVITE_BONUS_CNY`, `SIGNUP_OPEN`, `ALLOWED_IDENTIFIERS`; all three figures adjustable while the relay runs, relay 0.15; see -[`cloud/README.md`](../cloud/README.md)). +[`cloud/README.md`](../cloud/README.md)). The operator can see who invited +whom: the admin page's *Invites* view ranks the inviters by the accounts their +code brought, with how many of those ever made a request and how many were +seen from one of the inviter's own addresses, and an account's page names its +inviter and lists the people it brought (`GET /v1/admin/invites`). nanoMuse asks for one thing in return: a star on [GitHub](https://github.com/nano-muse/nanoMuse), which is what helps the diff --git a/docs/zh/cloud.md b/docs/zh/cloud.md index d215ea43f..70087306a 100644 --- a/docs/zh/cloud.md +++ b/docs/zh/cloud.md @@ -78,7 +78,7 @@ nanoMuse 是社区项目,不收费。`cloud.nanomuse.cn` 这个公共中继由 *设置 → nanoMuse Cloud* 显示池子用了多少(以 ¥ 和 $ 计)、还剩多少、池子怎么增长。用到 80 % 时 App 提示一次;池子花完后中继以 `allowance_exhausted` 拒绝,App 显示接下来的路:自己的 key、你已经在付费的套餐,或者邀请(你们各加 ¥5,或者中继当天说的数)。先推荐哪家服务商取决于你在哪里(0.1.34:中继的 `region`,从号码的国家码或它自己磁盘上一份 ip2region 的离线副本读出;什么都不往外发):中国大陆账号被指向阿里云百炼(服务商表单打开时已经预填好,[指南](own-key.md)),其他所有人指向 OpenRouter 或 OpenAI,因为百炼只接受中国大陆的注册。 -中继 0.21 起,拒绝响应和 `/v1/me` 把整张卡片作为数据带上,而不只是两个链接(契约 C11):`spend.guidance`(以及 `allowance_exhausted` 错误旁边的 `guidance`)按顺序列出该地区的服务商和每家 key 覆盖的范围(`covers: chat | vision | image | video`,来自共享目录 [`nanomuse/llm/providers.json`](../../nanomuse/llm/providers.json),中继自带一份副本)、一个人可能已经在付费的套餐和哪些客户端能用它们登录(`plans`:ChatGPT 到处都行,Claude 和 Kimi 在手机上,OpenRouter 在手机上)、本地服务器(`local`)、文档链接,以及关于 ChatGPT 登录的那句实话(`caveats.chatgpt`、`caveats.chatgpt_zh`)。0.17 的 `ways` 行仍然发送,现在每行带着服务商的 `name`、`name_zh`、`key_url`、`covers` 和 `auth`,所以 0.1.38 的客户端照旧画出它一直画的那两个按钮。`/app` 的控制台用 `guidance` 画卡片,遇到旧中继则退回两个链接。厂商要求每个对话带一个固定 id 的服务商(目录里的 `session_header`,比如 OpenCode Go)单独列在 `session_providers` 里,并写明那个请求头:1.0.1 及更早的手机端只读 `providers`,也不发这个 id,所以不会推荐它;会发 id 的应用把这份列表接在 `providers` 后面。其他中继可以定其他规则(`ALLOWANCE_CNY`、`INVITE_BONUS_CNY`、`SIGNUP_OPEN`、`ALLOWED_IDENTIFIERS`;三个数字都能在中继运行时调整,中继 0.15;见 [`cloud/README.md`](../../cloud/README.md))。 +中继 0.21 起,拒绝响应和 `/v1/me` 把整张卡片作为数据带上,而不只是两个链接(契约 C11):`spend.guidance`(以及 `allowance_exhausted` 错误旁边的 `guidance`)按顺序列出该地区的服务商和每家 key 覆盖的范围(`covers: chat | vision | image | video`,来自共享目录 [`nanomuse/llm/providers.json`](../../nanomuse/llm/providers.json),中继自带一份副本)、一个人可能已经在付费的套餐和哪些客户端能用它们登录(`plans`:ChatGPT 到处都行,Claude 和 Kimi 在手机上,OpenRouter 在手机上)、本地服务器(`local`)、文档链接,以及关于 ChatGPT 登录的那句实话(`caveats.chatgpt`、`caveats.chatgpt_zh`)。0.17 的 `ways` 行仍然发送,现在每行带着服务商的 `name`、`name_zh`、`key_url`、`covers` 和 `auth`,所以 0.1.38 的客户端照旧画出它一直画的那两个按钮。`/app` 的控制台用 `guidance` 画卡片,遇到旧中继则退回两个链接。厂商要求每个对话带一个固定 id 的服务商(目录里的 `session_header`,比如 OpenCode Go)单独列在 `session_providers` 里,并写明那个请求头:1.0.1 及更早的手机端只读 `providers`,也不发这个 id,所以不会推荐它;会发 id 的应用把这份列表接在 `providers` 后面。其他中继可以定其他规则(`ALLOWANCE_CNY`、`INVITE_BONUS_CNY`、`SIGNUP_OPEN`、`ALLOWED_IDENTIFIERS`;三个数字都能在中继运行时调整,中继 0.15;见 [`cloud/README.md`](../../cloud/README.md))。运营者能看到谁邀请了谁:管理页的「邀请」视图按邀请码带来的账号数给邀请人排序,并列出其中有多少人用过、有多少人的地址与邀请人相同;一个账号的页面写明它的邀请人,并列出它带来的人(`GET /v1/admin/invites`)。 nanoMuse 只求一样回报:在 [GitHub](https://github.com/nano-muse/nanoMuse) 上点一个 star,这是帮项目被人找到的东西。什么时候开口由中继定,不由 App 定(0.1.35):`GET /v1/nudges` 说明什么时候问是合理的:它替你完成第三、第十和第三十个任务之后,你打开它的第七天和第三十天,达成一个目标时,画出一个新形象时,在账号页上一次,以及池子花完时,两次之间至少隔一周,每台设备最多四次。每次都是一张出现在当下位置的卡片;「以后再说」也算一次,去过那个页面或点了「已经点过了」之后就不再出现(只记在本机,账号不同步这个标记)。运营者在管理页(*设置 › 请求 star*)改这项策略,不用更新 App;每个 App 都内置同样的默认值,供连不上中继时使用。策略定的是*什么时候*,运营者愿意的话也可以定*说什么*:卡片上的文字默认是每个 App 自己的、用它的语言写的;策略里带了句子就用策略的:`star.text`(英文)和 `star.text_zh`(简体中文),各最多 200 字,默认为空。中文界面的 App 先看 `text_zh`,没有再看 `text`,都没有就用自己的句子;其他语言的 App 看 `text`,没有就用自己的。只换卡片上的那句话,标题和按钮还是 App 自己的。按中继 0.22 及更早版本做的 App 不认这两个字段。 From df23dbb031d9fada0e35c8814f4ade61d1a271d2 Mon Sep 17 00:00:00 2001 From: Zeeshan Haque Date: Sun, 11 Oct 2026 23:17:42 -0700 Subject: [PATCH 91/98] build(web): regenerate committed static from the merged source (Node 22) `nanomuse/server/static/**` is a committed build artifact, so it is never merged by hand: the previous commit took upstream's tree and this one replaces it with the output of the merged source. cd web && PATH=/opt/homebrew/opt/node@22/bin:$PATH npm ci && npm run build vite.config.ts writes `outDir: "../nanomuse/server/static"` with `emptyOutDir: true`. Node 22 is required; the default node on this machine is v26. `grep -rl 'nanomuse\.cn' nanomuse/server/static/` is empty. Signed-off-by: Zeeshan Haque --- .../static/assets/AccountScreen-Bws27b-C.js | 1 + .../static/assets/AccountScreen-CfcZ3emY.js | 1 - ...r-DUnXfRVQ.js => AvatarPicker-BCihUURa.js} | 2 +- ...Z1Gf.js => AvatarStudioScreen-Dgqo0TEO.js} | 2 +- ...ackBar-DmScFXW_.js => BackBar-JEuC8Q_e.js} | 2 +- ...DGK7O7Nz.js => ChannelsScreen-D_7Ynsew.js} | 4 +- ...Card-CZ8tYr3g.js => CloudCard-D5foJm1I.js} | 2 +- ...n-DAGGlv2e.js => CodingScreen-BLVF-Er8.js} | 4 +- .../assets/ConnectionsScreen-CuIVN07d.js | 1 + .../assets/ConnectionsScreen-DIFZneZ_.js | 1 - .../static/assets/DevicesScreen-BLIuBnuO.js | 1 - .../static/assets/DevicesScreen-BkPa89LS.js | 1 + .../{Form-C77NCy9F.js => Form-H3s9oTHq.js} | 2 +- ...en-DgatXriG.js => GoalsScreen-yUUdUKV2.js} | 4 +- ...en-Bwp6l7Xs.js => IdeasScreen-CmecfnoP.js} | 2 +- ...m-IeJQ0HCo.js => IdentityForm-g-zvQ2IC.js} | 2 +- ...-BclDd8-A.js => LibraryScreen-BoofKOos.js} | 2 +- ...n-6ZrrpUSE.js => MemoryScreen-DHNxjNpq.js} | 2 +- .../static/assets/MuseHeader-BvAlmxiL.js | 1 - .../static/assets/MuseHeader-RC--uR8o.js | 1 + .../static/assets/Onboarding-B0JPnst7.js | 1 - .../static/assets/Onboarding-DBBDNzyW.js | 1 + .../static/assets/SettingsScreen-B84xmoRg.js | 1 + .../static/assets/SettingsScreen-CJQ-5PSy.js | 1 - ...n-ZetN1PPI.js => SkillsScreen-DsMpJe1f.js} | 4 +- ...udge-Cr_QPa4y.js => StarNudge-Df6LQyo9.js} | 2 +- ...d-90G9CI1B.js => clapperboard-CuoVHGrc.js} | 2 +- ...p-Bv9NPF9E.js => database-zap-Bce5E3JJ.js} | 2 +- ...-V2ISE5bW.js => external-link-TvxP_dKX.js} | 2 +- .../{image-Cn9LGhlN.js => image-nIygWCIp.js} | 2 +- .../server/static/assets/index-tYqPtwPX.js | 44 +++++++++++++++++++ .../server/static/assets/index-tZx-TDX4.js | 44 ------------------- .../{plug-u8jLJjTk.js => plug-DV_c5_Ny.js} | 2 +- ...-cw-BMLOGb5p.js => refresh-cw-CxZ3ZdI3.js} | 2 +- nanomuse/server/static/index.html | 12 ++--- 35 files changed, 80 insertions(+), 80 deletions(-) create mode 100644 nanomuse/server/static/assets/AccountScreen-Bws27b-C.js delete mode 100644 nanomuse/server/static/assets/AccountScreen-CfcZ3emY.js rename nanomuse/server/static/assets/{AvatarPicker-DUnXfRVQ.js => AvatarPicker-BCihUURa.js} (95%) rename nanomuse/server/static/assets/{AvatarStudioScreen-DuBIZ1Gf.js => AvatarStudioScreen-Dgqo0TEO.js} (95%) rename nanomuse/server/static/assets/{BackBar-DmScFXW_.js => BackBar-JEuC8Q_e.js} (85%) rename nanomuse/server/static/assets/{ChannelsScreen-DGK7O7Nz.js => ChannelsScreen-D_7Ynsew.js} (90%) rename nanomuse/server/static/assets/{CloudCard-CZ8tYr3g.js => CloudCard-D5foJm1I.js} (88%) rename nanomuse/server/static/assets/{CodingScreen-DAGGlv2e.js => CodingScreen-BLVF-Er8.js} (84%) create mode 100644 nanomuse/server/static/assets/ConnectionsScreen-CuIVN07d.js delete mode 100644 nanomuse/server/static/assets/ConnectionsScreen-DIFZneZ_.js delete mode 100644 nanomuse/server/static/assets/DevicesScreen-BLIuBnuO.js create mode 100644 nanomuse/server/static/assets/DevicesScreen-BkPa89LS.js rename nanomuse/server/static/assets/{Form-C77NCy9F.js => Form-H3s9oTHq.js} (97%) rename nanomuse/server/static/assets/{GoalsScreen-DgatXriG.js => GoalsScreen-yUUdUKV2.js} (64%) rename nanomuse/server/static/assets/{IdeasScreen-Bwp6l7Xs.js => IdeasScreen-CmecfnoP.js} (98%) rename nanomuse/server/static/assets/{IdentityForm-IeJQ0HCo.js => IdentityForm-g-zvQ2IC.js} (97%) rename nanomuse/server/static/assets/{LibraryScreen-BclDd8-A.js => LibraryScreen-BoofKOos.js} (86%) rename nanomuse/server/static/assets/{MemoryScreen-6ZrrpUSE.js => MemoryScreen-DHNxjNpq.js} (92%) delete mode 100644 nanomuse/server/static/assets/MuseHeader-BvAlmxiL.js create mode 100644 nanomuse/server/static/assets/MuseHeader-RC--uR8o.js delete mode 100644 nanomuse/server/static/assets/Onboarding-B0JPnst7.js create mode 100644 nanomuse/server/static/assets/Onboarding-DBBDNzyW.js create mode 100644 nanomuse/server/static/assets/SettingsScreen-B84xmoRg.js delete mode 100644 nanomuse/server/static/assets/SettingsScreen-CJQ-5PSy.js rename nanomuse/server/static/assets/{SkillsScreen-ZetN1PPI.js => SkillsScreen-DsMpJe1f.js} (74%) rename nanomuse/server/static/assets/{StarNudge-Cr_QPa4y.js => StarNudge-Df6LQyo9.js} (71%) rename nanomuse/server/static/assets/{clapperboard-90G9CI1B.js => clapperboard-CuoVHGrc.js} (81%) rename nanomuse/server/static/assets/{database-zap-Bv9NPF9E.js => database-zap-Bce5E3JJ.js} (80%) rename nanomuse/server/static/assets/{external-link-V2ISE5bW.js => external-link-TvxP_dKX.js} (79%) rename nanomuse/server/static/assets/{image-Cn9LGhlN.js => image-nIygWCIp.js} (75%) create mode 100644 nanomuse/server/static/assets/index-tYqPtwPX.js delete mode 100644 nanomuse/server/static/assets/index-tZx-TDX4.js rename nanomuse/server/static/assets/{plug-u8jLJjTk.js => plug-DV_c5_Ny.js} (77%) rename nanomuse/server/static/assets/{refresh-cw-BMLOGb5p.js => refresh-cw-CxZ3ZdI3.js} (79%) diff --git a/nanomuse/server/static/assets/AccountScreen-Bws27b-C.js b/nanomuse/server/static/assets/AccountScreen-Bws27b-C.js new file mode 100644 index 000000000..c24cba302 --- /dev/null +++ b/nanomuse/server/static/assets/AccountScreen-Bws27b-C.js @@ -0,0 +1 @@ +import{E as e,J as t,K as n,Q as r,R as i,Y as a,b as o,f as s,k as c,q as l,x as u}from"./MuseHeader-RC--uR8o.js";import{k as d,s as f,t as p}from"./StarNudge-Df6LQyo9.js";import{n as m}from"./external-link-TvxP_dKX.js";import{a as h,i as g}from"./Form-H3s9oTHq.js";import{t as _}from"./clapperboard-CuoVHGrc.js";import{t as v}from"./database-zap-Bce5E3JJ.js";import{t as y}from"./image-nIygWCIp.js";import{B as b,G as x,Q as S,W as C,at as w,ht as T,k as E,lt as D,q as O,st as k,t as A}from"./index-tYqPtwPX.js";import{t as j}from"./BackBar-JEuC8Q_e.js";var M=t(`gift`,[[`path`,{d:`M12 7v14`,key:`1akyts`}],[`path`,{d:`M20 11v8a2 2 0 0 1-2 2H6a2 2 0 0 1-2-2v-8`,key:`1sqzm4`}],[`path`,{d:`M7.5 7a1 1 0 0 1 0-5A4.8 8 0 0 1 12 7a4.8 8 0 0 1 4.5-5 1 1 0 0 1 0 5`,key:`kc0143`}],[`rect`,{x:`3`,y:`7`,width:`18`,height:`4`,rx:`1`,key:`1hberx`}]]),N=r(a(),1),P=o();function F(){let{state:e,toast:t,setTab:r}=s(),i=n(),a=e.hub?.account??null,[o,c]=(0,N.useState)(null),[l,d]=(0,N.useState)(null),[m,h]=(0,N.useState)(null),[g,_]=(0,N.useState)(!1),v=!!a?.signed_in,y=f(),b=async()=>{if(v){_(!0);try{let[e,t,n]=await Promise.all([u.cloudMe(),u.cloudSessions(),u.cloudEvents(40)]);c(e),d(t.sessions),h(n.events)}catch(e){t(e.message)}finally{_(!1)}}};return(0,N.useEffect)(()=>{b()},[v,a?.has_password]),(0,P.jsxs)(`div`,{className:`flex h-full flex-col`,children:[(0,P.jsx)(j,{title:i(`Account`),description:i(v?`nanoMuse Cloud · one account for all your devices`:`Sign in to nanoMuse Cloud`)}),(0,P.jsx)(`div`,{className:`flex-1 overflow-y-auto px-4 pb-8 space-y-4`,children:v?(0,P.jsxs)(P.Fragment,{children:[(0,P.jsx)(L,{account:a,me:o}),o&&(0,P.jsx)(p,{moment:`signed_in`}),o&&(0,P.jsx)(R,{me:o,onChanged:()=>void b()}),o?.invite?.code&&(0,P.jsx)(B,{invite:o.invite}),o&&(0,P.jsx)(H,{me:o}),o&&(0,P.jsx)(z,{me:o}),(0,P.jsx)(W,{account:a,onChanged:()=>void b()}),(0,P.jsx)(G,{sessions:l,loading:g,onChanged:()=>void b()}),m&&m.length>0&&(0,P.jsx)(q,{events:m}),(0,P.jsx)(J,{account:a,onDone:()=>r(`chat`)})]}):(0,P.jsxs)(I,{children:[(0,P.jsx)(`p`,{className:`text-[13.5px] text-muted leading-relaxed`,children:i(`Free. One account for all your devices, with a model and ¥{allowance} of use to start; a code the first time, a password afterwards if you like.`,{allowance:(y.allowance_cny??10).toFixed(0)})}),(0,P.jsx)(A,{onSignedIn:()=>t(i(`Signed in to nanoMuse Cloud.`))})]})})]})}function I({title:t,children:n,tone:r}){return(0,P.jsxs)(`section`,{className:e(`rounded-3xl border p-4 space-y-3 shadow-sm`,r===`danger`?`border-rose-500/25 bg-rose-500/[0.04]`:`border-border/70 bg-surface`),children:[t&&(0,P.jsx)(`h2`,{className:`text-[12px] font-semibold uppercase tracking-wide text-muted`,children:t}),n]})}function L({account:e,me:t}){let r=n(),a=e?.hint??``,o=t?.account.created_at?new Date(t.account.created_at*1e3):null;return(0,P.jsxs)(`section`,{className:`relative overflow-hidden rounded-3xl border border-border/70 bg-surface p-5 shadow-sm`,children:[(0,P.jsx)(`div`,{className:`pointer-events-none absolute -right-16 -top-20 h-48 w-48 rounded-full bg-accent/15 blur-3xl`}),(0,P.jsxs)(`div`,{className:`flex items-center gap-4`,children:[(0,P.jsx)(`div`,{className:`flex h-14 w-14 shrink-0 items-center justify-center rounded-2xl bg-gradient-to-br from-accent to-sky-400 text-[22px] font-bold text-white shadow-md`,children:(a.replace(/[^a-z0-9]/gi,``).slice(0,1)||`n`).toUpperCase()}),(0,P.jsxs)(`div`,{className:`min-w-0 flex-1`,children:[(0,P.jsx)(`div`,{className:`truncate text-[18px] font-semibold tracking-tight`,children:a}),(0,P.jsxs)(`div`,{className:`mt-0.5 flex flex-wrap items-center gap-x-2 gap-y-0.5 text-[12.5px] text-muted`,children:[(0,P.jsx)(`span`,{children:e?.channel===`phone`||e?.channel===`sms`?r(`Mobile number`):r(`E-mail`)}),o&&(0,P.jsxs)(`span`,{children:[`· `,r(`since {date}`,{date:o.toLocaleDateString(i())})]}),t?.account.member&&(0,P.jsxs)(`span`,{className:`inline-flex items-center gap-1 rounded-full bg-emerald-500/12 px-2 py-0.5 text-[11px] font-medium text-emerald-700 dark:text-emerald-300`,children:[(0,P.jsx)(x,{size:11}),` `,r(`Unlimited`)]})]})]})]}),e?.account_id&&(0,P.jsxs)(`div`,{className:`mt-4 flex items-center justify-between gap-3 rounded-2xl bg-surface-2/70 px-3 py-2 text-[12px]`,children:[(0,P.jsx)(`span`,{className:`text-muted`,children:r(`Account id`)}),(0,P.jsx)(`code`,{className:`truncate font-mono text-[11.5px] text-fg/80`,children:e.account_id})]})]})}function R({me:t,onChanged:r}){let i=n(),a=t.spend,o=a.grant??a.daily_cap??0,s=a.grant===void 0?a.today:a.total,c=a.left??(a.unlimited?null:Math.max(0,o-s)),l=!a.unlimited&&o>0,u=l?Math.min(100,Math.round(s/o*100)):0,f=a.usd_cny??0,p=e=>f>0?` ≈ $${(e/f).toFixed(2)}`:``,m=l&&(c??0)<=0,h=l&&!m&&(a.warn??u>=80),g={left:c,grant:o,invite_url:t.invite?.url,invite_bonus_cny:a.invite_bonus_cny??t.invite?.bonus_cny,invitee_bonus_cny:a.invitee_bonus_cny??t.invite?.invitee_bonus_cny,own_key_docs:a.own_key_docs,guidance:a.guidance};return(0,P.jsxs)(I,{title:i(`Free allowance`),children:[(0,P.jsxs)(`div`,{className:`flex items-end justify-between gap-3`,children:[(0,P.jsxs)(`div`,{children:[(0,P.jsx)(`div`,{className:`text-[28px] font-bold tracking-tight leading-none`,children:l?(0,P.jsxs)(P.Fragment,{children:[`¥`,(c??0).toFixed(2),(0,P.jsxs)(`span`,{className:`text-[14px] font-medium text-muted`,children:[` `,i(`left of ¥{grant}`,{grant:o.toFixed(0)})]})]}):(0,P.jsxs)(P.Fragment,{children:[`¥`,s.toFixed(2)]})}),(0,P.jsx)(`div`,{className:`mt-1 text-[12.5px] text-muted`,children:l?i(`¥{spent} used{usd}; the allowance does not reset.`,{spent:s.toFixed(2),usd:p(s)}):i(`No limit on this account.`)})]}),(0,P.jsxs)(`div`,{className:`text-right text-[12.5px] text-muted`,children:[(0,P.jsx)(`div`,{children:i(`All time`)}),(0,P.jsxs)(`div`,{className:`text-[15px] font-semibold text-fg`,children:[`¥`,a.total.toFixed(2)]}),f>0&&(0,P.jsxs)(`div`,{className:`text-[11.5px]`,children:[`≈ $`,(a.total/f).toFixed(2)]})]})]}),l&&(0,P.jsx)(`div`,{className:`h-2 overflow-hidden rounded-full bg-surface-2`,children:(0,P.jsx)(`div`,{className:e(`h-full rounded-full transition-all`,u>=100?`bg-rose-500`:u>=80?`bg-amber-500`:`bg-accent`),style:{width:`${u}%`}})}),l&&(0,P.jsxs)(`p`,{className:`text-[12.5px] text-muted`,children:[i(`¥{allowance} to start, +¥{invite} for each friend you invite, and +¥{invite} for them; after that, your own key keeps the model going.`,{allowance:(a.allowance_cny??10).toFixed(0),invite:(g.invite_bonus_cny??5).toFixed(0)}),` `,!m&&!h&&d(i,{signed_in:!0,channel:t.account.channel,region:t.account.region})]}),(m||h)&&(0,P.jsx)(E,{info:g,exhausted:m,onChanged:r})]})}function z({me:e}){let t=n(),{setTab:r}=s(),i=e.contribute??{on:!1,samples:0};return(0,P.jsx)(I,{title:t(`Data controls`),children:(0,P.jsxs)(`button`,{type:`button`,onClick:()=>{window.location.hash=`data`,r(`you`)},className:`flex w-full items-center gap-3 text-left`,children:[(0,P.jsx)(`span`,{className:`flex h-9 w-9 shrink-0 items-center justify-center rounded-xl bg-surface-2 text-fg`,children:(0,P.jsx)(v,{size:18})}),(0,P.jsxs)(`span`,{className:`min-w-0 flex-1`,children:[(0,P.jsx)(`span`,{className:`block text-[14px] font-medium`,children:t(`Help improve nanoMuse's AI models`)}),(0,P.jsxs)(`span`,{className:`block text-[12.5px] text-muted`,children:[i.on?t(`On`):t(`Off`),i.samples>0&&` · ${t(`{n} turns kept so far`,{n:String(i.samples)})}`]})]}),(0,P.jsx)(`span`,{className:`text-[13px] font-medium text-accent`,children:t(`Open`)})]})})}function B({invite:t}){let r=n(),{toast:i}=s(),a=t.url||``,o=t.earned_cny??t.invites*t.bonus_cny,c=async e=>{try{await navigator.clipboard.writeText(e),i(r(`Copied`))}catch{i(e)}},l=async()=>{let e=a?r(`Try nanoMuse with me, a fully open-source personal agent, free to use. Sign up with my code {code}: {link}`,{code:t.code,link:a}):r(`Try nanoMuse with me, a fully open-source personal agent, free to use. Sign up with my code {code}`,{code:t.code}),n=navigator;if(n.share)try{await n.share({text:e});return}catch{}await c(e)};return(0,P.jsxs)(I,{title:r(`Invite a friend`),children:[(0,P.jsx)(`p`,{className:`text-[12.5px] text-muted`,children:r(`Each new person who signs up with your code adds ¥{bonus} to your allowance, and ¥{bonus} to theirs. It never expires.`,{bonus:t.bonus_cny.toFixed(0)})}),(0,P.jsxs)(`div`,{className:`flex items-center justify-between gap-3 rounded-2xl bg-surface-2/70 px-3 py-2`,children:[(0,P.jsxs)(`div`,{children:[(0,P.jsx)(`div`,{className:`text-[11px] text-muted`,children:r(`Your code`)}),(0,P.jsx)(`code`,{className:`font-mono text-[18px] font-semibold tracking-[0.2em]`,children:t.code})]}),(0,P.jsxs)(`button`,{type:`button`,onClick:()=>void c(t.code),className:e(h,`inline-flex items-center gap-1.5`),children:[(0,P.jsx)(T,{size:14}),` `,r(`Copy`)]})]}),(0,P.jsxs)(`div`,{className:`flex gap-2`,children:[(0,P.jsxs)(`button`,{type:`button`,onClick:()=>void l(),className:e(g,`inline-flex flex-1 items-center justify-center gap-1.5 py-2.5`),children:[(0,P.jsx)(O,{size:14}),` `,r(a?`Share the link`:`Share the code`)]}),a?(0,P.jsxs)(`button`,{type:`button`,onClick:()=>void c(a),className:e(h,`inline-flex items-center gap-1.5`),children:[(0,P.jsx)(M,{size:14}),` `,r(`Copy the link`)]}):null]}),(0,P.jsxs)(`p`,{className:`text-[12.5px] text-muted`,children:[r(`{n} friends joined`,{n:String(t.invites)}),o>0&&(0,P.jsxs)(P.Fragment,{children:[` · `,r(`¥{amount} added by invitations`,{amount:o.toFixed(0)})]})]})]})}var V={chat:{label:`Chat`,icon:(0,P.jsx)(w,{size:15}),tone:`bg-accent`},image:{label:`Pictures`,icon:(0,P.jsx)(y,{size:15}),tone:`bg-violet-500`},video:{label:`Clips`,icon:(0,P.jsx)(_,{size:15}),tone:`bg-pink-500`},realtime:{label:`Calls`,icon:(0,P.jsx)(S,{size:15}),tone:`bg-emerald-500`}};function H({me:t}){let r=n(),[i,a]=(0,N.useState)(`today`),o=i===`today`?t.usage.today.by_kind:t.usage.total.by_kind,s=t.usage.kinds.length?t.usage.kinds:[`chat`,`image`,`video`,`realtime`],c=new Map(o.map(e=>[e.kind,e])),l=o.reduce((e,t)=>e+t.cost_cny,0),u=t.usage.total.by_model.slice(0,8);return(0,P.jsxs)(I,{title:r(`Usage`),children:[(0,P.jsxs)(`div`,{className:`flex items-center justify-between`,children:[(0,P.jsx)(`p`,{className:`text-[12.5px] text-muted`,children:r(`Every kind of use is counted, not just the chat model.`)}),(0,P.jsx)(`div`,{className:`flex rounded-full bg-surface-2/80 p-0.5 text-[12px] font-medium`,children:[`today`,`total`].map(t=>(0,P.jsx)(`button`,{type:`button`,onClick:()=>a(t),className:e(`rounded-full px-2.5 py-1 transition`,i===t?`bg-surface shadow-sm`:`text-muted`),children:r(t===`today`?`Today`:`All time`)},t))})]}),l>0&&(0,P.jsx)(`div`,{className:`flex h-2.5 overflow-hidden rounded-full bg-surface-2`,children:s.map(t=>{let n=c.get(t);return!n||n.cost_cny<=0?null:(0,P.jsx)(`div`,{className:e(`h-full`,V[t]?.tone??`bg-fg/40`),style:{width:`${n.cost_cny/l*100}%`},title:r(V[t]?.label??t)},t)})}),(0,P.jsx)(`ul`,{className:`grid grid-cols-2 gap-2`,children:s.map(t=>{let n=c.get(t),i=V[t];return(0,P.jsxs)(`li`,{className:`rounded-2xl bg-surface-2/60 p-3`,children:[(0,P.jsxs)(`div`,{className:`flex items-center gap-1.5 text-[12.5px] text-muted`,children:[(0,P.jsx)(`span`,{className:e(`flex h-5 w-5 items-center justify-center rounded-md text-white`,i?.tone??`bg-fg/40`),children:i?.icon}),r(i?.label??t)]}),(0,P.jsxs)(`div`,{className:`mt-1.5 text-[17px] font-semibold tracking-tight`,children:[`¥`,(n?.cost_cny??0).toFixed(2)]}),(0,P.jsx)(`div`,{className:`text-[11.5px] text-muted`,children:n?t===`realtime`?r(`{n} answers · {tokens} tokens`,{n:n.requests,tokens:U(n.prompt_tokens+n.completion_tokens)}):t===`chat`?r(`{n} requests · {tokens} tokens`,{n:n.requests,tokens:U(n.prompt_tokens+n.completion_tokens)}):r(`{n} requests`,{n:n.requests}):r(`Nothing yet`)})]},t)})}),u.length>0&&(0,P.jsxs)(`div`,{children:[(0,P.jsx)(`div`,{className:`mb-1.5 text-[12px] font-medium text-muted`,children:r(`By model, all time`)}),(0,P.jsx)(`ul`,{className:`divide-y divide-border/60 rounded-2xl border border-border/60`,children:u.map(t=>(0,P.jsxs)(`li`,{className:`flex items-center gap-2 px-3 py-2 text-[12.5px]`,children:[(0,P.jsx)(`span`,{className:e(`h-2 w-2 shrink-0 rounded-full`,V[t.kind]?.tone??`bg-fg/40`)}),(0,P.jsx)(`span`,{className:`min-w-0 flex-1 truncate font-mono text-[12px]`,children:t.model}),(0,P.jsx)(`span`,{className:`text-muted`,children:U(t.prompt_tokens+t.completion_tokens)}),(0,P.jsxs)(`span`,{className:`w-16 text-right font-medium`,children:[`¥`,t.cost_cny.toFixed(2)]})]},`${t.model}-${t.kind}`))})]})]})}function U(e){return e>=1e6?`${(e/1e6).toFixed(1)}M`:e>=1e3?`${(e/1e3).toFixed(e>=1e5?0:1)}k`:String(e)}function W({account:t,onChanged:r}){let i=n(),{toast:a}=s(),o=!!t?.has_password,[c,d]=(0,N.useState)(!1),[f,p]=(0,N.useState)(``),[h,g]=(0,N.useState)(``),[_,v]=(0,N.useState)(``),[y,b]=(0,N.useState)(!1),[x,S]=(0,N.useState)(null),C=async(e=!1)=>{if(!(!e&&(h.length<8||h!==_))){b(!0),S(null);try{await u.cloudPassword(e?``:h,o?f:void 0),a(i(e?`Password removed.`:o?`Password changed.`:`Password set.`)),d(!1),p(``),g(``),v(``),r()}catch(e){S(i(e.message))}finally{b(!1)}}};return(0,P.jsxs)(I,{title:i(`Password`),children:[(0,P.jsxs)(`div`,{className:`flex items-center gap-3`,children:[(0,P.jsx)(`span`,{className:e(`flex h-9 w-9 items-center justify-center rounded-xl`,o?`bg-emerald-500/12 text-emerald-600 dark:text-emerald-300`:`bg-surface-2 text-muted`),children:(0,P.jsx)(D,{size:17})}),(0,P.jsxs)(`div`,{className:`min-w-0 flex-1 text-[13.5px]`,children:[(0,P.jsx)(`div`,{className:`font-medium`,children:i(o?`A password is set`:`No password yet`)}),(0,P.jsx)(`div`,{className:`text-[12.5px] text-muted`,children:i(o?`Sign in with it on a new device, or with a code as before.`:`Optional. With one, a new device can sign in without waiting for a code.`)})]}),!c&&(0,P.jsx)(`button`,{type:`button`,onClick:()=>d(!0),className:e(`flex items-center justify-center gap-1.5 rounded-2xl border border-border px-4 py-2.5 text-[14px] font-medium text-muted disabled:opacity-40`,`shrink-0 px-3 py-2 text-[13px]`),children:i(o?`Change`:`Set`)})]}),c&&(0,P.jsxs)(`form`,{className:`space-y-2.5`,onSubmit:e=>{e.preventDefault(),C()},children:[o&&(0,P.jsx)(`input`,{type:`password`,value:f,onChange:e=>p(e.target.value),placeholder:i(`Current password`),autoComplete:`current-password`,className:`w-full rounded-2xl bg-surface-2 px-3.5 py-2.5 text-[14.5px] outline-none focus:ring-2 focus:ring-accent/40`}),(0,P.jsx)(`input`,{type:`password`,value:h,onChange:e=>g(e.target.value),placeholder:i(`New password (8 characters or more)`),autoComplete:`new-password`,autoFocus:!0,className:`w-full rounded-2xl bg-surface-2 px-3.5 py-2.5 text-[14.5px] outline-none focus:ring-2 focus:ring-accent/40`}),(0,P.jsx)(`input`,{type:`password`,value:_,onChange:e=>v(e.target.value),placeholder:i(`Once more`),autoComplete:`new-password`,className:`w-full rounded-2xl bg-surface-2 px-3.5 py-2.5 text-[14.5px] outline-none focus:ring-2 focus:ring-accent/40`}),_&&h!==_&&(0,P.jsx)(`p`,{className:`text-[12px] text-rose-600 dark:text-rose-300`,children:i(`The two do not match.`)}),x&&(0,P.jsx)(`p`,{className:`rounded-2xl bg-rose-500/12 px-3 py-2 text-[12.5px] text-rose-700 dark:text-rose-300`,children:x}),(0,P.jsxs)(`div`,{className:`flex flex-wrap gap-2`,children:[(0,P.jsxs)(`button`,{type:`submit`,disabled:y||h.length<8||h!==_||o&&!f,className:e(`flex items-center justify-center gap-1.5 rounded-2xl bg-accent text-accent-fg px-4 py-2.5 text-[14px] font-medium disabled:opacity-40`,`flex-1`),children:[y?(0,P.jsx)(l,{size:15,className:`animate-spin`}):(0,P.jsx)(m,{size:15}),` `,i(o?`Change password`:`Set password`)]}),o&&(0,P.jsx)(`button`,{type:`button`,disabled:y||!f,onClick:()=>void C(!0),className:`flex items-center justify-center gap-1.5 rounded-2xl border border-border px-4 py-2.5 text-[14px] font-medium text-muted disabled:opacity-40`,children:i(`Remove`)}),(0,P.jsx)(`button`,{type:`button`,onClick:()=>d(!1),className:`flex items-center justify-center gap-1.5 rounded-2xl border border-border px-4 py-2.5 text-[14px] font-medium text-muted disabled:opacity-40`,children:i(`Cancel`)})]})]})]})}function G({sessions:e,loading:t,onChanged:r}){let a=n(),{toast:o}=s(),[d,f]=(0,N.useState)(null),p=async e=>{if(window.confirm(a(`Sign out {device}? It will need to sign in again.`,{device:e.device||e.prefix}))){f(e.prefix);try{await u.cloudRevokeSession(e.prefix),r()}catch(e){o(e.message)}finally{f(null)}}};return(0,P.jsx)(I,{title:a(`Signed in on`),children:e?(0,P.jsx)(`ul`,{className:`divide-y divide-border/60`,children:e.map(e=>(0,P.jsxs)(`li`,{className:`flex items-center gap-3 py-2.5`,children:[(0,P.jsx)(`span`,{className:`flex h-9 w-9 shrink-0 items-center justify-center rounded-xl bg-surface-2 text-fg/70`,children:(0,P.jsx)(C,{size:17})}),(0,P.jsxs)(`div`,{className:`min-w-0 flex-1`,children:[(0,P.jsxs)(`div`,{className:`flex items-center gap-2 text-[13.5px] font-medium`,children:[(0,P.jsx)(`span`,{className:`truncate`,children:e.device||a(`Unnamed device`)}),e.current&&(0,P.jsx)(`span`,{className:`rounded-full bg-accent/12 px-2 py-0.5 text-[10.5px] font-semibold text-accent`,children:a(`This one`)})]}),(0,P.jsxs)(`div`,{className:`truncate text-[12px] text-muted`,children:[e.via===`password`?a(`password`):a(`code`),` · `,a(`since {date}`,{date:new Date(e.created_at*1e3).toLocaleDateString(i())}),e.last_used_at?` · ${a(`used {when}`,{when:c(e.last_used_at)})}`:``]})]}),!e.current&&(0,P.jsx)(`button`,{type:`button`,disabled:d!==null,onClick:()=>void p(e),className:`rounded-full px-3 py-1.5 text-[12.5px] font-medium text-rose-600 hover:bg-rose-500/10 dark:text-rose-300`,children:d===e.prefix?(0,P.jsx)(l,{size:14,className:`animate-spin`}):a(`Sign out`)})]},e.prefix))}):(0,P.jsx)(`div`,{className:`flex justify-center py-3 text-muted`,children:t?(0,P.jsx)(l,{size:18,className:`animate-spin`}):null})})}var K={"account.created":`Account created`,"sign_in.code":`Signed in with a code`,"sign_in.password":`Signed in with the password`,"sign_in.failed":`A sign-in attempt failed`,sign_out:`Signed out`,"sign_out.all":`Signed out everywhere`,"password.set":`Password set`,"password.changed":`Password changed`,"password.cleared":`Password removed`,"budget.refused":`A request was refused: the allowance is used up`,"call.ended":`Call ended`,"upstream.error":`The model provider returned an error`,"credit.granted":`Allowance added`,"pool.set":`Allowance adjusted`,"invite.accepted":`Signed up with a friend's code`,"invite.used":`A friend signed up with your code`,"invite.unknown":`An invite code was not recognised`,"contribute.default":`Data controls: on for new accounts`,"contribute.on":`Data controls: help improve turned on`,"contribute.off":`Data controls: help improve turned off`,"contribute.deleted":`Data controls: kept conversations deleted`,"profile.put":`Agent's name and look saved`,"profile.clear":`Agent's name and look cleared`};function q({events:e}){let t=n(),[r,i]=(0,N.useState)(!1),a=r?e:e.slice(0,6);return(0,P.jsxs)(I,{title:t(`Recent activity`),children:[(0,P.jsx)(`ul`,{className:`space-y-2`,children:a.map((e,n)=>(0,P.jsxs)(`li`,{className:`flex gap-3 text-[12.5px]`,children:[(0,P.jsx)(`span`,{className:`w-[74px] shrink-0 text-muted`,children:c(e.ts)}),(0,P.jsxs)(`span`,{className:`min-w-0 flex-1`,children:[(0,P.jsx)(`span`,{className:`font-medium`,children:t(K[e.kind]??e.kind)}),e.detail&&(0,P.jsx)(`span`,{className:`ml-1.5 break-all text-muted`,children:e.detail})]})]},`${e.ts}-${n}`))}),e.length>6&&(0,P.jsx)(`button`,{type:`button`,onClick:()=>i(e=>!e),className:`text-[12.5px] font-medium text-accent`,children:r?t(`Show less`):t(`Show all {n}`,{n:e.length})})]})}function J({account:t,onDone:r}){let i=n(),{toast:a}=s(),[o,c]=(0,N.useState)(null),d=async e=>{let t=i(e===`here`?`Sign out of nanoMuse Cloud on this device? The hub and the Cloud model stop working here until you sign in again.`:e===`all`?`Sign out on every device, including this one?`:`Delete the account? The relay forgets your identifier, your devices and your usage. This cannot be undone.`);if(window.confirm(t)&&(e!==`delete`||window.confirm(i(`Really delete it?`)))){c(e);try{e===`here`?await u.cloudSignOut():e===`all`?await u.cloudSignOutAll(!0):await u.cloudDelete(),a(i(e===`delete`?`Account deleted.`:`Signed out.`)),r()}catch(e){a(e.message)}finally{c(null)}}};return(0,P.jsxs)(I,{tone:`danger`,children:[(0,P.jsxs)(`div`,{className:`flex flex-wrap gap-2`,children:[(0,P.jsxs)(`button`,{type:`button`,disabled:o!==null,onClick:()=>void d(`here`),className:e(h,`flex-1`),children:[o===`here`?(0,P.jsx)(l,{size:15,className:`animate-spin`}):(0,P.jsx)(k,{size:15}),` `,i(`Sign out`)]}),(0,P.jsxs)(`button`,{type:`button`,disabled:o!==null,onClick:()=>void d(`all`),className:e(h,`flex-1`),children:[o===`all`?(0,P.jsx)(l,{size:15,className:`animate-spin`}):(0,P.jsx)(C,{size:15}),` `,i(`Sign out everywhere`)]})]}),(0,P.jsxs)(`button`,{type:`button`,disabled:o!==null,onClick:()=>void d(`delete`),className:`flex w-full items-center justify-center gap-1.5 rounded-2xl py-2 text-[13px] font-medium text-rose-600 hover:bg-rose-500/10 dark:text-rose-300`,children:[o===`delete`?(0,P.jsx)(l,{size:15,className:`animate-spin`}):(0,P.jsx)(b,{size:15}),` `,i(`Delete the account`)]}),t?.is_model&&(0,P.jsx)(`p`,{className:`text-center text-[11.5px] text-muted`,children:i(`The Cloud model is in use; after signing out, pick another under Connections.`)})]})}export{F as AccountScreen}; \ No newline at end of file diff --git a/nanomuse/server/static/assets/AccountScreen-CfcZ3emY.js b/nanomuse/server/static/assets/AccountScreen-CfcZ3emY.js deleted file mode 100644 index 812d2ef93..000000000 --- a/nanomuse/server/static/assets/AccountScreen-CfcZ3emY.js +++ /dev/null @@ -1 +0,0 @@ -import{E as e,J as t,K as n,Q as r,R as i,Y as a,b as o,f as s,k as c,q as l,x as u}from"./MuseHeader-BvAlmxiL.js";import{A as d,s as f,t as p}from"./StarNudge-Cr_QPa4y.js";import{n as m}from"./external-link-V2ISE5bW.js";import{a as h,i as g}from"./Form-C77NCy9F.js";import{t as _}from"./clapperboard-90G9CI1B.js";import{t as v}from"./database-zap-Bv9NPF9E.js";import{t as y}from"./image-Cn9LGhlN.js";import{$ as b,A as x,G as S,J as C,K as w,V as T,ct as E,gt as D,ot as O,t as k,ut as A}from"./index-tZx-TDX4.js";import{t as j}from"./BackBar-DmScFXW_.js";var M=t(`gift`,[[`path`,{d:`M12 7v14`,key:`1akyts`}],[`path`,{d:`M20 11v8a2 2 0 0 1-2 2H6a2 2 0 0 1-2-2v-8`,key:`1sqzm4`}],[`path`,{d:`M7.5 7a1 1 0 0 1 0-5A4.8 8 0 0 1 12 7a4.8 8 0 0 1 4.5-5 1 1 0 0 1 0 5`,key:`kc0143`}],[`rect`,{x:`3`,y:`7`,width:`18`,height:`4`,rx:`1`,key:`1hberx`}]]),N=r(a(),1),P=o();function F(){let{state:e,toast:t,setTab:r}=s(),i=n(),a=e.hub?.account??null,[o,c]=(0,N.useState)(null),[l,d]=(0,N.useState)(null),[m,h]=(0,N.useState)(null),[g,_]=(0,N.useState)(!1),v=!!a?.signed_in,y=f(),b=async()=>{if(v){_(!0);try{let[e,t,n]=await Promise.all([u.cloudMe(),u.cloudSessions(),u.cloudEvents(40)]);c(e),d(t.sessions),h(n.events)}catch(e){t(e.message)}finally{_(!1)}}};return(0,N.useEffect)(()=>{b()},[v,a?.has_password]),(0,P.jsxs)(`div`,{className:`flex h-full flex-col`,children:[(0,P.jsx)(j,{title:i(`Account`),description:i(v?`nanoMuse Cloud · one account for all your devices`:`Sign in to nanoMuse Cloud`)}),(0,P.jsx)(`div`,{className:`flex-1 overflow-y-auto px-4 pb-8 space-y-4`,children:v?(0,P.jsxs)(P.Fragment,{children:[(0,P.jsx)(L,{account:a,me:o}),o&&(0,P.jsx)(p,{moment:`signed_in`}),o&&(0,P.jsx)(R,{me:o,onChanged:()=>void b()}),o?.invite?.code&&(0,P.jsx)(B,{invite:o.invite}),o&&(0,P.jsx)(H,{me:o}),o&&(0,P.jsx)(z,{me:o}),(0,P.jsx)(W,{account:a,onChanged:()=>void b()}),(0,P.jsx)(G,{sessions:l,loading:g,onChanged:()=>void b()}),m&&m.length>0&&(0,P.jsx)(q,{events:m}),(0,P.jsx)(J,{account:a,onDone:()=>r(`chat`)})]}):(0,P.jsxs)(I,{children:[(0,P.jsx)(`p`,{className:`text-[13.5px] text-muted leading-relaxed`,children:i(`Free. One account for all your devices, with a model and ¥{allowance} of use to start; a code the first time, a password afterwards if you like.`,{allowance:(y.allowance_cny??10).toFixed(0)})}),(0,P.jsx)(k,{onSignedIn:()=>t(i(`Signed in to nanoMuse Cloud.`))})]})})]})}function I({title:t,children:n,tone:r}){return(0,P.jsxs)(`section`,{className:e(`rounded-3xl border p-4 space-y-3 shadow-sm`,r===`danger`?`border-rose-500/25 bg-rose-500/[0.04]`:`border-border/70 bg-surface`),children:[t&&(0,P.jsx)(`h2`,{className:`text-[12px] font-semibold uppercase tracking-wide text-muted`,children:t}),n]})}function L({account:e,me:t}){let r=n(),a=e?.hint??``,o=t?.account.created_at?new Date(t.account.created_at*1e3):null;return(0,P.jsxs)(`section`,{className:`relative overflow-hidden rounded-3xl border border-border/70 bg-surface p-5 shadow-sm`,children:[(0,P.jsx)(`div`,{className:`pointer-events-none absolute -right-16 -top-20 h-48 w-48 rounded-full bg-accent/15 blur-3xl`}),(0,P.jsxs)(`div`,{className:`flex items-center gap-4`,children:[(0,P.jsx)(`div`,{className:`flex h-14 w-14 shrink-0 items-center justify-center rounded-2xl bg-gradient-to-br from-accent to-sky-400 text-[22px] font-bold text-white shadow-md`,children:(a.replace(/[^a-z0-9]/gi,``).slice(0,1)||`n`).toUpperCase()}),(0,P.jsxs)(`div`,{className:`min-w-0 flex-1`,children:[(0,P.jsx)(`div`,{className:`truncate text-[18px] font-semibold tracking-tight`,children:a}),(0,P.jsxs)(`div`,{className:`mt-0.5 flex flex-wrap items-center gap-x-2 gap-y-0.5 text-[12.5px] text-muted`,children:[(0,P.jsx)(`span`,{children:e?.channel===`phone`||e?.channel===`sms`?r(`Mobile number`):r(`E-mail`)}),o&&(0,P.jsxs)(`span`,{children:[`· `,r(`since {date}`,{date:o.toLocaleDateString(i())})]}),t?.account.member&&(0,P.jsxs)(`span`,{className:`inline-flex items-center gap-1 rounded-full bg-emerald-500/12 px-2 py-0.5 text-[11px] font-medium text-emerald-700 dark:text-emerald-300`,children:[(0,P.jsx)(w,{size:11}),` `,r(`Unlimited`)]})]})]})]}),e?.account_id&&(0,P.jsxs)(`div`,{className:`mt-4 flex items-center justify-between gap-3 rounded-2xl bg-surface-2/70 px-3 py-2 text-[12px]`,children:[(0,P.jsx)(`span`,{className:`text-muted`,children:r(`Account id`)}),(0,P.jsx)(`code`,{className:`truncate font-mono text-[11.5px] text-fg/80`,children:e.account_id})]})]})}function R({me:t,onChanged:r}){let i=n(),a=t.spend,o=a.grant??a.daily_cap??0,s=a.grant===void 0?a.today:a.total,c=a.left??(a.unlimited?null:Math.max(0,o-s)),l=!a.unlimited&&o>0,u=l?Math.min(100,Math.round(s/o*100)):0,f=a.usd_cny??0,p=e=>f>0?` ≈ $${(e/f).toFixed(2)}`:``,m=l&&(c??0)<=0,h=l&&!m&&(a.warn??u>=80),g={left:c,grant:o,invite_url:t.invite?.url,invite_bonus_cny:a.invite_bonus_cny??t.invite?.bonus_cny,invitee_bonus_cny:a.invitee_bonus_cny??t.invite?.invitee_bonus_cny,own_key_docs:a.own_key_docs,guidance:a.guidance};return(0,P.jsxs)(I,{title:i(`Free allowance`),children:[(0,P.jsxs)(`div`,{className:`flex items-end justify-between gap-3`,children:[(0,P.jsxs)(`div`,{children:[(0,P.jsx)(`div`,{className:`text-[28px] font-bold tracking-tight leading-none`,children:l?(0,P.jsxs)(P.Fragment,{children:[`¥`,(c??0).toFixed(2),(0,P.jsxs)(`span`,{className:`text-[14px] font-medium text-muted`,children:[` `,i(`left of ¥{grant}`,{grant:o.toFixed(0)})]})]}):(0,P.jsxs)(P.Fragment,{children:[`¥`,s.toFixed(2)]})}),(0,P.jsx)(`div`,{className:`mt-1 text-[12.5px] text-muted`,children:l?i(`¥{spent} used{usd}; the allowance does not reset.`,{spent:s.toFixed(2),usd:p(s)}):i(`No limit on this account.`)})]}),(0,P.jsxs)(`div`,{className:`text-right text-[12.5px] text-muted`,children:[(0,P.jsx)(`div`,{children:i(`All time`)}),(0,P.jsxs)(`div`,{className:`text-[15px] font-semibold text-fg`,children:[`¥`,a.total.toFixed(2)]}),f>0&&(0,P.jsxs)(`div`,{className:`text-[11.5px]`,children:[`≈ $`,(a.total/f).toFixed(2)]})]})]}),l&&(0,P.jsx)(`div`,{className:`h-2 overflow-hidden rounded-full bg-surface-2`,children:(0,P.jsx)(`div`,{className:e(`h-full rounded-full transition-all`,u>=100?`bg-rose-500`:u>=80?`bg-amber-500`:`bg-accent`),style:{width:`${u}%`}})}),l&&(0,P.jsxs)(`p`,{className:`text-[12.5px] text-muted`,children:[i(`¥{allowance} to start, +¥{invite} for each friend you invite, and +¥{invite} for them; after that, your own key keeps the model going.`,{allowance:(a.allowance_cny??10).toFixed(0),invite:(g.invite_bonus_cny??5).toFixed(0)}),` `,!m&&!h&&d(i,{signed_in:!0,channel:t.account.channel,region:t.account.region})]}),(m||h)&&(0,P.jsx)(x,{info:g,exhausted:m,onChanged:r})]})}function z({me:e}){let t=n(),{setTab:r}=s(),i=e.contribute??{on:!1,samples:0};return(0,P.jsx)(I,{title:t(`Data controls`),children:(0,P.jsxs)(`button`,{type:`button`,onClick:()=>{window.location.hash=`data`,r(`you`)},className:`flex w-full items-center gap-3 text-left`,children:[(0,P.jsx)(`span`,{className:`flex h-9 w-9 shrink-0 items-center justify-center rounded-xl bg-surface-2 text-fg`,children:(0,P.jsx)(v,{size:18})}),(0,P.jsxs)(`span`,{className:`min-w-0 flex-1`,children:[(0,P.jsx)(`span`,{className:`block text-[14px] font-medium`,children:t(`Help improve nanoMuse's AI models`)}),(0,P.jsxs)(`span`,{className:`block text-[12.5px] text-muted`,children:[i.on?t(`On`):t(`Off`),i.samples>0&&` · ${t(`{n} turns kept so far`,{n:String(i.samples)})}`]})]}),(0,P.jsx)(`span`,{className:`text-[13px] font-medium text-accent`,children:t(`Open`)})]})})}function B({invite:t}){let r=n(),{toast:i}=s(),a=t.url||`https://nanomuse.cn/web/?invite=${t.code}`,o=t.earned_cny??t.invites*t.bonus_cny,c=async e=>{try{await navigator.clipboard.writeText(e),i(r(`Copied`))}catch{i(e)}},l=async()=>{let e=r(`Try nanoMuse with me, a fully open-source personal agent, free to use. Sign up with my code {code}: {link}`,{code:t.code,link:a}),n=navigator;if(n.share)try{await n.share({text:e});return}catch{}await c(e)};return(0,P.jsxs)(I,{title:r(`Invite a friend`),children:[(0,P.jsx)(`p`,{className:`text-[12.5px] text-muted`,children:r(`Each new person who signs up with your code adds ¥{bonus} to your allowance, and ¥{bonus} to theirs. It never expires.`,{bonus:t.bonus_cny.toFixed(0)})}),(0,P.jsxs)(`div`,{className:`flex items-center justify-between gap-3 rounded-2xl bg-surface-2/70 px-3 py-2`,children:[(0,P.jsxs)(`div`,{children:[(0,P.jsx)(`div`,{className:`text-[11px] text-muted`,children:r(`Your code`)}),(0,P.jsx)(`code`,{className:`font-mono text-[18px] font-semibold tracking-[0.2em]`,children:t.code})]}),(0,P.jsxs)(`button`,{type:`button`,onClick:()=>void c(t.code),className:e(h,`inline-flex items-center gap-1.5`),children:[(0,P.jsx)(D,{size:14}),` `,r(`Copy`)]})]}),(0,P.jsxs)(`div`,{className:`flex gap-2`,children:[(0,P.jsxs)(`button`,{type:`button`,onClick:()=>void l(),className:e(g,`inline-flex flex-1 items-center justify-center gap-1.5 py-2.5`),children:[(0,P.jsx)(C,{size:14}),` `,r(`Share the link`)]}),(0,P.jsxs)(`button`,{type:`button`,onClick:()=>void c(a),className:e(h,`inline-flex items-center gap-1.5`),children:[(0,P.jsx)(M,{size:14}),` `,r(`Copy the link`)]})]}),(0,P.jsxs)(`p`,{className:`text-[12.5px] text-muted`,children:[r(`{n} friends joined`,{n:String(t.invites)}),o>0&&(0,P.jsxs)(P.Fragment,{children:[` · `,r(`¥{amount} added by invitations`,{amount:o.toFixed(0)})]})]})]})}var V={chat:{label:`Chat`,icon:(0,P.jsx)(O,{size:15}),tone:`bg-accent`},image:{label:`Pictures`,icon:(0,P.jsx)(y,{size:15}),tone:`bg-violet-500`},video:{label:`Clips`,icon:(0,P.jsx)(_,{size:15}),tone:`bg-pink-500`},realtime:{label:`Calls`,icon:(0,P.jsx)(b,{size:15}),tone:`bg-emerald-500`}};function H({me:t}){let r=n(),[i,a]=(0,N.useState)(`today`),o=i===`today`?t.usage.today.by_kind:t.usage.total.by_kind,s=t.usage.kinds.length?t.usage.kinds:[`chat`,`image`,`video`,`realtime`],c=new Map(o.map(e=>[e.kind,e])),l=o.reduce((e,t)=>e+t.cost_cny,0),u=t.usage.total.by_model.slice(0,8);return(0,P.jsxs)(I,{title:r(`Usage`),children:[(0,P.jsxs)(`div`,{className:`flex items-center justify-between`,children:[(0,P.jsx)(`p`,{className:`text-[12.5px] text-muted`,children:r(`Every kind of use is counted, not just the chat model.`)}),(0,P.jsx)(`div`,{className:`flex rounded-full bg-surface-2/80 p-0.5 text-[12px] font-medium`,children:[`today`,`total`].map(t=>(0,P.jsx)(`button`,{type:`button`,onClick:()=>a(t),className:e(`rounded-full px-2.5 py-1 transition`,i===t?`bg-surface shadow-sm`:`text-muted`),children:r(t===`today`?`Today`:`All time`)},t))})]}),l>0&&(0,P.jsx)(`div`,{className:`flex h-2.5 overflow-hidden rounded-full bg-surface-2`,children:s.map(t=>{let n=c.get(t);return!n||n.cost_cny<=0?null:(0,P.jsx)(`div`,{className:e(`h-full`,V[t]?.tone??`bg-fg/40`),style:{width:`${n.cost_cny/l*100}%`},title:r(V[t]?.label??t)},t)})}),(0,P.jsx)(`ul`,{className:`grid grid-cols-2 gap-2`,children:s.map(t=>{let n=c.get(t),i=V[t];return(0,P.jsxs)(`li`,{className:`rounded-2xl bg-surface-2/60 p-3`,children:[(0,P.jsxs)(`div`,{className:`flex items-center gap-1.5 text-[12.5px] text-muted`,children:[(0,P.jsx)(`span`,{className:e(`flex h-5 w-5 items-center justify-center rounded-md text-white`,i?.tone??`bg-fg/40`),children:i?.icon}),r(i?.label??t)]}),(0,P.jsxs)(`div`,{className:`mt-1.5 text-[17px] font-semibold tracking-tight`,children:[`¥`,(n?.cost_cny??0).toFixed(2)]}),(0,P.jsx)(`div`,{className:`text-[11.5px] text-muted`,children:n?t===`realtime`?r(`{n} answers · {tokens} tokens`,{n:n.requests,tokens:U(n.prompt_tokens+n.completion_tokens)}):t===`chat`?r(`{n} requests · {tokens} tokens`,{n:n.requests,tokens:U(n.prompt_tokens+n.completion_tokens)}):r(`{n} requests`,{n:n.requests}):r(`Nothing yet`)})]},t)})}),u.length>0&&(0,P.jsxs)(`div`,{children:[(0,P.jsx)(`div`,{className:`mb-1.5 text-[12px] font-medium text-muted`,children:r(`By model, all time`)}),(0,P.jsx)(`ul`,{className:`divide-y divide-border/60 rounded-2xl border border-border/60`,children:u.map(t=>(0,P.jsxs)(`li`,{className:`flex items-center gap-2 px-3 py-2 text-[12.5px]`,children:[(0,P.jsx)(`span`,{className:e(`h-2 w-2 shrink-0 rounded-full`,V[t.kind]?.tone??`bg-fg/40`)}),(0,P.jsx)(`span`,{className:`min-w-0 flex-1 truncate font-mono text-[12px]`,children:t.model}),(0,P.jsx)(`span`,{className:`text-muted`,children:U(t.prompt_tokens+t.completion_tokens)}),(0,P.jsxs)(`span`,{className:`w-16 text-right font-medium`,children:[`¥`,t.cost_cny.toFixed(2)]})]},`${t.model}-${t.kind}`))})]})]})}function U(e){return e>=1e6?`${(e/1e6).toFixed(1)}M`:e>=1e3?`${(e/1e3).toFixed(e>=1e5?0:1)}k`:String(e)}function W({account:t,onChanged:r}){let i=n(),{toast:a}=s(),o=!!t?.has_password,[c,d]=(0,N.useState)(!1),[f,p]=(0,N.useState)(``),[h,g]=(0,N.useState)(``),[_,v]=(0,N.useState)(``),[y,b]=(0,N.useState)(!1),[x,S]=(0,N.useState)(null),C=async(e=!1)=>{if(!(!e&&(h.length<8||h!==_))){b(!0),S(null);try{await u.cloudPassword(e?``:h,o?f:void 0),a(i(e?`Password removed.`:o?`Password changed.`:`Password set.`)),d(!1),p(``),g(``),v(``),r()}catch(e){S(i(e.message))}finally{b(!1)}}};return(0,P.jsxs)(I,{title:i(`Password`),children:[(0,P.jsxs)(`div`,{className:`flex items-center gap-3`,children:[(0,P.jsx)(`span`,{className:e(`flex h-9 w-9 items-center justify-center rounded-xl`,o?`bg-emerald-500/12 text-emerald-600 dark:text-emerald-300`:`bg-surface-2 text-muted`),children:(0,P.jsx)(A,{size:17})}),(0,P.jsxs)(`div`,{className:`min-w-0 flex-1 text-[13.5px]`,children:[(0,P.jsx)(`div`,{className:`font-medium`,children:i(o?`A password is set`:`No password yet`)}),(0,P.jsx)(`div`,{className:`text-[12.5px] text-muted`,children:i(o?`Sign in with it on a new device, or with a code as before.`:`Optional. With one, a new device can sign in without waiting for a code.`)})]}),!c&&(0,P.jsx)(`button`,{type:`button`,onClick:()=>d(!0),className:e(`flex items-center justify-center gap-1.5 rounded-2xl border border-border px-4 py-2.5 text-[14px] font-medium text-muted disabled:opacity-40`,`shrink-0 px-3 py-2 text-[13px]`),children:i(o?`Change`:`Set`)})]}),c&&(0,P.jsxs)(`form`,{className:`space-y-2.5`,onSubmit:e=>{e.preventDefault(),C()},children:[o&&(0,P.jsx)(`input`,{type:`password`,value:f,onChange:e=>p(e.target.value),placeholder:i(`Current password`),autoComplete:`current-password`,className:`w-full rounded-2xl bg-surface-2 px-3.5 py-2.5 text-[14.5px] outline-none focus:ring-2 focus:ring-accent/40`}),(0,P.jsx)(`input`,{type:`password`,value:h,onChange:e=>g(e.target.value),placeholder:i(`New password (8 characters or more)`),autoComplete:`new-password`,autoFocus:!0,className:`w-full rounded-2xl bg-surface-2 px-3.5 py-2.5 text-[14.5px] outline-none focus:ring-2 focus:ring-accent/40`}),(0,P.jsx)(`input`,{type:`password`,value:_,onChange:e=>v(e.target.value),placeholder:i(`Once more`),autoComplete:`new-password`,className:`w-full rounded-2xl bg-surface-2 px-3.5 py-2.5 text-[14.5px] outline-none focus:ring-2 focus:ring-accent/40`}),_&&h!==_&&(0,P.jsx)(`p`,{className:`text-[12px] text-rose-600 dark:text-rose-300`,children:i(`The two do not match.`)}),x&&(0,P.jsx)(`p`,{className:`rounded-2xl bg-rose-500/12 px-3 py-2 text-[12.5px] text-rose-700 dark:text-rose-300`,children:x}),(0,P.jsxs)(`div`,{className:`flex flex-wrap gap-2`,children:[(0,P.jsxs)(`button`,{type:`submit`,disabled:y||h.length<8||h!==_||o&&!f,className:e(`flex items-center justify-center gap-1.5 rounded-2xl bg-accent text-accent-fg px-4 py-2.5 text-[14px] font-medium disabled:opacity-40`,`flex-1`),children:[y?(0,P.jsx)(l,{size:15,className:`animate-spin`}):(0,P.jsx)(m,{size:15}),` `,i(o?`Change password`:`Set password`)]}),o&&(0,P.jsx)(`button`,{type:`button`,disabled:y||!f,onClick:()=>void C(!0),className:`flex items-center justify-center gap-1.5 rounded-2xl border border-border px-4 py-2.5 text-[14px] font-medium text-muted disabled:opacity-40`,children:i(`Remove`)}),(0,P.jsx)(`button`,{type:`button`,onClick:()=>d(!1),className:`flex items-center justify-center gap-1.5 rounded-2xl border border-border px-4 py-2.5 text-[14px] font-medium text-muted disabled:opacity-40`,children:i(`Cancel`)})]})]})]})}function G({sessions:e,loading:t,onChanged:r}){let a=n(),{toast:o}=s(),[d,f]=(0,N.useState)(null),p=async e=>{if(window.confirm(a(`Sign out {device}? It will need to sign in again.`,{device:e.device||e.prefix}))){f(e.prefix);try{await u.cloudRevokeSession(e.prefix),r()}catch(e){o(e.message)}finally{f(null)}}};return(0,P.jsx)(I,{title:a(`Signed in on`),children:e?(0,P.jsx)(`ul`,{className:`divide-y divide-border/60`,children:e.map(e=>(0,P.jsxs)(`li`,{className:`flex items-center gap-3 py-2.5`,children:[(0,P.jsx)(`span`,{className:`flex h-9 w-9 shrink-0 items-center justify-center rounded-xl bg-surface-2 text-fg/70`,children:(0,P.jsx)(S,{size:17})}),(0,P.jsxs)(`div`,{className:`min-w-0 flex-1`,children:[(0,P.jsxs)(`div`,{className:`flex items-center gap-2 text-[13.5px] font-medium`,children:[(0,P.jsx)(`span`,{className:`truncate`,children:e.device||a(`Unnamed device`)}),e.current&&(0,P.jsx)(`span`,{className:`rounded-full bg-accent/12 px-2 py-0.5 text-[10.5px] font-semibold text-accent`,children:a(`This one`)})]}),(0,P.jsxs)(`div`,{className:`truncate text-[12px] text-muted`,children:[e.via===`password`?a(`password`):a(`code`),` · `,a(`since {date}`,{date:new Date(e.created_at*1e3).toLocaleDateString(i())}),e.last_used_at?` · ${a(`used {when}`,{when:c(e.last_used_at)})}`:``]})]}),!e.current&&(0,P.jsx)(`button`,{type:`button`,disabled:d!==null,onClick:()=>void p(e),className:`rounded-full px-3 py-1.5 text-[12.5px] font-medium text-rose-600 hover:bg-rose-500/10 dark:text-rose-300`,children:d===e.prefix?(0,P.jsx)(l,{size:14,className:`animate-spin`}):a(`Sign out`)})]},e.prefix))}):(0,P.jsx)(`div`,{className:`flex justify-center py-3 text-muted`,children:t?(0,P.jsx)(l,{size:18,className:`animate-spin`}):null})})}var K={"account.created":`Account created`,"sign_in.code":`Signed in with a code`,"sign_in.password":`Signed in with the password`,"sign_in.failed":`A sign-in attempt failed`,sign_out:`Signed out`,"sign_out.all":`Signed out everywhere`,"password.set":`Password set`,"password.changed":`Password changed`,"password.cleared":`Password removed`,"budget.refused":`A request was refused: the allowance is used up`,"call.ended":`Call ended`,"upstream.error":`The model provider returned an error`,"credit.granted":`Allowance added`,"pool.set":`Allowance adjusted`,"invite.accepted":`Signed up with a friend's code`,"invite.used":`A friend signed up with your code`,"invite.unknown":`An invite code was not recognised`,"contribute.default":`Data controls: on for new accounts`,"contribute.on":`Data controls: help improve turned on`,"contribute.off":`Data controls: help improve turned off`,"contribute.deleted":`Data controls: kept conversations deleted`,"profile.put":`Agent's name and look saved`,"profile.clear":`Agent's name and look cleared`};function q({events:e}){let t=n(),[r,i]=(0,N.useState)(!1),a=r?e:e.slice(0,6);return(0,P.jsxs)(I,{title:t(`Recent activity`),children:[(0,P.jsx)(`ul`,{className:`space-y-2`,children:a.map((e,n)=>(0,P.jsxs)(`li`,{className:`flex gap-3 text-[12.5px]`,children:[(0,P.jsx)(`span`,{className:`w-[74px] shrink-0 text-muted`,children:c(e.ts)}),(0,P.jsxs)(`span`,{className:`min-w-0 flex-1`,children:[(0,P.jsx)(`span`,{className:`font-medium`,children:t(K[e.kind]??e.kind)}),e.detail&&(0,P.jsx)(`span`,{className:`ml-1.5 break-all text-muted`,children:e.detail})]})]},`${e.ts}-${n}`))}),e.length>6&&(0,P.jsx)(`button`,{type:`button`,onClick:()=>i(e=>!e),className:`text-[12.5px] font-medium text-accent`,children:r?t(`Show less`):t(`Show all {n}`,{n:e.length})})]})}function J({account:t,onDone:r}){let i=n(),{toast:a}=s(),[o,c]=(0,N.useState)(null),d=async e=>{let t=i(e===`here`?`Sign out of nanoMuse Cloud on this device? The hub and the Cloud model stop working here until you sign in again.`:e===`all`?`Sign out on every device, including this one?`:`Delete the account? The relay forgets your identifier, your devices and your usage. This cannot be undone.`);if(window.confirm(t)&&(e!==`delete`||window.confirm(i(`Really delete it?`)))){c(e);try{e===`here`?await u.cloudSignOut():e===`all`?await u.cloudSignOutAll(!0):await u.cloudDelete(),a(i(e===`delete`?`Account deleted.`:`Signed out.`)),r()}catch(e){a(e.message)}finally{c(null)}}};return(0,P.jsxs)(I,{tone:`danger`,children:[(0,P.jsxs)(`div`,{className:`flex flex-wrap gap-2`,children:[(0,P.jsxs)(`button`,{type:`button`,disabled:o!==null,onClick:()=>void d(`here`),className:e(h,`flex-1`),children:[o===`here`?(0,P.jsx)(l,{size:15,className:`animate-spin`}):(0,P.jsx)(E,{size:15}),` `,i(`Sign out`)]}),(0,P.jsxs)(`button`,{type:`button`,disabled:o!==null,onClick:()=>void d(`all`),className:e(h,`flex-1`),children:[o===`all`?(0,P.jsx)(l,{size:15,className:`animate-spin`}):(0,P.jsx)(S,{size:15}),` `,i(`Sign out everywhere`)]})]}),(0,P.jsxs)(`button`,{type:`button`,disabled:o!==null,onClick:()=>void d(`delete`),className:`flex w-full items-center justify-center gap-1.5 rounded-2xl py-2 text-[13px] font-medium text-rose-600 hover:bg-rose-500/10 dark:text-rose-300`,children:[o===`delete`?(0,P.jsx)(l,{size:15,className:`animate-spin`}):(0,P.jsx)(T,{size:15}),` `,i(`Delete the account`)]}),t?.is_model&&(0,P.jsx)(`p`,{className:`text-center text-[11.5px] text-muted`,children:i(`The Cloud model is in use; after signing out, pick another under Connections.`)})]})}export{F as AccountScreen}; \ No newline at end of file diff --git a/nanomuse/server/static/assets/AvatarPicker-DUnXfRVQ.js b/nanomuse/server/static/assets/AvatarPicker-BCihUURa.js similarity index 95% rename from nanomuse/server/static/assets/AvatarPicker-DUnXfRVQ.js rename to nanomuse/server/static/assets/AvatarPicker-BCihUURa.js index 19f62190e..e8d25717a 100644 --- a/nanomuse/server/static/assets/AvatarPicker-DUnXfRVQ.js +++ b/nanomuse/server/static/assets/AvatarPicker-BCihUURa.js @@ -1 +1 @@ -import{E as e,K as t,a as n,b as r,c as i,s as a,u as o}from"./MuseHeader-BvAlmxiL.js";import{n as s}from"./external-link-V2ISE5bW.js";import{W as c}from"./index-tZx-TDX4.js";var l=r(),u=[`✨`,`🌙`,`🪐`,`🌿`,`🔥`,`🌊`,`🦉`,`🦊`,`🐙`,`🎯`,`🧭`,`💎`,`🍀`,`🎈`,`🤖`,`🧠`],d=[`#0064d4`,`#7c3aed`,`#0891b2`,`#059669`,`#d97706`,`#dc2626`,`#db2777`,`#4b5563`],f=[{id:`muse`,label:`3D toy (Muse)`},{id:`flat`,label:`Flat`},{id:`clay`,label:`3D clay`},{id:`watercolor`,label:`Watercolour`},{id:`pixel`,label:`Pixel`},{id:`line`,label:`Line`},{id:`sticker`,label:`Sticker`}];function p({value:r,onChange:f,onStudio:p}){let m=t(),h=r.avatar===``,g=!h&&!i(r.avatar)?r.avatar:null,_=`ring-[2.5px] ring-accent ring-offset-2 ring-offset-bg`,v=`relative h-[72px] w-[72px] shrink-0 overflow-hidden rounded-full transition`;return(0,l.jsxs)(`div`,{className:`space-y-3`,children:[(0,l.jsxs)(`div`,{className:`flex flex-wrap gap-3`,children:[(0,l.jsx)(`button`,{type:`button`,"aria-label":m(`The dragon`),"aria-pressed":r.avatar===n,onClick:()=>f({...r,avatar:n}),className:e(v,`bg-[#f1efeb]`,r.avatar===`dragon`?_:`opacity-90 hover:opacity-100`),children:(0,l.jsx)(`img`,{src:a(r.avatar===`dragon`?`happy`:`idle`),alt:``,draggable:!1,className:`h-full w-full object-cover`})}),g&&(0,l.jsx)(`button`,{type:`button`,"aria-label":m(`The face drawn for you`),"aria-pressed":!0,className:e(v,`bg-surface-2`,_),children:(0,l.jsx)(`img`,{src:o(g,`happy`),alt:``,draggable:!1,className:`h-full w-full object-cover`})}),p&&(0,l.jsx)(`button`,{type:`button`,"aria-label":m(`Avatar studio`),onClick:p,className:e(v,`flex items-center justify-center border border-dashed border-border text-accent hover:bg-surface-2`),children:(0,l.jsx)(c,{size:22})}),(0,l.jsx)(`button`,{type:`button`,"aria-label":m(`An emoji instead`),"aria-pressed":h,onClick:()=>f({...r,avatar:``}),className:e(`flex h-[72px] w-[72px] shrink-0 items-center justify-center rounded-full text-[26px] transition`,h?_:`opacity-90 hover:opacity-100`),style:{background:`linear-gradient(135deg, ${r.color}, color-mix(in srgb, ${r.color} 60%, #ffffff))`},children:r.emoji})]}),h&&(0,l.jsxs)(l.Fragment,{children:[(0,l.jsx)(`div`,{className:`grid grid-cols-8 gap-1.5`,children:u.map(t=>(0,l.jsx)(`button`,{type:`button`,onClick:()=>f({...r,emoji:t}),className:e(`flex aspect-square items-center justify-center rounded-2xl bg-surface-2 text-[22px]`,r.emoji===t&&`ring-2 ring-accent`),children:t},t))}),(0,l.jsx)(`div`,{className:`flex gap-2`,children:d.map(e=>(0,l.jsx)(`button`,{type:`button`,"aria-label":e,onClick:()=>f({...r,color:e}),className:`flex h-8 w-8 items-center justify-center rounded-full text-white`,style:{background:e},children:r.color===e&&(0,l.jsx)(s,{size:16})},e))})]})]})}export{f as n,p as r,d as t}; \ No newline at end of file +import{E as e,K as t,a as n,b as r,c as i,s as a,u as o}from"./MuseHeader-RC--uR8o.js";import{n as s}from"./external-link-TvxP_dKX.js";import{U as c}from"./index-tYqPtwPX.js";var l=r(),u=[`✨`,`🌙`,`🪐`,`🌿`,`🔥`,`🌊`,`🦉`,`🦊`,`🐙`,`🎯`,`🧭`,`💎`,`🍀`,`🎈`,`🤖`,`🧠`],d=[`#0064d4`,`#7c3aed`,`#0891b2`,`#059669`,`#d97706`,`#dc2626`,`#db2777`,`#4b5563`],f=[{id:`muse`,label:`3D toy (Muse)`},{id:`flat`,label:`Flat`},{id:`clay`,label:`3D clay`},{id:`watercolor`,label:`Watercolour`},{id:`pixel`,label:`Pixel`},{id:`line`,label:`Line`},{id:`sticker`,label:`Sticker`}];function p({value:r,onChange:f,onStudio:p}){let m=t(),h=r.avatar===``,g=!h&&!i(r.avatar)?r.avatar:null,_=`ring-[2.5px] ring-accent ring-offset-2 ring-offset-bg`,v=`relative h-[72px] w-[72px] shrink-0 overflow-hidden rounded-full transition`;return(0,l.jsxs)(`div`,{className:`space-y-3`,children:[(0,l.jsxs)(`div`,{className:`flex flex-wrap gap-3`,children:[(0,l.jsx)(`button`,{type:`button`,"aria-label":m(`The dragon`),"aria-pressed":r.avatar===n,onClick:()=>f({...r,avatar:n}),className:e(v,`bg-[#f1efeb]`,r.avatar===`dragon`?_:`opacity-90 hover:opacity-100`),children:(0,l.jsx)(`img`,{src:a(r.avatar===`dragon`?`happy`:`idle`),alt:``,draggable:!1,className:`h-full w-full object-cover`})}),g&&(0,l.jsx)(`button`,{type:`button`,"aria-label":m(`The face drawn for you`),"aria-pressed":!0,className:e(v,`bg-surface-2`,_),children:(0,l.jsx)(`img`,{src:o(g,`happy`),alt:``,draggable:!1,className:`h-full w-full object-cover`})}),p&&(0,l.jsx)(`button`,{type:`button`,"aria-label":m(`Avatar studio`),onClick:p,className:e(v,`flex items-center justify-center border border-dashed border-border text-accent hover:bg-surface-2`),children:(0,l.jsx)(c,{size:22})}),(0,l.jsx)(`button`,{type:`button`,"aria-label":m(`An emoji instead`),"aria-pressed":h,onClick:()=>f({...r,avatar:``}),className:e(`flex h-[72px] w-[72px] shrink-0 items-center justify-center rounded-full text-[26px] transition`,h?_:`opacity-90 hover:opacity-100`),style:{background:`linear-gradient(135deg, ${r.color}, color-mix(in srgb, ${r.color} 60%, #ffffff))`},children:r.emoji})]}),h&&(0,l.jsxs)(l.Fragment,{children:[(0,l.jsx)(`div`,{className:`grid grid-cols-8 gap-1.5`,children:u.map(t=>(0,l.jsx)(`button`,{type:`button`,onClick:()=>f({...r,emoji:t}),className:e(`flex aspect-square items-center justify-center rounded-2xl bg-surface-2 text-[22px]`,r.emoji===t&&`ring-2 ring-accent`),children:t},t))}),(0,l.jsx)(`div`,{className:`flex gap-2`,children:d.map(e=>(0,l.jsx)(`button`,{type:`button`,"aria-label":e,onClick:()=>f({...r,color:e}),className:`flex h-8 w-8 items-center justify-center rounded-full text-white`,style:{background:e},children:r.color===e&&(0,l.jsx)(s,{size:16})},e))})]})]})}export{f as n,p as r,d as t}; \ No newline at end of file diff --git a/nanomuse/server/static/assets/AvatarStudioScreen-DuBIZ1Gf.js b/nanomuse/server/static/assets/AvatarStudioScreen-Dgqo0TEO.js similarity index 95% rename from nanomuse/server/static/assets/AvatarStudioScreen-DuBIZ1Gf.js rename to nanomuse/server/static/assets/AvatarStudioScreen-Dgqo0TEO.js index cdd38a7d8..3d7999247 100644 --- a/nanomuse/server/static/assets/AvatarStudioScreen-DuBIZ1Gf.js +++ b/nanomuse/server/static/assets/AvatarStudioScreen-Dgqo0TEO.js @@ -1 +1 @@ -import{E as e,K as t,L as n,Q as r,S as i,Y as a,a as o,b as s,c,f as l,l as u,o as d,q as f,r as p,s as m,u as h,x as g}from"./MuseHeader-BvAlmxiL.js";import{C as _,t as v,w as y}from"./StarNudge-Cr_QPa4y.js";import{n as b}from"./external-link-V2ISE5bW.js";import{i as x,o as S}from"./Form-C77NCy9F.js";import{t as ee}from"./refresh-cw-BMLOGb5p.js";import{W as C,ht as te}from"./index-tZx-TDX4.js";import{t as ne}from"./BackBar-DmScFXW_.js";import{n as w}from"./AvatarPicker-DUnXfRVQ.js";var T=r(a(),1),E=s(),D=[`idle`,`working`,`waiting`,`happy`,`error`],O={idle:`Idle`,working:`Working`,waiting:`Waiting for you`,happy:`Done`,error:`Something went wrong`},re=4,k=`a round, custard-yellow baby dragon with small orange horns and folded little wings`;function A(){let{state:r,setTab:a,toast:s,draft:u,refreshSettings:d}=l(),m=t(),h=r.profile,O=h?.name??`nanoMuse`,[A,oe]=(0,T.useState)(null),[M,se]=(0,T.useState)(``),[N,ce]=(0,T.useState)(`muse`),[P,F]=(0,T.useState)(null),[I,L]=(0,T.useState)(null),[R,z]=(0,T.useState)(!1),[B,V]=(0,T.useState)(``),H=r.studio??A?.current??null,U=H?.stage??``,W=U===`drawing`,G=H?.candidates??[],K=(U===`drawing`||U===`choose`)&&G.length>0,le=()=>g.avatarView().then(oe,e=>s(e.message));(0,T.useEffect)(()=>{le()},[h?.avatar,r.settings?.llm.model,r.connectionsVersion]),(0,T.useEffect)(()=>{U!==`choose`&&F(null)},[U]);let q=async(e,t)=>{L(e),V(``);try{await t()}catch(e){V(e.message)}finally{L(null)}},ue=()=>q(`draw`,async()=>{let e=M.trim()||k,t=await g.avatarBegin(e,``,N);if(t.available===!1)throw Error(y(m,`image`,_(r.hub?.account),n()));t.cost?.cloud===!1&&t.session&&await g.avatarStart(t.session)}),de=()=>q(`reset`,async()=>{await g.updateSettings({profile:{avatar:o}}),await d(),s(m(`Back to the built-in look.`))}),J=A?.face??null,fe=!!h?.avatar&&!c(h.avatar),Y=H&&(U===`posing`||U===`animating`||U===`done`)&&H.face===h?.avatar,pe=Y?Object.keys(H.moods??{}).length:0,me=Y?Object.keys(H.clips??{}).length:0,X=Y?(H.errors??[]).filter(e=>!/clip/.test(e)).length:0,Z=H?.cost??{},Q=Z.clips?m(`{n} pictures and {c} clips`,{n:Z.pictures??8,c:Z.clips}):m(`{n} pictures`,{n:Z.pictures??8}),he=(()=>{if(Z.error)return m(`The cost could not be checked: {error}`,{error:Z.error});if(typeof Z.cny!=`number`)return m(`Checking the cost…`);if(Z.unlimited)return m(`About ¥{cny} for {what}; your account has no limit.`,{cny:Z.cny.toFixed(2),what:Q});let e=typeof Z.left_cny==`number`?Z.left_cny.toFixed(2):`?`;return Z.affordable===!1?m(`About ¥{cny} for {what}, more than the ¥{left} left in your allowance.`,{cny:Z.cny.toFixed(2),what:Q,left:e}):m(`About ¥{cny} for {what}; ¥{left} left in your allowance.`,{cny:Z.cny.toFixed(2),what:Q,left:e})})(),$=e=>w.find(t=>t.id===e)?.label,ge=A?.cloud?`nanoMuse Cloud`:ie(A?.host??``,m);return(0,E.jsxs)(`div`,{className:`flex h-full flex-col`,children:[(0,E.jsx)(ne,{title:m(`Avatar studio`),description:m(`Draw a look with your image model; it moves with what it is doing.`),actions:(0,E.jsxs)(`div`,{className:`relative`,children:[(0,E.jsx)(p,{small:!0,onClick:()=>z(e=>!e),label:m(`More`),expanded:R,children:(0,E.jsx)(te,{size:20})}),R&&(0,E.jsxs)(`div`,{className:`absolute right-0 z-20 mt-1 w-56 overflow-hidden rounded-2xl border border-border/70 bg-surface py-1 text-[14px] shadow-lg`,children:[(0,E.jsx)(j,{label:m(`Name & style`),onClick:()=>{z(!1),a(`you`)}}),(0,E.jsx)(j,{label:m(`Image model`),onClick:()=>{z(!1),a(`connections`)}}),fe&&(0,E.jsxs)(E.Fragment,{children:[(0,E.jsx)(j,{label:m(`Redraw the poses`),onClick:()=>{z(!1),q(`moods`,()=>g.avatarMoods())}}),(0,E.jsx)(j,{label:m(`Back to the built-in look`),danger:!0,onClick:()=>{z(!1),de()}})]})]})]})}),(0,E.jsxs)(`div`,{className:`flex-1 overflow-y-auto px-4 pb-8 space-y-5`,onClick:()=>R&&z(!1),children:[(0,E.jsxs)(`div`,{className:`flex flex-col items-center pt-2 text-center`,children:[(0,E.jsx)(ae,{avatar:h?.avatar,emoji:h?.emoji,color:h?.color,name:O}),J&&(0,E.jsx)(`div`,{className:`mt-0.5 max-w-sm text-[12.5px] text-muted`,children:[J.description,$(J.style)&&m($(J.style))].filter(Boolean).join(` · `)}),Y&&(0,E.jsxs)(`div`,{className:`mt-2.5 flex items-center gap-2 text-[13px] text-muted`,children:[U===`posing`&&(0,E.jsxs)(E.Fragment,{children:[(0,E.jsx)(f,{size:14,className:`animate-spin text-accent`}),(0,E.jsx)(`span`,{children:m(`Drawing the poses… {done}/{total}`,{done:pe,total:D.length})})]}),U===`animating`&&(0,E.jsxs)(E.Fragment,{children:[(0,E.jsx)(f,{size:14,className:`animate-spin text-accent`}),(0,E.jsx)(`span`,{children:m(`The new look is on; making the clips… {done}/{total}`,{done:me,total:re})})]}),U===`done`&&(0,E.jsxs)(E.Fragment,{children:[(0,E.jsx)(`span`,{children:X===0?m(`All five poses are in.`):m(`{done} of {total} poses are in; the rest show the main picture.`,{done:D.length-X,total:D.length})}),X>0&&(0,E.jsx)(`button`,{type:`button`,onClick:()=>void q(`moods`,()=>g.avatarMoods()),className:`font-medium text-accent`,children:m(`Retry`)})]})]})]}),U===`done`&&X===0&&(0,E.jsx)(v,{moment:`new_look`}),(0,E.jsxs)(`section`,{className:`rounded-3xl border border-border/70 bg-surface p-4 shadow-sm space-y-3`,children:[(0,E.jsxs)(`div`,{children:[(0,E.jsx)(`h2`,{className:`text-[17px] font-semibold`,children:m(`Describe a new look`)}),(0,E.jsx)(`p`,{className:`mt-0.5 text-[13px] leading-snug text-muted`,children:m(`One sentence is enough: what it is, what it wears, its air. Pick a style and your image model draws four to choose from.`)})]}),(0,E.jsx)(`textarea`,{value:M,onChange:e=>se(e.target.value),rows:2,maxLength:200,placeholder:m(k),className:`w-full resize-none rounded-2xl bg-surface-2 px-3.5 py-2.5 text-[14.5px] outline-none focus:ring-2 focus:ring-accent/40`}),(0,E.jsx)(`div`,{className:`flex flex-wrap gap-1.5`,children:w.map(t=>(0,E.jsx)(`button`,{type:`button`,onClick:()=>ce(t.id),className:e(`rounded-full px-3 py-1.5 text-[13px] font-medium transition`,N===t.id?`bg-fg text-bg`:`bg-surface-2 text-fg hover:bg-border/60`),children:m(t.label)},t.id))}),(0,E.jsxs)(`button`,{type:`button`,disabled:I!==null||W||A?.available===!1,onClick:()=>void ue(),className:e(x,`w-full rounded-full py-3`),children:[W||I===`draw`?(0,E.jsx)(f,{size:16,className:`animate-spin`}):(0,E.jsx)(C,{size:16}),m(W?`Drawing…`:K||U===`choose`?`Draw four more`:`Draw four`)]}),(0,E.jsxs)(`button`,{type:`button`,onClick:()=>a(`connections`),className:`flex w-full items-center justify-between gap-3 py-1 text-left text-[12.5px] text-muted`,children:[(0,E.jsx)(`span`,{className:`min-w-0 flex-1`,children:A===null?`…`:A.available?m(`Drawn by {provider} · {model}`,{provider:ge,model:A.image_model||m(`default model`)}):y(m,`image`,_(r.hub?.account),n())}),(0,E.jsx)(`span`,{className:`shrink-0 font-medium text-accent`,children:m(`Change model`)})]}),B&&(0,E.jsx)(`p`,{className:`text-[13px] text-rose-600 dark:text-rose-300`,children:B})]}),U===`estimate`&&H&&(0,E.jsxs)(`section`,{className:`rounded-3xl border border-accent/50 bg-surface p-4 shadow-sm space-y-3`,children:[(0,E.jsxs)(`div`,{children:[(0,E.jsx)(`h2`,{className:`text-[15px] font-semibold`,children:m(`A new look for {name}`,{name:O})}),(0,E.jsx)(`p`,{className:`mt-0.5 text-[13px] text-muted`,children:H.description})]}),(0,E.jsx)(`p`,{className:`text-[12.5px] text-muted`,children:he}),(0,E.jsxs)(`div`,{className:`flex gap-2`,children:[(0,E.jsxs)(`button`,{type:`button`,disabled:I!==null||typeof Z.cny!=`number`&&!Z.error,onClick:()=>void q(`start`,()=>g.avatarStart(H.session)),className:e(`flex items-center justify-center gap-1.5 rounded-2xl bg-accent text-accent-fg px-4 py-2.5 text-[14px] font-medium disabled:opacity-40`,`rounded-full`),children:[I===`start`?(0,E.jsx)(f,{size:14,className:`animate-spin`}):(0,E.jsx)(C,{size:14}),` `,m(`Draw`)]}),(0,E.jsxs)(`button`,{type:`button`,disabled:I!==null,onClick:()=>void q(`cancel`,()=>g.avatarCancel(H.session)),className:e(`flex items-center justify-center gap-1.5 rounded-2xl border border-border px-4 py-2.5 text-[14px] font-medium text-muted disabled:opacity-40`,`rounded-full`),children:[(0,E.jsx)(S,{size:14}),` `,m(`Not now`)]})]})]}),K&&H&&(0,E.jsxs)(`section`,{className:`space-y-3 px-1`,children:[(0,E.jsxs)(`div`,{children:[(0,E.jsx)(`h2`,{className:`text-[17px] font-semibold`,children:m(`Pick one`)}),(0,E.jsx)(`p`,{className:`mt-0.5 text-[13px] leading-snug text-muted`,children:m(`Draw four more any time; the old ones stay until you do.`)})]}),(0,E.jsx)(`div`,{className:`grid grid-cols-2 gap-3 wide:grid-cols-4`,children:G.map((t,n)=>(0,E.jsxs)(`button`,{type:`button`,disabled:!t||U!==`choose`,onClick:()=>F(e=>e===n?null:n),"aria-label":m(`Candidate {n}`,{n:n+1}),"aria-pressed":P===n,className:e(`relative aspect-square overflow-hidden rounded-[20px] bg-[#f1efeb] transition`,P===n?`ring-[3px] ring-accent`:t&&U===`choose`?`hover:ring-2 hover:ring-accent/60`:``),children:[t?(0,E.jsx)(`img`,{src:i(t),alt:``,draggable:!1,className:`h-full w-full object-cover`}):(0,E.jsx)(`span`,{className:`absolute inset-0 flex items-center justify-center text-muted`,children:W?(0,E.jsx)(f,{size:22,className:`animate-spin`}):(0,E.jsx)(S,{size:18,className:`opacity-50`})}),P===n&&(0,E.jsx)(`span`,{className:`absolute right-2 top-2 flex h-7 w-7 items-center justify-center rounded-full bg-accent text-accent-fg shadow`,children:(0,E.jsx)(b,{size:16})})]},n))}),H.errors&&H.errors.length>0&&U===`choose`&&(0,E.jsx)(`p`,{className:`text-[12.5px] text-rose-600 dark:text-rose-300`,children:m(H.errors[0])}),P!==null&&U===`choose`&&(0,E.jsxs)(`div`,{className:`space-y-1.5 pt-1`,children:[(0,E.jsxs)(`button`,{type:`button`,disabled:I!==null,onClick:()=>void q(`choose`,()=>g.avatarChoose(H.session,P)),className:e(`flex items-center justify-center gap-1.5 rounded-2xl bg-accent text-accent-fg px-4 py-2.5 text-[14px] font-medium disabled:opacity-40`,`w-full rounded-full py-3`),children:[I===`choose`?(0,E.jsx)(f,{size:16,className:`animate-spin`}):(0,E.jsx)(b,{size:16}),` `,m(`Use this one`)]}),(0,E.jsx)(`p`,{className:`text-center text-[12px] leading-snug text-muted`,children:m(`Next, its poses are drawn from it in the background: working, waiting for you, done, something wrong.`)})]}),U===`choose`&&(0,E.jsx)(`button`,{type:`button`,disabled:I!==null,onClick:()=>void q(`cancel`,()=>g.avatarCancel(H.session)),className:`w-full py-1 text-center text-[13px] text-muted`,children:m(`Keep the current look`)})]}),U===`failed`&&H&&(0,E.jsxs)(`section`,{className:`rounded-3xl border border-border/70 bg-surface p-4 shadow-sm space-y-2`,children:[(0,E.jsx)(`h2`,{className:`text-[15px] font-semibold`,children:m(`That did not work`)}),(0,E.jsx)(`p`,{className:`text-[13px] text-muted`,children:m(H.message||`Nothing came back.`)}),(0,E.jsxs)(`button`,{type:`button`,disabled:I!==null,onClick:()=>void q(`retry`,()=>g.avatarStart(H.session)),className:e(`flex items-center justify-center gap-1.5 rounded-2xl border border-border px-4 py-2.5 text-[14px] font-medium text-muted disabled:opacity-40`,`rounded-full`),children:[(0,E.jsx)(ee,{size:14}),` `,m(`Try again`)]})]}),(0,E.jsx)(`p`,{className:`px-1 text-[12px] leading-snug text-muted`,children:m(`The pictures stay in this computer's workspace under avatar/. Each new look asks your provider for eight pictures (four to choose from and four poses) and four short clips where there is a video model.`)}),(0,E.jsx)(`p`,{className:`px-1 text-[12px] leading-snug text-muted`,children:(0,E.jsx)(`button`,{type:`button`,onClick:()=>{u(m(`Change your avatar to `)),a(`chat`)},className:`font-medium text-accent`,children:m(`Or just say it in the chat: “change your avatar to a corgi”.`)})})]})]})}function ie(e,t){return e?/dashscope|aliyuncs/.test(e)?t(`Alibaba Cloud Bailian`):/openai\.com/.test(e)?`OpenAI`:/deepseek/.test(e)?`DeepSeek`:/moonshot/.test(e)?`Moonshot`:/bigmodel|zhipu/.test(e)?t(`Zhipu`):/siliconflow/.test(e)?`SiliconFlow`:/volces|ark/.test(e)?t(`Volcano Ark`):/openrouter/.test(e)?`OpenRouter`:/googleapis/.test(e)?`Gemini`:/x\.ai/.test(e)?`xAI`:/^(127\.0\.0\.1|localhost)/.test(e)?t(`this computer`):e:t(`your provider`)}function j({label:t,onClick:n,danger:r=!1}){return(0,E.jsx)(`button`,{type:`button`,onClick:n,className:e(`block w-full px-4 py-2.5 text-left hover:bg-surface-2`,r?`text-rose-600 dark:text-rose-300`:``),children:t})}function ae({avatar:e,emoji:n,color:r,name:i}){let a=t(),[o,s]=(0,T.useState)(0),l=D[o%D.length],f=(0,T.useRef)(0);(0,T.useEffect)(()=>(f.current=window.setTimeout(()=>s(e=>(e+1)%D.length),l===`idle`?2600:2e3),()=>window.clearTimeout(f.current)),[o,l]);let p=c(e),g=!p&&e?e:null,_=p?m(l):g?h(g,l):``,v=p?d(l):g?u(g,l):null,[y,b]=(0,T.useState)(()=>new Set),x=v&&!y.has(v)?v:null;return(0,E.jsxs)(E.Fragment,{children:[(0,E.jsx)(`div`,{className:`avatar-pop h-[148px] w-[148px] overflow-hidden rounded-full`,style:_?{background:`#f1efeb`}:{background:`linear-gradient(135deg, ${r??`#0064d4`}, color-mix(in srgb, ${r??`#0064d4`} 60%, #ffffff))`},children:x?(0,E.jsx)(`video`,{src:x,poster:_,autoPlay:!0,loop:!0,muted:!0,playsInline:!0,disablePictureInPicture:!0,onError:()=>b(e=>new Set(e).add(x)),className:`h-full w-full object-cover`},x):_?(0,E.jsx)(`img`,{src:_,alt:``,draggable:!1,className:`h-full w-full object-cover`}):(0,E.jsx)(`span`,{className:`flex h-full w-full items-center justify-center text-[64px] leading-none`,children:n??`✨`})},e),(0,E.jsx)(`div`,{className:`mt-3 text-[20px] font-semibold tracking-tight`,children:i}),(0,E.jsx)(`div`,{className:`mt-1 text-[13px] text-muted`,children:a(O[l])})]})}export{A as AvatarStudioScreen}; \ No newline at end of file +import{E as e,K as t,L as n,Q as r,S as i,Y as a,a as o,b as s,c,f as l,l as u,o as d,q as f,r as p,s as m,u as h,x as g}from"./MuseHeader-RC--uR8o.js";import{C as _,S as v,t as y}from"./StarNudge-Df6LQyo9.js";import{n as b}from"./external-link-TvxP_dKX.js";import{i as x,o as S}from"./Form-H3s9oTHq.js";import{t as ee}from"./refresh-cw-CxZ3ZdI3.js";import{U as C,mt as te}from"./index-tYqPtwPX.js";import{t as ne}from"./BackBar-JEuC8Q_e.js";import{n as w}from"./AvatarPicker-BCihUURa.js";var T=r(a(),1),E=s(),D=[`idle`,`working`,`waiting`,`happy`,`error`],O={idle:`Idle`,working:`Working`,waiting:`Waiting for you`,happy:`Done`,error:`Something went wrong`},re=4,k=`a round, custard-yellow baby dragon with small orange horns and folded little wings`;function A(){let{state:r,setTab:a,toast:s,draft:u,refreshSettings:d}=l(),m=t(),h=r.profile,O=h?.name??`nanoMuse`,[A,oe]=(0,T.useState)(null),[M,se]=(0,T.useState)(``),[N,ce]=(0,T.useState)(`muse`),[P,F]=(0,T.useState)(null),[I,L]=(0,T.useState)(null),[R,z]=(0,T.useState)(!1),[B,V]=(0,T.useState)(``),H=r.studio??A?.current??null,U=H?.stage??``,W=U===`drawing`,G=H?.candidates??[],K=(U===`drawing`||U===`choose`)&&G.length>0,le=()=>g.avatarView().then(oe,e=>s(e.message));(0,T.useEffect)(()=>{le()},[h?.avatar,r.settings?.llm.model,r.connectionsVersion]),(0,T.useEffect)(()=>{U!==`choose`&&F(null)},[U]);let q=async(e,t)=>{L(e),V(``);try{await t()}catch(e){V(e.message)}finally{L(null)}},ue=()=>q(`draw`,async()=>{let e=M.trim()||k,t=await g.avatarBegin(e,``,N);if(t.available===!1)throw Error(_(m,`image`,v(r.hub?.account),n()));t.cost?.cloud===!1&&t.session&&await g.avatarStart(t.session)}),de=()=>q(`reset`,async()=>{await g.updateSettings({profile:{avatar:o}}),await d(),s(m(`Back to the built-in look.`))}),J=A?.face??null,fe=!!h?.avatar&&!c(h.avatar),Y=H&&(U===`posing`||U===`animating`||U===`done`)&&H.face===h?.avatar,pe=Y?Object.keys(H.moods??{}).length:0,me=Y?Object.keys(H.clips??{}).length:0,X=Y?(H.errors??[]).filter(e=>!/clip/.test(e)).length:0,Z=H?.cost??{},Q=Z.clips?m(`{n} pictures and {c} clips`,{n:Z.pictures??8,c:Z.clips}):m(`{n} pictures`,{n:Z.pictures??8}),he=(()=>{if(Z.error)return m(`The cost could not be checked: {error}`,{error:Z.error});if(typeof Z.cny!=`number`)return m(`Checking the cost…`);if(Z.unlimited)return m(`About ¥{cny} for {what}; your account has no limit.`,{cny:Z.cny.toFixed(2),what:Q});let e=typeof Z.left_cny==`number`?Z.left_cny.toFixed(2):`?`;return Z.affordable===!1?m(`About ¥{cny} for {what}, more than the ¥{left} left in your allowance.`,{cny:Z.cny.toFixed(2),what:Q,left:e}):m(`About ¥{cny} for {what}; ¥{left} left in your allowance.`,{cny:Z.cny.toFixed(2),what:Q,left:e})})(),$=e=>w.find(t=>t.id===e)?.label,ge=A?.cloud?`nanoMuse Cloud`:ie(A?.host??``,m);return(0,E.jsxs)(`div`,{className:`flex h-full flex-col`,children:[(0,E.jsx)(ne,{title:m(`Avatar studio`),description:m(`Draw a look with your image model; it moves with what it is doing.`),actions:(0,E.jsxs)(`div`,{className:`relative`,children:[(0,E.jsx)(p,{small:!0,onClick:()=>z(e=>!e),label:m(`More`),expanded:R,children:(0,E.jsx)(te,{size:20})}),R&&(0,E.jsxs)(`div`,{className:`absolute right-0 z-20 mt-1 w-56 overflow-hidden rounded-2xl border border-border/70 bg-surface py-1 text-[14px] shadow-lg`,children:[(0,E.jsx)(j,{label:m(`Name & style`),onClick:()=>{z(!1),a(`you`)}}),(0,E.jsx)(j,{label:m(`Image model`),onClick:()=>{z(!1),a(`connections`)}}),fe&&(0,E.jsxs)(E.Fragment,{children:[(0,E.jsx)(j,{label:m(`Redraw the poses`),onClick:()=>{z(!1),q(`moods`,()=>g.avatarMoods())}}),(0,E.jsx)(j,{label:m(`Back to the built-in look`),danger:!0,onClick:()=>{z(!1),de()}})]})]})]})}),(0,E.jsxs)(`div`,{className:`flex-1 overflow-y-auto px-4 pb-8 space-y-5`,onClick:()=>R&&z(!1),children:[(0,E.jsxs)(`div`,{className:`flex flex-col items-center pt-2 text-center`,children:[(0,E.jsx)(ae,{avatar:h?.avatar,emoji:h?.emoji,color:h?.color,name:O}),J&&(0,E.jsx)(`div`,{className:`mt-0.5 max-w-sm text-[12.5px] text-muted`,children:[J.description,$(J.style)&&m($(J.style))].filter(Boolean).join(` · `)}),Y&&(0,E.jsxs)(`div`,{className:`mt-2.5 flex items-center gap-2 text-[13px] text-muted`,children:[U===`posing`&&(0,E.jsxs)(E.Fragment,{children:[(0,E.jsx)(f,{size:14,className:`animate-spin text-accent`}),(0,E.jsx)(`span`,{children:m(`Drawing the poses… {done}/{total}`,{done:pe,total:D.length})})]}),U===`animating`&&(0,E.jsxs)(E.Fragment,{children:[(0,E.jsx)(f,{size:14,className:`animate-spin text-accent`}),(0,E.jsx)(`span`,{children:m(`The new look is on; making the clips… {done}/{total}`,{done:me,total:re})})]}),U===`done`&&(0,E.jsxs)(E.Fragment,{children:[(0,E.jsx)(`span`,{children:X===0?m(`All five poses are in.`):m(`{done} of {total} poses are in; the rest show the main picture.`,{done:D.length-X,total:D.length})}),X>0&&(0,E.jsx)(`button`,{type:`button`,onClick:()=>void q(`moods`,()=>g.avatarMoods()),className:`font-medium text-accent`,children:m(`Retry`)})]})]})]}),U===`done`&&X===0&&(0,E.jsx)(y,{moment:`new_look`}),(0,E.jsxs)(`section`,{className:`rounded-3xl border border-border/70 bg-surface p-4 shadow-sm space-y-3`,children:[(0,E.jsxs)(`div`,{children:[(0,E.jsx)(`h2`,{className:`text-[17px] font-semibold`,children:m(`Describe a new look`)}),(0,E.jsx)(`p`,{className:`mt-0.5 text-[13px] leading-snug text-muted`,children:m(`One sentence is enough: what it is, what it wears, its air. Pick a style and your image model draws four to choose from.`)})]}),(0,E.jsx)(`textarea`,{value:M,onChange:e=>se(e.target.value),rows:2,maxLength:200,placeholder:m(k),className:`w-full resize-none rounded-2xl bg-surface-2 px-3.5 py-2.5 text-[14.5px] outline-none focus:ring-2 focus:ring-accent/40`}),(0,E.jsx)(`div`,{className:`flex flex-wrap gap-1.5`,children:w.map(t=>(0,E.jsx)(`button`,{type:`button`,onClick:()=>ce(t.id),className:e(`rounded-full px-3 py-1.5 text-[13px] font-medium transition`,N===t.id?`bg-fg text-bg`:`bg-surface-2 text-fg hover:bg-border/60`),children:m(t.label)},t.id))}),(0,E.jsxs)(`button`,{type:`button`,disabled:I!==null||W||A?.available===!1,onClick:()=>void ue(),className:e(x,`w-full rounded-full py-3`),children:[W||I===`draw`?(0,E.jsx)(f,{size:16,className:`animate-spin`}):(0,E.jsx)(C,{size:16}),m(W?`Drawing…`:K||U===`choose`?`Draw four more`:`Draw four`)]}),(0,E.jsxs)(`button`,{type:`button`,onClick:()=>a(`connections`),className:`flex w-full items-center justify-between gap-3 py-1 text-left text-[12.5px] text-muted`,children:[(0,E.jsx)(`span`,{className:`min-w-0 flex-1`,children:A===null?`…`:A.available?m(`Drawn by {provider} · {model}`,{provider:ge,model:A.image_model||m(`default model`)}):_(m,`image`,v(r.hub?.account),n())}),(0,E.jsx)(`span`,{className:`shrink-0 font-medium text-accent`,children:m(`Change model`)})]}),B&&(0,E.jsx)(`p`,{className:`text-[13px] text-rose-600 dark:text-rose-300`,children:B})]}),U===`estimate`&&H&&(0,E.jsxs)(`section`,{className:`rounded-3xl border border-accent/50 bg-surface p-4 shadow-sm space-y-3`,children:[(0,E.jsxs)(`div`,{children:[(0,E.jsx)(`h2`,{className:`text-[15px] font-semibold`,children:m(`A new look for {name}`,{name:O})}),(0,E.jsx)(`p`,{className:`mt-0.5 text-[13px] text-muted`,children:H.description})]}),(0,E.jsx)(`p`,{className:`text-[12.5px] text-muted`,children:he}),(0,E.jsxs)(`div`,{className:`flex gap-2`,children:[(0,E.jsxs)(`button`,{type:`button`,disabled:I!==null||typeof Z.cny!=`number`&&!Z.error,onClick:()=>void q(`start`,()=>g.avatarStart(H.session)),className:e(`flex items-center justify-center gap-1.5 rounded-2xl bg-accent text-accent-fg px-4 py-2.5 text-[14px] font-medium disabled:opacity-40`,`rounded-full`),children:[I===`start`?(0,E.jsx)(f,{size:14,className:`animate-spin`}):(0,E.jsx)(C,{size:14}),` `,m(`Draw`)]}),(0,E.jsxs)(`button`,{type:`button`,disabled:I!==null,onClick:()=>void q(`cancel`,()=>g.avatarCancel(H.session)),className:e(`flex items-center justify-center gap-1.5 rounded-2xl border border-border px-4 py-2.5 text-[14px] font-medium text-muted disabled:opacity-40`,`rounded-full`),children:[(0,E.jsx)(S,{size:14}),` `,m(`Not now`)]})]})]}),K&&H&&(0,E.jsxs)(`section`,{className:`space-y-3 px-1`,children:[(0,E.jsxs)(`div`,{children:[(0,E.jsx)(`h2`,{className:`text-[17px] font-semibold`,children:m(`Pick one`)}),(0,E.jsx)(`p`,{className:`mt-0.5 text-[13px] leading-snug text-muted`,children:m(`Draw four more any time; the old ones stay until you do.`)})]}),(0,E.jsx)(`div`,{className:`grid grid-cols-2 gap-3 wide:grid-cols-4`,children:G.map((t,n)=>(0,E.jsxs)(`button`,{type:`button`,disabled:!t||U!==`choose`,onClick:()=>F(e=>e===n?null:n),"aria-label":m(`Candidate {n}`,{n:n+1}),"aria-pressed":P===n,className:e(`relative aspect-square overflow-hidden rounded-[20px] bg-[#f1efeb] transition`,P===n?`ring-[3px] ring-accent`:t&&U===`choose`?`hover:ring-2 hover:ring-accent/60`:``),children:[t?(0,E.jsx)(`img`,{src:i(t),alt:``,draggable:!1,className:`h-full w-full object-cover`}):(0,E.jsx)(`span`,{className:`absolute inset-0 flex items-center justify-center text-muted`,children:W?(0,E.jsx)(f,{size:22,className:`animate-spin`}):(0,E.jsx)(S,{size:18,className:`opacity-50`})}),P===n&&(0,E.jsx)(`span`,{className:`absolute right-2 top-2 flex h-7 w-7 items-center justify-center rounded-full bg-accent text-accent-fg shadow`,children:(0,E.jsx)(b,{size:16})})]},n))}),H.errors&&H.errors.length>0&&U===`choose`&&(0,E.jsx)(`p`,{className:`text-[12.5px] text-rose-600 dark:text-rose-300`,children:m(H.errors[0])}),P!==null&&U===`choose`&&(0,E.jsxs)(`div`,{className:`space-y-1.5 pt-1`,children:[(0,E.jsxs)(`button`,{type:`button`,disabled:I!==null,onClick:()=>void q(`choose`,()=>g.avatarChoose(H.session,P)),className:e(`flex items-center justify-center gap-1.5 rounded-2xl bg-accent text-accent-fg px-4 py-2.5 text-[14px] font-medium disabled:opacity-40`,`w-full rounded-full py-3`),children:[I===`choose`?(0,E.jsx)(f,{size:16,className:`animate-spin`}):(0,E.jsx)(b,{size:16}),` `,m(`Use this one`)]}),(0,E.jsx)(`p`,{className:`text-center text-[12px] leading-snug text-muted`,children:m(`Next, its poses are drawn from it in the background: working, waiting for you, done, something wrong.`)})]}),U===`choose`&&(0,E.jsx)(`button`,{type:`button`,disabled:I!==null,onClick:()=>void q(`cancel`,()=>g.avatarCancel(H.session)),className:`w-full py-1 text-center text-[13px] text-muted`,children:m(`Keep the current look`)})]}),U===`failed`&&H&&(0,E.jsxs)(`section`,{className:`rounded-3xl border border-border/70 bg-surface p-4 shadow-sm space-y-2`,children:[(0,E.jsx)(`h2`,{className:`text-[15px] font-semibold`,children:m(`That did not work`)}),(0,E.jsx)(`p`,{className:`text-[13px] text-muted`,children:m(H.message||`Nothing came back.`)}),(0,E.jsxs)(`button`,{type:`button`,disabled:I!==null,onClick:()=>void q(`retry`,()=>g.avatarStart(H.session)),className:e(`flex items-center justify-center gap-1.5 rounded-2xl border border-border px-4 py-2.5 text-[14px] font-medium text-muted disabled:opacity-40`,`rounded-full`),children:[(0,E.jsx)(ee,{size:14}),` `,m(`Try again`)]})]}),(0,E.jsx)(`p`,{className:`px-1 text-[12px] leading-snug text-muted`,children:m(`The pictures stay in this computer's workspace under avatar/. Each new look asks your provider for eight pictures (four to choose from and four poses) and four short clips where there is a video model.`)}),(0,E.jsx)(`p`,{className:`px-1 text-[12px] leading-snug text-muted`,children:(0,E.jsx)(`button`,{type:`button`,onClick:()=>{u(m(`Change your avatar to `)),a(`chat`)},className:`font-medium text-accent`,children:m(`Or just say it in the chat: “change your avatar to a corgi”.`)})})]})]})}function ie(e,t){return e?/dashscope|aliyuncs/.test(e)?t(`Alibaba Cloud Bailian`):/openai\.com/.test(e)?`OpenAI`:/deepseek/.test(e)?`DeepSeek`:/moonshot/.test(e)?`Moonshot`:/bigmodel|zhipu/.test(e)?t(`Zhipu`):/siliconflow/.test(e)?`SiliconFlow`:/volces|ark/.test(e)?t(`Volcano Ark`):/openrouter/.test(e)?`OpenRouter`:/googleapis/.test(e)?`Gemini`:/x\.ai/.test(e)?`xAI`:/^(127\.0\.0\.1|localhost)/.test(e)?t(`this computer`):e:t(`your provider`)}function j({label:t,onClick:n,danger:r=!1}){return(0,E.jsx)(`button`,{type:`button`,onClick:n,className:e(`block w-full px-4 py-2.5 text-left hover:bg-surface-2`,r?`text-rose-600 dark:text-rose-300`:``),children:t})}function ae({avatar:e,emoji:n,color:r,name:i}){let a=t(),[o,s]=(0,T.useState)(0),l=D[o%D.length],f=(0,T.useRef)(0);(0,T.useEffect)(()=>(f.current=window.setTimeout(()=>s(e=>(e+1)%D.length),l===`idle`?2600:2e3),()=>window.clearTimeout(f.current)),[o,l]);let p=c(e),g=!p&&e?e:null,_=p?m(l):g?h(g,l):``,v=p?d(l):g?u(g,l):null,[y,b]=(0,T.useState)(()=>new Set),x=v&&!y.has(v)?v:null;return(0,E.jsxs)(E.Fragment,{children:[(0,E.jsx)(`div`,{className:`avatar-pop h-[148px] w-[148px] overflow-hidden rounded-full`,style:_?{background:`#f1efeb`}:{background:`linear-gradient(135deg, ${r??`#0064d4`}, color-mix(in srgb, ${r??`#0064d4`} 60%, #ffffff))`},children:x?(0,E.jsx)(`video`,{src:x,poster:_,autoPlay:!0,loop:!0,muted:!0,playsInline:!0,disablePictureInPicture:!0,onError:()=>b(e=>new Set(e).add(x)),className:`h-full w-full object-cover`},x):_?(0,E.jsx)(`img`,{src:_,alt:``,draggable:!1,className:`h-full w-full object-cover`}):(0,E.jsx)(`span`,{className:`flex h-full w-full items-center justify-center text-[64px] leading-none`,children:n??`✨`})},e),(0,E.jsx)(`div`,{className:`mt-3 text-[20px] font-semibold tracking-tight`,children:i}),(0,E.jsx)(`div`,{className:`mt-1 text-[13px] text-muted`,children:a(O[l])})]})}export{A as AvatarStudioScreen}; \ No newline at end of file diff --git a/nanomuse/server/static/assets/BackBar-DmScFXW_.js b/nanomuse/server/static/assets/BackBar-JEuC8Q_e.js similarity index 85% rename from nanomuse/server/static/assets/BackBar-DmScFXW_.js rename to nanomuse/server/static/assets/BackBar-JEuC8Q_e.js index 753f3cbe3..5175646fa 100644 --- a/nanomuse/server/static/assets/BackBar-DmScFXW_.js +++ b/nanomuse/server/static/assets/BackBar-JEuC8Q_e.js @@ -1 +1 @@ -import{K as e,b as t,f as n,r}from"./MuseHeader-BvAlmxiL.js";import{Dt as i}from"./index-tZx-TDX4.js";var a=t();function o({title:t,description:o,actions:s,onBack:c,backLabel:l}){let{setTab:u}=n(),d=e();return(0,a.jsxs)(`header`,{className:`safe-top shrink-0`,children:[(0,a.jsxs)(`div`,{className:`relative flex h-14 items-center justify-center px-3`,children:[(0,a.jsx)(`div`,{className:`absolute left-3 top-1/2 -translate-y-1/2`,children:(0,a.jsx)(r,{small:!0,onClick:c??(()=>u(`chat`)),label:l??d(`Back`),children:(0,a.jsx)(i,{size:20})})}),(0,a.jsx)(`h1`,{className:`max-w-[calc(100%-128px)] truncate text-[17px] font-semibold leading-[22px]`,children:t}),s&&(0,a.jsx)(`div`,{className:`absolute right-3 top-1/2 flex -translate-y-1/2 items-center gap-2`,children:s})]}),o&&(0,a.jsx)(`p`,{className:`px-5 pb-2 text-[13px] leading-[18px] text-muted`,children:o})]})}export{o as t}; \ No newline at end of file +import{K as e,b as t,f as n,r}from"./MuseHeader-RC--uR8o.js";import{Et as i}from"./index-tYqPtwPX.js";var a=t();function o({title:t,description:o,actions:s,onBack:c,backLabel:l}){let{setTab:u}=n(),d=e();return(0,a.jsxs)(`header`,{className:`safe-top shrink-0`,children:[(0,a.jsxs)(`div`,{className:`relative flex h-14 items-center justify-center px-3`,children:[(0,a.jsx)(`div`,{className:`absolute left-3 top-1/2 -translate-y-1/2`,children:(0,a.jsx)(r,{small:!0,onClick:c??(()=>u(`chat`)),label:l??d(`Back`),children:(0,a.jsx)(i,{size:20})})}),(0,a.jsx)(`h1`,{className:`max-w-[calc(100%-128px)] truncate text-[17px] font-semibold leading-[22px]`,children:t}),s&&(0,a.jsx)(`div`,{className:`absolute right-3 top-1/2 flex -translate-y-1/2 items-center gap-2`,children:s})]}),o&&(0,a.jsx)(`p`,{className:`px-5 pb-2 text-[13px] leading-[18px] text-muted`,children:o})]})}export{o as t}; \ No newline at end of file diff --git a/nanomuse/server/static/assets/ChannelsScreen-DGK7O7Nz.js b/nanomuse/server/static/assets/ChannelsScreen-D_7Ynsew.js similarity index 90% rename from nanomuse/server/static/assets/ChannelsScreen-DGK7O7Nz.js rename to nanomuse/server/static/assets/ChannelsScreen-D_7Ynsew.js index da9cc4bdb..4a83a8933 100644 --- a/nanomuse/server/static/assets/ChannelsScreen-DGK7O7Nz.js +++ b/nanomuse/server/static/assets/ChannelsScreen-D_7Ynsew.js @@ -1,2 +1,2 @@ -import{E as e,J as t,K as n,Q as r,Y as i,b as a,f as o,q as s,w as c}from"./MuseHeader-BvAlmxiL.js";import{n as l,t as u}from"./external-link-V2ISE5bW.js";import{a as d,i as f,o as p,r as m}from"./Form-C77NCy9F.js";import{t as h}from"./refresh-cw-BMLOGb5p.js";import{C as g,V as _,Y as v,a as y,at as b,c as x,i as S,l as C,o as w,s as T}from"./index-tZx-TDX4.js";import{t as E}from"./BackBar-DmScFXW_.js";var D=t(`qr-code`,[[`rect`,{width:`5`,height:`5`,x:`3`,y:`3`,rx:`1`,key:`1tu5fj`}],[`rect`,{width:`5`,height:`5`,x:`16`,y:`3`,rx:`1`,key:`1v8r4q`}],[`rect`,{width:`5`,height:`5`,x:`3`,y:`16`,rx:`1`,key:`1x03jg`}],[`path`,{d:`M21 16h-3a2 2 0 0 0-2 2v3`,key:`177gqh`}],[`path`,{d:`M21 21v.01`,key:`ents32`}],[`path`,{d:`M12 7v3a2 2 0 0 1-2 2H7`,key:`8crl2c`}],[`path`,{d:`M3 12h.01`,key:`nlz23k`}],[`path`,{d:`M12 3h.01`,key:`n36tog`}],[`path`,{d:`M12 16v.01`,key:`133mhm`}],[`path`,{d:`M16 12h1`,key:`1slzba`}],[`path`,{d:`M21 12v.01`,key:`1lwtk9`}],[`path`,{d:`M12 21v-1`,key:`1880an`}]]),O=r(i(),1),k=(e,t)=>({method:e,body:JSON.stringify(t)}),A=encodeURIComponent,j={view:()=>c(`/api/channels`),update:(e,t)=>c(`/api/channels/${A(e)}`,k(`PUT`,t)),reload:()=>c(`/api/channels/reload`,{method:`POST`}),test:(e,t=``)=>c(`/api/channels/${A(e)}/test`,k(`POST`,{chat_id:t})),approve:e=>c(`/api/channels/pairing/${A(e)}/approve`,{method:`POST`}),deny:e=>c(`/api/channels/pairing/${A(e)}/deny`,{method:`POST`}),setDeliver:(e,t,n)=>c(`/api/channels/${A(e)}/chats/${A(t)}`,k(`PUT`,{deliver:n})),removeChat:(e,t)=>c(`/api/channels/${A(e)}/chats/${A(t)}`,{method:`DELETE`}),loginBegin:(e,t)=>c(`/api/channels/${A(e)}/login`,k(`POST`,{domain:t})),loginPoll:(e,t)=>c(`/api/channels/${A(e)}/login/${A(t)}`),deliver:e=>c(`/api/channels/deliver`,k(`POST`,{text:e}))},M=a(),N={feishu:[`In the Feishu developer console create a custom app and add the Bot capability.`,`Permissions: im:message, im:message.p2p_msg:readonly, im:message.group_at_msg:readonly, im:resource.`,`Events & callbacks: subscription mode Long connection; add im.message.receive_v1; callback mode Long connection; add card.action.trigger.`,`Copy App ID and App Secret from Credentials & Basic Info, then publish a version.`],dingtalk:[`In the DingTalk developer console create an internal app and add the Robot capability.`,`Set the message receive mode to Stream.`,`Copy Client ID (AppKey) and Client Secret (AppSecret) from Credentials & Basic Info.`,`Add the robot send-message permission and publish the version.`],wecom:[`In the WeCom admin console open Intelligent robot and create a robot in API mode with a long connection.`,`Copy the Bot ID and Secret.`,`Add the robot to the chats where it should listen.`],telegram:[`In Telegram talk to @BotFather, send /newbot and copy the token.`,`Direct messages work at once. For a group, add the bot to it; with Group Privacy on it only hears @-mentions and replies.`,`If api.telegram.org is out of reach from this computer, set a proxy below.`]},P={telegram:(0,M.jsx)(v,{size:20})};function F(e,t){let n=t.status.state;return e(n===`off`?`Off`:n===`unconfigured`?`Needs settings`:n===`missing_sdk`?`Not installed`:n===`connecting`?`Connecting…`:n===`connected`?`Connected`:`Error`)}function I({state:t}){return(0,M.jsx)(`span`,{"aria-hidden":!0,className:e(`inline-block h-2 w-2 rounded-full`,t===`connected`?`bg-emerald-500`:t===`error`?`bg-red-500`:t===`connecting`?`bg-amber-400`:`bg-border`)})}function L(){let{toast:e}=o(),t=n(),[r,i]=(0,O.useState)(null),[a,c]=(0,O.useState)(null),l=async()=>{try{i(await j.view()),c(null)}catch(e){c(e.message||`Could not load.`)}};(0,O.useEffect)(()=>{l();let e=window.setInterval(()=>void l(),5e3),t=()=>void l();return window.addEventListener(`focus`,t),()=>{window.clearInterval(e),window.removeEventListener(`focus`,t)}},[]);let u=async(t,n)=>{try{i(await t()),n&&e(n)}catch(t){e(t.message)}};return(0,M.jsxs)(`div`,{className:`flex h-full flex-col`,children:[(0,M.jsx)(E,{title:t(`Chat apps`),description:t(`Talk to your Muse from the chat apps you already use. Nothing needs a public address: each app keeps a long connection open.`)}),(0,M.jsxs)(`div`,{className:`flex-1 overflow-y-auto pb-8`,children:[r===null&&a&&(0,M.jsx)(g,{message:a,onRetry:()=>void l()}),r===null&&!a&&(0,M.jsx)(`div`,{className:`flex justify-center py-10 text-muted`,children:(0,M.jsx)(s,{className:`animate-spin`,size:20})}),r&&r.pending.length>0&&(0,M.jsxs)(M.Fragment,{children:[(0,M.jsx)(x,{children:t(`Waiting for a yes`)}),(0,M.jsx)(y,{children:r.pending.map((e,t)=>(0,M.jsxs)(`div`,{children:[t>0&&(0,M.jsx)(w,{inset:16}),(0,M.jsx)(R,{p:e,label:r.channels.find(t=>t.name===e.channel)?.label??e.channel,onApprove:()=>u(()=>j.approve(e.code)),onDeny:()=>u(()=>j.deny(e.code))})]},e.code))})]}),r?.channels.map(e=>(0,M.jsx)(z,{c:e,run:u,reload:l},e.name)),r&&(0,M.jsx)(S,{children:t(`Each chat is one conversation of your Muse; its replies stream back as they are written.`)})]})]})}function R({p:t,label:r,onApprove:i,onDeny:a}){let o=n(),s=t.sender_name||t.sender_id;return(0,M.jsxs)(`div`,{className:`flex items-center gap-3 px-4 py-3`,children:[(0,M.jsxs)(`div`,{className:`min-w-0 flex-1`,children:[(0,M.jsx)(`p`,{className:`truncate text-[15px]`,children:o(`{name} wrote to the bot. Approve to let them talk to your Muse.`,{name:`${s} · ${r}`})}),(0,M.jsx)(`p`,{className:`text-[13px] text-muted`,children:o(`Code {code}`,{code:t.code})})]}),(0,M.jsxs)(`button`,{type:`button`,className:e(f,`px-3 py-2`),onClick:i,"aria-label":o(`Approve`),children:[(0,M.jsx)(l,{size:16}),` `,o(`Approve`)]}),(0,M.jsx)(`button`,{type:`button`,className:e(d,`px-3 py-2`),onClick:a,"aria-label":o(`Deny`),children:(0,M.jsx)(p,{size:16})})]})}function z({c:t,run:r,reload:i}){let a=n(),{toast:s}=o(),[c,l]=(0,O.useState)(!1),[d,f]=(0,O.useState)({}),[p,m]=(0,O.useState)([]),[g,v]=(0,O.useState)(null),[E,k]=(0,O.useState)(!1),[A,L]=(0,O.useState)(!1),[R,z]=(0,O.useState)(!1),[V,H]=(0,O.useState)(null),[U,W]=(0,O.useState)(``),[G,K]=(0,O.useState)(!1),q=(0,O.useRef)(null),J=Object.keys(d).length>0||g!==null,Y=g??t.allow_from.join(` -`),X=async()=>{k(!0);try{let e={},n={};for(let[e,r]of Object.entries(d))(t.fields.find(t=>t.key===e)?.kind!==`secret`||r!==``||p.includes(e))&&(n[e]=r);Object.keys(n).length&&(e.settings=n),g!==null&&(e.allow_from=g.split(/[\n,]/).map(e=>e.trim()).filter(Boolean)),await r(()=>j.update(t.name,e),a(`Saved.`)),f({}),m([]),v(null)}finally{k(!1)}},Z=async()=>{L(!0);try{let e=await j.test(t.name);s(e.detail)}catch(e){s(e.message)}finally{L(!1)}},Q=()=>{q.current!==null&&window.clearTimeout(q.current),q.current=null};(0,O.useEffect)(()=>Q,[]);let $=async()=>{W(``);try{let e=await j.loginBegin(t.name,G?`lark`:`feishu`);H(e);let n=Date.now(),r=async()=>{try{let r=await j.loginPoll(t.name,e.device_code);if(r.status===`succeeded`){H(null),W(a(`The bot was created and is connecting.`)),await i();return}if(r.status===`failed`||Date.now()-n>e.expires_in*1e3){H(null),W(a(`The login did not finish ({error}).`,{error:r.error??`expired`}));return}}catch(e){H(null),W(e.message);return}q.current=window.setTimeout(()=>void r(),Math.max(2,e.interval)*1e3)};q.current=window.setTimeout(()=>void r(),Math.max(2,e.interval)*1e3)}catch(e){s(e.message)}},ee=()=>{Q(),H(null)},te=t.fields.filter(e=>e.required&&(e.kind===`secret`?!e.has_value:!e.value)).map(e=>e.label);return(0,M.jsxs)(M.Fragment,{children:[(0,M.jsx)(x,{children:t.label}),(0,M.jsxs)(y,{children:[(0,M.jsx)(T,{icon:P[t.name]??(0,M.jsx)(b,{size:20}),label:t.label,value:F(a,t),trailing:(0,M.jsx)(I,{state:t.status.state}),onClick:()=>l(e=>!e)}),(0,M.jsx)(w,{}),(0,M.jsx)(C,{label:a(`Switched on`),checked:t.enabled,disabled:!t.sdk_available&&!t.enabled,onChange:e=>void r(()=>j.update(t.name,{enabled:e}))}),t.status.state===`error`&&t.status.detail&&(0,M.jsx)(`p`,{className:`px-4 pb-3 text-[13px] leading-[18px] text-red-600 dark:text-red-400`,children:t.status.detail}),t.status.state===`unconfigured`&&(0,M.jsxs)(`p`,{className:`px-4 pb-3 text-[13px] leading-[18px] text-muted`,children:[a(`Missing`),`: `,t.status.detail||te.join(`, `)]}),!t.sdk_available&&(0,M.jsxs)(`div`,{className:`px-4 pb-3 text-[13px] leading-[18px] text-muted`,children:[a(`Install on the computer running nanoMuse, then switch it on again:`),(0,M.jsx)(`code`,{className:`mt-1 block select-all rounded-lg bg-surface-2 px-2 py-1 text-[12.5px] text-fg`,children:t.install})]}),(c||t.enabled)&&(0,M.jsxs)(M.Fragment,{children:[(0,M.jsx)(w,{inset:16}),(0,M.jsxs)(`div`,{className:`space-y-3 px-4 py-3`,children:[t.fields.map(e=>(0,M.jsx)(B,{f:e,value:d[e.key],onChange:t=>{f(n=>({...n,[e.key]:t})),t!==``&&m(t=>t.filter(t=>t!==e.key))},onClear:()=>{f(t=>({...t,[e.key]:``})),m(t=>t.includes(e.key)?t:[...t,e.key])}},e.key)),(0,M.jsxs)(`label`,{className:`block`,children:[(0,M.jsx)(`span`,{className:`mb-1 block text-[13px] text-muted`,children:a(`In groups, reply`)}),(0,M.jsxs)(`select`,{className:`w-full rounded-2xl bg-surface-2 px-3.5 py-2.5 text-[14.5px] outline-none focus:ring-2 focus:ring-accent/40`,value:t.group_policy,onChange:e=>void r(()=>j.update(t.name,{group_policy:e.target.value})),children:[(0,M.jsx)(`option`,{value:`mention`,children:a(`only when @-mentioned`)}),(0,M.jsx)(`option`,{value:`open`,children:a(`to every message`)})]})]}),(0,M.jsxs)(`label`,{className:`block`,children:[(0,M.jsx)(`span`,{className:`mb-1 block text-[13px] text-muted`,children:a(`Always allowed (ids, one per line)`)}),(0,M.jsx)(`textarea`,{className:e(`w-full rounded-2xl bg-surface-2 px-3.5 py-2.5 text-[14.5px] outline-none focus:ring-2 focus:ring-accent/40`,`min-h-[56px] font-mono text-[13px]`),value:Y,onChange:e=>v(e.target.value),rows:2}),(0,M.jsx)(`span`,{className:`mt-1 block text-[12.5px] leading-[17px] text-muted`,children:a(`People listed here never need a pairing code. A lone * lets anyone in; do that only on a bot nobody else can reach.`)})]}),(0,M.jsxs)(`div`,{className:`flex flex-wrap gap-2`,children:[(0,M.jsx)(`button`,{type:`button`,className:`flex items-center justify-center gap-1.5 rounded-2xl bg-accent text-accent-fg px-4 py-2.5 text-[14px] font-medium disabled:opacity-40`,disabled:!J||E,onClick:()=>void X(),children:a(E?`Saving`:`Save`)}),(0,M.jsxs)(`button`,{type:`button`,className:`flex items-center justify-center gap-1.5 rounded-2xl border border-border px-4 py-2.5 text-[14px] font-medium text-muted disabled:opacity-40`,disabled:A||t.status.state!==`connected`,onClick:()=>void Z(),children:[(0,M.jsx)(h,{size:14,className:A?`animate-spin`:``}),` `,a(A?`Sending`:`Send a test message`)]}),t.name===`feishu`&&!V&&(0,M.jsxs)(`button`,{type:`button`,className:`flex items-center justify-center gap-1.5 rounded-2xl border border-border px-4 py-2.5 text-[14px] font-medium text-muted disabled:opacity-40`,onClick:()=>void $(),children:[(0,M.jsx)(D,{size:14}),` `,a(`Create the bot by QR code`)]}),(0,M.jsx)(`button`,{type:`button`,className:`flex items-center justify-center gap-1.5 rounded-2xl border border-border px-4 py-2.5 text-[14px] font-medium text-muted disabled:opacity-40`,onClick:()=>z(e=>!e),"aria-expanded":R,children:a(`Set up`)})]}),t.name===`feishu`&&!V&&(0,M.jsxs)(`label`,{className:`flex items-center gap-2 text-[13px] text-muted`,children:[(0,M.jsx)(`input`,{type:`checkbox`,checked:G,onChange:e=>K(e.target.checked)}),a(`Lark (international) instead of 飞书`)]}),V&&(0,M.jsxs)(`div`,{className:`rounded-2xl bg-surface-2 p-3 text-center`,children:[V.qr_png?(0,M.jsx)(`img`,{src:`data:image/png;base64,${V.qr_png}`,alt:`QR`,className:`mx-auto h-44 w-44 rounded-lg bg-white p-1`}):null,(0,M.jsx)(`p`,{className:`mt-2 text-[13px] text-muted`,children:a(`Scan with Feishu, confirm the new bot, and the App ID and Secret are saved for you.`)}),(0,M.jsx)(`p`,{className:`text-[13px] text-muted`,children:a(`Waiting for the scan…`)}),(0,M.jsxs)(`div`,{className:`mt-2 flex justify-center gap-2`,children:[(0,M.jsxs)(`a`,{href:V.url,target:`_blank`,rel:`noreferrer`,className:e(`flex items-center justify-center gap-1.5 rounded-2xl border border-border px-4 py-2.5 text-[14px] font-medium text-muted disabled:opacity-40`,`px-3 py-1.5`),children:[(0,M.jsx)(u,{size:14}),` `,a(`Open in Feishu`)]}),(0,M.jsx)(`button`,{type:`button`,className:e(`flex items-center justify-center gap-1.5 rounded-2xl border border-border px-4 py-2.5 text-[14px] font-medium text-muted disabled:opacity-40`,`px-3 py-1.5`),onClick:ee,children:a(`Cancel`)})]})]}),U&&(0,M.jsx)(`p`,{className:`text-[13px] text-muted`,children:U}),R&&(0,M.jsxs)(`div`,{className:`rounded-2xl bg-surface-2 p-3 text-[13.5px] leading-[19px]`,children:[(0,M.jsx)(`ol`,{className:`list-decimal space-y-1 pl-5`,children:(N[t.name]??[]).map(e=>(0,M.jsx)(`li`,{children:a(e)},e))}),(0,M.jsxs)(`p`,{className:`mt-2 text-muted`,children:[a(`Then write to the bot from the app. The first message gets a pairing code; approve it here or run`),` `,(0,M.jsx)(`code`,{className:`rounded bg-surface px-1`,children:`nanomuse channels approve `})]}),t.console_url&&(0,M.jsxs)(`a`,{href:t.console_url,target:`_blank`,rel:`noreferrer`,className:`mt-2 inline-flex items-center gap-1 text-accent underline-offset-2 hover:underline`,children:[(0,M.jsx)(u,{size:14}),` `,a(`Open the console`)]})]})]}),(0,M.jsx)(w,{inset:16}),(0,M.jsx)(`p`,{className:`px-4 pt-3 text-[13px] text-muted`,children:a(`Paired chats`)}),t.paired.length===0?(0,M.jsx)(`p`,{className:`px-4 pb-3 pt-1 text-[13px] leading-[18px] text-muted`,children:a(`Nobody yet. Write to the bot from the app; a pairing code comes back, approve it here.`)}):t.paired.map(e=>(0,M.jsxs)(`div`,{className:`flex items-center`,children:[(0,M.jsx)(`div`,{className:`min-w-0 flex-1`,children:(0,M.jsx)(C,{label:e.sender_name||e.sender_id,value:a(`Deliver here`),checked:e.deliver,onChange:n=>void r(()=>j.setDeliver(t.name,e.sender_id,n))})}),(0,M.jsx)(`button`,{type:`button`,className:`mr-3 rounded-full p-2 text-muted hover:bg-surface-2`,"aria-label":a(`Remove`),onClick:()=>{window.confirm(a(`Remove {name}? They will need a new pairing code.`,{name:e.sender_name||e.sender_id}))&&r(()=>j.removeChat(t.name,e.sender_id))},children:(0,M.jsx)(_,{size:16})})]},e.sender_id))]})]}),(c||t.enabled)&&t.paired.length>0&&(0,M.jsx)(S,{children:a(`Chats with “deliver here” on also get what the Muse does on its own: check-ins, reminders, the results of background work, and the questions it needs answered.`)})]})}function B({f:t,value:r,onChange:i,onClear:a}){let o=n();if(t.kind===`choice`)return(0,M.jsxs)(`label`,{className:`block`,children:[(0,M.jsx)(`span`,{className:`mb-1 block text-[13px] text-muted`,children:t.label}),(0,M.jsx)(`select`,{className:m,value:r??String(t.value??t.default),onChange:e=>i(e.target.value),children:t.choices.map(e=>(0,M.jsx)(`option`,{value:e,children:e},e))}),t.help&&(0,M.jsx)(`span`,{className:`mt-1 block text-[12.5px] text-muted`,children:t.help})]});let s=t.kind===`secret`;return(0,M.jsxs)(`label`,{className:`block`,children:[(0,M.jsxs)(`span`,{className:`mb-1 block text-[13px] text-muted`,children:[t.label,t.required?` *`:``]}),(0,M.jsxs)(`div`,{className:`flex gap-2`,children:[(0,M.jsx)(`input`,{type:s?`password`:`text`,autoComplete:`off`,className:m,value:r??(s?``:String(t.value??``)),placeholder:s&&t.has_value?o(`Set; leave blank to keep`):t.help,onChange:e=>i(e.target.value)}),s&&t.has_value&&(0,M.jsx)(`button`,{type:`button`,className:e(`flex items-center justify-center gap-1.5 rounded-2xl border border-border px-4 py-2.5 text-[14px] font-medium text-muted disabled:opacity-40`,`shrink-0 px-3`),onClick:a,title:o(`Clear the saved value`),"aria-label":o(`Clear the saved value`),children:(0,M.jsx)(p,{size:14})})]}),t.help&&!s&&(0,M.jsx)(`span`,{className:`mt-1 block text-[12.5px] text-muted`,children:t.help})]})}export{L as ChannelsScreen}; \ No newline at end of file +import{E as e,J as t,K as n,Q as r,Y as i,b as a,f as o,q as s,w as c}from"./MuseHeader-RC--uR8o.js";import{n as l,t as u}from"./external-link-TvxP_dKX.js";import{a as d,i as f,o as p,r as m}from"./Form-H3s9oTHq.js";import{t as h}from"./refresh-cw-CxZ3ZdI3.js";import{B as g,J as _,S as v,a as y,c as b,i as x,it as S,o as C,r as w,s as T}from"./index-tYqPtwPX.js";import{t as E}from"./BackBar-JEuC8Q_e.js";var D=t(`qr-code`,[[`rect`,{width:`5`,height:`5`,x:`3`,y:`3`,rx:`1`,key:`1tu5fj`}],[`rect`,{width:`5`,height:`5`,x:`16`,y:`3`,rx:`1`,key:`1v8r4q`}],[`rect`,{width:`5`,height:`5`,x:`3`,y:`16`,rx:`1`,key:`1x03jg`}],[`path`,{d:`M21 16h-3a2 2 0 0 0-2 2v3`,key:`177gqh`}],[`path`,{d:`M21 21v.01`,key:`ents32`}],[`path`,{d:`M12 7v3a2 2 0 0 1-2 2H7`,key:`8crl2c`}],[`path`,{d:`M3 12h.01`,key:`nlz23k`}],[`path`,{d:`M12 3h.01`,key:`n36tog`}],[`path`,{d:`M12 16v.01`,key:`133mhm`}],[`path`,{d:`M16 12h1`,key:`1slzba`}],[`path`,{d:`M21 12v.01`,key:`1lwtk9`}],[`path`,{d:`M12 21v-1`,key:`1880an`}]]),O=r(i(),1),k=(e,t)=>({method:e,body:JSON.stringify(t)}),A=encodeURIComponent,j={view:()=>c(`/api/channels`),update:(e,t)=>c(`/api/channels/${A(e)}`,k(`PUT`,t)),reload:()=>c(`/api/channels/reload`,{method:`POST`}),test:(e,t=``)=>c(`/api/channels/${A(e)}/test`,k(`POST`,{chat_id:t})),approve:e=>c(`/api/channels/pairing/${A(e)}/approve`,{method:`POST`}),deny:e=>c(`/api/channels/pairing/${A(e)}/deny`,{method:`POST`}),setDeliver:(e,t,n)=>c(`/api/channels/${A(e)}/chats/${A(t)}`,k(`PUT`,{deliver:n})),removeChat:(e,t)=>c(`/api/channels/${A(e)}/chats/${A(t)}`,{method:`DELETE`}),loginBegin:(e,t)=>c(`/api/channels/${A(e)}/login`,k(`POST`,{domain:t})),loginPoll:(e,t)=>c(`/api/channels/${A(e)}/login/${A(t)}`),deliver:e=>c(`/api/channels/deliver`,k(`POST`,{text:e}))},M=a(),N={feishu:[`In the Feishu developer console create a custom app and add the Bot capability.`,`Permissions: im:message, im:message.p2p_msg:readonly, im:message.group_at_msg:readonly, im:resource.`,`Events & callbacks: subscription mode Long connection; add im.message.receive_v1; callback mode Long connection; add card.action.trigger.`,`Copy App ID and App Secret from Credentials & Basic Info, then publish a version.`],dingtalk:[`In the DingTalk developer console create an internal app and add the Robot capability.`,`Set the message receive mode to Stream.`,`Copy Client ID (AppKey) and Client Secret (AppSecret) from Credentials & Basic Info.`,`Add the robot send-message permission and publish the version.`],wecom:[`In the WeCom admin console open Intelligent robot and create a robot in API mode with a long connection.`,`Copy the Bot ID and Secret.`,`Add the robot to the chats where it should listen.`],telegram:[`In Telegram talk to @BotFather, send /newbot and copy the token.`,`Direct messages work at once. For a group, add the bot to it; with Group Privacy on it only hears @-mentions and replies.`,`If api.telegram.org is out of reach from this computer, set a proxy below.`]},P={telegram:(0,M.jsx)(_,{size:20})};function F(e,t){let n=t.status.state;return e(n===`off`?`Off`:n===`unconfigured`?`Needs settings`:n===`missing_sdk`?`Not installed`:n===`connecting`?`Connecting…`:n===`connected`?`Connected`:`Error`)}function I({state:t}){return(0,M.jsx)(`span`,{"aria-hidden":!0,className:e(`inline-block h-2 w-2 rounded-full`,t===`connected`?`bg-emerald-500`:t===`error`?`bg-red-500`:t===`connecting`?`bg-amber-400`:`bg-border`)})}function L(){let{toast:e}=o(),t=n(),[r,i]=(0,O.useState)(null),[a,c]=(0,O.useState)(null),l=async()=>{try{i(await j.view()),c(null)}catch(e){c(e.message||`Could not load.`)}};(0,O.useEffect)(()=>{l();let e=window.setInterval(()=>void l(),5e3),t=()=>void l();return window.addEventListener(`focus`,t),()=>{window.clearInterval(e),window.removeEventListener(`focus`,t)}},[]);let u=async(t,n)=>{try{i(await t()),n&&e(n)}catch(t){e(t.message)}};return(0,M.jsxs)(`div`,{className:`flex h-full flex-col`,children:[(0,M.jsx)(E,{title:t(`Chat apps`),description:t(`Talk to your Muse from the chat apps you already use. Nothing needs a public address: each app keeps a long connection open.`)}),(0,M.jsxs)(`div`,{className:`flex-1 overflow-y-auto pb-8`,children:[r===null&&a&&(0,M.jsx)(v,{message:a,onRetry:()=>void l()}),r===null&&!a&&(0,M.jsx)(`div`,{className:`flex justify-center py-10 text-muted`,children:(0,M.jsx)(s,{className:`animate-spin`,size:20})}),r&&r.pending.length>0&&(0,M.jsxs)(M.Fragment,{children:[(0,M.jsx)(T,{children:t(`Waiting for a yes`)}),(0,M.jsx)(x,{children:r.pending.map((e,t)=>(0,M.jsxs)(`div`,{children:[t>0&&(0,M.jsx)(y,{inset:16}),(0,M.jsx)(R,{p:e,label:r.channels.find(t=>t.name===e.channel)?.label??e.channel,onApprove:()=>u(()=>j.approve(e.code)),onDeny:()=>u(()=>j.deny(e.code))})]},e.code))})]}),r?.channels.map(e=>(0,M.jsx)(z,{c:e,run:u,reload:l},e.name)),r&&(0,M.jsx)(w,{children:t(`Each chat is one conversation of your Muse; its replies stream back as they are written.`)})]})]})}function R({p:t,label:r,onApprove:i,onDeny:a}){let o=n(),s=t.sender_name||t.sender_id;return(0,M.jsxs)(`div`,{className:`flex items-center gap-3 px-4 py-3`,children:[(0,M.jsxs)(`div`,{className:`min-w-0 flex-1`,children:[(0,M.jsx)(`p`,{className:`truncate text-[15px]`,children:o(`{name} wrote to the bot. Approve to let them talk to your Muse.`,{name:`${s} · ${r}`})}),(0,M.jsx)(`p`,{className:`text-[13px] text-muted`,children:o(`Code {code}`,{code:t.code})})]}),(0,M.jsxs)(`button`,{type:`button`,className:e(f,`px-3 py-2`),onClick:i,"aria-label":o(`Approve`),children:[(0,M.jsx)(l,{size:16}),` `,o(`Approve`)]}),(0,M.jsx)(`button`,{type:`button`,className:e(d,`px-3 py-2`),onClick:a,"aria-label":o(`Deny`),children:(0,M.jsx)(p,{size:16})})]})}function z({c:t,run:r,reload:i}){let a=n(),{toast:s}=o(),[c,l]=(0,O.useState)(!1),[d,f]=(0,O.useState)({}),[p,m]=(0,O.useState)([]),[_,v]=(0,O.useState)(null),[E,k]=(0,O.useState)(!1),[A,L]=(0,O.useState)(!1),[R,z]=(0,O.useState)(!1),[V,H]=(0,O.useState)(null),[U,W]=(0,O.useState)(``),[G,K]=(0,O.useState)(!1),q=(0,O.useRef)(null),J=Object.keys(d).length>0||_!==null,Y=_??t.allow_from.join(` +`),X=async()=>{k(!0);try{let e={},n={};for(let[e,r]of Object.entries(d))(t.fields.find(t=>t.key===e)?.kind!==`secret`||r!==``||p.includes(e))&&(n[e]=r);Object.keys(n).length&&(e.settings=n),_!==null&&(e.allow_from=_.split(/[\n,]/).map(e=>e.trim()).filter(Boolean)),await r(()=>j.update(t.name,e),a(`Saved.`)),f({}),m([]),v(null)}finally{k(!1)}},Z=async()=>{L(!0);try{let e=await j.test(t.name);s(e.detail)}catch(e){s(e.message)}finally{L(!1)}},Q=()=>{q.current!==null&&window.clearTimeout(q.current),q.current=null};(0,O.useEffect)(()=>Q,[]);let $=async()=>{W(``);try{let e=await j.loginBegin(t.name,G?`lark`:`feishu`);H(e);let n=Date.now(),r=async()=>{try{let r=await j.loginPoll(t.name,e.device_code);if(r.status===`succeeded`){H(null),W(a(`The bot was created and is connecting.`)),await i();return}if(r.status===`failed`||Date.now()-n>e.expires_in*1e3){H(null),W(a(`The login did not finish ({error}).`,{error:r.error??`expired`}));return}}catch(e){H(null),W(e.message);return}q.current=window.setTimeout(()=>void r(),Math.max(2,e.interval)*1e3)};q.current=window.setTimeout(()=>void r(),Math.max(2,e.interval)*1e3)}catch(e){s(e.message)}},ee=()=>{Q(),H(null)},te=t.fields.filter(e=>e.required&&(e.kind===`secret`?!e.has_value:!e.value)).map(e=>e.label);return(0,M.jsxs)(M.Fragment,{children:[(0,M.jsx)(T,{children:t.label}),(0,M.jsxs)(x,{children:[(0,M.jsx)(C,{icon:P[t.name]??(0,M.jsx)(S,{size:20}),label:t.label,value:F(a,t),trailing:(0,M.jsx)(I,{state:t.status.state}),onClick:()=>l(e=>!e)}),(0,M.jsx)(y,{}),(0,M.jsx)(b,{label:a(`Switched on`),checked:t.enabled,disabled:!t.sdk_available&&!t.enabled,onChange:e=>void r(()=>j.update(t.name,{enabled:e}))}),t.status.state===`error`&&t.status.detail&&(0,M.jsx)(`p`,{className:`px-4 pb-3 text-[13px] leading-[18px] text-red-600 dark:text-red-400`,children:t.status.detail}),t.status.state===`unconfigured`&&(0,M.jsxs)(`p`,{className:`px-4 pb-3 text-[13px] leading-[18px] text-muted`,children:[a(`Missing`),`: `,t.status.detail||te.join(`, `)]}),!t.sdk_available&&(0,M.jsxs)(`div`,{className:`px-4 pb-3 text-[13px] leading-[18px] text-muted`,children:[a(`Install on the computer running nanoMuse, then switch it on again:`),(0,M.jsx)(`code`,{className:`mt-1 block select-all rounded-lg bg-surface-2 px-2 py-1 text-[12.5px] text-fg`,children:t.install})]}),(c||t.enabled)&&(0,M.jsxs)(M.Fragment,{children:[(0,M.jsx)(y,{inset:16}),(0,M.jsxs)(`div`,{className:`space-y-3 px-4 py-3`,children:[t.fields.map(e=>(0,M.jsx)(B,{f:e,value:d[e.key],onChange:t=>{f(n=>({...n,[e.key]:t})),t!==``&&m(t=>t.filter(t=>t!==e.key))},onClear:()=>{f(t=>({...t,[e.key]:``})),m(t=>t.includes(e.key)?t:[...t,e.key])}},e.key)),(0,M.jsxs)(`label`,{className:`block`,children:[(0,M.jsx)(`span`,{className:`mb-1 block text-[13px] text-muted`,children:a(`In groups, reply`)}),(0,M.jsxs)(`select`,{className:`w-full rounded-2xl bg-surface-2 px-3.5 py-2.5 text-[14.5px] outline-none focus:ring-2 focus:ring-accent/40`,value:t.group_policy,onChange:e=>void r(()=>j.update(t.name,{group_policy:e.target.value})),children:[(0,M.jsx)(`option`,{value:`mention`,children:a(`only when @-mentioned`)}),(0,M.jsx)(`option`,{value:`open`,children:a(`to every message`)})]})]}),(0,M.jsxs)(`label`,{className:`block`,children:[(0,M.jsx)(`span`,{className:`mb-1 block text-[13px] text-muted`,children:a(`Always allowed (ids, one per line)`)}),(0,M.jsx)(`textarea`,{className:e(`w-full rounded-2xl bg-surface-2 px-3.5 py-2.5 text-[14.5px] outline-none focus:ring-2 focus:ring-accent/40`,`min-h-[56px] font-mono text-[13px]`),value:Y,onChange:e=>v(e.target.value),rows:2}),(0,M.jsx)(`span`,{className:`mt-1 block text-[12.5px] leading-[17px] text-muted`,children:a(`People listed here never need a pairing code. A lone * lets anyone in; do that only on a bot nobody else can reach.`)})]}),(0,M.jsxs)(`div`,{className:`flex flex-wrap gap-2`,children:[(0,M.jsx)(`button`,{type:`button`,className:`flex items-center justify-center gap-1.5 rounded-2xl bg-accent text-accent-fg px-4 py-2.5 text-[14px] font-medium disabled:opacity-40`,disabled:!J||E,onClick:()=>void X(),children:a(E?`Saving`:`Save`)}),(0,M.jsxs)(`button`,{type:`button`,className:`flex items-center justify-center gap-1.5 rounded-2xl border border-border px-4 py-2.5 text-[14px] font-medium text-muted disabled:opacity-40`,disabled:A||t.status.state!==`connected`,onClick:()=>void Z(),children:[(0,M.jsx)(h,{size:14,className:A?`animate-spin`:``}),` `,a(A?`Sending`:`Send a test message`)]}),t.name===`feishu`&&!V&&(0,M.jsxs)(`button`,{type:`button`,className:`flex items-center justify-center gap-1.5 rounded-2xl border border-border px-4 py-2.5 text-[14px] font-medium text-muted disabled:opacity-40`,onClick:()=>void $(),children:[(0,M.jsx)(D,{size:14}),` `,a(`Create the bot by QR code`)]}),(0,M.jsx)(`button`,{type:`button`,className:`flex items-center justify-center gap-1.5 rounded-2xl border border-border px-4 py-2.5 text-[14px] font-medium text-muted disabled:opacity-40`,onClick:()=>z(e=>!e),"aria-expanded":R,children:a(`Set up`)})]}),t.name===`feishu`&&!V&&(0,M.jsxs)(`label`,{className:`flex items-center gap-2 text-[13px] text-muted`,children:[(0,M.jsx)(`input`,{type:`checkbox`,checked:G,onChange:e=>K(e.target.checked)}),a(`Lark (international) instead of 飞书`)]}),V&&(0,M.jsxs)(`div`,{className:`rounded-2xl bg-surface-2 p-3 text-center`,children:[V.qr_png?(0,M.jsx)(`img`,{src:`data:image/png;base64,${V.qr_png}`,alt:`QR`,className:`mx-auto h-44 w-44 rounded-lg bg-white p-1`}):null,(0,M.jsx)(`p`,{className:`mt-2 text-[13px] text-muted`,children:a(`Scan with Feishu, confirm the new bot, and the App ID and Secret are saved for you.`)}),(0,M.jsx)(`p`,{className:`text-[13px] text-muted`,children:a(`Waiting for the scan…`)}),(0,M.jsxs)(`div`,{className:`mt-2 flex justify-center gap-2`,children:[(0,M.jsxs)(`a`,{href:V.url,target:`_blank`,rel:`noreferrer`,className:e(`flex items-center justify-center gap-1.5 rounded-2xl border border-border px-4 py-2.5 text-[14px] font-medium text-muted disabled:opacity-40`,`px-3 py-1.5`),children:[(0,M.jsx)(u,{size:14}),` `,a(`Open in Feishu`)]}),(0,M.jsx)(`button`,{type:`button`,className:e(`flex items-center justify-center gap-1.5 rounded-2xl border border-border px-4 py-2.5 text-[14px] font-medium text-muted disabled:opacity-40`,`px-3 py-1.5`),onClick:ee,children:a(`Cancel`)})]})]}),U&&(0,M.jsx)(`p`,{className:`text-[13px] text-muted`,children:U}),R&&(0,M.jsxs)(`div`,{className:`rounded-2xl bg-surface-2 p-3 text-[13.5px] leading-[19px]`,children:[(0,M.jsx)(`ol`,{className:`list-decimal space-y-1 pl-5`,children:(N[t.name]??[]).map(e=>(0,M.jsx)(`li`,{children:a(e)},e))}),(0,M.jsxs)(`p`,{className:`mt-2 text-muted`,children:[a(`Then write to the bot from the app. The first message gets a pairing code; approve it here or run`),` `,(0,M.jsx)(`code`,{className:`rounded bg-surface px-1`,children:`nanomuse channels approve `})]}),t.console_url&&(0,M.jsxs)(`a`,{href:t.console_url,target:`_blank`,rel:`noreferrer`,className:`mt-2 inline-flex items-center gap-1 text-accent underline-offset-2 hover:underline`,children:[(0,M.jsx)(u,{size:14}),` `,a(`Open the console`)]})]})]}),(0,M.jsx)(y,{inset:16}),(0,M.jsx)(`p`,{className:`px-4 pt-3 text-[13px] text-muted`,children:a(`Paired chats`)}),t.paired.length===0?(0,M.jsx)(`p`,{className:`px-4 pb-3 pt-1 text-[13px] leading-[18px] text-muted`,children:a(`Nobody yet. Write to the bot from the app; a pairing code comes back, approve it here.`)}):t.paired.map(e=>(0,M.jsxs)(`div`,{className:`flex items-center`,children:[(0,M.jsx)(`div`,{className:`min-w-0 flex-1`,children:(0,M.jsx)(b,{label:e.sender_name||e.sender_id,value:a(`Deliver here`),checked:e.deliver,onChange:n=>void r(()=>j.setDeliver(t.name,e.sender_id,n))})}),(0,M.jsx)(`button`,{type:`button`,className:`mr-3 rounded-full p-2 text-muted hover:bg-surface-2`,"aria-label":a(`Remove`),onClick:()=>{window.confirm(a(`Remove {name}? They will need a new pairing code.`,{name:e.sender_name||e.sender_id}))&&r(()=>j.removeChat(t.name,e.sender_id))},children:(0,M.jsx)(g,{size:16})})]},e.sender_id))]})]}),(c||t.enabled)&&t.paired.length>0&&(0,M.jsx)(w,{children:a(`Chats with “deliver here” on also get what the Muse does on its own: check-ins, reminders, the results of background work, and the questions it needs answered.`)})]})}function B({f:t,value:r,onChange:i,onClear:a}){let o=n();if(t.kind===`choice`)return(0,M.jsxs)(`label`,{className:`block`,children:[(0,M.jsx)(`span`,{className:`mb-1 block text-[13px] text-muted`,children:t.label}),(0,M.jsx)(`select`,{className:m,value:r??String(t.value??t.default),onChange:e=>i(e.target.value),children:t.choices.map(e=>(0,M.jsx)(`option`,{value:e,children:e},e))}),t.help&&(0,M.jsx)(`span`,{className:`mt-1 block text-[12.5px] text-muted`,children:t.help})]});let s=t.kind===`secret`;return(0,M.jsxs)(`label`,{className:`block`,children:[(0,M.jsxs)(`span`,{className:`mb-1 block text-[13px] text-muted`,children:[t.label,t.required?` *`:``]}),(0,M.jsxs)(`div`,{className:`flex gap-2`,children:[(0,M.jsx)(`input`,{type:s?`password`:`text`,autoComplete:`off`,className:m,value:r??(s?``:String(t.value??``)),placeholder:s&&t.has_value?o(`Set; leave blank to keep`):t.help,onChange:e=>i(e.target.value)}),s&&t.has_value&&(0,M.jsx)(`button`,{type:`button`,className:e(`flex items-center justify-center gap-1.5 rounded-2xl border border-border px-4 py-2.5 text-[14px] font-medium text-muted disabled:opacity-40`,`shrink-0 px-3`),onClick:a,title:o(`Clear the saved value`),"aria-label":o(`Clear the saved value`),children:(0,M.jsx)(p,{size:14})})]}),t.help&&!s&&(0,M.jsx)(`span`,{className:`mt-1 block text-[12.5px] text-muted`,children:t.help})]})}export{L as ChannelsScreen}; \ No newline at end of file diff --git a/nanomuse/server/static/assets/CloudCard-CZ8tYr3g.js b/nanomuse/server/static/assets/CloudCard-D5foJm1I.js similarity index 88% rename from nanomuse/server/static/assets/CloudCard-CZ8tYr3g.js rename to nanomuse/server/static/assets/CloudCard-D5foJm1I.js index e4fbd8053..73f1855b8 100644 --- a/nanomuse/server/static/assets/CloudCard-CZ8tYr3g.js +++ b/nanomuse/server/static/assets/CloudCard-D5foJm1I.js @@ -1 +1 @@ -import{K as e,Q as t,Y as n,b as r,f as i,q as a,x as o}from"./MuseHeader-BvAlmxiL.js";import{a as s,t as c}from"./Form-C77NCy9F.js";import{ct as l,l as u,t as d,vt as f}from"./index-tZx-TDX4.js";var p=t(n(),1),m=r();function h({account:t,onChange:n,compact:r=!1,useAsModel:h=!1}){let{toast:_}=i(),v=e(),[y,b]=(0,p.useState)(r||!t?.signed_in),[x,S]=(0,p.useState)(null),[C,w]=(0,p.useState)(null),T=!!t?.signed_in,E=async()=>{S(`model`),w(null);try{await o.cloudUseAsModel(),_(v(`The Cloud model is in use.`)),n()}catch(e){w(v(e.message))}finally{S(null)}},D=t?.models!==!1,O=async e=>{S(`switch`),w(null);try{await o.cloudModels(e),n()}catch(e){w(v(e.message))}finally{S(null)}},k=async()=>{if(window.confirm(v(`Sign out of nanoMuse Cloud on this device? The hub and the Cloud model stop working here until you sign in again.`))){S(`out`);try{await o.cloudSignOut(),n()}catch(e){_(e.message)}finally{S(null)}}},A=T?{text:v(`Signed in`),tone:`ok`}:{text:v(`Not signed in`),tone:`off`},j=T?t?.is_model?v(`{hint} · model and hub`,{hint:t.hint}):v(`{hint} · hub`,{hint:t?.hint??``}):v(`Free. One account for all your devices, and a model to start with.`);return(0,m.jsx)(c,{icon:(0,m.jsx)(f,{size:20}),title:v(`nanoMuse Cloud`),summary:j,status:A,open:y,onToggle:r?void 0:()=>b(e=>!e),children:T?(0,m.jsxs)(`div`,{className:`space-y-3`,children:[(0,m.jsx)(`p`,{className:`text-[13px] text-muted leading-relaxed`,children:v(`Signed in as {hint}. Your devices meet here; the Cloud model comes with a free allowance.`,{hint:t?.hint??``})}),(0,m.jsx)(`div`,{className:`-mx-4 border-y border-border/60`,children:(0,m.jsx)(u,{label:v(`Use nanoMuse Cloud models`),checked:D,disabled:x!==null,onChange:e=>void O(e)})}),(0,m.jsx)(`p`,{className:`text-[12.5px] text-muted leading-relaxed`,children:v(D?`nanoMuse Cloud is one of the sources for the chat, the hands, pictures and clips; what runs on it comes off your allowance.`:`Off: nothing runs on nanoMuse Cloud unless you choose it yourself. You stay signed in for sync and your devices.`)}),(0,m.jsxs)(`div`,{className:`flex flex-wrap gap-2`,children:[!t?.is_model&&(0,m.jsxs)(`button`,{type:`button`,disabled:x!==null,onClick:()=>void E(),className:`flex items-center justify-center gap-1.5 rounded-2xl bg-accent text-accent-fg px-4 py-2.5 text-[14px] font-medium disabled:opacity-40`,children:[x===`model`?(0,m.jsx)(a,{size:15,className:`animate-spin`}):null,` `,v(`Use the Cloud model`)]}),(0,m.jsxs)(`button`,{type:`button`,disabled:x!==null,onClick:()=>void k(),className:s,children:[(0,m.jsx)(l,{size:15}),` `,v(`Sign out`)]})]}),C&&(0,m.jsx)(g,{text:C})]}):(0,m.jsx)(d,{useAsModel:h,autoFocus:!1,onSignedIn:()=>{_(v(`Signed in to nanoMuse Cloud.`)),n()}})})}function g({text:e}){return(0,m.jsx)(`div`,{className:`rounded-2xl bg-rose-500/12 px-3 py-2 text-[12.5px] text-rose-700 dark:text-rose-300`,children:e})}export{h as t}; \ No newline at end of file +import{K as e,Q as t,Y as n,b as r,f as i,q as a,x as o}from"./MuseHeader-RC--uR8o.js";import{a as s,t as c}from"./Form-H3s9oTHq.js";import{_t as l,c as u,st as d,t as f}from"./index-tYqPtwPX.js";var p=t(n(),1),m=r();function h({account:t,onChange:n,compact:r=!1,useAsModel:h=!1}){let{toast:_}=i(),v=e(),[y,b]=(0,p.useState)(r||!t?.signed_in),[x,S]=(0,p.useState)(null),[C,w]=(0,p.useState)(null),T=!!t?.signed_in,E=async()=>{S(`model`),w(null);try{await o.cloudUseAsModel(),_(v(`The Cloud model is in use.`)),n()}catch(e){w(v(e.message))}finally{S(null)}},D=t?.models!==!1,O=async e=>{S(`switch`),w(null);try{await o.cloudModels(e),n()}catch(e){w(v(e.message))}finally{S(null)}},k=async()=>{if(window.confirm(v(`Sign out of nanoMuse Cloud on this device? The hub and the Cloud model stop working here until you sign in again.`))){S(`out`);try{await o.cloudSignOut(),n()}catch(e){_(e.message)}finally{S(null)}}},A=T?{text:v(`Signed in`),tone:`ok`}:{text:v(`Not signed in`),tone:`off`},j=T?t?.is_model?v(`{hint} · model and hub`,{hint:t.hint}):v(`{hint} · hub`,{hint:t?.hint??``}):v(`Free. One account for all your devices, and a model to start with.`);return(0,m.jsx)(c,{icon:(0,m.jsx)(l,{size:20}),title:v(`nanoMuse Cloud`),summary:j,status:A,open:y,onToggle:r?void 0:()=>b(e=>!e),children:T?(0,m.jsxs)(`div`,{className:`space-y-3`,children:[(0,m.jsx)(`p`,{className:`text-[13px] text-muted leading-relaxed`,children:v(`Signed in as {hint}. Your devices meet here; the Cloud model comes with a free allowance.`,{hint:t?.hint??``})}),(0,m.jsx)(`div`,{className:`-mx-4 border-y border-border/60`,children:(0,m.jsx)(u,{label:v(`Use nanoMuse Cloud models`),checked:D,disabled:x!==null,onChange:e=>void O(e)})}),(0,m.jsx)(`p`,{className:`text-[12.5px] text-muted leading-relaxed`,children:v(D?`nanoMuse Cloud is one of the sources for the chat, the hands, pictures and clips; what runs on it comes off your allowance.`:`Off: nothing runs on nanoMuse Cloud unless you choose it yourself. You stay signed in for sync and your devices.`)}),(0,m.jsxs)(`div`,{className:`flex flex-wrap gap-2`,children:[!t?.is_model&&(0,m.jsxs)(`button`,{type:`button`,disabled:x!==null,onClick:()=>void E(),className:`flex items-center justify-center gap-1.5 rounded-2xl bg-accent text-accent-fg px-4 py-2.5 text-[14px] font-medium disabled:opacity-40`,children:[x===`model`?(0,m.jsx)(a,{size:15,className:`animate-spin`}):null,` `,v(`Use the Cloud model`)]}),(0,m.jsxs)(`button`,{type:`button`,disabled:x!==null,onClick:()=>void k(),className:s,children:[(0,m.jsx)(d,{size:15}),` `,v(`Sign out`)]})]}),C&&(0,m.jsx)(g,{text:C})]}):(0,m.jsx)(f,{useAsModel:h,autoFocus:!1,onSignedIn:()=>{_(v(`Signed in to nanoMuse Cloud.`)),n()}})})}function g({text:e}){return(0,m.jsx)(`div`,{className:`rounded-2xl bg-rose-500/12 px-3 py-2 text-[12.5px] text-rose-700 dark:text-rose-300`,children:e})}export{h as t}; \ No newline at end of file diff --git a/nanomuse/server/static/assets/CodingScreen-DAGGlv2e.js b/nanomuse/server/static/assets/CodingScreen-BLVF-Er8.js similarity index 84% rename from nanomuse/server/static/assets/CodingScreen-DAGGlv2e.js rename to nanomuse/server/static/assets/CodingScreen-BLVF-Er8.js index 41b26c5b1..79618f519 100644 --- a/nanomuse/server/static/assets/CodingScreen-DAGGlv2e.js +++ b/nanomuse/server/static/assets/CodingScreen-BLVF-Er8.js @@ -1,3 +1,3 @@ -import{E as e,J as t,K as n,Q as r,Y as i,b as a,f as o,k as s,q as c,r as l,x as u}from"./MuseHeader-BvAlmxiL.js";import{a as d,i as f,r as p}from"./Form-C77NCy9F.js";import{t as m}from"./refresh-cw-BMLOGb5p.js";import{Ct as h,F as g,H as _,Tt as v,U as y,Z as b,bt as x,it as S,w as C,z as w}from"./index-tZx-TDX4.js";import{t as T}from"./BackBar-DmScFXW_.js";var E=t(`folder-open`,[[`path`,{d:`m6 14 1.5-2.9A2 2 0 0 1 9.24 10H20a2 2 0 0 1 1.94 2.5l-1.54 6a2 2 0 0 1-1.95 1.5H4a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h3.9a2 2 0 0 1 1.69.9l.81 1.2a2 2 0 0 0 1.67.9H18a2 2 0 0 1 2 2v2`,key:`usdka0`}]]),D=r(i(),1),O=a(),k={cursor:{label:`Cursor`,tone:`from-slate-700 to-slate-900`,glyph:`C`},codex:{label:`Codex`,tone:`from-emerald-500 to-teal-700`,glyph:`X`},claude:{label:`Claude Code`,tone:`from-orange-400 to-amber-600`,glyph:`A`}};function A(){let{state:t,toast:r}=o(),i=n(),[a,d]=(0,D.useState)(``),[f,p]=(0,D.useState)(null),[h,g]=(0,D.useState)([]),[_,v]=(0,D.useState)(null),[C,w]=(0,D.useState)(``),[A,M]=(0,D.useState)(!1),[F,V]=(0,D.useState)(null),[H,U]=(0,D.useState)(null),[W,G]=(0,D.useState)(null),K=(0,D.useMemo)(()=>(t.hub?.devices??[]).filter(e=>!e.this&&e.online&&e.kind!==`web`&&(e.actions??[]).includes(`coding.sessions`)),[t.hub?.devices]),q=(0,D.useCallback)(async()=>{M(!0),V(null);try{let[e,t]=await Promise.all([u.coding(a),u.codingSessions({device:a,limit:40})]);p(e.agents),g(e.runs??[]),v(t.sessions)}catch(e){V(e.message),p([]),v([])}finally{M(!1)}},[a]);(0,D.useEffect)(()=>{q()},[q]);let J=Object.values(t.codingLive),Y=J.filter(e=>e.run.status!==`running`).length;(0,D.useEffect)(()=>{Y&&q()},[Y]);let X=(_??[]).filter(e=>(!C||e.agent===C)&&(e.messages>0||e.status===`running`)),Z=(f??[]).filter(e=>e.installed),Q=new Set(J.filter(e=>e.run.status===`running`&&(e.run.device??``)===(a?z(K,a):``)).map(e=>e.run.session_id||e.run.asked_session_id));return(0,O.jsxs)(`div`,{className:`flex h-full flex-col`,children:[(0,O.jsx)(T,{title:i(`Coding agents`),description:i(`Cursor, Codex and Claude Code: see what they are doing, and tell them things from anywhere.`),actions:(0,O.jsx)(l,{small:!0,onClick:()=>void q(),label:i(`Refresh`),children:(0,O.jsx)(m,{size:18,className:A?`animate-spin`:``})})}),(0,O.jsxs)(`div`,{className:`flex-1 overflow-y-auto px-4 pb-8 space-y-4`,children:[(K.length>0||a)&&(0,O.jsxs)(`div`,{className:`no-scrollbar -mx-4 flex gap-2 overflow-x-auto px-4`,children:[(0,O.jsx)(R,{active:!a,onClick:()=>d(``),icon:(0,O.jsx)(y,{size:14}),label:t.hub?.device?.name?i(`This one · {name}`,{name:t.hub.device.name}):i(`This computer`)}),K.map(e=>(0,O.jsx)(R,{active:a===e.id,onClick:()=>d(e.id),icon:(0,O.jsx)(S,{size:14}),label:e.name},e.id))]}),f&&(0,O.jsx)(`div`,{className:`grid grid-cols-3 gap-2`,children:f.map(t=>{let n=k[t.id];return(0,O.jsxs)(`button`,{type:`button`,disabled:!t.installed,onClick:()=>w(e=>e===t.id?``:t.id),className:e(`rounded-3xl border p-3 text-left transition`,C===t.id?`border-accent/40 bg-accent/5`:`border-border/70 bg-surface`,!t.installed&&`opacity-45`),children:[(0,O.jsxs)(`div`,{className:`flex items-center justify-between`,children:[(0,O.jsx)(I,{agent:t.id,size:30}),t.running>0&&(0,O.jsxs)(`span`,{className:`flex items-center gap-1 rounded-full bg-emerald-500/12 px-1.5 py-0.5 text-[10.5px] font-semibold text-emerald-700 dark:text-emerald-300`,children:[(0,O.jsx)(`span`,{className:`h-1.5 w-1.5 animate-pulse rounded-full bg-emerald-500`}),` `,t.running]})]}),(0,O.jsx)(`div`,{className:`mt-2 truncate text-[13.5px] font-semibold`,children:n?.label??t.name}),(0,O.jsx)(`div`,{className:`truncate text-[11.5px] text-muted`,children:t.installed?t.cli?t.version||i(`installed`):i(`chats only`):i(`not found`)})]},t.id)})}),F&&(0,O.jsx)(`div`,{className:`rounded-2xl bg-rose-500/12 px-3 py-2 text-[12.5px] text-rose-700 dark:text-rose-300`,children:F}),J.filter(e=>e.run.status===`running`).length>0&&(0,O.jsxs)(`section`,{className:`space-y-2`,children:[(0,O.jsx)(`h2`,{className:`px-1 text-[12px] font-semibold uppercase tracking-wide text-muted`,children:i(`Working now`)}),J.filter(e=>e.run.status===`running`).map(e=>(0,O.jsx)(N,{live:e,onOpen:()=>U({agent:e.run.agent,id:e.run.session_id||e.run.asked_session_id||``})},e.run.id))]}),(0,O.jsxs)(`section`,{className:`space-y-2`,children:[(0,O.jsxs)(`div`,{className:`flex items-center justify-between px-1`,children:[(0,O.jsx)(`h2`,{className:`text-[12px] font-semibold uppercase tracking-wide text-muted`,children:C?i(`{agent} chats`,{agent:k[C]?.label??C}):i(`Recent chats`)}),Z.some(e=>e.cli)&&(0,O.jsxs)(`button`,{type:`button`,onClick:()=>G(C&&Z.find(e=>e.id===C&&e.cli)?C:Z.find(e=>e.cli)?.id??null),className:`flex items-center gap-1 text-[12.5px] font-medium text-accent`,children:[(0,O.jsx)(b,{size:14}),` `,i(`New chat`)]})]}),_===null?(0,O.jsx)(`div`,{className:`flex justify-center py-10 text-muted`,children:(0,O.jsx)(c,{size:20,className:`animate-spin`})}):X.length===0?(0,O.jsx)(`div`,{className:`rounded-3xl border border-dashed border-border/80 px-4 py-8 text-center text-[13.5px] text-muted`,children:f&&f.every(e=>!e.installed)?i(`No coding agent found on this computer. Install Cursor, Codex or Claude Code and their chats appear here.`):i(`No chats yet.`)}):(0,O.jsx)(`ul`,{className:`divide-y divide-border/60 overflow-hidden rounded-3xl border border-border/70 bg-surface`,children:X.map(e=>(0,O.jsx)(`li`,{children:(0,O.jsxs)(`button`,{type:`button`,onClick:()=>U({agent:e.agent,id:e.id}),className:`flex w-full items-center gap-3 px-3.5 py-3 text-left hover:bg-surface-2/60 active:bg-surface-2`,children:[(0,O.jsx)(I,{agent:e.agent,size:34}),(0,O.jsxs)(`span`,{className:`min-w-0 flex-1`,children:[(0,O.jsxs)(`span`,{className:`flex items-center gap-2`,children:[(0,O.jsx)(`span`,{className:`truncate text-[14.5px] font-medium`,children:e.title||i(`Untitled chat`)}),(0,O.jsx)(L,{status:Q.has(e.id)?`running`:e.status})]}),(0,O.jsxs)(`span`,{className:`mt-0.5 flex items-center gap-1.5 truncate text-[12px] text-muted`,children:[e.workspace&&(0,O.jsxs)(`span`,{className:`flex min-w-0 items-center gap-1`,children:[(0,O.jsx)(E,{size:11}),` `,(0,O.jsx)(`span`,{className:`truncate`,children:B(e.workspace)})]}),(0,O.jsxs)(`span`,{children:[`· `,s(e.updated_at)]}),(0,O.jsxs)(`span`,{children:[`· `,i(`{n} messages`,{n:e.messages})]})]})]}),(0,O.jsx)(x,{size:16,className:`shrink-0 text-muted`})]})},`${e.agent}-${e.id}`))})]}),h.filter(e=>e.status!==`running`).length>0&&(0,O.jsxs)(`section`,{className:`space-y-2`,children:[(0,O.jsx)(`h2`,{className:`px-1 text-[12px] font-semibold uppercase tracking-wide text-muted`,children:i(`Sent through nanoMuse`)}),(0,O.jsx)(`ul`,{className:`divide-y divide-border/60 overflow-hidden rounded-3xl border border-border/70 bg-surface`,children:h.filter(e=>e.status!==`running`).slice(0,8).map(e=>(0,O.jsxs)(`li`,{className:`flex items-center gap-3 px-3.5 py-2.5`,children:[(0,O.jsx)(I,{agent:e.agent,size:28}),(0,O.jsxs)(`span`,{className:`min-w-0 flex-1`,children:[(0,O.jsx)(`span`,{className:`block truncate text-[13.5px]`,children:e.text}),(0,O.jsxs)(`span`,{className:`block truncate text-[11.5px] text-muted`,children:[e.status===`done`?i(`done`):e.status===`failed`?i(`failed`):i(`stopped`),` · `,s(e.started_at),e.tools?` · ${i(`{n} steps`,{n:e.tools})}`:``,e.error?` · ${e.error}`:``]})]}),e.session_id&&(0,O.jsx)(`button`,{type:`button`,onClick:()=>U({agent:e.agent,id:e.session_id}),className:`text-[12.5px] font-medium text-accent`,children:i(`Open`)})]},e.id))})]})]}),H&&(0,O.jsx)(j,{agent:H.agent,id:H.id,device:a,deviceLabel:a?z(K,a):``,onClose:()=>U(null)}),W&&(0,O.jsx)(P,{agent:W,agents:Z.filter(e=>e.cli),device:a,onClose:()=>G(null),onStarted:e=>{G(null),r(i(`Sent to {agent}.`,{agent:k[e.agent]?.label??e.agent}))}})]})}function j({agent:t,id:r,device:i,deviceLabel:a,onClose:s}){let{state:l,toast:d}=o(),f=n(),[m,h]=(0,D.useState)(null),[y,b]=(0,D.useState)(null),[x,S]=(0,D.useState)(``),[w,T]=(0,D.useState)(!1),E=(0,D.useRef)(null),A=(0,D.useCallback)(async()=>{try{h(await u.codingSession(t,r,i)),b(null)}catch(e){b(e.message)}},[t,r,i]);(0,D.useEffect)(()=>{A()},[A]);let j=Object.values(l.codingLive).filter(e=>e.run.agent===t&&(e.run.session_id===r||e.run.asked_session_id===r)),N=j.find(e=>e.run.status===`running`),P=j.filter(e=>e.run.status!==`running`).length;(0,D.useEffect)(()=>{P&&A()},[P]),(0,D.useEffect)(()=>{let e=E.current;e&&(e.scrollTop=e.scrollHeight)},[m?.transcript?.length,N?.events.length,N?.current.length]);let L=async()=>{let e=x.trim();if(e&&!w){T(!0);try{await u.codingSend({agent:t,text:e,session_id:r,workspace:m?.workspace??``,device:i}),S(``)}catch(e){d(e.message)}finally{T(!1)}}},R=k[t],z=m?.transcript??[],V=!!m||!!N,H=!!m&&!m.resumable&&!N;return(0,O.jsx)(C,{open:!0,onClose:s,title:(0,O.jsxs)(`span`,{className:`flex items-center gap-2.5`,children:[(0,O.jsx)(I,{agent:t,size:30}),(0,O.jsxs)(`span`,{className:`min-w-0`,children:[(0,O.jsx)(`span`,{className:`block truncate`,children:m?.title||R?.label||t}),(0,O.jsxs)(`span`,{className:`block truncate text-[12px] font-normal text-muted`,children:[a?`${a} · `:``,m?.workspace?B(m.workspace):R?.label,m?.source&&m.source!==`ide`&&m.source!==`cli`?` · ${m.source}`:``]})]})]}),footer:(0,O.jsxs)(O.Fragment,{children:[H&&(0,O.jsx)(`p`,{className:`mb-1.5 px-1 text-[11.5px] leading-snug text-muted`,children:f(`Made in the IDE: your message starts a new chat in the same workspace, with the last exchange quoted.`)}),(0,O.jsxs)(`form`,{className:`flex items-end gap-2`,onSubmit:e=>{e.preventDefault(),L()},children:[(0,O.jsx)(`textarea`,{value:x,onChange:e=>S(e.target.value),onKeyDown:e=>{e.key===`Enter`&&!e.shiftKey&&(e.preventDefault(),L())},rows:1,disabled:!V||!!N,placeholder:N?f(`{agent} is working…`,{agent:R?.label??t}):m?H?f(`Continue in a new chat…`):f(`Tell {agent}…`,{agent:R?.label??t}):`…`,className:e(p,`max-h-32 min-h-[44px] resize-none py-2.5`)}),N?(0,O.jsx)(`button`,{type:`button`,onClick:()=>void u.codingStop(N.run.id,i).catch(e=>d(e.message)),"aria-label":f(`Stop`),className:`flex h-11 w-11 shrink-0 items-center justify-center rounded-full bg-rose-500 text-white`,children:(0,O.jsx)(_,{size:16})}):(0,O.jsx)(`button`,{type:`submit`,disabled:!x.trim()||w||!V,"aria-label":f(`Send`),className:`flex h-11 w-11 shrink-0 items-center justify-center rounded-full bg-accent text-white disabled:opacity-40`,children:w?(0,O.jsx)(c,{size:16,className:`animate-spin`}):(0,O.jsx)(v,{size:18})})]})]}),children:(0,O.jsxs)(`div`,{ref:E,className:`space-y-2.5 py-1`,children:[y&&(0,O.jsx)(`div`,{className:`rounded-2xl bg-rose-500/12 px-3 py-2 text-[12.5px] text-rose-700 dark:text-rose-300`,children:y}),!m&&!y&&(0,O.jsx)(`div`,{className:`flex justify-center py-10 text-muted`,children:(0,O.jsx)(c,{size:20,className:`animate-spin`})}),z.map((e,n)=>(0,O.jsx)(F,{who:e.role===`user`?`you`:`agent`,agent:t,children:e.role===`user`?(0,O.jsx)(`span`,{className:`whitespace-pre-wrap`,children:e.text}):(0,O.jsx)(g,{text:e.text})},n)),j.filter(e=>!(e.run.status===`done`&&(e.run.resumed||!e.run.asked_session_id)&&z.some(t=>t.role===`user`&&t.text.trim()===e.run.text.trim()))).map(e=>(0,O.jsx)(M,{live:e,agent:t,hideFinishedText:z.length>0&&e.run.status===`done`},e.run.id)),m&&z.length===0&&j.length===0&&(0,O.jsx)(`p`,{className:`py-6 text-center text-[13px] text-muted`,children:f(`Nothing readable in this chat yet.`)})]})})}function M({live:e,agent:t,hideFinishedText:r}){let i=n(),{run:a,events:o,current:s}=e,l=o.filter(e=>e.kind===`tool`),u=k[t];return(0,O.jsxs)(O.Fragment,{children:[(0,O.jsx)(F,{who:`you`,agent:t,badge:i(`via nanoMuse`),children:(0,O.jsx)(`span`,{className:`whitespace-pre-wrap`,children:a.text})}),(l.length>0||a.status===`running`)&&(0,O.jsxs)(`div`,{className:`mx-1 rounded-2xl border border-border/60 bg-surface-2/40 px-3 py-2 text-[12.5px]`,children:[(0,O.jsxs)(`div`,{className:`flex items-center gap-1.5 font-medium text-fg/80`,children:[a.status===`running`?(0,O.jsx)(c,{size:13,className:`animate-spin text-accent`}):(0,O.jsx)(w,{size:13,className:`text-muted`}),a.status===`running`?i(`{agent} is working…`,{agent:u?.label??t}):i(`{n} steps`,{n:l.length}),a.device&&(0,O.jsxs)(`span`,{className:`ml-auto flex items-center gap-1 text-muted`,children:[(0,O.jsx)(S,{size:11}),` `,a.device]})]}),l.length>0&&(0,O.jsx)(`ul`,{className:`mt-1.5 max-h-28 space-y-0.5 overflow-y-auto font-mono text-[11.5px] text-muted`,children:l.slice(-12).map((e,t)=>(0,O.jsx)(`li`,{className:`truncate`,children:e.text},t))})]}),(s||a.output&&!r)&&(0,O.jsxs)(F,{who:`agent`,agent:t,children:[(0,O.jsx)(g,{text:a.status===`running`?(a.output?a.output+` +import{E as e,J as t,K as n,Q as r,Y as i,b as a,f as o,k as s,q as c,r as l,x as u}from"./MuseHeader-RC--uR8o.js";import{a as d,i as f,r as p}from"./Form-H3s9oTHq.js";import{t as m}from"./refresh-cw-CxZ3ZdI3.js";import{C as h,H as g,P as _,R as v,St as y,V as b,X as x,rt as S,wt as C,yt as w}from"./index-tYqPtwPX.js";import{t as T}from"./BackBar-JEuC8Q_e.js";var E=t(`folder-open`,[[`path`,{d:`m6 14 1.5-2.9A2 2 0 0 1 9.24 10H20a2 2 0 0 1 1.94 2.5l-1.54 6a2 2 0 0 1-1.95 1.5H4a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h3.9a2 2 0 0 1 1.69.9l.81 1.2a2 2 0 0 0 1.67.9H18a2 2 0 0 1 2 2v2`,key:`usdka0`}]]),D=r(i(),1),O=a(),k={cursor:{label:`Cursor`,tone:`from-slate-700 to-slate-900`,glyph:`C`},codex:{label:`Codex`,tone:`from-emerald-500 to-teal-700`,glyph:`X`},claude:{label:`Claude Code`,tone:`from-orange-400 to-amber-600`,glyph:`A`}};function A(){let{state:t,toast:r}=o(),i=n(),[a,d]=(0,D.useState)(``),[f,p]=(0,D.useState)(null),[h,_]=(0,D.useState)([]),[v,y]=(0,D.useState)(null),[b,C]=(0,D.useState)(``),[A,M]=(0,D.useState)(!1),[F,V]=(0,D.useState)(null),[H,U]=(0,D.useState)(null),[W,G]=(0,D.useState)(null),K=(0,D.useMemo)(()=>(t.hub?.devices??[]).filter(e=>!e.this&&e.online&&e.kind!==`web`&&(e.actions??[]).includes(`coding.sessions`)),[t.hub?.devices]),q=(0,D.useCallback)(async()=>{M(!0),V(null);try{let[e,t]=await Promise.all([u.coding(a),u.codingSessions({device:a,limit:40})]);p(e.agents),_(e.runs??[]),y(t.sessions)}catch(e){V(e.message),p([]),y([])}finally{M(!1)}},[a]);(0,D.useEffect)(()=>{q()},[q]);let J=Object.values(t.codingLive),Y=J.filter(e=>e.run.status!==`running`).length;(0,D.useEffect)(()=>{Y&&q()},[Y]);let X=(v??[]).filter(e=>(!b||e.agent===b)&&(e.messages>0||e.status===`running`)),Z=(f??[]).filter(e=>e.installed),Q=new Set(J.filter(e=>e.run.status===`running`&&(e.run.device??``)===(a?z(K,a):``)).map(e=>e.run.session_id||e.run.asked_session_id));return(0,O.jsxs)(`div`,{className:`flex h-full flex-col`,children:[(0,O.jsx)(T,{title:i(`Coding agents`),description:i(`Cursor, Codex and Claude Code: see what they are doing, and tell them things from anywhere.`),actions:(0,O.jsx)(l,{small:!0,onClick:()=>void q(),label:i(`Refresh`),children:(0,O.jsx)(m,{size:18,className:A?`animate-spin`:``})})}),(0,O.jsxs)(`div`,{className:`flex-1 overflow-y-auto px-4 pb-8 space-y-4`,children:[(K.length>0||a)&&(0,O.jsxs)(`div`,{className:`no-scrollbar -mx-4 flex gap-2 overflow-x-auto px-4`,children:[(0,O.jsx)(R,{active:!a,onClick:()=>d(``),icon:(0,O.jsx)(g,{size:14}),label:t.hub?.device?.name?i(`This one · {name}`,{name:t.hub.device.name}):i(`This computer`)}),K.map(e=>(0,O.jsx)(R,{active:a===e.id,onClick:()=>d(e.id),icon:(0,O.jsx)(S,{size:14}),label:e.name},e.id))]}),f&&(0,O.jsx)(`div`,{className:`grid grid-cols-3 gap-2`,children:f.map(t=>{let n=k[t.id];return(0,O.jsxs)(`button`,{type:`button`,disabled:!t.installed,onClick:()=>C(e=>e===t.id?``:t.id),className:e(`rounded-3xl border p-3 text-left transition`,b===t.id?`border-accent/40 bg-accent/5`:`border-border/70 bg-surface`,!t.installed&&`opacity-45`),children:[(0,O.jsxs)(`div`,{className:`flex items-center justify-between`,children:[(0,O.jsx)(I,{agent:t.id,size:30}),t.running>0&&(0,O.jsxs)(`span`,{className:`flex items-center gap-1 rounded-full bg-emerald-500/12 px-1.5 py-0.5 text-[10.5px] font-semibold text-emerald-700 dark:text-emerald-300`,children:[(0,O.jsx)(`span`,{className:`h-1.5 w-1.5 animate-pulse rounded-full bg-emerald-500`}),` `,t.running]})]}),(0,O.jsx)(`div`,{className:`mt-2 truncate text-[13.5px] font-semibold`,children:n?.label??t.name}),(0,O.jsx)(`div`,{className:`truncate text-[11.5px] text-muted`,children:t.installed?t.cli?t.version||i(`installed`):i(`chats only`):i(`not found`)})]},t.id)})}),F&&(0,O.jsx)(`div`,{className:`rounded-2xl bg-rose-500/12 px-3 py-2 text-[12.5px] text-rose-700 dark:text-rose-300`,children:F}),J.filter(e=>e.run.status===`running`).length>0&&(0,O.jsxs)(`section`,{className:`space-y-2`,children:[(0,O.jsx)(`h2`,{className:`px-1 text-[12px] font-semibold uppercase tracking-wide text-muted`,children:i(`Working now`)}),J.filter(e=>e.run.status===`running`).map(e=>(0,O.jsx)(N,{live:e,onOpen:()=>U({agent:e.run.agent,id:e.run.session_id||e.run.asked_session_id||``})},e.run.id))]}),(0,O.jsxs)(`section`,{className:`space-y-2`,children:[(0,O.jsxs)(`div`,{className:`flex items-center justify-between px-1`,children:[(0,O.jsx)(`h2`,{className:`text-[12px] font-semibold uppercase tracking-wide text-muted`,children:b?i(`{agent} chats`,{agent:k[b]?.label??b}):i(`Recent chats`)}),Z.some(e=>e.cli)&&(0,O.jsxs)(`button`,{type:`button`,onClick:()=>G(b&&Z.find(e=>e.id===b&&e.cli)?b:Z.find(e=>e.cli)?.id??null),className:`flex items-center gap-1 text-[12.5px] font-medium text-accent`,children:[(0,O.jsx)(x,{size:14}),` `,i(`New chat`)]})]}),v===null?(0,O.jsx)(`div`,{className:`flex justify-center py-10 text-muted`,children:(0,O.jsx)(c,{size:20,className:`animate-spin`})}):X.length===0?(0,O.jsx)(`div`,{className:`rounded-3xl border border-dashed border-border/80 px-4 py-8 text-center text-[13.5px] text-muted`,children:f&&f.every(e=>!e.installed)?i(`No coding agent found on this computer. Install Cursor, Codex or Claude Code and their chats appear here.`):i(`No chats yet.`)}):(0,O.jsx)(`ul`,{className:`divide-y divide-border/60 overflow-hidden rounded-3xl border border-border/70 bg-surface`,children:X.map(e=>(0,O.jsx)(`li`,{children:(0,O.jsxs)(`button`,{type:`button`,onClick:()=>U({agent:e.agent,id:e.id}),className:`flex w-full items-center gap-3 px-3.5 py-3 text-left hover:bg-surface-2/60 active:bg-surface-2`,children:[(0,O.jsx)(I,{agent:e.agent,size:34}),(0,O.jsxs)(`span`,{className:`min-w-0 flex-1`,children:[(0,O.jsxs)(`span`,{className:`flex items-center gap-2`,children:[(0,O.jsx)(`span`,{className:`truncate text-[14.5px] font-medium`,children:e.title||i(`Untitled chat`)}),(0,O.jsx)(L,{status:Q.has(e.id)?`running`:e.status})]}),(0,O.jsxs)(`span`,{className:`mt-0.5 flex items-center gap-1.5 truncate text-[12px] text-muted`,children:[e.workspace&&(0,O.jsxs)(`span`,{className:`flex min-w-0 items-center gap-1`,children:[(0,O.jsx)(E,{size:11}),` `,(0,O.jsx)(`span`,{className:`truncate`,children:B(e.workspace)})]}),(0,O.jsxs)(`span`,{children:[`· `,s(e.updated_at)]}),(0,O.jsxs)(`span`,{children:[`· `,i(`{n} messages`,{n:e.messages})]})]})]}),(0,O.jsx)(w,{size:16,className:`shrink-0 text-muted`})]})},`${e.agent}-${e.id}`))})]}),h.filter(e=>e.status!==`running`).length>0&&(0,O.jsxs)(`section`,{className:`space-y-2`,children:[(0,O.jsx)(`h2`,{className:`px-1 text-[12px] font-semibold uppercase tracking-wide text-muted`,children:i(`Sent through nanoMuse`)}),(0,O.jsx)(`ul`,{className:`divide-y divide-border/60 overflow-hidden rounded-3xl border border-border/70 bg-surface`,children:h.filter(e=>e.status!==`running`).slice(0,8).map(e=>(0,O.jsxs)(`li`,{className:`flex items-center gap-3 px-3.5 py-2.5`,children:[(0,O.jsx)(I,{agent:e.agent,size:28}),(0,O.jsxs)(`span`,{className:`min-w-0 flex-1`,children:[(0,O.jsx)(`span`,{className:`block truncate text-[13.5px]`,children:e.text}),(0,O.jsxs)(`span`,{className:`block truncate text-[11.5px] text-muted`,children:[e.status===`done`?i(`done`):e.status===`failed`?i(`failed`):i(`stopped`),` · `,s(e.started_at),e.tools?` · ${i(`{n} steps`,{n:e.tools})}`:``,e.error?` · ${e.error}`:``]})]}),e.session_id&&(0,O.jsx)(`button`,{type:`button`,onClick:()=>U({agent:e.agent,id:e.session_id}),className:`text-[12.5px] font-medium text-accent`,children:i(`Open`)})]},e.id))})]})]}),H&&(0,O.jsx)(j,{agent:H.agent,id:H.id,device:a,deviceLabel:a?z(K,a):``,onClose:()=>U(null)}),W&&(0,O.jsx)(P,{agent:W,agents:Z.filter(e=>e.cli),device:a,onClose:()=>G(null),onStarted:e=>{G(null),r(i(`Sent to {agent}.`,{agent:k[e.agent]?.label??e.agent}))}})]})}function j({agent:t,id:r,device:i,deviceLabel:a,onClose:s}){let{state:l,toast:d}=o(),f=n(),[m,g]=(0,D.useState)(null),[v,y]=(0,D.useState)(null),[x,S]=(0,D.useState)(``),[w,T]=(0,D.useState)(!1),E=(0,D.useRef)(null),A=(0,D.useCallback)(async()=>{try{g(await u.codingSession(t,r,i)),y(null)}catch(e){y(e.message)}},[t,r,i]);(0,D.useEffect)(()=>{A()},[A]);let j=Object.values(l.codingLive).filter(e=>e.run.agent===t&&(e.run.session_id===r||e.run.asked_session_id===r)),N=j.find(e=>e.run.status===`running`),P=j.filter(e=>e.run.status!==`running`).length;(0,D.useEffect)(()=>{P&&A()},[P]),(0,D.useEffect)(()=>{let e=E.current;e&&(e.scrollTop=e.scrollHeight)},[m?.transcript?.length,N?.events.length,N?.current.length]);let L=async()=>{let e=x.trim();if(e&&!w){T(!0);try{await u.codingSend({agent:t,text:e,session_id:r,workspace:m?.workspace??``,device:i}),S(``)}catch(e){d(e.message)}finally{T(!1)}}},R=k[t],z=m?.transcript??[],V=!!m||!!N,H=!!m&&!m.resumable&&!N;return(0,O.jsx)(h,{open:!0,onClose:s,title:(0,O.jsxs)(`span`,{className:`flex items-center gap-2.5`,children:[(0,O.jsx)(I,{agent:t,size:30}),(0,O.jsxs)(`span`,{className:`min-w-0`,children:[(0,O.jsx)(`span`,{className:`block truncate`,children:m?.title||R?.label||t}),(0,O.jsxs)(`span`,{className:`block truncate text-[12px] font-normal text-muted`,children:[a?`${a} · `:``,m?.workspace?B(m.workspace):R?.label,m?.source&&m.source!==`ide`&&m.source!==`cli`?` · ${m.source}`:``]})]})]}),footer:(0,O.jsxs)(O.Fragment,{children:[H&&(0,O.jsx)(`p`,{className:`mb-1.5 px-1 text-[11.5px] leading-snug text-muted`,children:f(`Made in the IDE: your message starts a new chat in the same workspace, with the last exchange quoted.`)}),(0,O.jsxs)(`form`,{className:`flex items-end gap-2`,onSubmit:e=>{e.preventDefault(),L()},children:[(0,O.jsx)(`textarea`,{value:x,onChange:e=>S(e.target.value),onKeyDown:e=>{e.key===`Enter`&&!e.shiftKey&&(e.preventDefault(),L())},rows:1,disabled:!V||!!N,placeholder:N?f(`{agent} is working…`,{agent:R?.label??t}):m?H?f(`Continue in a new chat…`):f(`Tell {agent}…`,{agent:R?.label??t}):`…`,className:e(p,`max-h-32 min-h-[44px] resize-none py-2.5`)}),N?(0,O.jsx)(`button`,{type:`button`,onClick:()=>void u.codingStop(N.run.id,i).catch(e=>d(e.message)),"aria-label":f(`Stop`),className:`flex h-11 w-11 shrink-0 items-center justify-center rounded-full bg-rose-500 text-white`,children:(0,O.jsx)(b,{size:16})}):(0,O.jsx)(`button`,{type:`submit`,disabled:!x.trim()||w||!V,"aria-label":f(`Send`),className:`flex h-11 w-11 shrink-0 items-center justify-center rounded-full bg-accent text-white disabled:opacity-40`,children:w?(0,O.jsx)(c,{size:16,className:`animate-spin`}):(0,O.jsx)(C,{size:18})})]})]}),children:(0,O.jsxs)(`div`,{ref:E,className:`space-y-2.5 py-1`,children:[v&&(0,O.jsx)(`div`,{className:`rounded-2xl bg-rose-500/12 px-3 py-2 text-[12.5px] text-rose-700 dark:text-rose-300`,children:v}),!m&&!v&&(0,O.jsx)(`div`,{className:`flex justify-center py-10 text-muted`,children:(0,O.jsx)(c,{size:20,className:`animate-spin`})}),z.map((e,n)=>(0,O.jsx)(F,{who:e.role===`user`?`you`:`agent`,agent:t,children:e.role===`user`?(0,O.jsx)(`span`,{className:`whitespace-pre-wrap`,children:e.text}):(0,O.jsx)(_,{text:e.text})},n)),j.filter(e=>!(e.run.status===`done`&&(e.run.resumed||!e.run.asked_session_id)&&z.some(t=>t.role===`user`&&t.text.trim()===e.run.text.trim()))).map(e=>(0,O.jsx)(M,{live:e,agent:t,hideFinishedText:z.length>0&&e.run.status===`done`},e.run.id)),m&&z.length===0&&j.length===0&&(0,O.jsx)(`p`,{className:`py-6 text-center text-[13px] text-muted`,children:f(`Nothing readable in this chat yet.`)})]})})}function M({live:e,agent:t,hideFinishedText:r}){let i=n(),{run:a,events:o,current:s}=e,l=o.filter(e=>e.kind===`tool`),u=k[t];return(0,O.jsxs)(O.Fragment,{children:[(0,O.jsx)(F,{who:`you`,agent:t,badge:i(`via nanoMuse`),children:(0,O.jsx)(`span`,{className:`whitespace-pre-wrap`,children:a.text})}),(l.length>0||a.status===`running`)&&(0,O.jsxs)(`div`,{className:`mx-1 rounded-2xl border border-border/60 bg-surface-2/40 px-3 py-2 text-[12.5px]`,children:[(0,O.jsxs)(`div`,{className:`flex items-center gap-1.5 font-medium text-fg/80`,children:[a.status===`running`?(0,O.jsx)(c,{size:13,className:`animate-spin text-accent`}):(0,O.jsx)(v,{size:13,className:`text-muted`}),a.status===`running`?i(`{agent} is working…`,{agent:u?.label??t}):i(`{n} steps`,{n:l.length}),a.device&&(0,O.jsxs)(`span`,{className:`ml-auto flex items-center gap-1 text-muted`,children:[(0,O.jsx)(S,{size:11}),` `,a.device]})]}),l.length>0&&(0,O.jsx)(`ul`,{className:`mt-1.5 max-h-28 space-y-0.5 overflow-y-auto font-mono text-[11.5px] text-muted`,children:l.slice(-12).map((e,t)=>(0,O.jsx)(`li`,{className:`truncate`,children:e.text},t))})]}),(s||a.output&&!r)&&(0,O.jsxs)(F,{who:`agent`,agent:t,children:[(0,O.jsx)(_,{text:a.status===`running`?(a.output?a.output+` -`:``)+s:a.output}),a.status===`running`&&(0,O.jsx)(`span`,{className:`ml-1 inline-block h-3.5 w-1 animate-pulse bg-accent align-middle`})]}),a.status===`failed`&&(0,O.jsx)(`div`,{className:`mx-1 rounded-2xl bg-rose-500/12 px-3 py-2 text-[12.5px] text-rose-700 dark:text-rose-300`,children:a.error||i(`failed`)}),a.status===`stopped`&&(0,O.jsx)(`div`,{className:`mx-1 text-center text-[12px] text-muted`,children:i(`stopped`)}),!a.resumed&&a.asked_session_id&&a.status!==`running`&&(0,O.jsx)(`div`,{className:`mx-1 text-center text-[12px] text-muted`,children:i(`Continued as a new chat: the agent could not reopen the old one.`)})]})}function N({live:e,onOpen:t}){let r=n(),{run:i,events:a,current:o}=e,s=[...a].reverse().find(e=>e.kind===`tool`);return(0,O.jsxs)(`button`,{type:`button`,onClick:t,className:`flex w-full items-center gap-3 rounded-3xl border border-accent/25 bg-accent/5 px-3.5 py-3 text-left`,children:[(0,O.jsx)(I,{agent:i.agent,size:34}),(0,O.jsxs)(`span`,{className:`min-w-0 flex-1`,children:[(0,O.jsx)(`span`,{className:`block truncate text-[14px] font-medium`,children:i.text}),(0,O.jsxs)(`span`,{className:`mt-0.5 flex items-center gap-1.5 truncate text-[12px] text-muted`,children:[(0,O.jsx)(c,{size:11,className:`animate-spin text-accent`}),(0,O.jsx)(`span`,{className:`truncate`,children:o.slice(-80)||s?.text||r(`starting…`)})]})]}),i.device&&(0,O.jsx)(S,{size:14,className:`shrink-0 text-muted`})]})}function P({agent:t,agents:r,device:i,onClose:a,onStarted:s}){let{toast:l}=o(),m=n(),[h,g]=(0,D.useState)(t),[_,y]=(0,D.useState)(``),[b,x]=(0,D.useState)(``),[S,w]=(0,D.useState)(!1),[T,E]=(0,D.useState)([]);(0,D.useEffect)(()=>{u.codingSessions({agent:h,device:i,limit:30}).then(e=>E(Array.from(new Set(e.sessions.map(e=>e.workspace).filter(Boolean))).slice(0,6))).catch(()=>E([]))},[h,i]);let A=async()=>{if(b.trim()&&!S){w(!0);try{s(await u.codingSend({agent:h,text:b.trim(),workspace:_.trim(),device:i}))}catch(e){l(e.message)}finally{w(!1)}}};return(0,O.jsx)(C,{open:!0,onClose:a,title:m(`New chat`),footer:(0,O.jsxs)(`button`,{type:`button`,disabled:!b.trim()||S,onClick:()=>void A(),className:e(f,`w-full py-3`),children:[S?(0,O.jsx)(c,{size:15,className:`animate-spin`}):(0,O.jsx)(v,{size:15}),` `,m(`Send to {agent}`,{agent:k[h]?.label??h})]}),children:(0,O.jsxs)(`div`,{className:`space-y-4 py-1`,children:[(0,O.jsx)(`div`,{className:`grid grid-cols-3 gap-1 rounded-2xl bg-surface-2/70 p-1 text-[13px] font-medium`,children:r.map(t=>(0,O.jsxs)(`button`,{type:`button`,onClick:()=>g(t.id),className:e(`flex items-center justify-center gap-1.5 rounded-xl px-2 py-2 transition`,h===t.id?`bg-surface text-fg shadow-sm`:`text-muted`),children:[(0,O.jsx)(I,{agent:t.id,size:18}),` `,k[t.id]?.label??t.name]},t.id))}),(0,O.jsxs)(`div`,{children:[(0,O.jsx)(`label`,{className:`text-[12px] text-muted`,children:m(`Project folder`)}),(0,O.jsx)(`input`,{value:_,onChange:e=>y(e.target.value),placeholder:`/home/you/project`,className:e(p,`mt-1 font-mono text-[13px]`)}),T.length>0&&(0,O.jsx)(`div`,{className:`mt-2 flex flex-wrap gap-1.5`,children:T.map(t=>(0,O.jsx)(`button`,{type:`button`,onClick:()=>y(t),className:e(`rounded-full border px-2.5 py-1 text-[12px]`,_===t?`border-accent/40 bg-accent/10 text-accent`:`border-border text-muted`),children:B(t)},t))})]}),(0,O.jsxs)(`div`,{children:[(0,O.jsx)(`label`,{className:`text-[12px] text-muted`,children:m(`What to do`)}),(0,O.jsx)(`textarea`,{value:b,onChange:e=>x(e.target.value),rows:4,autoFocus:!0,placeholder:m(`Add tests for the parser and run them`),className:e(p,`mt-1 resize-none`)})]}),(0,O.jsx)(`p`,{className:`text-[12px] text-muted`,children:m(`The agent runs on that computer with its own permissions; nanoMuse only carries the message and brings the answer back.`)}),(0,O.jsx)(`button`,{type:`button`,onClick:a,className:e(d,`w-full`),children:m(`Cancel`)})]})})}function F({who:t,agent:n,badge:r,children:i}){return(0,O.jsxs)(`div`,{className:e(`flex`,t===`you`?`justify-end`:`justify-start`),children:[t===`agent`&&(0,O.jsx)(I,{agent:n,size:24,className:`mr-2 mt-1 shrink-0`}),(0,O.jsxs)(`div`,{className:e(`max-w-[86%] rounded-3xl px-3.5 py-2 text-[14px] leading-relaxed`,t===`you`?`bubble-user rounded-br-lg bg-bubble-user text-bubble-user-fg`:`rounded-bl-lg bg-bubble-agent`),children:[r&&(0,O.jsx)(`div`,{className:`mb-0.5 text-[10.5px] font-semibold uppercase tracking-wide opacity-60`,children:r}),(0,O.jsx)(`div`,{className:`md break-words`,children:i})]})]})}function I({agent:t,size:n=28,className:r}){let i=k[t];return(0,O.jsx)(`span`,{className:e(`flex shrink-0 items-center justify-center rounded-xl bg-gradient-to-br font-bold text-white shadow-sm`,i?.tone??`from-slate-400 to-slate-600`,r),style:{width:n,height:n,fontSize:Math.round(n*.46)},"aria-hidden":!0,children:i?.glyph??(0,O.jsx)(h,{size:Math.round(n*.55)})})}function L({status:e}){let t=n();return e===`running`?(0,O.jsxs)(`span`,{className:`flex shrink-0 items-center gap-1 rounded-full bg-emerald-500/12 px-2 py-0.5 text-[10.5px] font-semibold text-emerald-700 dark:text-emerald-300`,children:[(0,O.jsx)(`span`,{className:`h-1.5 w-1.5 animate-pulse rounded-full bg-emerald-500`}),` `,t(`working`)]}):e===`active`?(0,O.jsx)(`span`,{className:`h-2 w-2 shrink-0 rounded-full bg-accent`,title:t(`active`)}):null}function R({active:t,onClick:n,icon:r,label:i}){return(0,O.jsxs)(`button`,{type:`button`,onClick:n,className:e(`flex shrink-0 items-center gap-1.5 rounded-full border px-3 py-1.5 text-[12.5px] font-medium transition`,t?`border-fg bg-fg text-bg`:`border-border bg-surface text-fg/75`),children:[r,` `,i]})}function z(e,t){return e.find(e=>e.id===t)?.name??t}function B(e){let t=e.replace(/[\\/]+$/,``).split(/[\\/]/);return t[t.length-1]||e}export{A as CodingScreen}; \ No newline at end of file +`:``)+s:a.output}),a.status===`running`&&(0,O.jsx)(`span`,{className:`ml-1 inline-block h-3.5 w-1 animate-pulse bg-accent align-middle`})]}),a.status===`failed`&&(0,O.jsx)(`div`,{className:`mx-1 rounded-2xl bg-rose-500/12 px-3 py-2 text-[12.5px] text-rose-700 dark:text-rose-300`,children:a.error||i(`failed`)}),a.status===`stopped`&&(0,O.jsx)(`div`,{className:`mx-1 text-center text-[12px] text-muted`,children:i(`stopped`)}),!a.resumed&&a.asked_session_id&&a.status!==`running`&&(0,O.jsx)(`div`,{className:`mx-1 text-center text-[12px] text-muted`,children:i(`Continued as a new chat: the agent could not reopen the old one.`)})]})}function N({live:e,onOpen:t}){let r=n(),{run:i,events:a,current:o}=e,s=[...a].reverse().find(e=>e.kind===`tool`);return(0,O.jsxs)(`button`,{type:`button`,onClick:t,className:`flex w-full items-center gap-3 rounded-3xl border border-accent/25 bg-accent/5 px-3.5 py-3 text-left`,children:[(0,O.jsx)(I,{agent:i.agent,size:34}),(0,O.jsxs)(`span`,{className:`min-w-0 flex-1`,children:[(0,O.jsx)(`span`,{className:`block truncate text-[14px] font-medium`,children:i.text}),(0,O.jsxs)(`span`,{className:`mt-0.5 flex items-center gap-1.5 truncate text-[12px] text-muted`,children:[(0,O.jsx)(c,{size:11,className:`animate-spin text-accent`}),(0,O.jsx)(`span`,{className:`truncate`,children:o.slice(-80)||s?.text||r(`starting…`)})]})]}),i.device&&(0,O.jsx)(S,{size:14,className:`shrink-0 text-muted`})]})}function P({agent:t,agents:r,device:i,onClose:a,onStarted:s}){let{toast:l}=o(),m=n(),[g,_]=(0,D.useState)(t),[v,y]=(0,D.useState)(``),[b,x]=(0,D.useState)(``),[S,w]=(0,D.useState)(!1),[T,E]=(0,D.useState)([]);(0,D.useEffect)(()=>{u.codingSessions({agent:g,device:i,limit:30}).then(e=>E(Array.from(new Set(e.sessions.map(e=>e.workspace).filter(Boolean))).slice(0,6))).catch(()=>E([]))},[g,i]);let A=async()=>{if(b.trim()&&!S){w(!0);try{s(await u.codingSend({agent:g,text:b.trim(),workspace:v.trim(),device:i}))}catch(e){l(e.message)}finally{w(!1)}}};return(0,O.jsx)(h,{open:!0,onClose:a,title:m(`New chat`),footer:(0,O.jsxs)(`button`,{type:`button`,disabled:!b.trim()||S,onClick:()=>void A(),className:e(f,`w-full py-3`),children:[S?(0,O.jsx)(c,{size:15,className:`animate-spin`}):(0,O.jsx)(C,{size:15}),` `,m(`Send to {agent}`,{agent:k[g]?.label??g})]}),children:(0,O.jsxs)(`div`,{className:`space-y-4 py-1`,children:[(0,O.jsx)(`div`,{className:`grid grid-cols-3 gap-1 rounded-2xl bg-surface-2/70 p-1 text-[13px] font-medium`,children:r.map(t=>(0,O.jsxs)(`button`,{type:`button`,onClick:()=>_(t.id),className:e(`flex items-center justify-center gap-1.5 rounded-xl px-2 py-2 transition`,g===t.id?`bg-surface text-fg shadow-sm`:`text-muted`),children:[(0,O.jsx)(I,{agent:t.id,size:18}),` `,k[t.id]?.label??t.name]},t.id))}),(0,O.jsxs)(`div`,{children:[(0,O.jsx)(`label`,{className:`text-[12px] text-muted`,children:m(`Project folder`)}),(0,O.jsx)(`input`,{value:v,onChange:e=>y(e.target.value),placeholder:`/home/you/project`,className:e(p,`mt-1 font-mono text-[13px]`)}),T.length>0&&(0,O.jsx)(`div`,{className:`mt-2 flex flex-wrap gap-1.5`,children:T.map(t=>(0,O.jsx)(`button`,{type:`button`,onClick:()=>y(t),className:e(`rounded-full border px-2.5 py-1 text-[12px]`,v===t?`border-accent/40 bg-accent/10 text-accent`:`border-border text-muted`),children:B(t)},t))})]}),(0,O.jsxs)(`div`,{children:[(0,O.jsx)(`label`,{className:`text-[12px] text-muted`,children:m(`What to do`)}),(0,O.jsx)(`textarea`,{value:b,onChange:e=>x(e.target.value),rows:4,autoFocus:!0,placeholder:m(`Add tests for the parser and run them`),className:e(p,`mt-1 resize-none`)})]}),(0,O.jsx)(`p`,{className:`text-[12px] text-muted`,children:m(`The agent runs on that computer with its own permissions; nanoMuse only carries the message and brings the answer back.`)}),(0,O.jsx)(`button`,{type:`button`,onClick:a,className:e(d,`w-full`),children:m(`Cancel`)})]})})}function F({who:t,agent:n,badge:r,children:i}){return(0,O.jsxs)(`div`,{className:e(`flex`,t===`you`?`justify-end`:`justify-start`),children:[t===`agent`&&(0,O.jsx)(I,{agent:n,size:24,className:`mr-2 mt-1 shrink-0`}),(0,O.jsxs)(`div`,{className:e(`max-w-[86%] rounded-3xl px-3.5 py-2 text-[14px] leading-relaxed`,t===`you`?`bubble-user rounded-br-lg bg-bubble-user text-bubble-user-fg`:`rounded-bl-lg bg-bubble-agent`),children:[r&&(0,O.jsx)(`div`,{className:`mb-0.5 text-[10.5px] font-semibold uppercase tracking-wide opacity-60`,children:r}),(0,O.jsx)(`div`,{className:`md break-words`,children:i})]})]})}function I({agent:t,size:n=28,className:r}){let i=k[t];return(0,O.jsx)(`span`,{className:e(`flex shrink-0 items-center justify-center rounded-xl bg-gradient-to-br font-bold text-white shadow-sm`,i?.tone??`from-slate-400 to-slate-600`,r),style:{width:n,height:n,fontSize:Math.round(n*.46)},"aria-hidden":!0,children:i?.glyph??(0,O.jsx)(y,{size:Math.round(n*.55)})})}function L({status:e}){let t=n();return e===`running`?(0,O.jsxs)(`span`,{className:`flex shrink-0 items-center gap-1 rounded-full bg-emerald-500/12 px-2 py-0.5 text-[10.5px] font-semibold text-emerald-700 dark:text-emerald-300`,children:[(0,O.jsx)(`span`,{className:`h-1.5 w-1.5 animate-pulse rounded-full bg-emerald-500`}),` `,t(`working`)]}):e===`active`?(0,O.jsx)(`span`,{className:`h-2 w-2 shrink-0 rounded-full bg-accent`,title:t(`active`)}):null}function R({active:t,onClick:n,icon:r,label:i}){return(0,O.jsxs)(`button`,{type:`button`,onClick:n,className:e(`flex shrink-0 items-center gap-1.5 rounded-full border px-3 py-1.5 text-[12.5px] font-medium transition`,t?`border-fg bg-fg text-bg`:`border-border bg-surface text-fg/75`),children:[r,` `,i]})}function z(e,t){return e.find(e=>e.id===t)?.name??t}function B(e){let t=e.replace(/[\\/]+$/,``).split(/[\\/]/);return t[t.length-1]||e}export{A as CodingScreen}; \ No newline at end of file diff --git a/nanomuse/server/static/assets/ConnectionsScreen-CuIVN07d.js b/nanomuse/server/static/assets/ConnectionsScreen-CuIVN07d.js new file mode 100644 index 000000000..d0dbee3c0 --- /dev/null +++ b/nanomuse/server/static/assets/ConnectionsScreen-CuIVN07d.js @@ -0,0 +1 @@ +import{A as e,E as t,J as n,K as r,L as i,Q as a,Y as o,b as s,f as c,q as l,x as u}from"./MuseHeader-RC--uR8o.js";import{C as d,D as f,O as p,S as m,_ as h,b as g,f as _,h as v,m as y,p as b,x,y as S}from"./StarNudge-Df6LQyo9.js";import{n as C,t as w}from"./external-link-TvxP_dKX.js";import{a as T,c as E,i as D,n as O,r as k,s as A,t as j}from"./Form-H3s9oTHq.js";import{t as M}from"./clapperboard-CuoVHGrc.js";import{t as N}from"./image-nIygWCIp.js";import{t as ee}from"./plug-DV_c5_Ny.js";import{t as P}from"./refresh-cw-CxZ3ZdI3.js";import{A as F,B as I,M as te,N as L,St as ne,T as R,W as z,X as re,Y as B,bt as ie,ct as ae,ft as V,lt as H,ot as oe,w as se}from"./index-tYqPtwPX.js";import{t as ce}from"./BackBar-JEuC8Q_e.js";import{t as le}from"./CloudCard-D5foJm1I.js";var ue=n(`brain-circuit`,[[`path`,{d:`M12 5a3 3 0 1 0-5.997.125 4 4 0 0 0-2.526 5.77 4 4 0 0 0 .556 6.588A4 4 0 1 0 12 18Z`,key:`l5xja`}],[`path`,{d:`M9 13a4.5 4.5 0 0 0 3-4`,key:`10igwf`}],[`path`,{d:`M6.003 5.125A3 3 0 0 0 6.401 6.5`,key:`105sqy`}],[`path`,{d:`M3.477 10.896a4 4 0 0 1 .585-.396`,key:`ql3yin`}],[`path`,{d:`M6 18a4 4 0 0 1-1.967-.516`,key:`2e4loj`}],[`path`,{d:`M12 13h4`,key:`1ku699`}],[`path`,{d:`M12 18h6a2 2 0 0 1 2 2v1`,key:`105ag5`}],[`path`,{d:`M12 8h8`,key:`1lhi5i`}],[`path`,{d:`M16 8V5a2 2 0 0 1 2-2`,key:`u6izg6`}],[`circle`,{cx:`16`,cy:`13`,r:`.5`,key:`ry7gng`}],[`circle`,{cx:`18`,cy:`3`,r:`.5`,key:`1aiba7`}],[`circle`,{cx:`20`,cy:`21`,r:`.5`,key:`yhc1fs`}],[`circle`,{cx:`20`,cy:`8`,r:`.5`,key:`1e43v0`}]]),U=n(`contact`,[[`path`,{d:`M16 2v2`,key:`scm5qe`}],[`path`,{d:`M7 22v-2a2 2 0 0 1 2-2h6a2 2 0 0 1 2 2v2`,key:`1waht3`}],[`path`,{d:`M8 2v2`,key:`pbkmx`}],[`circle`,{cx:`12`,cy:`11`,r:`3`,key:`itu57m`}],[`rect`,{x:`3`,y:`4`,width:`18`,height:`18`,rx:`2`,key:`12vinp`}]]),de=n(`eye-off`,[[`path`,{d:`M10.733 5.076a10.744 10.744 0 0 1 11.205 6.575 1 1 0 0 1 0 .696 10.747 10.747 0 0 1-1.444 2.49`,key:`ct8e1f`}],[`path`,{d:`M14.084 14.158a3 3 0 0 1-4.242-4.242`,key:`151rxh`}],[`path`,{d:`M17.479 17.499a10.75 10.75 0 0 1-15.417-5.151 1 1 0 0 1 0-.696 10.75 10.75 0 0 1 4.446-5.143`,key:`13bj9a`}],[`path`,{d:`m2 2 20 20`,key:`1ooewy`}]]),fe=n(`eye`,[[`path`,{d:`M2.062 12.348a1 1 0 0 1 0-.696 10.75 10.75 0 0 1 19.876 0 1 1 0 0 1 0 .696 10.75 10.75 0 0 1-19.876 0`,key:`1nclc0`}],[`circle`,{cx:`12`,cy:`12`,r:`3`,key:`1v7zrd`}]]),W=n(`unplug`,[[`path`,{d:`m19 5 3-3`,key:`yk6iyv`}],[`path`,{d:`m2 22 3-3`,key:`19mgm9`}],[`path`,{d:`M6.3 20.3a2.4 2.4 0 0 0 3.4 0L12 18l-6-6-2.3 2.3a2.4 2.4 0 0 0 0 3.4Z`,key:`goz73y`}],[`path`,{d:`M7.5 13.5 10 11`,key:`7xgeeb`}],[`path`,{d:`M10.5 16.5 13 14`,key:`10btkg`}],[`path`,{d:`m12 6 6 6 2.3-2.3a2.4 2.4 0 0 0 0-3.4l-2.6-2.6a2.4 2.4 0 0 0-3.4 0Z`,key:`1snsnr`}]]),pe=n(`upload`,[[`path`,{d:`M12 3v12`,key:`1x0j5s`}],[`path`,{d:`m17 8-5-5-5 5`,key:`7q97r8`}],[`path`,{d:`M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4`,key:`ih7n3h`}]]),G=a(o(),1);function me(e,t){let n=t.trim().toLowerCase();return!n||e.id.toLowerCase().includes(n)||e.name.toLowerCase().includes(n)}function he(e,t){let n=e.default&&e.rows.some(t=>t.id===e.default)?e.default:e.rows.find(e=>e.recommended)?.id,r=t&&t.group===e.key?t.id:void 0,i=[];for(let t of[n,r]){if(!t||i.some(e=>e.id===t))continue;let n=e.rows.find(e=>e.id===t);n&&i.push(n)}return[...i,...e.rows.filter(e=>!i.includes(e))]}function ge(e){return e.reduce((e,t)=>e+t.rows.length,0)}function K(e){return ge(e)>8}function _e(e,{current:t,query:n=``,expanded:r}={}){let i=n.trim().length>0,a=[];for(let o of e){let e=he(o,t);if(i){let t=e.filter(e=>me(e,n));t.length&&a.push({key:o.key,label:o.label,rows:t,more:0});continue}e.length>8&&!r?.has(o.key)?a.push({key:o.key,label:o.label,rows:e.slice(0,8),more:e.length-8}):a.push({key:o.key,label:o.label,rows:e,more:0})}return a}var q=s(),ve=`flex w-full items-center gap-2 rounded-xl px-3 py-2 text-left text-[14px] hover:bg-surface-2 focus:bg-surface-2 focus:outline-none`;function ye({label:e,text:n,heads:i=[],headValue:a,tail:o,groups:s,current:c,disabled:l,onHead:u,onPick:d,onTail:f,rowText:p}){let m=r(),[h,g]=(0,G.useState)(!1),[_,v]=(0,G.useState)(``),[y,b]=(0,G.useState)(()=>new Set),[x,S]=(0,G.useState)(!1),w=(0,G.useRef)(null),T=(0,G.useRef)(null),D=K(s),O=(0,G.useCallback)((e=!1)=>{g(!1),v(``),b(new Set),S(e)},[]);(0,G.useEffect)(()=>{!h&&x&&(S(!1),w.current?.focus())},[h,x]),(0,G.useEffect)(()=>{if(!h)return;let e=e=>{let t=e.target;T.current?.contains(t)||w.current?.contains(t)||O()},t=e=>{e.key===`Escape`&&(e.stopPropagation(),O(!0))};return document.addEventListener(`pointerdown`,e,!0),document.addEventListener(`keydown`,t,!0),()=>{document.removeEventListener(`pointerdown`,e,!0),document.removeEventListener(`keydown`,t,!0)}},[h,O]),(0,G.useEffect)(()=>{h&&T.current&&(T.current.querySelector(`input`)??T.current.querySelector(`[aria-selected="true"]`)??T.current.querySelector(`[data-row]`))?.focus()},[h]);let A=e=>{if(e.key!==`ArrowDown`&&e.key!==`ArrowUp`)return;let t=[...e.currentTarget.closest(`[role="listbox"]`)?.querySelectorAll(`[data-row]`)??[]];if(!t.length)return;e.preventDefault();let n=t.indexOf(e.target);t[e.key===`ArrowDown`?n<0?0:Math.min(t.length-1,n+1):n<0?t.length-1:Math.max(0,n-1)]?.focus()},j=_e(s,{current:c,query:_,expanded:y}),M=_.trim().length>0,N=(e,n,r,i,a)=>(0,q.jsxs)(`button`,{type:`button`,role:`option`,"aria-selected":n,"data-row":``,title:a,onClick:i,onKeyDown:A,className:t(ve,n&&`text-accent font-medium`),children:[(0,q.jsx)(`span`,{className:`min-w-0 flex-1 truncate`,children:r}),n&&(0,q.jsx)(C,{size:15,className:`shrink-0`})]},e);return(0,q.jsxs)(`div`,{className:`relative`,children:[(0,q.jsxs)(`button`,{ref:w,type:`button`,disabled:l,"aria-label":e,"aria-haspopup":`listbox`,"aria-expanded":h,title:n,onClick:()=>h?O():g(!0),className:t(k,`flex items-center gap-2 text-left text-fg disabled:opacity-50`),children:[(0,q.jsx)(`span`,{className:`min-w-0 flex-1 truncate`,children:n}),(0,q.jsx)(E,{size:16,className:`shrink-0 text-muted`})]}),h&&(0,q.jsxs)(`div`,{ref:T,role:`listbox`,"aria-label":e,className:`absolute left-0 right-0 top-full z-30 mt-1 flex max-h-[60vh] flex-col overflow-hidden rounded-2xl border border-border bg-surface p-1.5 shadow-xl`,children:[i.length>0&&(0,q.jsx)(`div`,{className:`mb-1 flex flex-col border-b border-border pb-1`,children:i.map(e=>N(`head:${e.value}`,a===e.value,e.label,()=>{u?.(e.value),O(!0)}))}),D&&(0,q.jsxs)(`label`,{className:`mb-1.5 flex items-center gap-2 rounded-xl bg-surface-2 px-3 py-2 text-muted focus-within:ring-2 focus-within:ring-accent/40`,children:[(0,q.jsx)(B,{size:15,className:`shrink-0`}),(0,q.jsx)(`input`,{type:`search`,value:_,onChange:e=>v(e.target.value),onKeyDown:A,placeholder:m(`Search models`),"aria-label":m(`Search models`),autoComplete:`off`,spellCheck:!1,className:`min-w-0 flex-1 bg-transparent text-[14px] text-fg outline-none placeholder:text-muted`})]}),(0,q.jsxs)(`div`,{className:`min-h-0 flex-1 overflow-y-auto`,children:[M&&j.length===0&&(0,q.jsx)(`div`,{className:`px-3 py-2.5 text-[13.5px] text-muted`,children:m(`No model matches`)}),j.map(e=>(0,q.jsxs)(`div`,{role:`group`,"aria-label":e.label,className:`[&+&]:mt-1.5`,children:[(0,q.jsx)(`div`,{className:`truncate px-3 pb-0.5 pt-1.5 text-[11px] font-semibold uppercase tracking-wide text-muted`,children:e.label}),e.rows.map(t=>N(`${e.key}:${t.id}`,c?.group===e.key&&c.id===t.id,p?p(t):t.name,()=>{d(e.key,t),O(!0)},t.id)),e.more>0&&(0,q.jsx)(`button`,{type:`button`,"data-row":``,onKeyDown:A,onClick:()=>b(t=>new Set([...t,e.key])),className:t(ve,`text-[13px] text-accent`),children:m(`Show {n} more`,{n:e.more})})]},e.key))]}),o&&!M&&(0,q.jsx)(`div`,{className:`mt-1 border-t border-border pt-1`,children:N(`tail`,!1,o,()=>{f?.(),O(!0)})})]})]})}var be=`nanomuse_cloud`,xe=`{{vault:NANOMUSE_CLOUD_KEY}}`,Se=`custom`,Ce=`endpoint:`,we=[`openai`,`openai_responses`];function J(e){try{return new URL(e).hostname.toLowerCase()}catch{return``}}function Te(e){return Ce+e}function Ee(e){return e.startsWith(`endpoint:`)&&e.length>9?e.slice(9):null}function De(e){if(e.label.trim())return e.label.trim();try{return new URL(e.base_url).host}catch{return e.base_url}}function Oe(e,t){return e?t.find(t=>t.id===e)??null:null}function ke(e,t=``){return e.filter(e=>e.id!==t&&e.models.length).map(e=>({key:Te(e.id),label:De(e),rows:e.models.filter(e=>f(e)!==!1).map(e=>({id:e,name:e}))})).filter(e=>e.rows.length)}function Ae(e,t,n=_){if(e&&!we.includes(e))return n.find(t=>t.id===e)??null;let r=J(t);if(!r)return null;let i=e=>[e.base_url,e.base_url_global].map(e=>J(e??``)).filter(Boolean);return n.find(e=>i(e).includes(r))||(n.find(e=>i(e).some(e=>{let t=e.indexOf(`.`);return t>0&&r.endsWith(e.slice(t))}))??null)}function je(e,t,n=``,r=_){if(e===`nanomuse_cloud`)return`nanoMuse Cloud`;if(e===`chatgpt`)return`ChatGPT`;let i=r.find(t=>t.id===e);return i&&e!==`custom`?g(i,t):J(n)||e}function Y(e,t,n=_,r=[]){if(!e.effective_provider)return``;let i=Oe(e.endpoint,r),a=i?De(i):je(e.effective_provider,t,e.base_url,n);return e.effective_model?`${a} · ${e.effective_model}`:a}function Me(e,t,n,r=_,i=[]){let a=e.effective_model??``;if(!a)return``;let o=(e,t)=>je(Ae(e,t,r)?.id??(we.includes(e)?`custom`:e),n,t,r),s,c=Oe(e.endpoint,i),l=Oe(t.endpoint,i);return s=e.effective_source===`cloud`?`nanoMuse Cloud`:e.effective_source===`gui`&&c?De(c):e.effective_source===`gui`&&(e.provider_id||e.base_url||!we.includes(e.provider||`openai`))?e.provider_id?je(e.provider_id,n,e.base_url,r):o(e.provider,e.base_url):t.cloud?`nanoMuse Cloud`:l?De(l):o(t.provider,t.base_url),`${s} · ${a}`}function Ne(e,t){let n=t.list??_,r=[];t.signedIn&&r.push({value:be,label:`nanoMuse Cloud`,group:`cloud`,needsKey:!1,entry:null});let i=t.chat.cloud?null:Ae(t.chat.provider,t.chat.base_url,n);i&&i.capabilities.includes(e)&&r.push({value:i.id,label:g(i,t.locale),group:`chat`,needsKey:!1,entry:i});for(let e of t.endpoints??[])r.push({value:Te(e.id),label:De(e),group:`endpoints`,needsKey:!1,entry:null});for(let a of x(t.region,e,n))a.id!==i?.id&&r.push({value:a.id,label:g(a,t.locale),group:`add`,needsKey:!0,entry:a});return r.push({value:Se,label:``,group:`add`,needsKey:!1,entry:null}),r}function Pe(e,t){return e.configured?t&&e.base_url&&J(e.base_url)===J(t)?be:e.endpoint?Te(e.endpoint):e.provider_id||`custom`:``}var Fe=`nanomuse_cloud`,Ie=`add-endpoint`;function Le(){let{state:e}=c(),[t,n]=(0,G.useState)(null),[i,a]=(0,G.useState)(null),o=e.profile?.name??`nanoMuse`,s=r(),d=(0,G.useCallback)(async()=>{try{n(await u.connections()),a(null)}catch(e){a(s(e.message))}},[s]);return(0,G.useEffect)(()=>{d()},[d,e.connectionsVersion]),(0,q.jsxs)(`div`,{className:`flex h-full flex-col`,children:[(0,q.jsx)(ce,{title:s(`Connections`),description:s(`What {name} can reach; keys stay in the vault on this machine.`,{name:o})}),(0,q.jsxs)(`div`,{className:`flex-1 overflow-y-auto px-4 pb-8 space-y-4`,children:[i&&(0,q.jsx)(`div`,{className:`rounded-2xl bg-rose-500/12 text-rose-700 dark:text-rose-300 p-3 text-[13.5px]`,children:i}),!t&&!i&&(0,q.jsx)(`div`,{className:`flex justify-center py-10 text-muted`,children:(0,q.jsx)(l,{className:`animate-spin`,size:20})}),t&&(0,q.jsxs)(q.Fragment,{children:[(0,q.jsx)(Re,{data:t,onChange:d}),t.image&&(0,q.jsx)(X,{slot:`image`,data:t,onChange:d}),t.video&&(0,q.jsx)(X,{slot:`video`,data:t,onChange:d}),(0,q.jsx)(le,{account:e.hub?.account??null,onChange:d}),t.embeddings.memory_enabled&&(0,q.jsx)(Z,{data:t,onChange:d}),(0,q.jsx)(He,{data:t,onChange:d}),(0,q.jsx)(We,{data:t,onChange:d}),(0,q.jsx)(Ke,{data:t,onChange:d}),(0,q.jsx)(qe,{data:t,onChange:d}),(0,q.jsx)(Je,{data:t,onChange:d}),(0,q.jsx)(Ye,{data:t,onChange:d}),(0,q.jsx)(Xe,{data:t,onChange:d}),(0,q.jsx)(Ze,{data:t,onChange:d})]})]})]})}function Re({data:e,onChange:n,compact:a}){let{toast:o,state:s}=c(),v=r(),[x,S]=(0,G.useState)(!!a),T=e.providers,D=e.endpoints??[],O=e.endpoints!==void 0,k=D.find(t=>t.id===e.llm.endpoint)??null,M=!!s.hub?.account?.any_model,N=(k?Te(k.id):null)??Object.entries(T).find(([t,n])=>t!==`custom`&&n.base_url&&e.llm.base_url.startsWith(n.base_url)&&n.provider===e.llm.provider)?.[0]??Object.entries(T).find(([t,n])=>t!==`custom`&&n.base_url&&e.llm.base_url.startsWith(n.base_url))?.[0]??(e.llm.base_url?`custom`:`deepseek`),P=e=>{if(e===Ie)return{label:v(`Add an endpoint`),subtitle:T.custom?.subtitle,group:`local`,provider:`openai`,base_url:``,key_optional:!0};let t=Ee(e);if(!t)return T[e];let n=D.find(e=>e.id===t);return n?{label:De(n),group:`local`,provider:`openai`,base_url:n.base_url,models:n.models,no_key:!0}:void 0},[F,I]=(0,G.useState)(N),R=(0,G.useRef)(``),[z,B]=(0,G.useState)(e.llm.model),[ie,V]=(0,G.useState)(e.llm.base_url),[H,oe]=(0,G.useState)(``),[se,ce]=(0,G.useState)(!1),[le,ue]=(0,G.useState)(!1),[U,W]=(0,G.useState)(e.llm.key_source===`none`&&!!T[N]?.key_optional),[pe,me]=(0,G.useState)(e.llm.tool_mode||`auto`),[he,ge]=(0,G.useState)(e.llm.proxy??``),[K,_e]=(0,G.useState)(!1),[ve,be]=(0,G.useState)(!1),[xe,Se]=(0,G.useState)(null),[Ce,we]=(0,G.useState)(!1),[J,Oe]=(0,G.useState)(e.gui?.model??``),[Ae,je]=(0,G.useState)(e.gui?.endpoint??``),[Y,Ne]=(0,G.useState)({list:P(N)?.models??[],image:[],video:[],menu:[],catalog:[],imageCatalog:[],videoCatalog:[],vision:[],gui:T[N]?.gui_models??[],source:`catalogue`}),[Pe,Le]=(0,G.useState)(!1),[Re,ze]=(0,G.useState)(!1);(0,G.useEffect)(()=>{B(e.llm.model),V(e.llm.base_url),me(e.llm.tool_mode||`auto`),ge(e.llm.proxy??``),_e(!1),Oe(e.gui?.model??``),je(e.gui?.endpoint??``);let t=D.find(e=>e.id===R.current);if(t){R.current=``,I(Te(t.id)),V(t.base_url),t.models.includes(e.llm.model)||B(t.models[0]??``),Le(!1);return}I(N)},[e.llm,e.gui?.model,e.gui?.endpoint,e.endpoints]);let X=P(F),Z=D.find(e=>Te(e.id)===F)??null,He=F===Ie,Ue=F===`custom`||!X?.base_url?ie:X.base_url;(0,G.useEffect)(()=>{if(!x||He)return;let e=!0,t=setTimeout(()=>{Ne(e=>({...e,source:`loading`})),u.llmModels(Z?{endpoint:Z.id}:{preset:F,base_url:Ue,api_key:H||void 0}).then(t=>{e&&(Ne({list:t.models,image:t.image_models??[],video:t.video_models??[],menu:t.menu??[],catalog:t.catalog??[],imageCatalog:t.image_catalog??[],videoCatalog:t.video_catalog??[],vision:t.vision??[],gui:t.gui??T[F]?.gui_models??[],source:t.source}),t.source===`live`&&t.models.length&&!Pe&&B(e=>t.models.includes(e)?e:t.models[0]))}).catch(()=>e&&Ne({list:X?.models??[],image:[],video:[],menu:[],catalog:[],imageCatalog:[],videoCatalog:[],vision:[],gui:X?.gui_models??[],source:`catalogue`}))},H?600:150);return()=>{e=!1,clearTimeout(t)}},[x,F,Ue,H]);let We=t=>{I(t);let n=P(t);n&&(n.base_url?V(n.base_url):X?.base_url&&V(``),(!z||Object.values(T).some(e=>e.models?.includes(z))||D.some(e=>e.models.includes(z)))&&n.models?.length&&!n.models.includes(z)&&B(n.models[0]),Ne({list:n.models??[],image:[],video:[],menu:[],catalog:[],imageCatalog:[],videoCatalog:[],vision:[],gui:n.gui_models??[],source:`catalogue`}),(!e.gui?.model||Object.values(T).some(t=>t.gui_model===e.gui?.model))&&Oe(n.cloud?``:n.gui_model??``),ze(!1),Le(!1),W(!1))};(0,G.useEffect)(()=>{let e=te();e&&T[e]&&(S(!0),We(e))},[]);let Ge=!!X?.no_key||U&&!!X?.key_optional,Ke=e.llm.cloud?{text:v(`Your account's model`),tone:`ok`}:e.llm.key_source===`none`&&k?{text:v(`No key`),tone:`ok`}:e.llm.key_source===`none`&&!T[N]?.no_key&&!T[N]?.key_optional?{text:v(`No key yet`),tone:`warn`}:e.llm.key_source===`missing`?{text:v(`Key missing from vault`),tone:`warn`}:{text:e.llm.key_source===`vault`?v(`Key in vault`):e.llm.key_source===`config`?v(`Key from config`):v(`No key needed`),tone:`ok`},qe=async()=>{be(!0),Se(null);try{X?.cloud?await u.cloudUseAsModel(z.trim()):Z?await u.setLLM({endpoint:Z.id,model:z.trim(),tool_mode:pe,proxy:K&&e.llm.proxy!==void 0?he.trim():null}):await u.setLLM({provider:X?.provider??`openai`,model:z.trim(),base_url:Ue.trim(),tool_mode:pe,api_key:H||(Ge?``:null),proxy:K&&e.llm.proxy!==void 0?he.trim():null});let t={model:e.gui?.model??``,endpoint:e.gui?.endpoint??``};(J.trim()!==t.model||Ae!==t.endpoint)&&(Ae?await u.setGui({endpoint:Ae,model:J.trim()}):t.endpoint?await u.setGui({model:J.trim(),provider:``,base_url:``,api_key:``}):await u.setGui({model:J.trim()})),oe(``),h(),o(v(`Model saved`)),n(),a||S(!1)}catch(e){o(e.message)}finally{be(!1)}},Je=async()=>{we(!0);try{Se(await u.testLLM())}catch(e){Se({ok:!1,error:e.message})}finally{we(!1)}},Ye=[{id:`cloud`,title:v(`Your account`),ids:[]},{id:`openai`,title:v(`OpenAI-compatible · Chat Completions`),ids:[]},{id:`responses`,title:v(`Responses API`),ids:[]},{id:`local`,title:v(`Local or your own endpoint`),ids:[]}];for(let[e,t]of Object.entries(T))(Ye.find(e=>e.id===(t.group??`openai`))??Ye[0]).ids.push(e);for(let e of Ye)e.ids=p(e.ids,T,s.hub?.account);let Xe=Ye.find(e=>e.id===`local`);if(Xe){let e=Xe.ids.filter(e=>e!==`custom`||!O||N===`custom`);Xe.ids=[...D.map(e=>Te(e.id)),...e,...O?[Ie]:[]]}let Ze=!Z&&!He&&(F===`custom`||!X?.base_url),Q=X?.cloud||Z||He?null:_.find(e=>e.id===b(F))??null,et=m(s.hub?.account),tt=i(),nt=e=>!!Q&&!Q.user_capabilities&&!Q.capabilities.includes(e),at=T[Fe],ot=X?.cloud?Y.gui[0]??X.gui_model??``:Q&&!Q.user_capabilities?Q.capabilities.includes(`vision`)?Q.defaults.hands||z.trim():at?.gui_model??z.trim():z.trim(),st=!X?.cloud&&nt(`vision`)&&!!at,ct=e.gui?Me(e.gui,e.llm,tt,_,D):``,lt=Array.from(new Set([...X?.cloud?Y.gui:[],...X?.gui_model?[X.gui_model]:[],...Y.list.filter(e=>Y.vision.includes(e)||f(e)===!0)])).filter(Boolean),ut=X?.cloud?`nanoMuse Cloud`:Z?De(Z):Q?g(Q,tt):it(Ue)||F,dt=X?.cloud?Y.gui[0]??X.gui_model??``:Q?.defaults.hands??X?.gui_model??``,ft=[{key:`hands`,label:ut,rows:lt.map(e=>({id:e,name:e})),...dt?{default:dt}:{}},...ke(D,Z?.id??``)],pt=Ae&&Ae!==Z?.id?Te(Ae):`hands`,mt=D.find(e=>e.id===Ae)??null,ht=J?`${pt===`hands`?ut:mt?De(mt):``} · ${J}`:v(`Automatic`),gt=Ze&&/^https?:\/\/[^/]+\/?$/.test(ie.trim());return(0,q.jsxs)(j,{icon:(0,q.jsx)(ne,{size:19}),title:v(`Chat model`),summary:e.llm.cloud?`nanoMuse Cloud · ${e.llm.model||v(`No model yet`)}`:k?`${e.llm.model||v(`No model yet`)} · ${De(k)}`:`${e.llm.model||v(`No model yet`)}${e.llm.base_url?` · ${it(e.llm.base_url)}`:``}`,status:Ke,open:x,onToggle:a?void 0:()=>S(!x),children:[(0,q.jsx)($,{label:v(`Provider`),children:(0,q.jsxs)(`div`,{className:`space-y-2.5`,children:[Ye.filter(e=>e.ids.length).map(e=>(0,q.jsxs)(`div`,{children:[(0,q.jsx)(`div`,{className:`mb-1 text-[11px] uppercase tracking-wide text-muted`,children:e.title}),(0,q.jsx)(`div`,{className:`flex flex-wrap gap-1.5`,children:e.ids.map(e=>{let n=P(e);if(!n)return null;let r=D.find(t=>Te(t.id)===e),i=r?it(r.base_url)===n.label?void 0:it(r.base_url):n.subtitle?v(n.subtitle):void 0;return(0,q.jsxs)(`button`,{type:`button`,onClick:()=>We(e),className:t(`rounded-2xl px-3 py-1.5 text-left border leading-tight`,F===e?`border-accent bg-accent/10 text-accent`:`border-border text-muted`),children:[(0,q.jsxs)(`span`,{className:t(`block text-[13px]`,F===e&&`font-medium`,e===Ie&&`inline-flex items-center gap-1`),children:[e===Ie&&(0,q.jsx)(re,{size:13}),n.label]}),i&&(0,q.jsx)(`span`,{className:`block text-[10.5px] opacity-80`,children:i})]},e)})})]},e.id)),Q&&(0,q.jsxs)(`p`,{className:`text-[12px] text-muted`,children:[(0,q.jsx)(`span`,{className:`font-medium text-fg`,children:g(Q,tt)}),` · `,y(v,Q.capabilities),`. `,tt===`zh-CN`?Q.note_zh:Q.note]}),(0,q.jsxs)(`div`,{children:[(0,q.jsxs)(`button`,{type:`button`,onClick:()=>ue(!le),className:`inline-flex items-center gap-1.5 text-[12.5px] text-accent`,children:[(0,q.jsx)(ae,{size:13}),` `,v(`Or sign in with a ChatGPT plan`),` `,le?(0,q.jsx)(A,{size:13}):(0,q.jsx)(E,{size:13})]}),le&&(0,q.jsx)(`div`,{className:`mt-2`,children:(0,q.jsx)(L,{compact:!0,onChanged:()=>{n()}})})]})]})}),He&&(0,q.jsx)(Be,{onAdded:e=>{R.current=e.id,h(),n()}}),Z&&(0,q.jsx)($,{label:v(`Endpoint`),children:(0,q.jsx)(Ve,{endpoint:Z,onChange:()=>{h(),n()},onModels:e=>{Ne(t=>({...t,list:e,source:`live`})),e.length&&!Pe&&!e.includes(z)&&B(e[0])}})}),Ze&&(0,q.jsx)($,{label:v(`Base URL`),hint:v(gt?`/v1 is added when the URL has no path.`:`The endpoint that serves /chat/completions, for example http://127.0.0.1:8000/v1.`),children:(0,q.jsx)(`input`,{value:ie,onChange:e=>V(e.target.value),className:`w-full rounded-2xl bg-surface-2 px-3.5 py-2.5 text-[14.5px] outline-none focus:ring-2 focus:ring-accent/40`,placeholder:`https://host/v1`,inputMode:`url`,autoCapitalize:`off`})}),!He&&(0,q.jsxs)($,{label:v(`Chat model`),hint:X?.cloud&&M&&Y.catalog.length?v(`{n} models your account may use: the menu first, then everything else the provider lists under the Cloud key. Pick one; the ones beyond the menu are priced as the dearest menu model of their kind.`,{n:Y.list.length}):X?.cloud&&M?v(`Your account may name any model the provider has, not only these: type its id (a chat model here, a picture or clip model below) and it goes through as typed.`):Y.source===`live`?v(`{n} models from the endpoint`,{n:Y.list.length}):Y.source===`loading`?v(`Asking the endpoint…`):Y.list.length&&Z?v(`{n} models saved with this endpoint`,{n:Y.list.length}):Y.list.length?v(`Could not list the endpoint's models; these are the usual ones.`):void 0,children:[X?.cloud&&Y.catalog.length>0&&!Re&&(!z||Y.list.includes(z))?(0,q.jsxs)(`select`,{value:z,onChange:e=>{if(e.target.value===Qe){ze(!0);return}B(e.target.value),Le(!0)},className:t(`w-full rounded-2xl bg-surface-2 px-3.5 py-2.5 text-[14.5px] outline-none focus:ring-2 focus:ring-accent/40`,`text-fg`),children:[!z&&(0,q.jsx)(`option`,{value:``,children:v(`model name`)}),(0,q.jsx)(`optgroup`,{label:v(`Menu`),children:Y.menu.map(e=>(0,q.jsx)(`option`,{value:e,children:Y.vision.includes(e)?`${e} · ${v(`reads pictures`)}`:e},e))}),(0,q.jsx)(`optgroup`,{label:v(`More models on your account`),children:Y.catalog.map(e=>(0,q.jsx)(`option`,{value:e,children:Y.vision.includes(e)?`${e} · ${v(`reads pictures`)}`:e},e))}),(0,q.jsx)(`option`,{value:Qe,children:v(`Type a model id…`)})]}):(0,q.jsxs)(q.Fragment,{children:[(0,q.jsx)(`input`,{list:`om-models`,value:z,onChange:e=>{B(e.target.value),Le(!0)},className:`w-full rounded-2xl bg-surface-2 px-3.5 py-2.5 text-[14.5px] outline-none focus:ring-2 focus:ring-accent/40`,placeholder:v(`model name`),autoCapitalize:`off`,autoCorrect:`off`,autoFocus:Re}),(0,q.jsx)(`datalist`,{id:`om-models`,children:Y.list.map(e=>(0,q.jsx)(`option`,{value:e},e))}),X?.cloud&&Y.catalog.length>0&&(0,q.jsx)(`button`,{type:`button`,className:`mt-1.5 text-[12px] text-accent`,onClick:()=>{ze(!1),Y.list.includes(z)||B(Y.menu[0]??Y.list[0]??``)},children:v(`Pick from the list`)})]}),Y.list.length>0&&(0,q.jsx)(`div`,{className:`mt-1.5 flex flex-wrap gap-1.5`,children:(Y.menu.length?Y.menu:Y.list).slice(0,8).map(e=>(0,q.jsx)(`button`,{type:`button`,onClick:()=>B(e),className:t(`rounded-full px-2.5 py-1 text-[12px] border`,z===e?`border-accent bg-accent/10 text-accent font-medium`:`border-border text-muted`),children:e},e))})]}),!He&&(0,q.jsxs)($,{label:v(`Hands model`),hint:X?.cloud?v(`The model that looks at screens when the hands run: the phone, this computer, a page the browser cannot read. Your account's hands model is {model}; the chat model above is a different pick.`,{model:ot||v(`none`)}):st?v(`The model that looks at screens when the hands run. This provider has no model that sees, so the hands use your account's, {model}, unless you pick one here.`,{model:ot||v(`none`)}):D.length>+!!Z?v(`The model that looks at screens when the hands run: a small, fast one that takes pictures. Pick one of this provider's, or one from another endpoint of your list, which then lends its address and key.`):v(`The model that looks at screens when the hands run: a small, fast one that takes pictures, on the same endpoint and key. Default: this provider's own hands model.`),children:[(0,q.jsx)(ye,{label:v(`Hands model`),text:ht,heads:[{value:``,label:v(`Automatic`)}],headValue:J?void 0:``,groups:ft,current:J?{group:pt,id:J}:void 0,onHead:()=>{Oe(``),je(``)},onPick:(e,t)=>{Oe(t.id),je(Ee(e)??``)}}),ct&&(0,q.jsx)(`p`,{className:`mt-1.5 text-[12px] text-muted`,children:v(`Currently {value}`,{value:ct})}),!X?.cloud&&z.trim()&&!J&&f(z.trim())===!1&&(0,q.jsx)(`div`,{className:`mt-1.5 text-[12px] text-amber-700 dark:text-amber-300`,children:v(`{model} does not take pictures, so the hands would be blind with it. Pick a model that sees for them.`,{model:z.trim()})}),nt(`vision`)&&!st&&(0,q.jsxs)(`div`,{className:`mt-1.5 text-[12px] text-amber-700 dark:text-amber-300`,children:[d(v,`vision`,et,tt),` `,(0,q.jsx)($e,{})]})]}),!X?.no_key&&!He&&(0,q.jsxs)($,{label:v(`API key`),hint:U&&X?.key_optional?v(`No key will be sent.`):e.llm.key_source===`vault`&&F===N?v(`A key is in the vault. Leave blank to keep it.`):v(`Stored encrypted in the vault as LLM_API_KEY.`),children:[(0,q.jsxs)(`div`,{className:`relative`,children:[(0,q.jsx)(`input`,{type:se?`text`:`password`,value:H,onChange:e=>oe(e.target.value),disabled:U&&!!X?.key_optional,"aria-label":v(`API key`),className:t(`w-full rounded-2xl bg-surface-2 px-3.5 py-2.5 text-[14.5px] outline-none focus:ring-2 focus:ring-accent/40`,`pr-10 disabled:opacity-50`),placeholder:e.llm.key_source===`vault`&&F===N?`••••••••`:X?.key_hint||`sk-…`,autoComplete:`off`,autoCapitalize:`off`,spellCheck:!1}),(0,q.jsx)(`button`,{type:`button`,onClick:()=>ce(!se),"aria-label":v(se?`Hide key`:`Show key`),className:`absolute right-2 top-1/2 -translate-y-1/2 rounded-full p-1.5 text-muted`,children:se?(0,q.jsx)(de,{size:16}):(0,q.jsx)(fe,{size:16})})]}),(0,q.jsxs)(`div`,{className:`mt-1.5 flex items-center justify-between gap-2 text-[12px]`,children:[X?.key_url?(0,q.jsxs)(`a`,{href:X.key_url,target:`_blank`,rel:`noreferrer`,className:`inline-flex items-center gap-1 text-accent`,children:[v(`Get a key from {vendor}`,{vendor:X.label}),` `,(0,q.jsx)(w,{size:12})]}):(0,q.jsx)(`span`,{}),X?.key_optional&&(0,q.jsxs)(`label`,{className:`inline-flex items-center gap-1.5 text-muted`,children:[(0,q.jsx)(`input`,{type:`checkbox`,checked:U,onChange:e=>W(e.target.checked),className:`accent-accent`}),` `,v(`No key`)]})]})]}),!He&&(0,q.jsx)($,{label:v(`Tool calling`),hint:v(`Auto uses the API's function calling and falls back to describing tools in the prompt when the endpoint rejects them. Prompt: for endpoints that silently ignore tools.`),children:(0,q.jsx)(`div`,{className:`flex gap-1.5`,children:[`auto`,`native`,`prompt`].map(e=>(0,q.jsx)(`button`,{type:`button`,onClick:()=>me(e),className:t(`rounded-full px-3 py-1.5 text-[13px] border`,pe===e?`border-accent bg-accent/10 text-accent font-medium`:`border-border text-muted`),children:e},e))})}),!X?.cloud&&!He&&e.llm.proxy!==void 0&&(0,q.jsx)($,{label:v(`Proxy (optional)`),hint:v(`Only this provider's requests go through it. nanoMuse Cloud never does.`),children:(0,q.jsx)(`input`,{className:`w-full rounded-2xl bg-surface-2 px-3.5 py-2.5 text-[14.5px] outline-none focus:ring-2 focus:ring-accent/40`,value:he,onChange:e=>{ge(e.target.value),_e(!0)},onFocus:()=>he.includes(`••••`)&&!K&&ge(``),onBlur:()=>!K&&ge(e.llm.proxy??``),placeholder:`http://host:port / socks5://host:port`,autoComplete:`off`,spellCheck:!1})}),!He&&(0,q.jsxs)(`div`,{className:`flex gap-2 pt-1`,children:[(0,q.jsxs)(`button`,{type:`button`,disabled:ve||!z.trim()||Ze&&!ie.trim(),onClick:()=>void qe(),className:`flex items-center justify-center gap-1.5 rounded-2xl bg-accent text-accent-fg px-4 py-2.5 text-[14px] font-medium disabled:opacity-40`,children:[ve?(0,q.jsx)(l,{size:16,className:`animate-spin`}):(0,q.jsx)(C,{size:16}),` `,v(`Save`)]}),(0,q.jsxs)(`button`,{type:`button`,disabled:Ce,onClick:()=>void Je(),className:`flex items-center justify-center gap-1.5 rounded-2xl border border-border px-4 py-2.5 text-[14px] font-medium text-muted disabled:opacity-40`,children:[Ce?(0,q.jsx)(l,{size:16,className:`animate-spin`}):(0,q.jsx)(ee,{size:16}),` `,v(`Test`)]})]}),xe&&(0,q.jsx)(rt,{result:xe,okText:v(`Replied "{reply}" in {ms} ms`,{reply:xe.reply??``,ms:xe.ms??0})})]})}var ze={chat:`the chat model`,hands:`the hands`,image:`pictures`,video:`clips`};function Be({onAdded:e}){let n=r(),{toast:i}=c(),[a,o]=(0,G.useState)(``),[s,d]=(0,G.useState)(``),[f,p]=(0,G.useState)(``),[m,h]=(0,G.useState)(!1),[g,_]=(0,G.useState)(!1),[v,y]=(0,G.useState)(``),[b,x]=(0,G.useState)(null),[S,C]=(0,G.useState)(!1),w=/^https?:\/\/[^/]+\/?$/.test(s.trim()),T=async()=>{C(!0),x(null);try{let t=await u.addEndpoint({label:a.trim(),base_url:s.trim(),api_key:g?``:f,models:v});i(n(`Endpoint added`)),e(t)}catch(e){x(n(e.message))}finally{C(!1)}};return(0,q.jsxs)(`div`,{className:`space-y-3 rounded-2xl border border-border p-3`,children:[(0,q.jsx)(`p`,{className:`text-[12.5px] text-muted leading-snug`,children:n(`An endpoint joins your list with its own key and stays there; add as many as you use. Pick one as the chat model, or use its models for the hands, pictures and clips.`)}),(0,q.jsx)($,{label:n(`Name (optional)`),hint:n(`How the endpoint reads in the lists; its host when left empty.`),children:(0,q.jsx)(`input`,{value:a,onChange:e=>o(e.target.value),className:k,placeholder:n(`for example: my gateway`),autoCapitalize:`off`})}),(0,q.jsx)($,{label:n(`Base URL`),hint:n(w?`/v1 is added when the URL has no path.`:`The endpoint that serves /chat/completions, for example http://127.0.0.1:8000/v1.`),children:(0,q.jsx)(`input`,{value:s,onChange:e=>d(e.target.value),className:k,placeholder:`https://host/v1`,inputMode:`url`,autoCapitalize:`off`})}),(0,q.jsxs)($,{label:n(`API key`),hint:n(g?`No key will be sent.`:`Stored encrypted in the vault under this endpoint's own name.`),children:[(0,q.jsxs)(`div`,{className:`relative`,children:[(0,q.jsx)(`input`,{type:m?`text`:`password`,value:f,onChange:e=>p(e.target.value),disabled:g,"aria-label":n(`API key`),className:t(k,`pr-10 disabled:opacity-50`),placeholder:`sk-…`,autoComplete:`off`,autoCapitalize:`off`,spellCheck:!1}),(0,q.jsx)(`button`,{type:`button`,onClick:()=>h(!m),"aria-label":n(m?`Hide key`:`Show key`),className:`absolute right-2 top-1/2 -translate-y-1/2 rounded-full p-1.5 text-muted`,children:m?(0,q.jsx)(de,{size:16}):(0,q.jsx)(fe,{size:16})})]}),(0,q.jsxs)(`label`,{className:`mt-1.5 inline-flex items-center gap-1.5 text-[12px] text-muted`,children:[(0,q.jsx)(`input`,{type:`checkbox`,checked:g,onChange:e=>_(e.target.checked),className:`accent-accent`}),` `,n(`No key`)]})]}),(0,q.jsx)($,{label:n(`Models (optional)`),hint:n(`Leave empty when the endpoint lists its models at /models. Otherwise type their ids, separated by commas.`),children:(0,q.jsx)(`input`,{value:v,onChange:e=>y(e.target.value),className:k,placeholder:`model-a, model-b`,autoCapitalize:`off`,autoCorrect:`off`,spellCheck:!1})}),b&&(0,q.jsx)(`div`,{className:`rounded-2xl bg-rose-500/12 px-3 py-2 text-[12.5px] text-rose-700 dark:text-rose-300`,children:b}),(0,q.jsxs)(`button`,{type:`button`,disabled:S||!s.trim(),onClick:()=>void T(),className:D,children:[S?(0,q.jsx)(l,{size:16,className:`animate-spin`}):(0,q.jsx)(re,{size:16}),` `,n(`Add endpoint`)]})]})}function Ve({endpoint:e,onChange:n,onModels:a}){let o=r(),{toast:s}=c(),[d,f]=(0,G.useState)(``),[p,m]=(0,G.useState)(e.label),[h,g]=(0,G.useState)(``),[_,v]=(0,G.useState)(!1),[y,b]=(0,G.useState)(!1),[x,S]=(0,G.useState)(e.models.join(`, `)),[C,w]=(0,G.useState)(!1),[T,E]=(0,G.useState)(null),D=e.models.join(`, `);(0,G.useEffect)(()=>{m(e.label),S(D),f(``),g(``),b(!1),E(null)},[e.id,e.label,D]);let O=async(e,t)=>{w(!0),E(null);try{await e(),t&&s(t),f(``),n()}catch(e){E(o(e.message))}finally{w(!1)}},k=async()=>{w(!0),E(null);try{let t=await u.refreshEndpointModels(e.id);t.source===`live`?(a(t.models),s(o(`{n} models from the endpoint`,{n:t.models.length})),n()):E(o(`The endpoint did not list its models; the saved list stands.`)+(t.error?` ${o(t.error)}`:``))}catch(e){E(o(e.message))}finally{w(!1)}},A=e.key_source===`vault`?o(`Key in vault`):e.key_source===`config`?o(`Key from config`):e.key_source===`missing`?o(`Key missing from vault`):o(`No key`),j=e.slots.map(e=>o(ze[e])).join(i()===`zh-CN`?`、`:`, `),M=e.slots.includes(`chat`),N=`text-[12.5px] text-accent disabled:opacity-50`;return(0,q.jsxs)(`div`,{className:`space-y-2 rounded-2xl border border-border p-3 text-[13px]`,children:[(0,q.jsxs)(`div`,{children:[(0,q.jsx)(`span`,{className:`font-medium text-fg`,children:De(e)}),(0,q.jsxs)(`span`,{className:`text-muted`,children:[` · `,it(e.base_url)]})]}),(0,q.jsxs)(`div`,{className:`text-[12px] text-muted`,children:[A,` · `,o(`{n} models`,{n:e.models.length}),j?` · ${o(`Used by {slots}`,{slots:j})}`:``]}),d===``&&(0,q.jsxs)(`div`,{className:`flex flex-wrap gap-x-3 gap-y-1`,children:[(0,q.jsx)(`button`,{type:`button`,className:N,disabled:C,onClick:()=>f(`rename`),children:o(`Rename`)}),(0,q.jsx)(`button`,{type:`button`,className:N,disabled:C,onClick:()=>f(`key`),children:o(`Change key`)}),(0,q.jsx)(`button`,{type:`button`,className:N,disabled:C,onClick:()=>f(`models`),children:o(`Edit models`)}),(0,q.jsxs)(`button`,{type:`button`,className:N,disabled:C,onClick:()=>void k(),children:[C?(0,q.jsx)(l,{size:12,className:`inline animate-spin`}):(0,q.jsx)(P,{size:12,className:`inline`}),` `,o(`Ask for its models`)]}),(0,q.jsx)(`button`,{type:`button`,className:t(N,`text-rose-600 dark:text-rose-300`),disabled:C,onClick:()=>f(`remove`),children:o(`Remove`)})]}),d===`rename`&&(0,q.jsxs)(`div`,{className:`space-y-2`,children:[(0,q.jsx)(`input`,{value:p,onChange:e=>m(e.target.value),className:`w-full rounded-2xl bg-surface-2 px-3.5 py-2.5 text-[14.5px] outline-none focus:ring-2 focus:ring-accent/40`,placeholder:it(e.base_url),autoCapitalize:`off`,"aria-label":o(`Name`)}),(0,q.jsxs)(`div`,{className:`flex gap-2`,children:[(0,q.jsx)(`button`,{type:`button`,disabled:C,className:`flex items-center justify-center gap-1.5 rounded-2xl bg-accent text-accent-fg px-4 py-2.5 text-[14px] font-medium disabled:opacity-40`,onClick:()=>void O(()=>u.updateEndpoint(e.id,{label:p.trim()}),o(`Endpoint renamed`)),children:o(`Save`)}),(0,q.jsx)(`button`,{type:`button`,className:`flex items-center justify-center gap-1.5 rounded-2xl border border-border px-4 py-2.5 text-[14px] font-medium text-muted disabled:opacity-40`,onClick:()=>f(``),children:o(`Cancel`)})]})]}),d===`key`&&(0,q.jsxs)(`div`,{className:`space-y-2`,children:[(0,q.jsxs)(`div`,{className:`relative`,children:[(0,q.jsx)(`input`,{type:_?`text`:`password`,value:h,onChange:e=>g(e.target.value),disabled:y,className:t(`w-full rounded-2xl bg-surface-2 px-3.5 py-2.5 text-[14.5px] outline-none focus:ring-2 focus:ring-accent/40`,`pr-10 disabled:opacity-50`),placeholder:e.key_source===`vault`?`••••••••`:`sk-…`,"aria-label":o(`API key`),autoComplete:`off`,autoCapitalize:`off`,spellCheck:!1}),(0,q.jsx)(`button`,{type:`button`,onClick:()=>v(!_),"aria-label":o(_?`Hide key`:`Show key`),className:`absolute right-2 top-1/2 -translate-y-1/2 rounded-full p-1.5 text-muted`,children:_?(0,q.jsx)(de,{size:16}):(0,q.jsx)(fe,{size:16})})]}),(0,q.jsxs)(`label`,{className:`inline-flex items-center gap-1.5 text-[12px] text-muted`,children:[(0,q.jsx)(`input`,{type:`checkbox`,checked:y,onChange:e=>b(e.target.checked),className:`accent-accent`}),` `,o(`No key`)]}),(0,q.jsxs)(`div`,{className:`flex gap-2`,children:[(0,q.jsx)(`button`,{type:`button`,disabled:C||!y&&!h.trim(),className:`flex items-center justify-center gap-1.5 rounded-2xl bg-accent text-accent-fg px-4 py-2.5 text-[14px] font-medium disabled:opacity-40`,onClick:()=>void O(()=>u.updateEndpoint(e.id,{api_key:y?``:h.trim()}),o(`Key saved`)),children:o(`Save`)}),(0,q.jsx)(`button`,{type:`button`,className:`flex items-center justify-center gap-1.5 rounded-2xl border border-border px-4 py-2.5 text-[14px] font-medium text-muted disabled:opacity-40`,onClick:()=>f(``),children:o(`Cancel`)})]})]}),d===`models`&&(0,q.jsxs)(`div`,{className:`space-y-2`,children:[(0,q.jsx)(`input`,{value:x,onChange:e=>S(e.target.value),className:`w-full rounded-2xl bg-surface-2 px-3.5 py-2.5 text-[14.5px] outline-none focus:ring-2 focus:ring-accent/40`,placeholder:`model-a, model-b`,"aria-label":o(`Models`),autoCapitalize:`off`,autoCorrect:`off`,spellCheck:!1}),(0,q.jsx)(`div`,{className:`text-[12px] text-muted`,children:o(`The ids of the models this endpoint serves, separated by commas; what it lists at /models is added after them.`)}),(0,q.jsxs)(`div`,{className:`flex gap-2`,children:[(0,q.jsx)(`button`,{type:`button`,disabled:C,className:`flex items-center justify-center gap-1.5 rounded-2xl bg-accent text-accent-fg px-4 py-2.5 text-[14px] font-medium disabled:opacity-40`,onClick:()=>void O(()=>u.updateEndpoint(e.id,{models:x}),o(`Models saved`)),children:o(`Save`)}),(0,q.jsx)(`button`,{type:`button`,className:`flex items-center justify-center gap-1.5 rounded-2xl border border-border px-4 py-2.5 text-[14px] font-medium text-muted disabled:opacity-40`,onClick:()=>f(``),children:o(`Cancel`)})]})]}),d===`remove`&&(0,q.jsxs)(`div`,{className:`space-y-2`,children:[(0,q.jsx)(`div`,{className:`text-[12.5px] text-muted`,children:o(M?`The chat model answers through this endpoint; pick another chat model first.`:`Its key goes with it, and the hands, pictures or clips set on it go back to automatic.`)}),(0,q.jsxs)(`div`,{className:`flex gap-2`,children:[(0,q.jsxs)(`button`,{type:`button`,disabled:C||M,className:t(`flex items-center justify-center gap-1.5 rounded-2xl bg-accent text-accent-fg px-4 py-2.5 text-[14px] font-medium disabled:opacity-40`,`bg-rose-600 hover:bg-rose-600/90`),onClick:()=>void O(()=>u.removeEndpoint(e.id),o(`Endpoint removed`)),children:[(0,q.jsx)(I,{size:16}),` `,o(`Remove`)]}),(0,q.jsx)(`button`,{type:`button`,className:`flex items-center justify-center gap-1.5 rounded-2xl border border-border px-4 py-2.5 text-[14px] font-medium text-muted disabled:opacity-40`,onClick:()=>f(``),children:o(`Cancel`)})]})]}),T&&(0,q.jsx)(`div`,{className:`rounded-2xl bg-rose-500/12 px-3 py-2 text-[12.5px] text-rose-700 dark:text-rose-300`,children:T})]})}function X({slot:e,data:n,onChange:a}){let{toast:o,state:s}=c(),f=r(),p=n[e],b=e,x=s.hub?.account??null,T=!!x?.signed_in,E=m(x),O=i(),A=n.providers[Fe]?.base_url??``,ee=n.endpoints??[],P=Ne(b,{signedIn:T,chat:{provider:n.llm.provider,base_url:n.llm.base_url,cloud:!!n.llm.cloud},region:E,locale:O,endpoints:ee}),F=Pe(p,A),[I,te]=(0,G.useState)(!1),[L,ne]=(0,G.useState)(F),[R,z]=(0,G.useState)(p.model),[B,ie]=(0,G.useState)(p.base_url),[ae,V]=(0,G.useState)(``),[H,oe]=(0,G.useState)(!1),[se,ce]=(0,G.useState)(!1),[le,ue]=(0,G.useState)({list:[],more:[],source:`catalogue`});(0,G.useEffect)(()=>{ne(F),z(p.model),ie(p.base_url),V(``)},[p]);let U=P.find(e=>e.value===L)??null,W=U?.entry??null,pe=W?v(W,E):null,me=ee.find(e=>Te(e.id)===L)??null,he=L===`nanomuse_cloud`?A:me?me.base_url:L===`custom`?B.trim():pe?.base_url??``,ge=F===L&&F!==``&&(p.key_source===`vault`||p.key_source===`config`),K=!!U?.needsKey&&!ae&&!ge,_e=L===`nanomuse_cloud`?le.list[0]??``:W?.defaults[e]??``;(0,G.useEffect)(()=>{if(!I||!L||L!==`nanomuse_cloud`&&!he){ue({list:[],more:[],source:`catalogue`});return}let t=!0,n=setTimeout(()=>{ue(e=>({...e,source:`loading`})),u.llmModels(L===`nanomuse_cloud`?{preset:Fe}:me?{endpoint:me.id}:{preset:W?S(W.id):``,base_url:he,api_key:ae||void 0}).then(n=>{if(!t)return;let r=(e===`image`?n.image_models:n.video_models)??[],i=(e===`image`?n.image_catalog:n.video_catalog)??[];ue({list:r.filter(e=>!i.includes(e)),more:i,source:n.source})}).catch(()=>t&&ue({list:[],more:[],source:`catalogue`}))},ae?600:150);return()=>{t=!1,clearTimeout(n)}},[I,L,he,ae]);let ve=f(e===`image`?`Making pictures`:`Making clips`),ye=f(e===`image`?`Portraits of your Muse.`:`Short clips of your Muse.`),be=Y(p,O,_,ee),Se=d(f,b,E,O),Ce=p.effective_provider?p.effective_source===`cloud`?{text:f(`Your account`),tone:`ok`}:p.effective_source===`chat`?{text:f(`The chat model's provider`),tone:`ok`}:{text:f(`Your key`),tone:`ok`}:{text:f(`Not set up`),tone:`warn`},we=async()=>{ce(!0);try{L?L===`nanomuse_cloud`?await u.setMedia(e,{provider:`openai`,base_url:A,model:R.trim(),api_key:xe}):me?await u.setMedia(e,{endpoint:me.id,model:R.trim()}):L===`custom`?await u.setMedia(e,{provider:`openai`,base_url:B.trim(),model:R.trim(),api_key:ae||null}):await u.setMedia(e,{provider:L,base_url:``,model:R.trim(),api_key:ae||(U?.group===`chat`?``:null)}):await u.setMedia(e,{provider:``,model:``,base_url:``,api_key:``}),V(``),h(),o(f(`Saved`)),a(),te(!1)}catch(e){o(e.message)}finally{ce(!1)}},J=e=>f(e===`cloud`?`Your account`:e===`chat`?`The chat model's provider`:e===`endpoints`?`Your endpoints`:`Add a provider`),Ee=[`cloud`,`chat`,`endpoints`,`add`].map(e=>({g:e,items:P.filter(t=>t.group===e)})).filter(e=>e.items.length),De=e===`image`?`IMAGE_API_KEY`:`VIDEO_API_KEY`;return(0,q.jsxs)(j,{icon:e===`image`?(0,q.jsx)(N,{size:19}):(0,q.jsx)(M,{size:19}),title:ve,summary:be||Se,status:Ce,open:I,onToggle:()=>te(!I),children:[(0,q.jsx)(`p`,{className:`text-[12.5px] text-muted`,children:ye}),(0,q.jsxs)($,{label:f(`Provider`),hint:!be&&!L?Se:void 0,children:[(0,q.jsxs)(`select`,{value:L,onChange:e=>{ne(e.target.value),z(``),V(``)},className:t(k,`text-fg`),children:[(0,q.jsx)(`option`,{value:``,children:f(`Automatic`)}),Ee.map(({g:e,items:t})=>(0,q.jsx)(`optgroup`,{label:J(e),children:t.map(e=>(0,q.jsx)(`option`,{value:e.value,children:e.value===`custom`?f(`Other OpenAI-compatible endpoint`):e.label},e.value))},e))]}),be&&(0,q.jsx)(`p`,{className:`mt-1.5 text-[12px] text-muted`,children:f(`Currently {value}`,{value:be})}),!be&&!L&&(0,q.jsxs)(`button`,{type:`button`,className:`mt-1.5 inline-flex items-center gap-1 text-[12.5px] text-accent`,onClick:()=>ne(P.find(e=>e.group===`add`)?.value??``),children:[(0,q.jsx)(re,{size:13}),` `,f(`Add a provider`)]}),W&&(0,q.jsxs)(`p`,{className:`mt-1.5 text-[12px] text-muted`,children:[(0,q.jsx)(`span`,{className:`font-medium text-fg`,children:g(W,O)}),` · `,y(f,W.capabilities),`. `,O===`zh-CN`?W.note_zh:W.note]})]}),L===`custom`&&(0,q.jsx)($,{label:f(`Base URL`),hint:f(`The endpoint that serves /images/generations, for example https://host/v1.`),children:(0,q.jsx)(`input`,{value:B,onChange:e=>ie(e.target.value),className:`w-full rounded-2xl bg-surface-2 px-3.5 py-2.5 text-[14.5px] outline-none focus:ring-2 focus:ring-accent/40`,placeholder:`https://host/v1`,inputMode:`url`,autoCapitalize:`off`})}),L&&(0,q.jsx)(Q,{label:f(e===`image`?`Picture model`:`Clip model`),provider:L===`nanomuse_cloud`?`nanoMuse Cloud`:L===`custom`?it(B)||f(`Other OpenAI-compatible endpoint`):U?.label??L,value:R,options:le.list,more:le.more,onChange:z,other:L!==`nanomuse_cloud`||!!x?.any_model,placeholder:_e||void 0}),L&&L!==`nanomuse_cloud`&&U?.group!==`chat`&&!me&&(0,q.jsxs)($,{label:f(`API key`),hint:ge?f(`A key is in the vault. Leave blank to keep it.`):f(`Stored encrypted in the vault as {name}.`,{name:De}),children:[(0,q.jsxs)(`div`,{className:`relative`,children:[(0,q.jsx)(`input`,{type:H?`text`:`password`,value:ae,onChange:e=>V(e.target.value),"aria-label":f(`API key`),className:t(`w-full rounded-2xl bg-surface-2 px-3.5 py-2.5 text-[14.5px] outline-none focus:ring-2 focus:ring-accent/40`,`pr-10`),placeholder:ge?`••••••••`:W?.key_hint||`sk-…`,autoComplete:`off`,autoCapitalize:`off`,spellCheck:!1}),(0,q.jsx)(`button`,{type:`button`,onClick:()=>oe(!H),"aria-label":f(H?`Hide key`:`Show key`),className:`absolute right-2 top-1/2 -translate-y-1/2 rounded-full p-1.5 text-muted`,children:H?(0,q.jsx)(de,{size:16}):(0,q.jsx)(fe,{size:16})})]}),pe?.key_url&&(0,q.jsxs)(`a`,{href:pe.key_url,target:`_blank`,rel:`noreferrer`,className:`mt-1.5 inline-flex items-center gap-1 text-[12px] text-accent`,children:[f(`Get a key from {vendor}`,{vendor:W?g(W,O):``}),` `,(0,q.jsx)(w,{size:12})]})]}),U?.group===`chat`&&(0,q.jsx)(`p`,{className:`text-[12px] text-muted`,children:f(`Uses the chat model's key.`)}),me&&(0,q.jsx)(`p`,{className:`text-[12px] text-muted`,children:f(`Uses the key saved with this endpoint.`)}),(0,q.jsx)(`div`,{className:`flex gap-2 pt-1`,children:(0,q.jsxs)(`button`,{type:`button`,disabled:se||K||L===`custom`&&!B.trim(),onClick:()=>void we(),className:D,children:[se?(0,q.jsx)(l,{size:16,className:`animate-spin`}):(0,q.jsx)(C,{size:16}),` `,f(`Save`)]})})]})}function Z({data:e,onChange:n}){let{toast:i}=c(),a=r(),o=e.embeddings,[s,d]=(0,G.useState)(!1),[f,p]=(0,G.useState)(o.mode),[m,h]=(0,G.useState)(!!o.base_url),[g,_]=(0,G.useState)(o.base_url),[v,y]=(0,G.useState)(o.model),[b,x]=(0,G.useState)(``),[S,w]=(0,G.useState)(!1),[E,O]=(0,G.useState)(null),[k,A]=(0,G.useState)(!1);(0,G.useEffect)(()=>{p(o.mode),h(!!o.base_url),_(o.base_url),y(o.model)},[e.embeddings]);let M=o.mode===`off`?{text:a(`Off`),tone:`off`}:o.available===!0?{text:a(`On`),tone:`ok`}:o.available===!1?{text:o.mode===`on`?a(`Not reachable`):a(`By keyword`),tone:`warn`}:{text:a(`Not tried yet`),tone:`off`},N=o.mode===`off`?a(`Keyword recall only`):o.available===!0?a(`{model} · {n} of {total} memories indexed`,{model:o.model||o.default_model,n:o.indexed,total:o.total}):o.available===!1?o.reason:a(`{model} at {host}`,{model:o.model||o.default_model,host:it(o.effective_base_url)}),P=async()=>{w(!0),O(null);try{await u.setEmbeddings({mode:f,base_url:m?g.trim():``,model:v.trim(),api_key:m?b||void 0:``}),x(``),i(a(`Saved`)),n()}catch(e){i(e.message)}finally{w(!1)}},F=async()=>{A(!0);try{O(await u.testEmbeddings()),n()}catch(e){O({ok:!1,error:e.message})}finally{A(!1)}},I=e=>t(`rounded-full px-3 py-1.5 text-[13px] border`,e?`border-accent bg-accent/10 text-accent font-medium`:`border-border text-muted`);return(0,q.jsxs)(j,{icon:(0,q.jsx)(ue,{size:19}),title:a(`Recall by meaning`),summary:N,status:M,open:s,onToggle:()=>d(!s),children:[(0,q.jsx)(`p`,{className:`text-[12.5px] text-muted leading-snug`,children:a(`Memories are embedded once and a message finds the ones that mean the same thing, in any language: “写邮件给房东” finds “the landlord is Bob Li”. Keyword recall stays; the two are fused.`)}),(0,q.jsx)($,{label:a(`Mode`),hint:a(`Auto uses the model's endpoint when it has embeddings and falls back to keywords when it does not. On insists and warns. Off: keywords only.`),children:(0,q.jsx)(`div`,{className:`flex gap-1.5`,children:[`auto`,`on`,`off`].map(e=>(0,q.jsx)(`button`,{type:`button`,onClick:()=>p(e),className:I(f===e),children:a(e===`auto`?`Auto`:e===`on`?`On`:`Off`)},e))})}),f!==`off`&&(0,q.jsxs)(q.Fragment,{children:[(0,q.jsx)($,{label:a(`Endpoint`),hint:a(m?`Any OpenAI-compatible /embeddings: Ollama with an embedding model pulled, OpenAI, a gateway.`:`The model's endpoint and key. DeepSeek has no embeddings; pick another endpoint.`),children:(0,q.jsxs)(`div`,{className:`flex gap-1.5`,children:[(0,q.jsx)(`button`,{type:`button`,onClick:()=>h(!1),className:I(!m),children:a(`Same as the model`)}),(0,q.jsx)(`button`,{type:`button`,onClick:()=>{h(!0),g||_(`http://127.0.0.1:11434/v1`)},className:I(m),children:a(`Another endpoint`)})]})}),m&&(0,q.jsxs)(q.Fragment,{children:[(0,q.jsx)($,{label:a(`Base URL`),children:(0,q.jsx)(`input`,{value:g,onChange:e=>_(e.target.value),className:`w-full rounded-2xl bg-surface-2 px-3.5 py-2.5 text-[14.5px] outline-none focus:ring-2 focus:ring-accent/40`,placeholder:`http://127.0.0.1:11434/v1`,inputMode:`url`})}),(0,q.jsx)($,{label:a(`API key`),hint:o.key_source===`vault`?a(`A key is in the vault. Leave blank to keep it.`):a(`Stored encrypted in the vault as EMBEDDINGS_API_KEY. Ollama needs none.`),children:(0,q.jsx)(`input`,{type:`password`,value:b,onChange:e=>x(e.target.value),className:`w-full rounded-2xl bg-surface-2 px-3.5 py-2.5 text-[14.5px] outline-none focus:ring-2 focus:ring-accent/40`,placeholder:o.key_source===`vault`?`••••••••`:`sk-…`,autoComplete:`off`})})]}),(0,q.jsx)($,{label:a(`Embedding model`),hint:a(`Blank uses the endpoint's default: {model}. On Ollama: ollama pull qwen3-embedding:0.6b (reads Chinese and English).`,{model:o.default_model}),children:(0,q.jsx)(`input`,{value:v,onChange:e=>y(e.target.value),className:`w-full rounded-2xl bg-surface-2 px-3.5 py-2.5 text-[14.5px] outline-none focus:ring-2 focus:ring-accent/40`,placeholder:o.default_model,autoComplete:`off`})})]}),(0,q.jsxs)(`div`,{className:`flex gap-2 pt-1`,children:[(0,q.jsxs)(`button`,{type:`button`,disabled:S||m&&!/^https?:\/\//.test(g.trim()),onClick:()=>void P(),className:D,children:[S?(0,q.jsx)(l,{size:16,className:`animate-spin`}):(0,q.jsx)(C,{size:16}),` `,a(`Save`)]}),(0,q.jsxs)(`button`,{type:`button`,disabled:k||o.mode===`off`,onClick:()=>void F(),className:T,children:[k?(0,q.jsx)(l,{size:16,className:`animate-spin`}):(0,q.jsx)(ee,{size:16}),` `,a(`Test`)]})]}),E&&(0,q.jsx)(rt,{result:E,okText:a(`{model} · {dims} dims · {n} memories indexed · {ms} ms`,{model:E.model??``,dims:E.dims??0,n:E.indexed??0,ms:E.ms??0})})]})}function He({data:e,onChange:n}){let{toast:i}=c(),a=r(),o=e.search,[s,d]=(0,G.useState)(!1),[f,p]=(0,G.useState)(o.provider),[m,h]=(0,G.useState)(o.base_url),[g,_]=(0,G.useState)(``),[v,y]=(0,G.useState)(!1),[b,x]=(0,G.useState)(null),[S,w]=(0,G.useState)(!1);(0,G.useEffect)(()=>{p(o.provider),h(o.base_url)},[e.search]);let E=o.providers.find(e=>e.id===o.provider),O=o.providers.find(e=>e.id===f),k=!!O?.needs_key,A=o.configured?{text:a(`On`),tone:`ok`}:{text:a(`Not set up`),tone:`warn`},M=o.configured?o.provider===`searxng`?a(`{provider} at {host}`,{provider:E?.label??o.provider,host:it(o.base_url)}):E?.label??o.provider:a(`{provider} needs {what}; searches use DuckDuckGo until then`,{provider:E?.label??o.provider,what:E?.needs_key?a(`a key`):a(`an instance URL`)}),N=async()=>{y(!0),x(null);try{await u.setSearch({provider:f,base_url:f===`searxng`?m.trim():``,api_key:k?g||void 0:``}),_(``),i(a(`Saved`)),n()}catch(e){i(e.message)}finally{y(!1)}},P=async()=>{w(!0);try{x(await u.testSearch())}catch(e){x({ok:!1,error:e.message})}finally{w(!1)}},F=e=>t(`rounded-full px-3 py-1.5 text-[13px] border`,e?`border-accent bg-accent/10 text-accent font-medium`:`border-border text-muted`),I=f!==`searxng`||/^https?:\/\//.test(m.trim());return(0,q.jsxs)(j,{icon:(0,q.jsx)(B,{size:19}),title:a(`Web search`),summary:M,status:A,open:s,onToggle:()=>d(!s),children:[(0,q.jsx)(`p`,{className:`text-[12.5px] text-muted leading-snug`,children:a(`DuckDuckGo needs nothing, but it is scraped and rate-limits now and then. For searches that always work, use a provider with an API. Whichever you pick, a failed search falls back to DuckDuckGo with a note.`)}),(0,q.jsx)($,{label:a(`Provider`),children:(0,q.jsx)(`div`,{className:`flex flex-wrap gap-1.5`,children:o.providers.map(e=>(0,q.jsx)(`button`,{type:`button`,onClick:()=>p(e.id),className:F(f===e.id),children:e.label},e.id))})}),k&&(0,q.jsxs)($,{label:a(`API key`),hint:o.key_source===`vault`&&o.provider===f?a(`A key is in the vault. Leave blank to keep it.`):a(`Stored encrypted in the vault as SEARCH_API_KEY.`),children:[(0,q.jsx)(`input`,{type:`password`,value:g,onChange:e=>_(e.target.value),"aria-label":a(`API key`),className:`w-full rounded-2xl bg-surface-2 px-3.5 py-2.5 text-[14.5px] outline-none focus:ring-2 focus:ring-accent/40`,placeholder:o.key_source===`vault`&&o.provider===f?`••••••••`:`…`,autoComplete:`off`}),O?.keys_url&&(0,q.jsx)(`a`,{href:O.keys_url,target:`_blank`,rel:`noreferrer`,className:`mt-1 inline-block text-[12px] text-accent`,children:a(`Get a key from {label}`,{label:O.label})})]}),f===`searxng`&&(0,q.jsx)($,{label:a(`Instance URL`),hint:a(`A SearXNG you run, with the JSON format enabled in its settings.`),children:(0,q.jsx)(`input`,{value:m,onChange:e=>h(e.target.value),className:`w-full rounded-2xl bg-surface-2 px-3.5 py-2.5 text-[14.5px] outline-none focus:ring-2 focus:ring-accent/40`,placeholder:`http://127.0.0.1:8080`,inputMode:`url`})}),(0,q.jsxs)(`div`,{className:`flex gap-2 pt-1`,children:[(0,q.jsxs)(`button`,{type:`button`,disabled:v||!I,onClick:()=>void N(),className:D,children:[v?(0,q.jsx)(l,{size:16,className:`animate-spin`}):(0,q.jsx)(C,{size:16}),` `,a(`Save`)]}),(0,q.jsxs)(`button`,{type:`button`,disabled:S,onClick:()=>void P(),className:T,children:[S?(0,q.jsx)(l,{size:16,className:`animate-spin`}):(0,q.jsx)(ee,{size:16}),` `,a(`Test`)]})]}),b&&(0,q.jsx)(rt,{result:b,okText:a(`{provider} · {n} results · {ms} ms`,{provider:b.provider??``,n:b.results??0,ms:b.ms??0})})]})}var Ue=[{id:`gmail`,label:`Gmail`,imap:`imap.gmail.com`,smtp:`smtp.gmail.com`,port:587,starttls:!0},{id:`outlook`,label:`Outlook`,imap:`outlook.office365.com`,smtp:`smtp.office365.com`,port:587,starttls:!0},{id:`icloud`,label:`iCloud`,imap:`imap.mail.me.com`,smtp:`smtp.mail.me.com`,port:587,starttls:!0},{id:`qq`,label:`QQ`,imap:`imap.qq.com`,smtp:`smtp.qq.com`,port:587,starttls:!0},{id:`163`,label:`163`,imap:`imap.163.com`,smtp:`smtp.163.com`,port:465,starttls:!1},{id:`fastmail`,label:`Fastmail`,imap:`imap.fastmail.com`,smtp:`smtp.fastmail.com`,port:587,starttls:!0}];function We({data:e,onChange:n,compact:i}){let{toast:a}=c(),o=r(),s=e.email,[d,f]=(0,G.useState)(!!i),[p,m]=(0,G.useState)(s.address),[h,g]=(0,G.useState)(``),[_,v]=(0,G.useState)(s.imap_host),[y,b]=(0,G.useState)(s.imap_port),[x,S]=(0,G.useState)(s.smtp_host),[C,w]=(0,G.useState)(s.smtp_port),[T,E]=(0,G.useState)(s.smtp_starttls),[O,A]=(0,G.useState)(null),[M,N]=(0,G.useState)(null);(0,G.useEffect)(()=>{m(s.address),v(s.imap_host),b(s.imap_port),S(s.smtp_host),w(s.smtp_port),E(s.smtp_starttls)},[s]);let P=e=>{v(e.imap),b(993),S(e.smtp),w(e.port),E(e.starttls)},F=async()=>{A(`save`),N(null);try{await u.setEmail({enabled:!0,address:p.trim(),password:h||void 0,imap_host:_.trim(),imap_port:y,smtp_host:x.trim(),smtp_port:C,smtp_starttls:T}),g(``);let e=await u.testEmail();N(e),a(e.ok?o(`Email connected`):o(`Saved, but the test failed`)),n()}catch(e){a(e.message)}finally{A(null)}},I=async()=>{A(`off`);try{await u.disconnectEmail(),N(null),a(o(`Email disconnected`)),n()}catch(e){a(e.message)}finally{A(null)}},te=s.enabled&&s.configured?{text:o(`Connected`),tone:`ok`}:s.enabled?{text:o(`Incomplete`),tone:`warn`}:{text:o(`Not connected`),tone:`off`};return(0,q.jsxs)(j,{icon:(0,q.jsx)(oe,{size:19}),title:o(`Email`),summary:s.configured&&s.enabled?`${s.address} · ${o(`reads and sends`)}`:o(`Read your inbox, draft and send mail`),status:te,open:d,onToggle:i?void 0:()=>f(!d),children:[(0,q.jsx)(`p`,{className:`text-[12.5px] text-muted -mt-1`,children:o(`Reading is a moderate action; sending always asks you first. Use an app password where your provider offers one.`)}),(0,q.jsx)($,{label:o(`Provider`),children:(0,q.jsx)(`div`,{className:`flex flex-wrap gap-1.5`,children:Ue.map(e=>(0,q.jsx)(`button`,{type:`button`,onClick:()=>P(e),className:t(`rounded-full px-3 py-1.5 text-[13px] border`,_===e.imap?`border-accent bg-accent/10 text-accent font-medium`:`border-border text-muted`),children:e.label},e.id))})}),(0,q.jsx)($,{label:o(`Address`),children:(0,q.jsx)(`input`,{value:p,onChange:e=>m(e.target.value),className:k,placeholder:`you@example.com`,inputMode:`email`,autoComplete:`off`})}),(0,q.jsx)($,{label:o(`Password`),hint:s.password_set?o(`A password is in the vault. Leave blank to keep it.`):o(`Stored encrypted in the vault as EMAIL_PASSWORD.`),children:(0,q.jsx)(`input`,{type:`password`,value:h,onChange:e=>g(e.target.value),className:k,placeholder:s.password_set?`••••••••`:o(`app password`),autoComplete:`off`})}),(0,q.jsxs)(`div`,{className:`grid grid-cols-[1fr_84px] gap-2`,children:[(0,q.jsx)($,{label:o(`IMAP server`),children:(0,q.jsx)(`input`,{value:_,onChange:e=>v(e.target.value),className:k,placeholder:`imap.example.com`})}),(0,q.jsx)($,{label:o(`Port`),children:(0,q.jsx)(`input`,{type:`number`,value:y,onChange:e=>b(Number(e.target.value)),className:k})}),(0,q.jsx)($,{label:o(`SMTP server`),children:(0,q.jsx)(`input`,{value:x,onChange:e=>S(e.target.value),className:k,placeholder:`smtp.example.com`})}),(0,q.jsx)($,{label:o(`Port`),children:(0,q.jsx)(`input`,{type:`number`,value:C,onChange:e=>w(Number(e.target.value)),className:k})})]}),(0,q.jsxs)(`label`,{className:`flex items-center gap-2 text-[13.5px]`,children:[(0,q.jsx)(`input`,{type:`checkbox`,checked:T,onChange:e=>E(e.target.checked),className:`accent-[var(--om-accent)]`}),` `,o(`STARTTLS for SMTP (off for port 465)`)]}),(0,q.jsxs)(`div`,{className:`flex gap-2 pt-1`,children:[(0,q.jsxs)(`button`,{type:`button`,disabled:O!==null||!p.trim()||!_.trim()||!x.trim()||!h&&!s.password_set,onClick:()=>void F(),className:D,children:[O===`save`?(0,q.jsx)(l,{size:16,className:`animate-spin`}):(0,q.jsx)(ee,{size:16}),` `,s.configured?o(`Save & test`):o(`Connect`)]}),s.enabled&&(0,q.jsxs)(`button`,{type:`button`,disabled:O!==null,onClick:()=>void I(),className:`flex items-center justify-center gap-1.5 rounded-2xl border border-border px-4 py-2.5 text-[14px] font-medium text-muted disabled:opacity-40`,children:[O===`off`?(0,q.jsx)(l,{size:16,className:`animate-spin`}):(0,q.jsx)(W,{size:16}),` `,o(`Disconnect`)]})]}),M&&(0,q.jsx)(rt,{result:M,okText:o(`Signed in · {n} messages in the inbox`,{n:M.inbox??`?`})})]})}var Ge=[{id:`google`,label:`Google`,hint:`Settings → your calendar → Integrate calendar → Secret address in iCal format`},{id:`outlook`,label:`Outlook`,hint:`Settings → Calendar → Shared calendars → Publish a calendar → ICS link`},{id:`icloud`,label:`iCloud`,hint:`Share Calendar → Public Calendar → copy the webcal:// link`},{id:`fastmail`,label:`Fastmail`,hint:`Settings → Calendars → Export → Calendar URL`},{id:`file`,label:`.ics file`,hint:`A path on the machine where nanoMuse runs, for example ~/calendar.ics`}];function Ke({data:n,onChange:i,compact:a}){let{toast:o}=c(),s=r(),d=n.calendar,[f,p]=(0,G.useState)(!!a),[m,h]=(0,G.useState)(!1),[g,_]=(0,G.useState)(``),[v,y]=(0,G.useState)(``),[b,x]=(0,G.useState)(null),[S,E]=(0,G.useState)(d.day_start),[A,M]=(0,G.useState)(d.day_end),[N,F]=(0,G.useState)(null),[te,L]=(0,G.useState)(null),[ne,R]=(0,G.useState)(null),[z,B]=(0,G.useState)(d.google.client_id),[ae,V]=(0,G.useState)(``),[H,oe]=(0,G.useState)(d.google.write);(0,G.useEffect)(()=>{E(d.day_start),M(d.day_end)},[d.day_start,d.day_end]),(0,G.useEffect)(()=>{B(d.google.client_id),oe(d.google.write)},[d.google.client_id,d.google.write]),(0,G.useEffect)(()=>{if(!d.google.connected){R(null);return}let e=!0;return(async()=>{try{let t=await u.googleCalendar();e&&R(t.calendars??[])}catch{e&&R([])}})(),()=>{e=!1}},[d.google.connected]);let se=async()=>{F(`add`),L(null);try{let e=await u.addCalendarFeed(g.trim(),v.trim());if(e.error)o(s(`Added, but it could not be read: {error}`,{error:e.error}));else{let t=e.feeds.find(e=>e.name===g.trim());o(`${s(`Calendar connected`)} · ${_e(t?.events??0)}`),_(``),y(``),h(!1)}i()}catch(e){o(e.message)}finally{F(null)}},ce=async e=>{F(e);try{await u.removeCalendarFeed(e),i()}catch(e){o(e.message)}finally{F(null)}},le=async()=>{F(`hours`);try{await u.setCalendar({day_start:S,day_end:A}),o(s(`Saved`)),i()}catch(e){o(e.message)}finally{F(null)}},ue=async()=>{F(`test`);try{L(await u.testCalendar()),i()}catch(e){o(e.message)}finally{F(null)}},U=async()=>{F(`gsave`);try{await u.setGoogleCalendar({client_id:z.trim(),client_secret:ae.trim()||void 0,write:H,enabled:!0}),V(``),o(s(`Saved`)),i()}catch(e){o(e.message)}finally{F(null)}},de=async()=>{F(`gconnect`);try{let{url:e}=await u.connectGoogleCalendar(H);window.open(e,`_blank`,`noopener`),o(s(`Finish signing in with Google in the window that opened.`)),i()}catch(e){o(e.message)}finally{F(null)}},fe=async()=>{F(`gdisconnect`);try{await u.disconnectGoogleCalendar(),R(null),o(s(`Disconnected`)),i()}catch(e){o(e.message)}finally{F(null)}},pe=async e=>{F(`gpick`);try{await u.setGoogleCalendars({default_calendar:e,calendar_ids:[e]}),i()}catch(e){o(e.message)}finally{F(null)}},me=async e=>{oe(e),F(`gwrite`);try{await u.setGoogleCalendar({write:e}),i()}catch(e){o(e.message)}finally{F(null)}},he=d.feeds.reduce((e,t)=>e+t.events,0),ge=d.feeds.filter(e=>e.error).length,K=d.google,_e=e=>e===1?s(`1 event`):s(`{n} events`,{n:e}),ve=K.connected?{text:K.can_write?s(`Connected`):s(`Read-only`),tone:`ok`}:K.configured?{text:s(`Sign in needed`),tone:`warn`}:d.configured?ge?{text:s(`{n} not reading`,{n:ge}),tone:`warn`}:{text:s(`Connected`),tone:`ok`}:{text:s(`Not connected`),tone:`off`},ye=K.connected?`${K.account||s(`Google Calendar`)} · ${K.can_write?s(`read + write`):s(`read-only`)}`:d.configured?d.feeds.length===1?`${d.feeds[0].name} · ${_e(he)}`:`${s(`{n} calendars`,{n:d.feeds.length})} · ${_e(he)}`:s(`Your agenda, free time, and events it can draft`);return(0,q.jsxs)(j,{icon:(0,q.jsx)(ie,{size:19}),title:s(`Calendar`),summary:K.connected||d.configured?ye:s(`Your agenda, free time, and events it can draft`),status:ve,open:f,onToggle:a?void 0:()=>p(!f),children:[(0,q.jsx)(`p`,{className:`text-[12.5px] text-muted -mt-1`,children:s(`Reads your calendar from its private .ics link; the link stays in the vault. It never changes your calendar; an event it proposes comes as a file you add with a tap.`)}),(0,q.jsxs)(`div`,{className:`space-y-2.5 rounded-2xl border border-border/70 p-3`,children:[(0,q.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,q.jsx)(`span`,{className:t(`h-2 w-2 rounded-full`,K.connected?`bg-emerald-500`:K.configured?`bg-amber-500`:`bg-surface-2 border border-border`)}),(0,q.jsxs)(`div`,{className:`min-w-0 flex-1`,children:[(0,q.jsx)(`div`,{className:`text-[13.5px] font-medium`,children:s(`Google Calendar`)}),(0,q.jsx)(`div`,{className:`text-[11.5px] text-muted truncate`,children:K.connected?`${K.account||s(`Signed in`)} · ${K.can_write?s(`read + write`):s(`read-only`)}`:K.configured?s(`Client set — sign in with Google`):s(`Paste your Google OAuth client id and secret`)})]}),K.connected?(0,q.jsx)(`button`,{type:`button`,"aria-label":s(`Disconnect`),disabled:N===`gdisconnect`,onClick:()=>void fe(),className:`p-1.5 rounded-full text-muted hover:bg-surface-2`,children:N===`gdisconnect`?(0,q.jsx)(l,{size:15,className:`animate-spin`}):(0,q.jsx)(W,{size:15})}):null]}),!K.connected&&(0,q.jsxs)(q.Fragment,{children:[(0,q.jsx)($,{label:s(`Client ID`),hint:s(`From the OAuth client you downloaded in Google Cloud Console.`),children:(0,q.jsx)(`input`,{value:z,onChange:e=>B(e.target.value),className:`w-full rounded-2xl bg-surface-2 px-3.5 py-2.5 text-[14.5px] outline-none focus:ring-2 focus:ring-accent/40`,placeholder:`…apps.googleusercontent.com`,autoComplete:`off`})}),(0,q.jsx)($,{label:s(`Client secret`),hint:K.has_secret?s(`A secret is saved. Type a new one only to replace it.`):s(`Stored encrypted in the vault as GOOGLE_CALENDAR_SECRET.`),children:(0,q.jsx)(`input`,{type:`password`,value:ae,onChange:e=>V(e.target.value),className:`w-full rounded-2xl bg-surface-2 px-3.5 py-2.5 text-[14.5px] outline-none focus:ring-2 focus:ring-accent/40`,placeholder:K.has_secret?`••••••••`:`GOCSPX-…`,autoComplete:`off`})}),(0,q.jsx)($,{label:s(`Callback URL`),hint:s(`Register this exact URL on the OAuth client as an authorized redirect URI.`),children:(0,q.jsx)(`input`,{value:K.redirect_uri,readOnly:!0,className:t(`w-full rounded-2xl bg-surface-2 px-3.5 py-2.5 text-[14.5px] outline-none focus:ring-2 focus:ring-accent/40`,`text-muted`)})}),(0,q.jsx)(O,{label:s(`Let the agent create and change events`),hint:s(`Off: read-only, the agent can look but not touch.`),checked:H,onChange:e=>oe(e)}),(0,q.jsxs)(`div`,{className:`flex flex-wrap gap-2`,children:[(0,q.jsxs)(`button`,{type:`button`,disabled:N===`gsave`,onClick:()=>void U(),className:`flex items-center justify-center gap-1.5 rounded-2xl border border-border px-4 py-2.5 text-[14px] font-medium text-muted disabled:opacity-40`,children:[N===`gsave`?(0,q.jsx)(l,{size:16,className:`animate-spin`}):(0,q.jsx)(C,{size:16}),` `,s(`Save client`)]}),(0,q.jsxs)(`button`,{type:`button`,disabled:N===`gconnect`||!K.configured,onClick:()=>void de(),className:`flex items-center justify-center gap-1.5 rounded-2xl bg-accent text-accent-fg px-4 py-2.5 text-[14px] font-medium disabled:opacity-40`,children:[N===`gconnect`?(0,q.jsx)(l,{size:16,className:`animate-spin`}):(0,q.jsx)(w,{size:16}),` `,s(`Sign in with Google`)]})]})]}),K.connected&&(0,q.jsxs)(q.Fragment,{children:[(0,q.jsx)(O,{label:s(`Let the agent create and change events`),hint:s(`Off: read-only, the agent can look but not touch.`),checked:H,onChange:e=>void me(e)}),ne&&ne.length>0&&(0,q.jsx)($,{label:s(`Calendar to read and write`),hint:s(`Events the agent reads and creates land here.`),children:(0,q.jsx)(`div`,{className:`flex flex-wrap gap-1.5`,children:ne.map(e=>{let n=(K.default_calendar||K.calendar_ids[0]||``)===e.id;return(0,q.jsx)(`button`,{type:`button`,disabled:N===`gpick`,onClick:()=>void pe(e.id),className:t(`rounded-full px-3 py-1.5 text-[13px] border`,n?`border-accent bg-accent/10 text-accent font-medium`:`border-border text-muted`),children:e.primary?s(`{name} (primary)`,{name:e.name}):e.name},e.id)})})}),K.error&&(0,q.jsx)(`div`,{className:`rounded-2xl bg-rose-500/12 px-3 py-2 text-[12.5px] text-rose-700 dark:text-rose-300`,children:K.error})]})]}),d.feeds.length>0&&(0,q.jsx)(`ul`,{className:`space-y-1.5`,children:d.feeds.map(n=>(0,q.jsxs)(`li`,{className:`flex items-center gap-2.5 rounded-2xl bg-surface-2/60 px-3 py-2`,children:[(0,q.jsx)(`span`,{className:t(`h-2 w-2 rounded-full`,n.error?`bg-rose-500`:n.fetched_at?`bg-emerald-500`:`bg-amber-500`)}),(0,q.jsxs)(`div`,{className:`min-w-0 flex-1`,children:[(0,q.jsx)(`div`,{className:`text-[13.5px] font-medium truncate`,children:n.name}),(0,q.jsxs)(`div`,{className:`text-[11.5px] text-muted truncate`,children:[n.error?n.error:n.fetched_at?`${_e(n.events)} · ${s(`read {when}`,{when:e(n.fetched_at)})}`:s(`not read yet`),!n.from_app&&` · ${s(`from config.toml`)}`]})]}),n.from_app&&(0,q.jsx)(`button`,{type:`button`,"aria-label":s(`Remove`),disabled:N===n.name,onClick:()=>void ce(n.name),className:`p-1.5 rounded-full text-muted hover:bg-surface-2`,children:N===n.name?(0,q.jsx)(l,{size:15,className:`animate-spin`}):(0,q.jsx)(I,{size:15})})]},n.name))}),m?(0,q.jsxs)(`div`,{className:`space-y-2.5 rounded-2xl border border-border/70 p-3`,children:[(0,q.jsxs)($,{label:s(`Where is the link?`),children:[(0,q.jsx)(`div`,{className:`flex flex-wrap gap-1.5`,children:Ge.map(e=>(0,q.jsx)(`button`,{type:`button`,onClick:()=>x(b===e.id?null:e.id),className:t(`rounded-full px-3 py-1.5 text-[13px] border`,b===e.id?`border-accent bg-accent/10 text-accent font-medium`:`border-border text-muted`),children:s(e.label)},e.id))}),b&&(0,q.jsx)(`div`,{className:`mt-1.5 text-[11.5px] text-muted leading-snug`,children:s(Ge.find(e=>e.id===b).hint)})]}),(0,q.jsx)($,{label:s(`Name`),children:(0,q.jsx)(`input`,{value:g,onChange:e=>_(e.target.value),className:k,placeholder:s(`Work`)})}),(0,q.jsx)($,{label:s(`Private .ics link or file path`),hint:s(`Stored encrypted in the vault as CALENDAR_{name}.`,{name:g.trim().toUpperCase().replace(/[^A-Z0-9]+/g,`_`).replace(/^_+|_+$/g,``)||`NAME`})+` `+s(`nanoMuse fetches whatever address you put here, from this machine; only paste links you trust.`),children:(0,q.jsx)(`input`,{value:v,onChange:e=>y(e.target.value),className:k,placeholder:`https://calendar.google.com/calendar/ical/…/basic.ics`,inputMode:`url`,autoComplete:`off`})}),(0,q.jsxs)(`div`,{className:`flex gap-2`,children:[(0,q.jsxs)(`button`,{type:`button`,disabled:N===`add`||!g.trim()||!v.trim(),onClick:()=>void se(),className:D,children:[N===`add`?(0,q.jsx)(l,{size:16,className:`animate-spin`}):(0,q.jsx)(ee,{size:16}),` `,s(`Connect`)]}),(0,q.jsx)(`button`,{type:`button`,onClick:()=>h(!1),className:T,children:s(`Cancel`)})]})]}):(0,q.jsxs)(`button`,{type:`button`,onClick:()=>h(!0),className:T,children:[(0,q.jsx)(re,{size:16}),` `,s(`Add a calendar`)]}),d.configured&&(0,q.jsxs)(q.Fragment,{children:[(0,q.jsx)($,{label:s(`Working hours`),hint:s(`Free time is looked for inside these hours.`),children:(0,q.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,q.jsx)(`input`,{type:`time`,value:S,onChange:e=>E(e.target.value),"aria-label":s(`Working hours start`),className:t(`w-full rounded-2xl bg-surface-2 px-3.5 py-2.5 text-[14.5px] outline-none focus:ring-2 focus:ring-accent/40`,`w-auto`)}),(0,q.jsx)(`span`,{className:`text-muted`,children:s(`to`)}),(0,q.jsx)(`input`,{type:`time`,value:A,onChange:e=>M(e.target.value),"aria-label":s(`Working hours end`),className:t(`w-full rounded-2xl bg-surface-2 px-3.5 py-2.5 text-[14.5px] outline-none focus:ring-2 focus:ring-accent/40`,`w-auto`)}),(S!==d.day_start||A!==d.day_end)&&(0,q.jsx)(`button`,{type:`button`,disabled:N===`hours`,onClick:()=>void le(),className:t(`flex items-center justify-center gap-1.5 rounded-2xl bg-accent text-accent-fg px-4 py-2.5 text-[14px] font-medium disabled:opacity-40`,`px-3`),"aria-label":s(`Save`),children:N===`hours`?(0,q.jsx)(l,{size:16,className:`animate-spin`}):(0,q.jsx)(C,{size:16})})]})}),(0,q.jsxs)(`button`,{type:`button`,disabled:N===`test`,onClick:()=>void ue(),className:`flex items-center justify-center gap-1.5 rounded-2xl border border-border px-4 py-2.5 text-[14px] font-medium text-muted disabled:opacity-40`,children:[N===`test`?(0,q.jsx)(l,{size:16,className:`animate-spin`}):(0,q.jsx)(P,{size:16}),` `,s(`Read again`)]}),te&&(0,q.jsx)(rt,{result:te,okText:d.feeds.length===1?_e(te.events??0):`${_e(te.events??0)} · ${s(`{n} calendars`,{n:d.feeds.length})}`})]})]})}function qe({data:n,onChange:i,compact:a}){let{toast:o}=c(),s=r(),d=n.contacts,[f,p]=(0,G.useState)(!!a),[m,h]=(0,G.useState)(!1),[g,_]=(0,G.useState)(``),[v,y]=(0,G.useState)(``),[b,x]=(0,G.useState)(null),[S,C]=(0,G.useState)(null),[w,E]=(0,G.useState)(``),[O,A]=(0,G.useState)(null),M=(0,G.useRef)(null),N=e=>e===1?s(`1 person`):s(`{n} people`,{n:e}),F=(e,t)=>{if(e.error)o(s(`Added, but it could not be read: {error}`,{error:e.error}));else{let n=e.sources.find(e=>e.name===t);o(`${s(`Address book connected`)} · ${N(n?.contacts??0)}`),_(``),y(``),h(!1)}i()},te=async()=>{x(`add`),C(null);try{F(await u.addContactsSource(g.trim(),v.trim()),g.trim())}catch(e){o(e.message)}finally{x(null)}},L=async e=>{x(`upload`),C(null);try{let t=(g.trim()||e.name.replace(/\.vcf$/i,``)||`Imported`).slice(0,40);F(await u.importContacts(t,await e.text()),t)}catch(e){o(e.message)}finally{x(null),M.current&&(M.current.value=``)}},ne=async e=>{x(e);try{await u.removeContactsSource(e),i()}catch(e){o(e.message)}finally{x(null)}},R=async()=>{x(`test`);try{C(await u.testContacts()),i()}catch(e){o(e.message)}finally{x(null)}};(0,G.useEffect)(()=>{if(!w.trim()){A(null);return}let e=setTimeout(()=>{u.contacts(w.trim(),5).then(e=>A(e.people)).catch(()=>A([]))},250);return()=>clearTimeout(e)},[w]);let z=d.sources.filter(e=>e.error).length,ie=d.enabled?d.configured?z?{text:s(`{n} not reading`,{n:z}),tone:`warn`}:{text:s(`Connected`),tone:`ok`}:{text:s(`Not connected`),tone:`off`}:{text:s(`Off`),tone:`off`};return(0,q.jsxs)(j,{icon:(0,q.jsx)(U,{size:19}),title:s(`Contacts`),summary:d.configured?d.sources.length===0?`${N(d.count)} · ${s(`told to it in chat`)}`:`${N(d.count)} · ${d.sources.length===1?d.sources[0].name:s(`{n} address books`,{n:d.sources.length})}`:s(`Who is who, so it never guesses an address`),status:ie,open:f,onToggle:a?void 0:()=>p(!f),children:[(0,q.jsx)(`p`,{className:`text-[12.5px] text-muted -mt-1`,children:s(`Import a .vcf export from Google Contacts, iCloud, Outlook or your phone, or paste a link to one. People you mention in chat go into its own book. It looks people up before writing to them and warns when an address is unknown.`)}),(d.sources.length>0||d.own>0)&&(0,q.jsxs)(`ul`,{className:`space-y-1.5`,children:[d.own>0&&(0,q.jsxs)(`li`,{className:`flex items-center gap-2.5 rounded-2xl bg-surface-2/60 px-3 py-2`,children:[(0,q.jsx)(`span`,{className:`h-2 w-2 rounded-full bg-emerald-500`}),(0,q.jsxs)(`div`,{className:`min-w-0 flex-1`,children:[(0,q.jsx)(`div`,{className:`text-[13.5px] font-medium truncate`,children:s(`My contacts`)}),(0,q.jsx)(`div`,{className:`text-[11.5px] text-muted truncate`,children:`${N(d.own)} · ${s(`added in chat`)}`})]})]}),d.sources.map(n=>(0,q.jsxs)(`li`,{className:`flex items-center gap-2.5 rounded-2xl bg-surface-2/60 px-3 py-2`,children:[(0,q.jsx)(`span`,{className:t(`h-2 w-2 rounded-full`,n.error?`bg-rose-500`:n.fetched_at?`bg-emerald-500`:`bg-amber-500`)}),(0,q.jsxs)(`div`,{className:`min-w-0 flex-1`,children:[(0,q.jsx)(`div`,{className:`text-[13.5px] font-medium truncate`,children:n.name}),(0,q.jsxs)(`div`,{className:`text-[11.5px] text-muted truncate`,children:[n.error?n.error:n.fetched_at?`${N(n.contacts)} · ${s(`read {when}`,{when:e(n.fetched_at)})}`:s(`not read yet`),!n.from_app&&` · ${s(`from config.toml`)}`]})]}),n.from_app&&(0,q.jsx)(`button`,{type:`button`,"aria-label":s(`Remove`),disabled:b===n.name,onClick:()=>void ne(n.name),className:`p-1.5 rounded-full text-muted hover:bg-surface-2`,children:b===n.name?(0,q.jsx)(l,{size:15,className:`animate-spin`}):(0,q.jsx)(I,{size:15})})]},n.name))]}),m?(0,q.jsxs)(`div`,{className:`space-y-2.5 rounded-2xl border border-border/70 p-3`,children:[(0,q.jsx)($,{label:s(`Name`),children:(0,q.jsx)(`input`,{value:g,onChange:e=>_(e.target.value),className:k,placeholder:s(`iPhone`)})}),(0,q.jsxs)($,{label:s(`A .vcf file from your phone or computer`),hint:s(`Google Contacts: Export → vCard. iPhone: Contacts → select all → Share → Save to Files. Outlook: People → Manage → Export.`),children:[(0,q.jsx)(`input`,{ref:M,type:`file`,accept:`.vcf,text/vcard,text/x-vcard`,className:`hidden`,onChange:e=>e.target.files?.[0]&&void L(e.target.files[0])}),(0,q.jsxs)(`button`,{type:`button`,disabled:b===`upload`,onClick:()=>M.current?.click(),className:T,children:[b===`upload`?(0,q.jsx)(l,{size:16,className:`animate-spin`}):(0,q.jsx)(pe,{size:16}),` `,s(`Choose a .vcf file`)]})]}),(0,q.jsx)($,{label:s(`Or a link / path to one`),hint:s(`A link is stored encrypted in the vault as CONTACTS_{name}.`,{name:g.trim().toUpperCase().replace(/[^A-Z0-9]+/g,`_`).replace(/^_+|_+$/g,``)||`NAME`})+` `+s(`nanoMuse fetches whatever address you put here, from this machine; only paste links you trust.`),children:(0,q.jsx)(`input`,{value:v,onChange:e=>y(e.target.value),className:k,placeholder:`https://… /contacts.vcf`,inputMode:`url`,autoComplete:`off`})}),(0,q.jsxs)(`div`,{className:`flex gap-2`,children:[(0,q.jsxs)(`button`,{type:`button`,disabled:b===`add`||!g.trim()||!v.trim(),onClick:()=>void te(),className:D,children:[b===`add`?(0,q.jsx)(l,{size:16,className:`animate-spin`}):(0,q.jsx)(ee,{size:16}),` `,s(`Connect`)]}),(0,q.jsx)(`button`,{type:`button`,onClick:()=>h(!1),className:T,children:s(`Cancel`)})]})]}):(0,q.jsxs)(`button`,{type:`button`,onClick:()=>h(!0),className:T,children:[(0,q.jsx)(re,{size:16}),` `,s(`Add an address book`)]}),d.configured&&(0,q.jsxs)(q.Fragment,{children:[(0,q.jsxs)(`div`,{className:`relative`,children:[(0,q.jsx)(B,{size:15,className:`absolute left-3 top-1/2 -translate-y-1/2 text-muted`}),(0,q.jsx)(`input`,{value:w,onChange:e=>E(e.target.value),"aria-label":s(`Find someone, as the agent would`),className:t(`w-full rounded-2xl bg-surface-2 px-3.5 py-2.5 text-[14.5px] outline-none focus:ring-2 focus:ring-accent/40`,`pl-9`),placeholder:s(`Find someone, as the agent would`),autoComplete:`off`})]}),O!==null&&(0,q.jsxs)(`ul`,{className:`space-y-1`,children:[O.length===0&&(0,q.jsx)(`li`,{className:`text-[12.5px] text-muted px-1`,children:s(`No one matches.`)}),O.map(e=>(0,q.jsxs)(`li`,{className:`rounded-2xl bg-surface-2/60 px-3 py-2`,children:[(0,q.jsxs)(`div`,{className:`text-[13.5px] font-medium`,children:[e.name,e.org&&(0,q.jsxs)(`span`,{className:`text-muted font-normal`,children:[` · `,e.org]})]}),(0,q.jsx)(`div`,{className:`text-[12px] text-muted break-words`,children:[...e.emails,...e.phones].join(` · `)})]},e.id))]}),d.sources.length>0&&(0,q.jsxs)(`button`,{type:`button`,disabled:b===`test`,onClick:()=>void R(),className:`flex items-center justify-center gap-1.5 rounded-2xl border border-border px-4 py-2.5 text-[14px] font-medium text-muted disabled:opacity-40`,children:[b===`test`?(0,q.jsx)(l,{size:16,className:`animate-spin`}):(0,q.jsx)(P,{size:16}),` `,s(`Read again`)]}),S&&(0,q.jsx)(rt,{result:S,okText:N(S.contacts??0)})]})]})}function Je({data:e,onChange:n}){let{toast:i}=c(),a=r(),o=e.browser,[s,l]=(0,G.useState)(!1),d=async()=>{l(!0);try{await u.setBrowser(!o.enabled),n()}catch(e){i(e.message)}finally{l(!1)}};return(0,q.jsx)(j,{icon:(0,q.jsx)(V,{size:19}),title:a(`Browser`),summary:o.available?a(`Open pages, click, fill forms, screenshot`):a(`Playwright is not installed on the server`),status:o.enabled&&o.available?{text:a(`On`),tone:`ok`}:o.enabled?{text:a(`Unavailable`),tone:`warn`}:{text:a(`Off`),tone:`off`},open:!1,trailing:(0,q.jsx)(`button`,{type:`button`,role:`switch`,"aria-checked":o.enabled,disabled:s,onClick:()=>void d(),className:t(`relative h-7 w-12 shrink-0 rounded-full transition`,o.enabled?`bg-accent`:`bg-surface-2 border border-border`),children:(0,q.jsx)(`span`,{className:t(`absolute top-0.5 h-6 w-6 rounded-full bg-white shadow transition`,o.enabled?`left-[22px]`:`left-0.5`)})}),children:!o.available&&(0,q.jsxs)(`p`,{className:`text-[12.5px] text-muted`,children:[a(`Install it where the server runs:`),` `,(0,q.jsx)(`code`,{className:`rounded bg-surface-2 px-1`,children:`pip install "nanomuse[browser]" && playwright install chromium`})]})})}function Ye({data:e,onChange:n}){let{toast:i}=c(),a=r(),o=e.gui,[s,d]=(0,G.useState)(!1),[f,p]=(0,G.useState)(!1),[m,h]=(0,G.useState)(o.model),[g,_]=(0,G.useState)(o.base_url),[v,y]=(0,G.useState)(``),[b,x]=(0,G.useState)(null);(0,G.useEffect)(()=>{h(o.model),_(o.base_url)},[o.model,o.base_url]);let S=async()=>{p(!0);try{await u.setGui({enabled:!o.enabled}),n()}catch(e){i(e.message)}finally{p(!1)}},w=async()=>{p(!0),x(null);try{await u.setGui({model:m.trim(),base_url:g.trim(),...v?{api_key:v.trim()}:{}}),y(``),n(),x(await u.testGui())}catch(e){i(e.message)}finally{p(!1)}},T=o.phone,[E,O]=(0,G.useState)(se),A=(0,G.useRef)(E);(0,G.useEffect)(()=>{if(!s)return;let e=()=>{let e=se();e!==A.current&&(A.current=e,O(e),setTimeout(n,400))};return e(),document.addEventListener(`visibilitychange`,e),window.addEventListener(`focus`,e),()=>{document.removeEventListener(`visibilitychange`,e),window.removeEventListener(`focus`,e)}},[s,n]);let M=T.connected?a(`{name} is connected`,{name:T.device?.name??a(`A phone`)}):o.enabled?a(`No phone connected. Open the app on the phone`):a(`Tap, type and swipe in the apps on your phone`);return(0,q.jsxs)(j,{icon:(0,q.jsx)(z,{size:19}),title:a(`Phone`),summary:M,status:o.enabled&&T.connected?{text:a(`On`),tone:`ok`}:o.enabled?{text:a(`Waiting`),tone:`warn`}:{text:a(`Off`),tone:`off`},open:s,onToggle:()=>d(e=>!e),children:[(0,q.jsxs)(`div`,{className:`flex items-center justify-between gap-3`,children:[(0,q.jsxs)(`div`,{className:`text-[13px] leading-snug`,children:[(0,q.jsx)(`div`,{className:`font-medium`,children:a(`Operate the phone`)}),(0,q.jsx)(`div`,{className:`text-[12px] text-muted`,children:a(`When on, the agent can read the screen and act in the apps on the connected phone: 12306, WeChat, Alipay… It asks before paying, sending or deleting.`)})]}),(0,q.jsx)(`button`,{type:`button`,role:`switch`,"aria-checked":o.enabled,disabled:f,onClick:()=>void S(),className:t(`relative h-7 w-12 shrink-0 rounded-full transition`,o.enabled?`bg-accent`:`bg-surface-2 border border-border`),children:(0,q.jsx)(`span`,{className:t(`absolute top-0.5 h-6 w-6 rounded-full bg-white shadow transition`,o.enabled?`left-[22px]`:`left-0.5`)})})]}),E!==null&&(0,q.jsxs)(`div`,{className:`rounded-2xl bg-surface-2 px-3 py-2.5 text-[12.5px] leading-snug space-y-1.5`,children:[(0,q.jsxs)(`div`,{className:`flex items-center justify-between gap-3`,children:[(0,q.jsx)(`span`,{className:`font-medium`,children:a(`This phone`)}),(0,q.jsx)(`span`,{className:t(`rounded-full px-2 py-0.5 text-[11px] font-medium`,E===`on`&&`bg-emerald-500/12 text-emerald-700 dark:text-emerald-300`,E===`off`&&`bg-amber-500/15 text-amber-700 dark:text-amber-300`,E===`unsupported`&&`bg-surface text-muted`),children:a(E===`on`?`Ready`:E===`off`?`Not yet`:`Not on this Android`)})]}),E===`unsupported`&&(0,q.jsx)(`div`,{className:`text-muted`,children:a(`Operating the screen needs Android 11 or newer; this phone can still be used for everything else.`)}),E===`off`&&(0,q.jsxs)(q.Fragment,{children:[(0,q.jsx)(`div`,{className:`text-muted`,children:a(`Turn on the nanoMuse accessibility service; that is how it sees the screen and taps for you, only while a task runs, with a Stop button on screen.`)}),(0,q.jsxs)(`div`,{className:`flex flex-wrap gap-2 pt-0.5`,children:[(0,q.jsx)(`button`,{type:`button`,onClick:()=>R()?.openAccessibilitySettings?.(),className:`rounded-full bg-accent px-3 py-1.5 text-[12.5px] font-medium text-white`,children:a(`Open Accessibility settings`)}),(0,q.jsx)(`button`,{type:`button`,onClick:()=>R()?.openAppSettings?.(),className:`rounded-full border border-border px-3 py-1.5 text-[12.5px]`,children:a(`App settings`)})]}),(0,q.jsx)(`div`,{className:`text-muted`,children:a(`Greyed out with “Restricted setting”? Android 13+ does that for apps installed from a download: in App settings tap ⋮ → Allow restricted settings, then come back.`)})]}),E===`on`&&(0,q.jsx)(`div`,{className:`text-muted`,children:a(`Android may switch the service off after an update or a battery clean-up; if the phone stops answering, come back here.`)})]}),T.connected&&T.device&&(0,q.jsxs)(`div`,{className:`rounded-2xl bg-surface-2 px-3 py-2 text-[12.5px] text-muted`,children:[a(`{name} ({platform}), {n} apps`,{name:T.device.name,platform:T.device.platform,n:String(T.device.apps)}),T.last_screen&&(0,q.jsxs)(q.Fragment,{children:[` `,`·`,` `,a(`last seen in {app}`,{app:T.last_screen.app_name||T.last_screen.app})]})]}),(0,q.jsx)(`div`,{className:`text-[12px] text-muted leading-snug`,children:a(`The operator's model looks at screens step by step: a small, fast model that takes pictures. The Hands model row under Chat model picks one on the same endpoint and key; the fields here are for a different endpoint. Empty = {model}.`,{model:o.default_model||a(`the chat model`)})}),(0,q.jsx)($,{label:a(`Model`),children:(0,q.jsx)(`input`,{value:m,onChange:e=>h(e.target.value),placeholder:o.default_model||a(`same as the chat model`),className:k})}),(0,q.jsx)($,{label:a(`Base URL`),children:(0,q.jsx)(`input`,{value:g,onChange:e=>_(e.target.value),placeholder:a(`same as the chat model`),className:k})}),(0,q.jsx)($,{label:a(`API key`),hint:o.key_source===`vault`?a(`A key is in the vault; leave empty to keep it.`):o.key_source===`config`?a(`Set in config.toml.`):a(`Leave empty to use the main model's key.`),children:(0,q.jsx)(`input`,{type:`password`,value:v,onChange:e=>y(e.target.value),placeholder:`sk-…`,className:k,autoComplete:`off`})}),(0,q.jsxs)(`button`,{type:`button`,disabled:f,onClick:()=>void w(),className:D,children:[f?(0,q.jsx)(l,{size:16,className:`animate-spin`}):(0,q.jsx)(C,{size:16}),a(`Save and test`)]}),b&&(0,q.jsx)(rt,{result:b,okText:a(`The operator's model answers.`)})]})}function Xe({data:e,onChange:n}){let{toast:i}=c(),a=r(),[o,s]=(0,G.useState)(!1),[d,f]=(0,G.useState)(!1),[p,m]=(0,G.useState)(``),[h,g]=(0,G.useState)(``),[_,v]=(0,G.useState)(``),[y,b]=(0,G.useState)(`moderate`),[x,S]=(0,G.useState)(null),C=async()=>{S(`add`);try{let e=h.trim().split(/\s+/).filter(Boolean);await u.addMCP({name:p.trim(),command:e[0]??null,args:e.slice(1),url:_.trim()||null,risk:y}),m(``),g(``),v(``),f(!1),i(a(`Server connected`)),n()}catch(e){i(e.message)}finally{S(null)}},w=async e=>{S(e);try{await u.removeMCP(e),n()}catch(e){i(e.message)}finally{S(null)}},E=e.mcp.filter(e=>e.connected).length,O=(e.shared??[]).filter(e=>e.enabled&&!e.here),A=e=>{m(e.id),v(e.url),g(``),f(!0),s(!0)};return(0,q.jsxs)(j,{icon:(0,q.jsx)(ee,{size:19}),title:a(`MCP servers`),summary:e.mcp.length?a(`{n} of {total} connected · {tools} tools`,{n:E,total:e.mcp.length,tools:e.mcp.reduce((e,t)=>e+t.tools,0)}):a(`Add tools from any Model Context Protocol server`),status:e.mcp.length?{text:a(`{n} on`,{n:E}),tone:E?`ok`:`warn`}:{text:a(`None`),tone:`off`},open:o,onToggle:()=>s(!o),children:[e.mcp.length>0&&(0,q.jsx)(`ul`,{className:`space-y-1.5`,children:e.mcp.map(e=>(0,q.jsxs)(`li`,{className:`flex items-center gap-2.5 rounded-2xl bg-surface-2/60 px-3 py-2`,children:[(0,q.jsx)(`span`,{className:t(`h-2 w-2 rounded-full`,e.connected?`bg-emerald-500`:`bg-rose-500`)}),(0,q.jsxs)(`div`,{className:`min-w-0 flex-1`,children:[(0,q.jsx)(`div`,{className:`text-[13.5px] font-medium truncate`,children:e.builtin?a(`This phone`):e.name}),(0,q.jsxs)(`div`,{className:`text-[11.5px] text-muted truncate`,children:[e.builtin?a(`clipboard, notifications, calendar, contacts, location, alarms, photos`):e.url??[e.command,...e.args].join(` `),` ·`,` `,a(`{n} tools`,{n:e.tools}),` · `,a(e.risk),!e.from_app&&!e.builtin&&` · ${a(`from config.toml`)}`]})]}),e.from_app&&(0,q.jsx)(`button`,{type:`button`,"aria-label":a(`Remove`),disabled:x===e.name,onClick:()=>void w(e.name),className:`p-1.5 rounded-full text-muted hover:bg-surface-2`,children:x===e.name?(0,q.jsx)(l,{size:15,className:`animate-spin`}):(0,q.jsx)(I,{size:15})})]},e.name))}),O.length>0&&(0,q.jsx)(`ul`,{className:`space-y-1.5`,children:O.map(e=>(0,q.jsxs)(`li`,{className:`flex items-center gap-2.5 rounded-2xl border border-dashed border-border/70 px-3 py-2`,children:[(0,q.jsx)(`span`,{className:`h-2 w-2 rounded-full bg-border`}),(0,q.jsxs)(`div`,{className:`min-w-0 flex-1`,children:[(0,q.jsx)(`div`,{className:`text-[13.5px] font-medium truncate`,children:e.label||e.id}),(0,q.jsxs)(`div`,{className:`text-[11.5px] text-muted truncate`,children:[a(`Connected on {device}; sign in here to use it on this device`,{device:e.device||e.device_id}),e.url?` · ${e.url}`:``]})]}),e.url&&(0,q.jsx)(`button`,{type:`button`,onClick:()=>A(e),className:t(`flex items-center justify-center gap-1.5 rounded-2xl border border-border px-4 py-2.5 text-[14px] font-medium text-muted disabled:opacity-40`,`py-1.5 text-[12.5px]`),children:a(`Sign in here`)})]},`${e.device_id}:${e.id}`))}),d?(0,q.jsxs)(`div`,{className:`space-y-2.5 rounded-2xl border border-border/70 p-3`,children:[(0,q.jsx)($,{label:a(`Name`),children:(0,q.jsx)(`input`,{value:p,onChange:e=>m(e.target.value),className:k,placeholder:`filesystem`})}),(0,q.jsx)($,{label:a(`Command`),hint:a(`Run locally over stdio, for example: npx -y @modelcontextprotocol/server-filesystem ./workspace`),children:(0,q.jsx)(`input`,{value:h,onChange:e=>g(e.target.value),className:k,placeholder:`npx -y @modelcontextprotocol/server-…`})}),(0,q.jsx)($,{label:a(`or URL`),hint:a(`A remote server over Streamable HTTP.`),children:(0,q.jsx)(`input`,{value:_,onChange:e=>v(e.target.value),className:k,placeholder:`https://host/mcp`,inputMode:`url`})}),(0,q.jsx)($,{label:a(`Risk of its tools`),hint:a(`Decides when the Sentinel asks you before a call.`),children:(0,q.jsx)(`div`,{className:`flex gap-1.5`,children:[`safe`,`moderate`,`sensitive`].map(e=>(0,q.jsx)(`button`,{type:`button`,onClick:()=>b(e),"aria-pressed":y===e,className:t(`rounded-full px-3 py-1.5 text-[13px] border`,y===e?`border-accent bg-accent/10 text-accent font-medium`:`border-border text-muted`),children:a(e)},e))})}),(0,q.jsxs)(`div`,{className:`flex gap-2`,children:[(0,q.jsxs)(`button`,{type:`button`,disabled:x===`add`||!p.trim()||!(h.trim()||_.trim()),onClick:()=>void C(),className:D,children:[x===`add`?(0,q.jsx)(l,{size:16,className:`animate-spin`}):(0,q.jsx)(ee,{size:16}),` `,a(`Connect`)]}),(0,q.jsx)(`button`,{type:`button`,onClick:()=>f(!1),className:T,children:a(`Cancel`)})]})]}):(0,q.jsxs)(`button`,{type:`button`,onClick:()=>f(!0),className:T,children:[(0,q.jsx)(re,{size:16}),` `,a(`Add a server`)]})]})}function Ze({data:e,onChange:n}){let{toast:i}=c(),a=r(),[o,s]=(0,G.useState)(!1),[d,f]=(0,G.useState)(``),[p,m]=(0,G.useState)(``),[h,g]=(0,G.useState)(null),_=async()=>{g(`add`);try{await u.vaultSet(d.trim(),p),f(``),m(``),i(a(`Stored in the vault`)),n()}catch(e){i(e.message)}finally{g(null)}},v=async e=>{g(e);try{await u.vaultDelete(e),n()}catch(e){i(e.message)}finally{g(null)}};return(0,q.jsxs)(j,{icon:(0,q.jsx)(H,{size:19}),title:a(`Vault`),summary:e.vault.length?a(`{n} secrets · encrypted on your machine`,{n:e.vault.length}):a(`Encrypted secrets the model never sees`),status:{text:`${e.vault.length}`,tone:`off`},open:o,onToggle:()=>s(!o),children:[(0,q.jsxs)(`p`,{className:`text-[12.5px] text-muted -mt-1`,children:[a(`Refer to a secret as`),` `,(0,q.jsx)(`code`,{className:`rounded bg-surface-2 px-1`,children:`{{vault:NAME}}`}),` `,a(`in a tool call or config: the value is filled in after the Sentinel approves and is redacted from everything the model reads.`)]}),e.vault.length>0&&(0,q.jsx)(`ul`,{className:`flex flex-wrap gap-1.5`,children:e.vault.map(e=>(0,q.jsxs)(`li`,{className:`flex items-center gap-1 rounded-full bg-surface-2 pl-3 pr-1 py-1 text-[12.5px] font-mono`,children:[e,(0,q.jsx)(`button`,{type:`button`,"aria-label":a(`Delete {name}`,{name:e}),disabled:h===e,onClick:()=>void v(e),className:`p-1 rounded-full text-muted hover:text-rose-500`,children:h===e?(0,q.jsx)(l,{size:13,className:`animate-spin`}):(0,q.jsx)(I,{size:13})})]},e))}),(0,q.jsxs)(`div`,{className:`grid grid-cols-[1fr_1fr_auto] gap-2 items-end`,children:[(0,q.jsx)($,{label:a(`Name`),children:(0,q.jsx)(`input`,{value:d,onChange:e=>f(e.target.value.toUpperCase().replace(/[^A-Z0-9_.-]/g,`_`)),className:t(k,`font-mono`),placeholder:`GITHUB_TOKEN`})}),(0,q.jsx)($,{label:a(`Value`),children:(0,q.jsx)(`input`,{type:`password`,value:p,onChange:e=>m(e.target.value),className:k,placeholder:a(`secret`),autoComplete:`off`})}),(0,q.jsx)(`button`,{type:`button`,disabled:h===`add`||!d||!p,onClick:()=>void _(),className:t(D,`px-3`),"aria-label":a(`Store`),children:h===`add`?(0,q.jsx)(l,{size:16,className:`animate-spin`}):(0,q.jsx)(re,{size:16})})]})]})}var Qe=`\0other`;function Q({label:e,provider:n,value:i,options:a,more:o=[],onChange:s,other:c=!0,placeholder:l}){let u=r(),d=a.includes(i)||o.includes(i),[f,p]=(0,G.useState)(!1),m=l?u(`Automatic · {model}`,{model:l}):u(`Automatic`),h=e=>e.map(e=>({id:e,name:e})),g=o.length?[{key:`menu`,label:u(`Menu`),rows:h(a),...l?{default:l}:{}},{key:`more`,label:u(`More models on your account`),rows:h(o)}]:[{key:`list`,label:n,rows:h(a),...l?{default:l}:{}}],_=i&&d?{group:a.includes(i)?g[0].key:`more`,id:i}:void 0;return(0,q.jsxs)(`div`,{className:`block text-[12.5px] text-muted`,children:[(0,q.jsx)(`span`,{className:`block mb-1`,children:e}),(a.length||o.length)&&(d||!i)&&!f?(0,q.jsx)(ye,{label:e,text:i?`${n} · ${i}`:m,heads:[{value:``,label:m}],headValue:i?void 0:``,groups:g,current:_,onHead:()=>s(``),onPick:(e,t)=>s(t.id),tail:c?u(`Other model…`):void 0,onTail:()=>{p(!0),s(``)}}):(0,q.jsx)(`input`,{value:i,onChange:e=>s(e.target.value),placeholder:m,"aria-label":e,className:t(k,`text-fg`),spellCheck:!1})]})}function $e(){let e=r();return F?(0,q.jsxs)(`a`,{href:F,target:`_blank`,rel:`noopener noreferrer`,className:`inline-flex items-center gap-0.5 text-accent`,children:[e(`How`),` `,(0,q.jsx)(w,{size:11})]}):null}var et=new Set([`input`,`select`,`textarea`]);function tt(e){return(0,G.isValidElement)(e)&&typeof e.type==`string`&&et.has(e.type)}function nt(e,t,n){let r=e=>{let r=e.props.id??t;return{node:(0,G.cloneElement)(e,{id:r,"aria-describedby":e.props[`aria-describedby`]??n}),id:r}};if(tt(e))return r(e);if(!(0,G.isValidElement)(e))return null;let i=G.Children.toArray(e.props.children),a=i.filter(tt);if(a.length!==1)return null;let o=r(a[0]),s=i.map(e=>e===a[0]?o.node:e);return{node:(0,G.cloneElement)(e,void 0,...s),id:o.id}}function $({label:e,hint:t,children:n}){let r=(0,G.useId)(),i=t?`${r}-hint`:void 0,a=`${r}-label`,o=nt(n,r,i);return(0,q.jsxs)(`div`,{children:[(0,q.jsx)(`label`,{id:a,htmlFor:o?.id,className:`text-[12px] text-muted`,children:e}),(0,q.jsx)(`div`,{className:`mt-1`,role:o?void 0:`group`,"aria-labelledby":o?void 0:a,"aria-describedby":o?void 0:i,children:o?o.node:n}),t&&(0,q.jsx)(`div`,{id:i,className:`mt-1 text-[11.5px] text-muted leading-snug`,children:t})]})}function rt({result:e,okText:n}){let i=r(),[a,o]=(0,G.useState)(!1),s=!e.ok&&e.detail&&e.detail!==e.error?e.detail:null;return(0,q.jsxs)(`div`,{className:t(`rounded-2xl px-3 py-2 text-[12.5px]`,e.ok?`bg-emerald-500/12 text-emerald-700 dark:text-emerald-300`:`bg-rose-500/12 text-rose-700 dark:text-rose-300`),children:[e.ok?n:i(e.error??`The model provider did not answer.`),s&&(0,q.jsxs)(q.Fragment,{children:[` `,(0,q.jsx)(`button`,{type:`button`,onClick:()=>o(e=>!e),className:`underline decoration-dotted underline-offset-2 opacity-70 hover:opacity-100`,children:i(a?`Hide details`:`Details`)}),a&&(0,q.jsx)(`div`,{className:`mt-1.5 break-all font-mono text-[11px] opacity-80`,children:s})]})]})}function it(e){try{return new URL(e).host}catch{return e}}export{Ke as CalendarCard,Le as ConnectionsScreen,qe as ContactsCard,We as EmailCard,Re as ModelCard}; \ No newline at end of file diff --git a/nanomuse/server/static/assets/ConnectionsScreen-DIFZneZ_.js b/nanomuse/server/static/assets/ConnectionsScreen-DIFZneZ_.js deleted file mode 100644 index 384daca2e..000000000 --- a/nanomuse/server/static/assets/ConnectionsScreen-DIFZneZ_.js +++ /dev/null @@ -1 +0,0 @@ -import{A as e,E as t,J as n,K as r,L as i,Q as a,Y as o,b as s,f as c,q as l,x as u}from"./MuseHeader-BvAlmxiL.js";import{C as d,O as f,S as p,b as m,f as h,g,h as _,k as v,m as y,v as b,w as x,x as S}from"./StarNudge-Cr_QPa4y.js";import{n as C,t as w}from"./external-link-V2ISE5bW.js";import{a as T,c as E,i as D,r as O,s as k,t as A}from"./Form-C77NCy9F.js";import{t as j}from"./clapperboard-90G9CI1B.js";import{t as M}from"./image-Cn9LGhlN.js";import{t as N}from"./plug-u8jLJjTk.js";import{t as P}from"./refresh-cw-BMLOGb5p.js";import{Ct as F,E as I,G as L,N as ee,P as R,T as te,V as z,X as B,Z as ne,j as V,lt as re,pt as H,st as ie,ut as ae,xt as oe}from"./index-tZx-TDX4.js";import{t as se}from"./BackBar-DmScFXW_.js";import{t as ce}from"./CloudCard-CZ8tYr3g.js";var le=n(`brain-circuit`,[[`path`,{d:`M12 5a3 3 0 1 0-5.997.125 4 4 0 0 0-2.526 5.77 4 4 0 0 0 .556 6.588A4 4 0 1 0 12 18Z`,key:`l5xja`}],[`path`,{d:`M9 13a4.5 4.5 0 0 0 3-4`,key:`10igwf`}],[`path`,{d:`M6.003 5.125A3 3 0 0 0 6.401 6.5`,key:`105sqy`}],[`path`,{d:`M3.477 10.896a4 4 0 0 1 .585-.396`,key:`ql3yin`}],[`path`,{d:`M6 18a4 4 0 0 1-1.967-.516`,key:`2e4loj`}],[`path`,{d:`M12 13h4`,key:`1ku699`}],[`path`,{d:`M12 18h6a2 2 0 0 1 2 2v1`,key:`105ag5`}],[`path`,{d:`M12 8h8`,key:`1lhi5i`}],[`path`,{d:`M16 8V5a2 2 0 0 1 2-2`,key:`u6izg6`}],[`circle`,{cx:`16`,cy:`13`,r:`.5`,key:`ry7gng`}],[`circle`,{cx:`18`,cy:`3`,r:`.5`,key:`1aiba7`}],[`circle`,{cx:`20`,cy:`21`,r:`.5`,key:`yhc1fs`}],[`circle`,{cx:`20`,cy:`8`,r:`.5`,key:`1e43v0`}]]),ue=n(`contact`,[[`path`,{d:`M16 2v2`,key:`scm5qe`}],[`path`,{d:`M7 22v-2a2 2 0 0 1 2-2h6a2 2 0 0 1 2 2v2`,key:`1waht3`}],[`path`,{d:`M8 2v2`,key:`pbkmx`}],[`circle`,{cx:`12`,cy:`11`,r:`3`,key:`itu57m`}],[`rect`,{x:`3`,y:`4`,width:`18`,height:`18`,rx:`2`,key:`12vinp`}]]),de=n(`eye-off`,[[`path`,{d:`M10.733 5.076a10.744 10.744 0 0 1 11.205 6.575 1 1 0 0 1 0 .696 10.747 10.747 0 0 1-1.444 2.49`,key:`ct8e1f`}],[`path`,{d:`M14.084 14.158a3 3 0 0 1-4.242-4.242`,key:`151rxh`}],[`path`,{d:`M17.479 17.499a10.75 10.75 0 0 1-15.417-5.151 1 1 0 0 1 0-.696 10.75 10.75 0 0 1 4.446-5.143`,key:`13bj9a`}],[`path`,{d:`m2 2 20 20`,key:`1ooewy`}]]),fe=n(`eye`,[[`path`,{d:`M2.062 12.348a1 1 0 0 1 0-.696 10.75 10.75 0 0 1 19.876 0 1 1 0 0 1 0 .696 10.75 10.75 0 0 1-19.876 0`,key:`1nclc0`}],[`circle`,{cx:`12`,cy:`12`,r:`3`,key:`1v7zrd`}]]),U=n(`unplug`,[[`path`,{d:`m19 5 3-3`,key:`yk6iyv`}],[`path`,{d:`m2 22 3-3`,key:`19mgm9`}],[`path`,{d:`M6.3 20.3a2.4 2.4 0 0 0 3.4 0L12 18l-6-6-2.3 2.3a2.4 2.4 0 0 0 0 3.4Z`,key:`goz73y`}],[`path`,{d:`M7.5 13.5 10 11`,key:`7xgeeb`}],[`path`,{d:`M10.5 16.5 13 14`,key:`10btkg`}],[`path`,{d:`m12 6 6 6 2.3-2.3a2.4 2.4 0 0 0 0-3.4l-2.6-2.6a2.4 2.4 0 0 0-3.4 0Z`,key:`1snsnr`}]]),W=n(`upload`,[[`path`,{d:`M12 3v12`,key:`1x0j5s`}],[`path`,{d:`m17 8-5-5-5 5`,key:`7q97r8`}],[`path`,{d:`M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4`,key:`ih7n3h`}]]),G=a(o(),1);function pe(e,t){let n=t.trim().toLowerCase();return!n||e.id.toLowerCase().includes(n)||e.name.toLowerCase().includes(n)}function K(e,t){let n=e.default&&e.rows.some(t=>t.id===e.default)?e.default:e.rows.find(e=>e.recommended)?.id,r=t&&t.group===e.key?t.id:void 0,i=[];for(let t of[n,r]){if(!t||i.some(e=>e.id===t))continue;let n=e.rows.find(e=>e.id===t);n&&i.push(n)}return[...i,...e.rows.filter(e=>!i.includes(e))]}function me(e){return e.reduce((e,t)=>e+t.rows.length,0)}function he(e){return me(e)>8}function ge(e,{current:t,query:n=``,expanded:r}={}){let i=n.trim().length>0,a=[];for(let o of e){let e=K(o,t);if(i){let t=e.filter(e=>pe(e,n));t.length&&a.push({key:o.key,label:o.label,rows:t,more:0});continue}e.length>8&&!r?.has(o.key)?a.push({key:o.key,label:o.label,rows:e.slice(0,8),more:e.length-8}):a.push({key:o.key,label:o.label,rows:e,more:0})}return a}var q=s(),_e=`flex w-full items-center gap-2 rounded-xl px-3 py-2 text-left text-[14px] hover:bg-surface-2 focus:bg-surface-2 focus:outline-none`;function ve({label:e,text:n,heads:i=[],headValue:a,tail:o,groups:s,current:c,disabled:l,onHead:u,onPick:d,onTail:f,rowText:p}){let m=r(),[h,g]=(0,G.useState)(!1),[_,v]=(0,G.useState)(``),[y,b]=(0,G.useState)(()=>new Set),[x,S]=(0,G.useState)(!1),w=(0,G.useRef)(null),T=(0,G.useRef)(null),D=he(s),k=(0,G.useCallback)((e=!1)=>{g(!1),v(``),b(new Set),S(e)},[]);(0,G.useEffect)(()=>{!h&&x&&(S(!1),w.current?.focus())},[h,x]),(0,G.useEffect)(()=>{if(!h)return;let e=e=>{let t=e.target;T.current?.contains(t)||w.current?.contains(t)||k()},t=e=>{e.key===`Escape`&&(e.stopPropagation(),k(!0))};return document.addEventListener(`pointerdown`,e,!0),document.addEventListener(`keydown`,t,!0),()=>{document.removeEventListener(`pointerdown`,e,!0),document.removeEventListener(`keydown`,t,!0)}},[h,k]),(0,G.useEffect)(()=>{h&&T.current&&(T.current.querySelector(`input`)??T.current.querySelector(`[aria-selected="true"]`)??T.current.querySelector(`[data-row]`))?.focus()},[h]);let A=e=>{if(e.key!==`ArrowDown`&&e.key!==`ArrowUp`)return;let t=[...e.currentTarget.closest(`[role="listbox"]`)?.querySelectorAll(`[data-row]`)??[]];if(!t.length)return;e.preventDefault();let n=t.indexOf(e.target);t[e.key===`ArrowDown`?n<0?0:Math.min(t.length-1,n+1):n<0?t.length-1:Math.max(0,n-1)]?.focus()},j=ge(s,{current:c,query:_,expanded:y}),M=_.trim().length>0,N=(e,n,r,i,a)=>(0,q.jsxs)(`button`,{type:`button`,role:`option`,"aria-selected":n,"data-row":``,title:a,onClick:i,onKeyDown:A,className:t(_e,n&&`text-accent font-medium`),children:[(0,q.jsx)(`span`,{className:`min-w-0 flex-1 truncate`,children:r}),n&&(0,q.jsx)(C,{size:15,className:`shrink-0`})]},e);return(0,q.jsxs)(`div`,{className:`relative`,children:[(0,q.jsxs)(`button`,{ref:w,type:`button`,disabled:l,"aria-label":e,"aria-haspopup":`listbox`,"aria-expanded":h,title:n,onClick:()=>h?k():g(!0),className:t(O,`flex items-center gap-2 text-left text-fg disabled:opacity-50`),children:[(0,q.jsx)(`span`,{className:`min-w-0 flex-1 truncate`,children:n}),(0,q.jsx)(E,{size:16,className:`shrink-0 text-muted`})]}),h&&(0,q.jsxs)(`div`,{ref:T,role:`listbox`,"aria-label":e,className:`absolute left-0 right-0 top-full z-30 mt-1 flex max-h-[60vh] flex-col overflow-hidden rounded-2xl border border-border bg-surface p-1.5 shadow-xl`,children:[i.length>0&&(0,q.jsx)(`div`,{className:`mb-1 flex flex-col border-b border-border pb-1`,children:i.map(e=>N(`head:${e.value}`,a===e.value,e.label,()=>{u?.(e.value),k(!0)}))}),D&&(0,q.jsxs)(`label`,{className:`mb-1.5 flex items-center gap-2 rounded-xl bg-surface-2 px-3 py-2 text-muted focus-within:ring-2 focus-within:ring-accent/40`,children:[(0,q.jsx)(B,{size:15,className:`shrink-0`}),(0,q.jsx)(`input`,{type:`search`,value:_,onChange:e=>v(e.target.value),onKeyDown:A,placeholder:m(`Search models`),"aria-label":m(`Search models`),autoComplete:`off`,spellCheck:!1,className:`min-w-0 flex-1 bg-transparent text-[14px] text-fg outline-none placeholder:text-muted`})]}),(0,q.jsxs)(`div`,{className:`min-h-0 flex-1 overflow-y-auto`,children:[M&&j.length===0&&(0,q.jsx)(`div`,{className:`px-3 py-2.5 text-[13.5px] text-muted`,children:m(`No model matches`)}),j.map(e=>(0,q.jsxs)(`div`,{role:`group`,"aria-label":e.label,className:`[&+&]:mt-1.5`,children:[(0,q.jsx)(`div`,{className:`truncate px-3 pb-0.5 pt-1.5 text-[11px] font-semibold uppercase tracking-wide text-muted`,children:e.label}),e.rows.map(t=>N(`${e.key}:${t.id}`,c?.group===e.key&&c.id===t.id,p?p(t):t.name,()=>{d(e.key,t),k(!0)},t.id)),e.more>0&&(0,q.jsx)(`button`,{type:`button`,"data-row":``,onKeyDown:A,onClick:()=>b(t=>new Set([...t,e.key])),className:t(_e,`text-[13px] text-accent`),children:m(`Show {n} more`,{n:e.more})})]},e.key))]}),o&&!M&&(0,q.jsx)(`div`,{className:`mt-1 border-t border-border pt-1`,children:N(`tail`,!1,o,()=>{f?.(),k(!0)})})]})]})}var ye=`nanomuse_cloud`,be=`{{vault:NANOMUSE_CLOUD_KEY}}`,xe=`custom`,Se=`endpoint:`,Ce=[`openai`,`openai_responses`];function we(e){try{return new URL(e).hostname.toLowerCase()}catch{return``}}function Te(e){return Se+e}function Ee(e){return e.startsWith(`endpoint:`)&&e.length>9?e.slice(9):null}function De(e){if(e.label.trim())return e.label.trim();try{return new URL(e.base_url).host}catch{return e.base_url}}function J(e,t){return e?t.find(t=>t.id===e)??null:null}function Oe(e,t=``){return e.filter(e=>e.id!==t&&e.models.length).map(e=>({key:Te(e.id),label:De(e),rows:e.models.filter(e=>f(e)!==!1).map(e=>({id:e,name:e}))})).filter(e=>e.rows.length)}function ke(e,t,n=h){if(e&&!Ce.includes(e))return n.find(t=>t.id===e)??null;let r=we(t);if(!r)return null;let i=e=>[e.base_url,e.base_url_global].map(e=>we(e??``)).filter(Boolean);return n.find(e=>i(e).includes(r))||(n.find(e=>i(e).some(e=>{let t=e.indexOf(`.`);return t>0&&r.endsWith(e.slice(t))}))??null)}function Ae(e,t,n=``,r=h){if(e===`nanomuse_cloud`)return`nanoMuse Cloud`;if(e===`chatgpt`)return`ChatGPT`;let i=r.find(t=>t.id===e);return i&&e!==`custom`?S(i,t):we(n)||e}function je(e,t,n=h,r=[]){if(!e.effective_provider)return``;let i=J(e.endpoint,r),a=i?De(i):Ae(e.effective_provider,t,e.base_url,n);return e.effective_model?`${a} · ${e.effective_model}`:a}function Me(e,t,n,r=h,i=[]){let a=e.effective_model??``;if(!a)return``;let o=(e,t)=>Ae(ke(e,t,r)?.id??(Ce.includes(e)?`custom`:e),n,t,r),s,c=J(e.endpoint,i),l=J(t.endpoint,i);return s=e.effective_source===`cloud`?`nanoMuse Cloud`:e.effective_source===`gui`&&c?De(c):e.effective_source===`gui`&&(e.provider_id||e.base_url||!Ce.includes(e.provider||`openai`))?e.provider_id?Ae(e.provider_id,n,e.base_url,r):o(e.provider,e.base_url):t.cloud?`nanoMuse Cloud`:l?De(l):o(t.provider,t.base_url),`${s} · ${a}`}function Y(e,t){let n=t.list??h,r=[];t.signedIn&&r.push({value:ye,label:`nanoMuse Cloud`,group:`cloud`,needsKey:!1,entry:null});let i=t.chat.cloud?null:ke(t.chat.provider,t.chat.base_url,n);i&&i.capabilities.includes(e)&&r.push({value:i.id,label:S(i,t.locale),group:`chat`,needsKey:!1,entry:i});for(let e of t.endpoints??[])r.push({value:Te(e.id),label:De(e),group:`endpoints`,needsKey:!1,entry:null});for(let a of p(t.region,e,n))a.id!==i?.id&&r.push({value:a.id,label:S(a,t.locale),group:`add`,needsKey:!0,entry:a});return r.push({value:xe,label:``,group:`add`,needsKey:!1,entry:null}),r}function Ne(e,t){return e.configured?t&&e.base_url&&we(e.base_url)===we(t)?ye:e.endpoint?Te(e.endpoint):e.provider_id||`custom`:``}var Pe=`nanomuse_cloud`,Fe=`add-endpoint`;function Ie(){let{state:e}=c(),[t,n]=(0,G.useState)(null),[i,a]=(0,G.useState)(null),o=e.profile?.name??`nanoMuse`,s=r(),d=(0,G.useCallback)(async()=>{try{n(await u.connections()),a(null)}catch(e){a(s(e.message))}},[s]);return(0,G.useEffect)(()=>{d()},[d,e.connectionsVersion]),(0,q.jsxs)(`div`,{className:`flex h-full flex-col`,children:[(0,q.jsx)(se,{title:s(`Connections`),description:s(`What {name} can reach; keys stay in the vault on this machine.`,{name:o})}),(0,q.jsxs)(`div`,{className:`flex-1 overflow-y-auto px-4 pb-8 space-y-4`,children:[i&&(0,q.jsx)(`div`,{className:`rounded-2xl bg-rose-500/12 text-rose-700 dark:text-rose-300 p-3 text-[13.5px]`,children:i}),!t&&!i&&(0,q.jsx)(`div`,{className:`flex justify-center py-10 text-muted`,children:(0,q.jsx)(l,{className:`animate-spin`,size:20})}),t&&(0,q.jsxs)(q.Fragment,{children:[(0,q.jsx)(Le,{data:t,onChange:d}),t.image&&(0,q.jsx)(Ve,{slot:`image`,data:t,onChange:d}),t.video&&(0,q.jsx)(Ve,{slot:`video`,data:t,onChange:d}),(0,q.jsx)(ce,{account:e.hub?.account??null,onChange:d}),t.embeddings.memory_enabled&&(0,q.jsx)(X,{data:t,onChange:d}),(0,q.jsx)(Z,{data:t,onChange:d}),(0,q.jsx)(Ue,{data:t,onChange:d}),(0,q.jsx)(Ge,{data:t,onChange:d}),(0,q.jsx)(Ke,{data:t,onChange:d}),(0,q.jsx)(qe,{data:t,onChange:d}),(0,q.jsx)(Je,{data:t,onChange:d}),(0,q.jsx)(Ye,{data:t,onChange:d}),(0,q.jsx)(Xe,{data:t,onChange:d})]})]})]})}function Le({data:e,onChange:n,compact:a}){let{toast:o,state:s}=c(),p=r(),[m,g]=(0,G.useState)(!!a),T=e.providers,D=e.endpoints??[],O=e.endpoints!==void 0,j=D.find(t=>t.id===e.llm.endpoint)??null,M=!!s.hub?.account?.any_model,P=(j?Te(j.id):null)??Object.entries(T).find(([t,n])=>t!==`custom`&&n.base_url&&e.llm.base_url.startsWith(n.base_url)&&n.provider===e.llm.provider)?.[0]??Object.entries(T).find(([t,n])=>t!==`custom`&&n.base_url&&e.llm.base_url.startsWith(n.base_url))?.[0]??(e.llm.base_url?`custom`:`deepseek`),I=e=>{if(e===Fe)return{label:p(`Add an endpoint`),subtitle:T.custom?.subtitle,group:`local`,provider:`openai`,base_url:``,key_optional:!0};let t=Ee(e);if(!t)return T[e];let n=D.find(e=>e.id===t);return n?{label:De(n),group:`local`,provider:`openai`,base_url:n.base_url,models:n.models,no_key:!0}:void 0},[L,te]=(0,G.useState)(P),z=(0,G.useRef)(``),[B,V]=(0,G.useState)(e.llm.model),[H,ie]=(0,G.useState)(e.llm.base_url),[ae,oe]=(0,G.useState)(``),[se,ce]=(0,G.useState)(!1),[le,ue]=(0,G.useState)(!1),[U,W]=(0,G.useState)(e.llm.key_source===`none`&&!!T[P]?.key_optional),[pe,K]=(0,G.useState)(e.llm.tool_mode||`auto`),[me,he]=(0,G.useState)(e.llm.proxy??``),[ge,_e]=(0,G.useState)(!1),[ye,be]=(0,G.useState)(!1),[xe,Se]=(0,G.useState)(null),[Ce,we]=(0,G.useState)(!1),[J,ke]=(0,G.useState)(e.gui?.model??``),[Ae,je]=(0,G.useState)(e.gui?.endpoint??``),[Y,Ne]=(0,G.useState)({list:I(P)?.models??[],image:[],video:[],menu:[],catalog:[],imageCatalog:[],videoCatalog:[],vision:[],gui:T[P]?.gui_models??[],source:`catalogue`}),[Ie,Le]=(0,G.useState)(!1),[Re,Ve]=(0,G.useState)(!1);(0,G.useEffect)(()=>{V(e.llm.model),ie(e.llm.base_url),K(e.llm.tool_mode||`auto`),he(e.llm.proxy??``),_e(!1),ke(e.gui?.model??``),je(e.gui?.endpoint??``);let t=D.find(e=>e.id===z.current);if(t){z.current=``,te(Te(t.id)),ie(t.base_url),t.models.includes(e.llm.model)||V(t.models[0]??``),Le(!1);return}te(P)},[e.llm,e.gui?.model,e.gui?.endpoint,e.endpoints]);let X=I(L),Z=D.find(e=>Te(e.id)===L)??null,He=L===Fe,Ue=L===`custom`||!X?.base_url?H:X.base_url;(0,G.useEffect)(()=>{if(!m||He)return;let e=!0,t=setTimeout(()=>{Ne(e=>({...e,source:`loading`})),u.llmModels(Z?{endpoint:Z.id}:{preset:L,base_url:Ue,api_key:ae||void 0}).then(t=>{e&&(Ne({list:t.models,image:t.image_models??[],video:t.video_models??[],menu:t.menu??[],catalog:t.catalog??[],imageCatalog:t.image_catalog??[],videoCatalog:t.video_catalog??[],vision:t.vision??[],gui:t.gui??T[L]?.gui_models??[],source:t.source}),t.source===`live`&&t.models.length&&!Ie&&V(e=>t.models.includes(e)?e:t.models[0]))}).catch(()=>e&&Ne({list:X?.models??[],image:[],video:[],menu:[],catalog:[],imageCatalog:[],videoCatalog:[],vision:[],gui:X?.gui_models??[],source:`catalogue`}))},ae?600:150);return()=>{e=!1,clearTimeout(t)}},[m,L,Ue,ae]);let We=t=>{te(t);let n=I(t);n&&(n.base_url?ie(n.base_url):X?.base_url&&ie(``),(!B||Object.values(T).some(e=>e.models?.includes(B))||D.some(e=>e.models.includes(B)))&&n.models?.length&&!n.models.includes(B)&&V(n.models[0]),Ne({list:n.models??[],image:[],video:[],menu:[],catalog:[],imageCatalog:[],videoCatalog:[],vision:[],gui:n.gui_models??[],source:`catalogue`}),(!e.gui?.model||Object.values(T).some(t=>t.gui_model===e.gui?.model))&&ke(n.cloud?``:n.gui_model??``),Ve(!1),Le(!1),W(!1))};(0,G.useEffect)(()=>{let e=ee();e&&T[e]&&(g(!0),We(e))},[]);let Ge=!!X?.no_key||U&&!!X?.key_optional,Ke=e.llm.cloud?{text:p(`Your account's model`),tone:`ok`}:e.llm.key_source===`none`&&j?{text:p(`No key`),tone:`ok`}:e.llm.key_source===`none`&&!T[P]?.no_key&&!T[P]?.key_optional?{text:p(`No key yet`),tone:`warn`}:e.llm.key_source===`missing`?{text:p(`Key missing from vault`),tone:`warn`}:{text:e.llm.key_source===`vault`?p(`Key in vault`):e.llm.key_source===`config`?p(`Key from config`):p(`No key needed`),tone:`ok`},qe=async()=>{be(!0),Se(null);try{X?.cloud?await u.cloudUseAsModel(B.trim()):Z?await u.setLLM({endpoint:Z.id,model:B.trim(),tool_mode:pe,proxy:ge&&e.llm.proxy!==void 0?me.trim():null}):await u.setLLM({provider:X?.provider??`openai`,model:B.trim(),base_url:Ue.trim(),tool_mode:pe,api_key:ae||(Ge?``:null),proxy:ge&&e.llm.proxy!==void 0?me.trim():null});let t={model:e.gui?.model??``,endpoint:e.gui?.endpoint??``};(J.trim()!==t.model||Ae!==t.endpoint)&&(Ae?await u.setGui({endpoint:Ae,model:J.trim()}):t.endpoint?await u.setGui({model:J.trim(),provider:``,base_url:``,api_key:``}):await u.setGui({model:J.trim()})),oe(``),b(),o(p(`Model saved`)),n(),a||g(!1)}catch(e){o(e.message)}finally{be(!1)}},Je=async()=>{we(!0);try{Se(await u.testLLM())}catch(e){Se({ok:!1,error:e.message})}finally{we(!1)}},Ye=[{id:`cloud`,title:p(`Your account`),ids:[]},{id:`openai`,title:p(`OpenAI-compatible · Chat Completions`),ids:[]},{id:`responses`,title:p(`Responses API`),ids:[]},{id:`local`,title:p(`Local or your own endpoint`),ids:[]}];for(let[e,t]of Object.entries(T))(Ye.find(e=>e.id===(t.group??`openai`))??Ye[0]).ids.push(e);for(let e of Ye)e.ids=v(e.ids,T,s.hub?.account);let Xe=Ye.find(e=>e.id===`local`);if(Xe){let e=Xe.ids.filter(e=>e!==`custom`||!O||P===`custom`);Xe.ids=[...D.map(e=>Te(e.id)),...e,...O?[Fe]:[]]}let Qe=!Z&&!He&&(L===`custom`||!X?.base_url),Q=X?.cloud||Z||He?null:h.find(e=>e.id===y(L))??null,et=d(s.hub?.account),tt=i(),it=e=>!!Q&&!Q.user_capabilities&&!Q.capabilities.includes(e),at=T[Pe],ot=X?.cloud?Y.gui[0]??X.gui_model??``:Q&&!Q.user_capabilities?Q.capabilities.includes(`vision`)?Q.defaults.hands||B.trim():at?.gui_model??B.trim():B.trim(),st=!X?.cloud&&it(`vision`)&&!!at,ct=e.gui?Me(e.gui,e.llm,tt,h,D):``,lt=Array.from(new Set([...X?.cloud?Y.gui:[],...X?.gui_model?[X.gui_model]:[],...Y.list.filter(e=>Y.vision.includes(e)||f(e)===!0)])).filter(Boolean),ut=X?.cloud?`nanoMuse Cloud`:Z?De(Z):Q?S(Q,tt):rt(Ue)||L,dt=X?.cloud?Y.gui[0]??X.gui_model??``:Q?.defaults.hands??X?.gui_model??``,ft=[{key:`hands`,label:ut,rows:lt.map(e=>({id:e,name:e})),...dt?{default:dt}:{}},...Oe(D,Z?.id??``)],pt=Ae&&Ae!==Z?.id?Te(Ae):`hands`,mt=D.find(e=>e.id===Ae)??null,ht=J?`${pt===`hands`?ut:mt?De(mt):``} · ${J}`:p(`Automatic`),gt=Qe&&/^https?:\/\/[^/]+\/?$/.test(H.trim());return(0,q.jsxs)(A,{icon:(0,q.jsx)(F,{size:19}),title:p(`Chat model`),summary:e.llm.cloud?`nanoMuse Cloud · ${e.llm.model||p(`No model yet`)}`:j?`${e.llm.model||p(`No model yet`)} · ${De(j)}`:`${e.llm.model||p(`No model yet`)}${e.llm.base_url?` · ${rt(e.llm.base_url)}`:``}`,status:Ke,open:m,onToggle:a?void 0:()=>g(!m),children:[(0,q.jsx)($,{label:p(`Provider`),children:(0,q.jsxs)(`div`,{className:`space-y-2.5`,children:[Ye.filter(e=>e.ids.length).map(e=>(0,q.jsxs)(`div`,{children:[(0,q.jsx)(`div`,{className:`mb-1 text-[11px] uppercase tracking-wide text-muted`,children:e.title}),(0,q.jsx)(`div`,{className:`flex flex-wrap gap-1.5`,children:e.ids.map(e=>{let n=I(e);if(!n)return null;let r=D.find(t=>Te(t.id)===e),i=r?rt(r.base_url)===n.label?void 0:rt(r.base_url):n.subtitle?p(n.subtitle):void 0;return(0,q.jsxs)(`button`,{type:`button`,onClick:()=>We(e),className:t(`rounded-2xl px-3 py-1.5 text-left border leading-tight`,L===e?`border-accent bg-accent/10 text-accent`:`border-border text-muted`),children:[(0,q.jsxs)(`span`,{className:t(`block text-[13px]`,L===e&&`font-medium`,e===Fe&&`inline-flex items-center gap-1`),children:[e===Fe&&(0,q.jsx)(ne,{size:13}),n.label]}),i&&(0,q.jsx)(`span`,{className:`block text-[10.5px] opacity-80`,children:i})]},e)})})]},e.id)),Q&&(0,q.jsxs)(`p`,{className:`text-[12px] text-muted`,children:[(0,q.jsx)(`span`,{className:`font-medium text-fg`,children:S(Q,tt)}),` · `,_(p,Q.capabilities),`. `,tt===`zh-CN`?Q.note_zh:Q.note]}),(0,q.jsxs)(`div`,{children:[(0,q.jsxs)(`button`,{type:`button`,onClick:()=>ue(!le),className:`inline-flex items-center gap-1.5 text-[12.5px] text-accent`,children:[(0,q.jsx)(re,{size:13}),` `,p(`Or sign in with a ChatGPT plan`),` `,le?(0,q.jsx)(k,{size:13}):(0,q.jsx)(E,{size:13})]}),le&&(0,q.jsx)(`div`,{className:`mt-2`,children:(0,q.jsx)(R,{compact:!0,onChanged:()=>{n()}})})]})]})}),He&&(0,q.jsx)(ze,{onAdded:e=>{z.current=e.id,b(),n()}}),Z&&(0,q.jsx)($,{label:p(`Endpoint`),children:(0,q.jsx)(Be,{endpoint:Z,onChange:()=>{b(),n()},onModels:e=>{Ne(t=>({...t,list:e,source:`live`})),e.length&&!Ie&&!e.includes(B)&&V(e[0])}})}),Qe&&(0,q.jsx)($,{label:p(`Base URL`),hint:p(gt?`/v1 is added when the URL has no path.`:`The endpoint that serves /chat/completions, for example http://127.0.0.1:8000/v1.`),children:(0,q.jsx)(`input`,{value:H,onChange:e=>ie(e.target.value),className:`w-full rounded-2xl bg-surface-2 px-3.5 py-2.5 text-[14.5px] outline-none focus:ring-2 focus:ring-accent/40`,placeholder:`https://host/v1`,inputMode:`url`,autoCapitalize:`off`})}),!He&&(0,q.jsxs)($,{label:p(`Chat model`),hint:X?.cloud&&M&&Y.catalog.length?p(`{n} models your account may use: the menu first, then everything else the provider lists under the Cloud key. Pick one; the ones beyond the menu are priced as the dearest menu model of their kind.`,{n:Y.list.length}):X?.cloud&&M?p(`Your account may name any model the provider has, not only these: type its id (a chat model here, a picture or clip model below) and it goes through as typed.`):Y.source===`live`?p(`{n} models from the endpoint`,{n:Y.list.length}):Y.source===`loading`?p(`Asking the endpoint…`):Y.list.length&&Z?p(`{n} models saved with this endpoint`,{n:Y.list.length}):Y.list.length?p(`Could not list the endpoint's models; these are the usual ones.`):void 0,children:[X?.cloud&&Y.catalog.length>0&&!Re&&(!B||Y.list.includes(B))?(0,q.jsxs)(`select`,{value:B,onChange:e=>{if(e.target.value===Ze){Ve(!0);return}V(e.target.value),Le(!0)},className:t(`w-full rounded-2xl bg-surface-2 px-3.5 py-2.5 text-[14.5px] outline-none focus:ring-2 focus:ring-accent/40`,`text-fg`),children:[!B&&(0,q.jsx)(`option`,{value:``,children:p(`model name`)}),(0,q.jsx)(`optgroup`,{label:p(`Menu`),children:Y.menu.map(e=>(0,q.jsx)(`option`,{value:e,children:Y.vision.includes(e)?`${e} · ${p(`reads pictures`)}`:e},e))}),(0,q.jsx)(`optgroup`,{label:p(`More models on your account`),children:Y.catalog.map(e=>(0,q.jsx)(`option`,{value:e,children:Y.vision.includes(e)?`${e} · ${p(`reads pictures`)}`:e},e))}),(0,q.jsx)(`option`,{value:Ze,children:p(`Type a model id…`)})]}):(0,q.jsxs)(q.Fragment,{children:[(0,q.jsx)(`input`,{list:`om-models`,value:B,onChange:e=>{V(e.target.value),Le(!0)},className:`w-full rounded-2xl bg-surface-2 px-3.5 py-2.5 text-[14.5px] outline-none focus:ring-2 focus:ring-accent/40`,placeholder:p(`model name`),autoCapitalize:`off`,autoCorrect:`off`,autoFocus:Re}),(0,q.jsx)(`datalist`,{id:`om-models`,children:Y.list.map(e=>(0,q.jsx)(`option`,{value:e},e))}),X?.cloud&&Y.catalog.length>0&&(0,q.jsx)(`button`,{type:`button`,className:`mt-1.5 text-[12px] text-accent`,onClick:()=>{Ve(!1),Y.list.includes(B)||V(Y.menu[0]??Y.list[0]??``)},children:p(`Pick from the list`)})]}),Y.list.length>0&&(0,q.jsx)(`div`,{className:`mt-1.5 flex flex-wrap gap-1.5`,children:(Y.menu.length?Y.menu:Y.list).slice(0,8).map(e=>(0,q.jsx)(`button`,{type:`button`,onClick:()=>V(e),className:t(`rounded-full px-2.5 py-1 text-[12px] border`,B===e?`border-accent bg-accent/10 text-accent font-medium`:`border-border text-muted`),children:e},e))})]}),!He&&(0,q.jsxs)($,{label:p(`Hands model`),hint:X?.cloud?p(`The model that looks at screens when the hands run: the phone, this computer, a page the browser cannot read. Your account's hands model is {model}; the chat model above is a different pick.`,{model:ot||p(`none`)}):st?p(`The model that looks at screens when the hands run. This provider has no model that sees, so the hands use your account's, {model}, unless you pick one here.`,{model:ot||p(`none`)}):D.length>+!!Z?p(`The model that looks at screens when the hands run: a small, fast one that takes pictures. Pick one of this provider's, or one from another endpoint of your list, which then lends its address and key.`):p(`The model that looks at screens when the hands run: a small, fast one that takes pictures, on the same endpoint and key. Default: this provider's own hands model.`),children:[(0,q.jsx)(ve,{label:p(`Hands model`),text:ht,heads:[{value:``,label:p(`Automatic`)}],headValue:J?void 0:``,groups:ft,current:J?{group:pt,id:J}:void 0,onHead:()=>{ke(``),je(``)},onPick:(e,t)=>{ke(t.id),je(Ee(e)??``)}}),ct&&(0,q.jsx)(`p`,{className:`mt-1.5 text-[12px] text-muted`,children:p(`Currently {value}`,{value:ct})}),!X?.cloud&&B.trim()&&!J&&f(B.trim())===!1&&(0,q.jsx)(`div`,{className:`mt-1.5 text-[12px] text-amber-700 dark:text-amber-300`,children:p(`{model} does not take pictures, so the hands would be blind with it. Pick a model that sees for them.`,{model:B.trim()})}),it(`vision`)&&!st&&(0,q.jsxs)(`div`,{className:`mt-1.5 text-[12px] text-amber-700 dark:text-amber-300`,children:[x(p,`vision`,et,tt),` `,(0,q.jsx)($e,{})]})]}),!X?.no_key&&!He&&(0,q.jsxs)($,{label:p(`API key`),hint:U&&X?.key_optional?p(`No key will be sent.`):e.llm.key_source===`vault`&&L===P?p(`A key is in the vault. Leave blank to keep it.`):p(`Stored encrypted in the vault as LLM_API_KEY.`),children:[(0,q.jsxs)(`div`,{className:`relative`,children:[(0,q.jsx)(`input`,{type:se?`text`:`password`,value:ae,onChange:e=>oe(e.target.value),disabled:U&&!!X?.key_optional,"aria-label":p(`API key`),className:t(`w-full rounded-2xl bg-surface-2 px-3.5 py-2.5 text-[14.5px] outline-none focus:ring-2 focus:ring-accent/40`,`pr-10 disabled:opacity-50`),placeholder:e.llm.key_source===`vault`&&L===P?`••••••••`:X?.key_hint||`sk-…`,autoComplete:`off`,autoCapitalize:`off`,spellCheck:!1}),(0,q.jsx)(`button`,{type:`button`,onClick:()=>ce(!se),"aria-label":p(se?`Hide key`:`Show key`),className:`absolute right-2 top-1/2 -translate-y-1/2 rounded-full p-1.5 text-muted`,children:se?(0,q.jsx)(de,{size:16}):(0,q.jsx)(fe,{size:16})})]}),(0,q.jsxs)(`div`,{className:`mt-1.5 flex items-center justify-between gap-2 text-[12px]`,children:[X?.key_url?(0,q.jsxs)(`a`,{href:X.key_url,target:`_blank`,rel:`noreferrer`,className:`inline-flex items-center gap-1 text-accent`,children:[p(`Get a key from {vendor}`,{vendor:X.label}),` `,(0,q.jsx)(w,{size:12})]}):(0,q.jsx)(`span`,{}),X?.key_optional&&(0,q.jsxs)(`label`,{className:`inline-flex items-center gap-1.5 text-muted`,children:[(0,q.jsx)(`input`,{type:`checkbox`,checked:U,onChange:e=>W(e.target.checked),className:`accent-accent`}),` `,p(`No key`)]})]})]}),!He&&(0,q.jsx)($,{label:p(`Tool calling`),hint:p(`Auto uses the API's function calling and falls back to describing tools in the prompt when the endpoint rejects them. Prompt: for endpoints that silently ignore tools.`),children:(0,q.jsx)(`div`,{className:`flex gap-1.5`,children:[`auto`,`native`,`prompt`].map(e=>(0,q.jsx)(`button`,{type:`button`,onClick:()=>K(e),className:t(`rounded-full px-3 py-1.5 text-[13px] border`,pe===e?`border-accent bg-accent/10 text-accent font-medium`:`border-border text-muted`),children:e},e))})}),!X?.cloud&&!He&&e.llm.proxy!==void 0&&(0,q.jsx)($,{label:p(`Proxy (optional)`),hint:p(`Only this provider's requests go through it. nanoMuse Cloud never does.`),children:(0,q.jsx)(`input`,{className:`w-full rounded-2xl bg-surface-2 px-3.5 py-2.5 text-[14.5px] outline-none focus:ring-2 focus:ring-accent/40`,value:me,onChange:e=>{he(e.target.value),_e(!0)},onFocus:()=>me.includes(`••••`)&&!ge&&he(``),onBlur:()=>!ge&&he(e.llm.proxy??``),placeholder:`http://host:port / socks5://host:port`,autoComplete:`off`,spellCheck:!1})}),!He&&(0,q.jsxs)(`div`,{className:`flex gap-2 pt-1`,children:[(0,q.jsxs)(`button`,{type:`button`,disabled:ye||!B.trim()||Qe&&!H.trim(),onClick:()=>void qe(),className:`flex items-center justify-center gap-1.5 rounded-2xl bg-accent text-accent-fg px-4 py-2.5 text-[14px] font-medium disabled:opacity-40`,children:[ye?(0,q.jsx)(l,{size:16,className:`animate-spin`}):(0,q.jsx)(C,{size:16}),` `,p(`Save`)]}),(0,q.jsxs)(`button`,{type:`button`,disabled:Ce,onClick:()=>void Je(),className:`flex items-center justify-center gap-1.5 rounded-2xl border border-border px-4 py-2.5 text-[14px] font-medium text-muted disabled:opacity-40`,children:[Ce?(0,q.jsx)(l,{size:16,className:`animate-spin`}):(0,q.jsx)(N,{size:16}),` `,p(`Test`)]})]}),xe&&(0,q.jsx)(nt,{result:xe,okText:p(`Replied "{reply}" in {ms} ms`,{reply:xe.reply??``,ms:xe.ms??0})})]})}var Re={chat:`the chat model`,hands:`the hands`,image:`pictures`,video:`clips`};function ze({onAdded:e}){let n=r(),{toast:i}=c(),[a,o]=(0,G.useState)(``),[s,d]=(0,G.useState)(``),[f,p]=(0,G.useState)(``),[m,h]=(0,G.useState)(!1),[g,_]=(0,G.useState)(!1),[v,y]=(0,G.useState)(``),[b,x]=(0,G.useState)(null),[S,C]=(0,G.useState)(!1),w=/^https?:\/\/[^/]+\/?$/.test(s.trim()),T=async()=>{C(!0),x(null);try{let t=await u.addEndpoint({label:a.trim(),base_url:s.trim(),api_key:g?``:f,models:v});i(n(`Endpoint added`)),e(t)}catch(e){x(n(e.message))}finally{C(!1)}};return(0,q.jsxs)(`div`,{className:`space-y-3 rounded-2xl border border-border p-3`,children:[(0,q.jsx)(`p`,{className:`text-[12.5px] text-muted leading-snug`,children:n(`An endpoint joins your list with its own key and stays there; add as many as you use. Pick one as the chat model, or use its models for the hands, pictures and clips.`)}),(0,q.jsx)($,{label:n(`Name (optional)`),hint:n(`How the endpoint reads in the lists; its host when left empty.`),children:(0,q.jsx)(`input`,{value:a,onChange:e=>o(e.target.value),className:O,placeholder:n(`for example: my gateway`),autoCapitalize:`off`})}),(0,q.jsx)($,{label:n(`Base URL`),hint:n(w?`/v1 is added when the URL has no path.`:`The endpoint that serves /chat/completions, for example http://127.0.0.1:8000/v1.`),children:(0,q.jsx)(`input`,{value:s,onChange:e=>d(e.target.value),className:O,placeholder:`https://host/v1`,inputMode:`url`,autoCapitalize:`off`})}),(0,q.jsxs)($,{label:n(`API key`),hint:n(g?`No key will be sent.`:`Stored encrypted in the vault under this endpoint's own name.`),children:[(0,q.jsxs)(`div`,{className:`relative`,children:[(0,q.jsx)(`input`,{type:m?`text`:`password`,value:f,onChange:e=>p(e.target.value),disabled:g,"aria-label":n(`API key`),className:t(O,`pr-10 disabled:opacity-50`),placeholder:`sk-…`,autoComplete:`off`,autoCapitalize:`off`,spellCheck:!1}),(0,q.jsx)(`button`,{type:`button`,onClick:()=>h(!m),"aria-label":n(m?`Hide key`:`Show key`),className:`absolute right-2 top-1/2 -translate-y-1/2 rounded-full p-1.5 text-muted`,children:m?(0,q.jsx)(de,{size:16}):(0,q.jsx)(fe,{size:16})})]}),(0,q.jsxs)(`label`,{className:`mt-1.5 inline-flex items-center gap-1.5 text-[12px] text-muted`,children:[(0,q.jsx)(`input`,{type:`checkbox`,checked:g,onChange:e=>_(e.target.checked),className:`accent-accent`}),` `,n(`No key`)]})]}),(0,q.jsx)($,{label:n(`Models (optional)`),hint:n(`Leave empty when the endpoint lists its models at /models. Otherwise type their ids, separated by commas.`),children:(0,q.jsx)(`input`,{value:v,onChange:e=>y(e.target.value),className:O,placeholder:`model-a, model-b`,autoCapitalize:`off`,autoCorrect:`off`,spellCheck:!1})}),b&&(0,q.jsx)(`div`,{className:`rounded-2xl bg-rose-500/12 px-3 py-2 text-[12.5px] text-rose-700 dark:text-rose-300`,children:b}),(0,q.jsxs)(`button`,{type:`button`,disabled:S||!s.trim(),onClick:()=>void T(),className:D,children:[S?(0,q.jsx)(l,{size:16,className:`animate-spin`}):(0,q.jsx)(ne,{size:16}),` `,n(`Add endpoint`)]})]})}function Be({endpoint:e,onChange:n,onModels:a}){let o=r(),{toast:s}=c(),[d,f]=(0,G.useState)(``),[p,m]=(0,G.useState)(e.label),[h,g]=(0,G.useState)(``),[_,v]=(0,G.useState)(!1),[y,b]=(0,G.useState)(!1),[x,S]=(0,G.useState)(e.models.join(`, `)),[C,w]=(0,G.useState)(!1),[T,E]=(0,G.useState)(null),D=e.models.join(`, `);(0,G.useEffect)(()=>{m(e.label),S(D),f(``),g(``),b(!1),E(null)},[e.id,e.label,D]);let O=async(e,t)=>{w(!0),E(null);try{await e(),t&&s(t),f(``),n()}catch(e){E(o(e.message))}finally{w(!1)}},k=async()=>{w(!0),E(null);try{let t=await u.refreshEndpointModels(e.id);t.source===`live`?(a(t.models),s(o(`{n} models from the endpoint`,{n:t.models.length})),n()):E(o(`The endpoint did not list its models; the saved list stands.`)+(t.error?` ${o(t.error)}`:``))}catch(e){E(o(e.message))}finally{w(!1)}},A=e.key_source===`vault`?o(`Key in vault`):e.key_source===`config`?o(`Key from config`):e.key_source===`missing`?o(`Key missing from vault`):o(`No key`),j=e.slots.map(e=>o(Re[e])).join(i()===`zh-CN`?`、`:`, `),M=e.slots.includes(`chat`),N=`text-[12.5px] text-accent disabled:opacity-50`;return(0,q.jsxs)(`div`,{className:`space-y-2 rounded-2xl border border-border p-3 text-[13px]`,children:[(0,q.jsxs)(`div`,{children:[(0,q.jsx)(`span`,{className:`font-medium text-fg`,children:De(e)}),(0,q.jsxs)(`span`,{className:`text-muted`,children:[` · `,rt(e.base_url)]})]}),(0,q.jsxs)(`div`,{className:`text-[12px] text-muted`,children:[A,` · `,o(`{n} models`,{n:e.models.length}),j?` · ${o(`Used by {slots}`,{slots:j})}`:``]}),d===``&&(0,q.jsxs)(`div`,{className:`flex flex-wrap gap-x-3 gap-y-1`,children:[(0,q.jsx)(`button`,{type:`button`,className:N,disabled:C,onClick:()=>f(`rename`),children:o(`Rename`)}),(0,q.jsx)(`button`,{type:`button`,className:N,disabled:C,onClick:()=>f(`key`),children:o(`Change key`)}),(0,q.jsx)(`button`,{type:`button`,className:N,disabled:C,onClick:()=>f(`models`),children:o(`Edit models`)}),(0,q.jsxs)(`button`,{type:`button`,className:N,disabled:C,onClick:()=>void k(),children:[C?(0,q.jsx)(l,{size:12,className:`inline animate-spin`}):(0,q.jsx)(P,{size:12,className:`inline`}),` `,o(`Ask for its models`)]}),(0,q.jsx)(`button`,{type:`button`,className:t(N,`text-rose-600 dark:text-rose-300`),disabled:C,onClick:()=>f(`remove`),children:o(`Remove`)})]}),d===`rename`&&(0,q.jsxs)(`div`,{className:`space-y-2`,children:[(0,q.jsx)(`input`,{value:p,onChange:e=>m(e.target.value),className:`w-full rounded-2xl bg-surface-2 px-3.5 py-2.5 text-[14.5px] outline-none focus:ring-2 focus:ring-accent/40`,placeholder:rt(e.base_url),autoCapitalize:`off`,"aria-label":o(`Name`)}),(0,q.jsxs)(`div`,{className:`flex gap-2`,children:[(0,q.jsx)(`button`,{type:`button`,disabled:C,className:`flex items-center justify-center gap-1.5 rounded-2xl bg-accent text-accent-fg px-4 py-2.5 text-[14px] font-medium disabled:opacity-40`,onClick:()=>void O(()=>u.updateEndpoint(e.id,{label:p.trim()}),o(`Endpoint renamed`)),children:o(`Save`)}),(0,q.jsx)(`button`,{type:`button`,className:`flex items-center justify-center gap-1.5 rounded-2xl border border-border px-4 py-2.5 text-[14px] font-medium text-muted disabled:opacity-40`,onClick:()=>f(``),children:o(`Cancel`)})]})]}),d===`key`&&(0,q.jsxs)(`div`,{className:`space-y-2`,children:[(0,q.jsxs)(`div`,{className:`relative`,children:[(0,q.jsx)(`input`,{type:_?`text`:`password`,value:h,onChange:e=>g(e.target.value),disabled:y,className:t(`w-full rounded-2xl bg-surface-2 px-3.5 py-2.5 text-[14.5px] outline-none focus:ring-2 focus:ring-accent/40`,`pr-10 disabled:opacity-50`),placeholder:e.key_source===`vault`?`••••••••`:`sk-…`,"aria-label":o(`API key`),autoComplete:`off`,autoCapitalize:`off`,spellCheck:!1}),(0,q.jsx)(`button`,{type:`button`,onClick:()=>v(!_),"aria-label":o(_?`Hide key`:`Show key`),className:`absolute right-2 top-1/2 -translate-y-1/2 rounded-full p-1.5 text-muted`,children:_?(0,q.jsx)(de,{size:16}):(0,q.jsx)(fe,{size:16})})]}),(0,q.jsxs)(`label`,{className:`inline-flex items-center gap-1.5 text-[12px] text-muted`,children:[(0,q.jsx)(`input`,{type:`checkbox`,checked:y,onChange:e=>b(e.target.checked),className:`accent-accent`}),` `,o(`No key`)]}),(0,q.jsxs)(`div`,{className:`flex gap-2`,children:[(0,q.jsx)(`button`,{type:`button`,disabled:C||!y&&!h.trim(),className:`flex items-center justify-center gap-1.5 rounded-2xl bg-accent text-accent-fg px-4 py-2.5 text-[14px] font-medium disabled:opacity-40`,onClick:()=>void O(()=>u.updateEndpoint(e.id,{api_key:y?``:h.trim()}),o(`Key saved`)),children:o(`Save`)}),(0,q.jsx)(`button`,{type:`button`,className:`flex items-center justify-center gap-1.5 rounded-2xl border border-border px-4 py-2.5 text-[14px] font-medium text-muted disabled:opacity-40`,onClick:()=>f(``),children:o(`Cancel`)})]})]}),d===`models`&&(0,q.jsxs)(`div`,{className:`space-y-2`,children:[(0,q.jsx)(`input`,{value:x,onChange:e=>S(e.target.value),className:`w-full rounded-2xl bg-surface-2 px-3.5 py-2.5 text-[14.5px] outline-none focus:ring-2 focus:ring-accent/40`,placeholder:`model-a, model-b`,"aria-label":o(`Models`),autoCapitalize:`off`,autoCorrect:`off`,spellCheck:!1}),(0,q.jsx)(`div`,{className:`text-[12px] text-muted`,children:o(`The ids of the models this endpoint serves, separated by commas; what it lists at /models is added after them.`)}),(0,q.jsxs)(`div`,{className:`flex gap-2`,children:[(0,q.jsx)(`button`,{type:`button`,disabled:C,className:`flex items-center justify-center gap-1.5 rounded-2xl bg-accent text-accent-fg px-4 py-2.5 text-[14px] font-medium disabled:opacity-40`,onClick:()=>void O(()=>u.updateEndpoint(e.id,{models:x}),o(`Models saved`)),children:o(`Save`)}),(0,q.jsx)(`button`,{type:`button`,className:`flex items-center justify-center gap-1.5 rounded-2xl border border-border px-4 py-2.5 text-[14px] font-medium text-muted disabled:opacity-40`,onClick:()=>f(``),children:o(`Cancel`)})]})]}),d===`remove`&&(0,q.jsxs)(`div`,{className:`space-y-2`,children:[(0,q.jsx)(`div`,{className:`text-[12.5px] text-muted`,children:o(M?`The chat model answers through this endpoint; pick another chat model first.`:`Its key goes with it, and the hands, pictures or clips set on it go back to automatic.`)}),(0,q.jsxs)(`div`,{className:`flex gap-2`,children:[(0,q.jsxs)(`button`,{type:`button`,disabled:C||M,className:t(`flex items-center justify-center gap-1.5 rounded-2xl bg-accent text-accent-fg px-4 py-2.5 text-[14px] font-medium disabled:opacity-40`,`bg-rose-600 hover:bg-rose-600/90`),onClick:()=>void O(()=>u.removeEndpoint(e.id),o(`Endpoint removed`)),children:[(0,q.jsx)(z,{size:16}),` `,o(`Remove`)]}),(0,q.jsx)(`button`,{type:`button`,className:`flex items-center justify-center gap-1.5 rounded-2xl border border-border px-4 py-2.5 text-[14px] font-medium text-muted disabled:opacity-40`,onClick:()=>f(``),children:o(`Cancel`)})]})]}),T&&(0,q.jsx)(`div`,{className:`rounded-2xl bg-rose-500/12 px-3 py-2 text-[12.5px] text-rose-700 dark:text-rose-300`,children:T})]})}function Ve({slot:e,data:n,onChange:a}){let{toast:o,state:s}=c(),f=r(),p=n[e],v=e,y=s.hub?.account??null,T=!!y?.signed_in,E=d(y),k=i(),N=n.providers[Pe]?.base_url??``,P=n.endpoints??[],F=Y(v,{signedIn:T,chat:{provider:n.llm.provider,base_url:n.llm.base_url,cloud:!!n.llm.cloud},region:E,locale:k,endpoints:P}),I=Ne(p,N),[L,ee]=(0,G.useState)(!1),[R,te]=(0,G.useState)(I),[z,B]=(0,G.useState)(p.model),[V,re]=(0,G.useState)(p.base_url),[H,ie]=(0,G.useState)(``),[ae,oe]=(0,G.useState)(!1),[se,ce]=(0,G.useState)(!1),[le,ue]=(0,G.useState)({list:[],more:[],source:`catalogue`});(0,G.useEffect)(()=>{te(I),B(p.model),re(p.base_url),ie(``)},[p]);let U=F.find(e=>e.value===R)??null,W=U?.entry??null,pe=W?g(W,E):null,K=P.find(e=>Te(e.id)===R)??null,me=R===`nanomuse_cloud`?N:K?K.base_url:R===`custom`?V.trim():pe?.base_url??``,he=I===R&&I!==``&&(p.key_source===`vault`||p.key_source===`config`),ge=!!U?.needsKey&&!H&&!he,_e=R===`nanomuse_cloud`?le.list[0]??``:W?.defaults[e]??``;(0,G.useEffect)(()=>{if(!L||!R||R!==`nanomuse_cloud`&&!me){ue({list:[],more:[],source:`catalogue`});return}let t=!0,n=setTimeout(()=>{ue(e=>({...e,source:`loading`})),u.llmModels(R===`nanomuse_cloud`?{preset:Pe}:K?{endpoint:K.id}:{preset:W?m(W.id):``,base_url:me,api_key:H||void 0}).then(n=>{if(!t)return;let r=(e===`image`?n.image_models:n.video_models)??[],i=(e===`image`?n.image_catalog:n.video_catalog)??[];ue({list:r.filter(e=>!i.includes(e)),more:i,source:n.source})}).catch(()=>t&&ue({list:[],more:[],source:`catalogue`}))},H?600:150);return()=>{t=!1,clearTimeout(n)}},[L,R,me,H]);let ve=f(e===`image`?`Making pictures`:`Making clips`),ye=f(e===`image`?`Portraits of your Muse.`:`Short clips of your Muse.`),xe=je(p,k,h,P),Se=x(f,v,E,k),Ce=p.effective_provider?p.effective_source===`cloud`?{text:f(`Your account`),tone:`ok`}:p.effective_source===`chat`?{text:f(`The chat model's provider`),tone:`ok`}:{text:f(`Your key`),tone:`ok`}:{text:f(`Not set up`),tone:`warn`},we=async()=>{ce(!0);try{R?R===`nanomuse_cloud`?await u.setMedia(e,{provider:`openai`,base_url:N,model:z.trim(),api_key:be}):K?await u.setMedia(e,{endpoint:K.id,model:z.trim()}):R===`custom`?await u.setMedia(e,{provider:`openai`,base_url:V.trim(),model:z.trim(),api_key:H||null}):await u.setMedia(e,{provider:R,base_url:``,model:z.trim(),api_key:H||(U?.group===`chat`?``:null)}):await u.setMedia(e,{provider:``,model:``,base_url:``,api_key:``}),ie(``),b(),o(f(`Saved`)),a(),ee(!1)}catch(e){o(e.message)}finally{ce(!1)}},Ee=e=>f(e===`cloud`?`Your account`:e===`chat`?`The chat model's provider`:e===`endpoints`?`Your endpoints`:`Add a provider`),De=[`cloud`,`chat`,`endpoints`,`add`].map(e=>({g:e,items:F.filter(t=>t.group===e)})).filter(e=>e.items.length),J=e===`image`?`IMAGE_API_KEY`:`VIDEO_API_KEY`;return(0,q.jsxs)(A,{icon:e===`image`?(0,q.jsx)(M,{size:19}):(0,q.jsx)(j,{size:19}),title:ve,summary:xe||Se,status:Ce,open:L,onToggle:()=>ee(!L),children:[(0,q.jsx)(`p`,{className:`text-[12.5px] text-muted`,children:ye}),(0,q.jsxs)($,{label:f(`Provider`),hint:!xe&&!R?Se:void 0,children:[(0,q.jsxs)(`select`,{value:R,onChange:e=>{te(e.target.value),B(``),ie(``)},className:t(O,`text-fg`),children:[(0,q.jsx)(`option`,{value:``,children:f(`Automatic`)}),De.map(({g:e,items:t})=>(0,q.jsx)(`optgroup`,{label:Ee(e),children:t.map(e=>(0,q.jsx)(`option`,{value:e.value,children:e.value===`custom`?f(`Other OpenAI-compatible endpoint`):e.label},e.value))},e))]}),xe&&(0,q.jsx)(`p`,{className:`mt-1.5 text-[12px] text-muted`,children:f(`Currently {value}`,{value:xe})}),!xe&&!R&&(0,q.jsxs)(`button`,{type:`button`,className:`mt-1.5 inline-flex items-center gap-1 text-[12.5px] text-accent`,onClick:()=>te(F.find(e=>e.group===`add`)?.value??``),children:[(0,q.jsx)(ne,{size:13}),` `,f(`Add a provider`)]}),W&&(0,q.jsxs)(`p`,{className:`mt-1.5 text-[12px] text-muted`,children:[(0,q.jsx)(`span`,{className:`font-medium text-fg`,children:S(W,k)}),` · `,_(f,W.capabilities),`. `,k===`zh-CN`?W.note_zh:W.note]})]}),R===`custom`&&(0,q.jsx)($,{label:f(`Base URL`),hint:f(`The endpoint that serves /images/generations, for example https://host/v1.`),children:(0,q.jsx)(`input`,{value:V,onChange:e=>re(e.target.value),className:`w-full rounded-2xl bg-surface-2 px-3.5 py-2.5 text-[14.5px] outline-none focus:ring-2 focus:ring-accent/40`,placeholder:`https://host/v1`,inputMode:`url`,autoCapitalize:`off`})}),R&&(0,q.jsx)(Qe,{label:f(e===`image`?`Picture model`:`Clip model`),provider:R===`nanomuse_cloud`?`nanoMuse Cloud`:R===`custom`?rt(V)||f(`Other OpenAI-compatible endpoint`):U?.label??R,value:z,options:le.list,more:le.more,onChange:B,other:R!==`nanomuse_cloud`||!!y?.any_model,placeholder:_e||void 0}),R&&R!==`nanomuse_cloud`&&U?.group!==`chat`&&!K&&(0,q.jsxs)($,{label:f(`API key`),hint:he?f(`A key is in the vault. Leave blank to keep it.`):f(`Stored encrypted in the vault as {name}.`,{name:J}),children:[(0,q.jsxs)(`div`,{className:`relative`,children:[(0,q.jsx)(`input`,{type:ae?`text`:`password`,value:H,onChange:e=>ie(e.target.value),"aria-label":f(`API key`),className:t(`w-full rounded-2xl bg-surface-2 px-3.5 py-2.5 text-[14.5px] outline-none focus:ring-2 focus:ring-accent/40`,`pr-10`),placeholder:he?`••••••••`:W?.key_hint||`sk-…`,autoComplete:`off`,autoCapitalize:`off`,spellCheck:!1}),(0,q.jsx)(`button`,{type:`button`,onClick:()=>oe(!ae),"aria-label":f(ae?`Hide key`:`Show key`),className:`absolute right-2 top-1/2 -translate-y-1/2 rounded-full p-1.5 text-muted`,children:ae?(0,q.jsx)(de,{size:16}):(0,q.jsx)(fe,{size:16})})]}),pe?.key_url&&(0,q.jsxs)(`a`,{href:pe.key_url,target:`_blank`,rel:`noreferrer`,className:`mt-1.5 inline-flex items-center gap-1 text-[12px] text-accent`,children:[f(`Get a key from {vendor}`,{vendor:W?S(W,k):``}),` `,(0,q.jsx)(w,{size:12})]})]}),U?.group===`chat`&&(0,q.jsx)(`p`,{className:`text-[12px] text-muted`,children:f(`Uses the chat model's key.`)}),K&&(0,q.jsx)(`p`,{className:`text-[12px] text-muted`,children:f(`Uses the key saved with this endpoint.`)}),(0,q.jsx)(`div`,{className:`flex gap-2 pt-1`,children:(0,q.jsxs)(`button`,{type:`button`,disabled:se||ge||R===`custom`&&!V.trim(),onClick:()=>void we(),className:D,children:[se?(0,q.jsx)(l,{size:16,className:`animate-spin`}):(0,q.jsx)(C,{size:16}),` `,f(`Save`)]})})]})}function X({data:e,onChange:n}){let{toast:i}=c(),a=r(),o=e.embeddings,[s,d]=(0,G.useState)(!1),[f,p]=(0,G.useState)(o.mode),[m,h]=(0,G.useState)(!!o.base_url),[g,_]=(0,G.useState)(o.base_url),[v,y]=(0,G.useState)(o.model),[b,x]=(0,G.useState)(``),[S,w]=(0,G.useState)(!1),[E,O]=(0,G.useState)(null),[k,j]=(0,G.useState)(!1);(0,G.useEffect)(()=>{p(o.mode),h(!!o.base_url),_(o.base_url),y(o.model)},[e.embeddings]);let M=o.mode===`off`?{text:a(`Off`),tone:`off`}:o.available===!0?{text:a(`On`),tone:`ok`}:o.available===!1?{text:o.mode===`on`?a(`Not reachable`):a(`By keyword`),tone:`warn`}:{text:a(`Not tried yet`),tone:`off`},P=o.mode===`off`?a(`Keyword recall only`):o.available===!0?a(`{model} · {n} of {total} memories indexed`,{model:o.model||o.default_model,n:o.indexed,total:o.total}):o.available===!1?o.reason:a(`{model} at {host}`,{model:o.model||o.default_model,host:rt(o.effective_base_url)}),F=async()=>{w(!0),O(null);try{await u.setEmbeddings({mode:f,base_url:m?g.trim():``,model:v.trim(),api_key:m?b||void 0:``}),x(``),i(a(`Saved`)),n()}catch(e){i(e.message)}finally{w(!1)}},I=async()=>{j(!0);try{O(await u.testEmbeddings()),n()}catch(e){O({ok:!1,error:e.message})}finally{j(!1)}},L=e=>t(`rounded-full px-3 py-1.5 text-[13px] border`,e?`border-accent bg-accent/10 text-accent font-medium`:`border-border text-muted`);return(0,q.jsxs)(A,{icon:(0,q.jsx)(le,{size:19}),title:a(`Recall by meaning`),summary:P,status:M,open:s,onToggle:()=>d(!s),children:[(0,q.jsx)(`p`,{className:`text-[12.5px] text-muted leading-snug`,children:a(`Memories are embedded once and a message finds the ones that mean the same thing, in any language: “写邮件给房东” finds “the landlord is Bob Li”. Keyword recall stays; the two are fused.`)}),(0,q.jsx)($,{label:a(`Mode`),hint:a(`Auto uses the model's endpoint when it has embeddings and falls back to keywords when it does not. On insists and warns. Off: keywords only.`),children:(0,q.jsx)(`div`,{className:`flex gap-1.5`,children:[`auto`,`on`,`off`].map(e=>(0,q.jsx)(`button`,{type:`button`,onClick:()=>p(e),className:L(f===e),children:a(e===`auto`?`Auto`:e===`on`?`On`:`Off`)},e))})}),f!==`off`&&(0,q.jsxs)(q.Fragment,{children:[(0,q.jsx)($,{label:a(`Endpoint`),hint:a(m?`Any OpenAI-compatible /embeddings: Ollama with an embedding model pulled, OpenAI, a gateway.`:`The model's endpoint and key. DeepSeek has no embeddings; pick another endpoint.`),children:(0,q.jsxs)(`div`,{className:`flex gap-1.5`,children:[(0,q.jsx)(`button`,{type:`button`,onClick:()=>h(!1),className:L(!m),children:a(`Same as the model`)}),(0,q.jsx)(`button`,{type:`button`,onClick:()=>{h(!0),g||_(`http://127.0.0.1:11434/v1`)},className:L(m),children:a(`Another endpoint`)})]})}),m&&(0,q.jsxs)(q.Fragment,{children:[(0,q.jsx)($,{label:a(`Base URL`),children:(0,q.jsx)(`input`,{value:g,onChange:e=>_(e.target.value),className:`w-full rounded-2xl bg-surface-2 px-3.5 py-2.5 text-[14.5px] outline-none focus:ring-2 focus:ring-accent/40`,placeholder:`http://127.0.0.1:11434/v1`,inputMode:`url`})}),(0,q.jsx)($,{label:a(`API key`),hint:o.key_source===`vault`?a(`A key is in the vault. Leave blank to keep it.`):a(`Stored encrypted in the vault as EMBEDDINGS_API_KEY. Ollama needs none.`),children:(0,q.jsx)(`input`,{type:`password`,value:b,onChange:e=>x(e.target.value),className:`w-full rounded-2xl bg-surface-2 px-3.5 py-2.5 text-[14.5px] outline-none focus:ring-2 focus:ring-accent/40`,placeholder:o.key_source===`vault`?`••••••••`:`sk-…`,autoComplete:`off`})})]}),(0,q.jsx)($,{label:a(`Embedding model`),hint:a(`Blank uses the endpoint's default: {model}. On Ollama: ollama pull qwen3-embedding:0.6b (reads Chinese and English).`,{model:o.default_model}),children:(0,q.jsx)(`input`,{value:v,onChange:e=>y(e.target.value),className:`w-full rounded-2xl bg-surface-2 px-3.5 py-2.5 text-[14.5px] outline-none focus:ring-2 focus:ring-accent/40`,placeholder:o.default_model,autoComplete:`off`})})]}),(0,q.jsxs)(`div`,{className:`flex gap-2 pt-1`,children:[(0,q.jsxs)(`button`,{type:`button`,disabled:S||m&&!/^https?:\/\//.test(g.trim()),onClick:()=>void F(),className:D,children:[S?(0,q.jsx)(l,{size:16,className:`animate-spin`}):(0,q.jsx)(C,{size:16}),` `,a(`Save`)]}),(0,q.jsxs)(`button`,{type:`button`,disabled:k||o.mode===`off`,onClick:()=>void I(),className:T,children:[k?(0,q.jsx)(l,{size:16,className:`animate-spin`}):(0,q.jsx)(N,{size:16}),` `,a(`Test`)]})]}),E&&(0,q.jsx)(nt,{result:E,okText:a(`{model} · {dims} dims · {n} memories indexed · {ms} ms`,{model:E.model??``,dims:E.dims??0,n:E.indexed??0,ms:E.ms??0})})]})}function Z({data:e,onChange:n}){let{toast:i}=c(),a=r(),o=e.search,[s,d]=(0,G.useState)(!1),[f,p]=(0,G.useState)(o.provider),[m,h]=(0,G.useState)(o.base_url),[g,_]=(0,G.useState)(``),[v,y]=(0,G.useState)(!1),[b,x]=(0,G.useState)(null),[S,w]=(0,G.useState)(!1);(0,G.useEffect)(()=>{p(o.provider),h(o.base_url)},[e.search]);let E=o.providers.find(e=>e.id===o.provider),O=o.providers.find(e=>e.id===f),k=!!O?.needs_key,j=o.configured?{text:a(`On`),tone:`ok`}:{text:a(`Not set up`),tone:`warn`},M=o.configured?o.provider===`searxng`?a(`{provider} at {host}`,{provider:E?.label??o.provider,host:rt(o.base_url)}):E?.label??o.provider:a(`{provider} needs {what}; searches use DuckDuckGo until then`,{provider:E?.label??o.provider,what:E?.needs_key?a(`a key`):a(`an instance URL`)}),P=async()=>{y(!0),x(null);try{await u.setSearch({provider:f,base_url:f===`searxng`?m.trim():``,api_key:k?g||void 0:``}),_(``),i(a(`Saved`)),n()}catch(e){i(e.message)}finally{y(!1)}},F=async()=>{w(!0);try{x(await u.testSearch())}catch(e){x({ok:!1,error:e.message})}finally{w(!1)}},I=e=>t(`rounded-full px-3 py-1.5 text-[13px] border`,e?`border-accent bg-accent/10 text-accent font-medium`:`border-border text-muted`),L=f!==`searxng`||/^https?:\/\//.test(m.trim());return(0,q.jsxs)(A,{icon:(0,q.jsx)(B,{size:19}),title:a(`Web search`),summary:M,status:j,open:s,onToggle:()=>d(!s),children:[(0,q.jsx)(`p`,{className:`text-[12.5px] text-muted leading-snug`,children:a(`DuckDuckGo needs nothing, but it is scraped and rate-limits now and then. For searches that always work, use a provider with an API. Whichever you pick, a failed search falls back to DuckDuckGo with a note.`)}),(0,q.jsx)($,{label:a(`Provider`),children:(0,q.jsx)(`div`,{className:`flex flex-wrap gap-1.5`,children:o.providers.map(e=>(0,q.jsx)(`button`,{type:`button`,onClick:()=>p(e.id),className:I(f===e.id),children:e.label},e.id))})}),k&&(0,q.jsxs)($,{label:a(`API key`),hint:o.key_source===`vault`&&o.provider===f?a(`A key is in the vault. Leave blank to keep it.`):a(`Stored encrypted in the vault as SEARCH_API_KEY.`),children:[(0,q.jsx)(`input`,{type:`password`,value:g,onChange:e=>_(e.target.value),"aria-label":a(`API key`),className:`w-full rounded-2xl bg-surface-2 px-3.5 py-2.5 text-[14.5px] outline-none focus:ring-2 focus:ring-accent/40`,placeholder:o.key_source===`vault`&&o.provider===f?`••••••••`:`…`,autoComplete:`off`}),O?.keys_url&&(0,q.jsx)(`a`,{href:O.keys_url,target:`_blank`,rel:`noreferrer`,className:`mt-1 inline-block text-[12px] text-accent`,children:a(`Get a key from {label}`,{label:O.label})})]}),f===`searxng`&&(0,q.jsx)($,{label:a(`Instance URL`),hint:a(`A SearXNG you run, with the JSON format enabled in its settings.`),children:(0,q.jsx)(`input`,{value:m,onChange:e=>h(e.target.value),className:`w-full rounded-2xl bg-surface-2 px-3.5 py-2.5 text-[14.5px] outline-none focus:ring-2 focus:ring-accent/40`,placeholder:`http://127.0.0.1:8080`,inputMode:`url`})}),(0,q.jsxs)(`div`,{className:`flex gap-2 pt-1`,children:[(0,q.jsxs)(`button`,{type:`button`,disabled:v||!L,onClick:()=>void P(),className:D,children:[v?(0,q.jsx)(l,{size:16,className:`animate-spin`}):(0,q.jsx)(C,{size:16}),` `,a(`Save`)]}),(0,q.jsxs)(`button`,{type:`button`,disabled:S,onClick:()=>void F(),className:T,children:[S?(0,q.jsx)(l,{size:16,className:`animate-spin`}):(0,q.jsx)(N,{size:16}),` `,a(`Test`)]})]}),b&&(0,q.jsx)(nt,{result:b,okText:a(`{provider} · {n} results · {ms} ms`,{provider:b.provider??``,n:b.results??0,ms:b.ms??0})})]})}var He=[{id:`gmail`,label:`Gmail`,imap:`imap.gmail.com`,smtp:`smtp.gmail.com`,port:587,starttls:!0},{id:`outlook`,label:`Outlook`,imap:`outlook.office365.com`,smtp:`smtp.office365.com`,port:587,starttls:!0},{id:`icloud`,label:`iCloud`,imap:`imap.mail.me.com`,smtp:`smtp.mail.me.com`,port:587,starttls:!0},{id:`qq`,label:`QQ`,imap:`imap.qq.com`,smtp:`smtp.qq.com`,port:587,starttls:!0},{id:`163`,label:`163`,imap:`imap.163.com`,smtp:`smtp.163.com`,port:465,starttls:!1},{id:`fastmail`,label:`Fastmail`,imap:`imap.fastmail.com`,smtp:`smtp.fastmail.com`,port:587,starttls:!0}];function Ue({data:e,onChange:n,compact:i}){let{toast:a}=c(),o=r(),s=e.email,[d,f]=(0,G.useState)(!!i),[p,m]=(0,G.useState)(s.address),[h,g]=(0,G.useState)(``),[_,v]=(0,G.useState)(s.imap_host),[y,b]=(0,G.useState)(s.imap_port),[x,S]=(0,G.useState)(s.smtp_host),[C,w]=(0,G.useState)(s.smtp_port),[T,E]=(0,G.useState)(s.smtp_starttls),[k,j]=(0,G.useState)(null),[M,P]=(0,G.useState)(null);(0,G.useEffect)(()=>{m(s.address),v(s.imap_host),b(s.imap_port),S(s.smtp_host),w(s.smtp_port),E(s.smtp_starttls)},[s]);let F=e=>{v(e.imap),b(993),S(e.smtp),w(e.port),E(e.starttls)},I=async()=>{j(`save`),P(null);try{await u.setEmail({enabled:!0,address:p.trim(),password:h||void 0,imap_host:_.trim(),imap_port:y,smtp_host:x.trim(),smtp_port:C,smtp_starttls:T}),g(``);let e=await u.testEmail();P(e),a(e.ok?o(`Email connected`):o(`Saved, but the test failed`)),n()}catch(e){a(e.message)}finally{j(null)}},L=async()=>{j(`off`);try{await u.disconnectEmail(),P(null),a(o(`Email disconnected`)),n()}catch(e){a(e.message)}finally{j(null)}},ee=s.enabled&&s.configured?{text:o(`Connected`),tone:`ok`}:s.enabled?{text:o(`Incomplete`),tone:`warn`}:{text:o(`Not connected`),tone:`off`};return(0,q.jsxs)(A,{icon:(0,q.jsx)(ie,{size:19}),title:o(`Email`),summary:s.configured&&s.enabled?`${s.address} · ${o(`reads and sends`)}`:o(`Read your inbox, draft and send mail`),status:ee,open:d,onToggle:i?void 0:()=>f(!d),children:[(0,q.jsx)(`p`,{className:`text-[12.5px] text-muted -mt-1`,children:o(`Reading is a moderate action; sending always asks you first. Use an app password where your provider offers one.`)}),(0,q.jsx)($,{label:o(`Provider`),children:(0,q.jsx)(`div`,{className:`flex flex-wrap gap-1.5`,children:He.map(e=>(0,q.jsx)(`button`,{type:`button`,onClick:()=>F(e),className:t(`rounded-full px-3 py-1.5 text-[13px] border`,_===e.imap?`border-accent bg-accent/10 text-accent font-medium`:`border-border text-muted`),children:e.label},e.id))})}),(0,q.jsx)($,{label:o(`Address`),children:(0,q.jsx)(`input`,{value:p,onChange:e=>m(e.target.value),className:O,placeholder:`you@example.com`,inputMode:`email`,autoComplete:`off`})}),(0,q.jsx)($,{label:o(`Password`),hint:s.password_set?o(`A password is in the vault. Leave blank to keep it.`):o(`Stored encrypted in the vault as EMAIL_PASSWORD.`),children:(0,q.jsx)(`input`,{type:`password`,value:h,onChange:e=>g(e.target.value),className:O,placeholder:s.password_set?`••••••••`:o(`app password`),autoComplete:`off`})}),(0,q.jsxs)(`div`,{className:`grid grid-cols-[1fr_84px] gap-2`,children:[(0,q.jsx)($,{label:o(`IMAP server`),children:(0,q.jsx)(`input`,{value:_,onChange:e=>v(e.target.value),className:O,placeholder:`imap.example.com`})}),(0,q.jsx)($,{label:o(`Port`),children:(0,q.jsx)(`input`,{type:`number`,value:y,onChange:e=>b(Number(e.target.value)),className:O})}),(0,q.jsx)($,{label:o(`SMTP server`),children:(0,q.jsx)(`input`,{value:x,onChange:e=>S(e.target.value),className:O,placeholder:`smtp.example.com`})}),(0,q.jsx)($,{label:o(`Port`),children:(0,q.jsx)(`input`,{type:`number`,value:C,onChange:e=>w(Number(e.target.value)),className:O})})]}),(0,q.jsxs)(`label`,{className:`flex items-center gap-2 text-[13.5px]`,children:[(0,q.jsx)(`input`,{type:`checkbox`,checked:T,onChange:e=>E(e.target.checked),className:`accent-[var(--om-accent)]`}),` `,o(`STARTTLS for SMTP (off for port 465)`)]}),(0,q.jsxs)(`div`,{className:`flex gap-2 pt-1`,children:[(0,q.jsxs)(`button`,{type:`button`,disabled:k!==null||!p.trim()||!_.trim()||!x.trim()||!h&&!s.password_set,onClick:()=>void I(),className:D,children:[k===`save`?(0,q.jsx)(l,{size:16,className:`animate-spin`}):(0,q.jsx)(N,{size:16}),` `,s.configured?o(`Save & test`):o(`Connect`)]}),s.enabled&&(0,q.jsxs)(`button`,{type:`button`,disabled:k!==null,onClick:()=>void L(),className:`flex items-center justify-center gap-1.5 rounded-2xl border border-border px-4 py-2.5 text-[14px] font-medium text-muted disabled:opacity-40`,children:[k===`off`?(0,q.jsx)(l,{size:16,className:`animate-spin`}):(0,q.jsx)(U,{size:16}),` `,o(`Disconnect`)]})]}),M&&(0,q.jsx)(nt,{result:M,okText:o(`Signed in · {n} messages in the inbox`,{n:M.inbox??`?`})})]})}var We=[{id:`google`,label:`Google`,hint:`Settings → your calendar → Integrate calendar → Secret address in iCal format`},{id:`outlook`,label:`Outlook`,hint:`Settings → Calendar → Shared calendars → Publish a calendar → ICS link`},{id:`icloud`,label:`iCloud`,hint:`Share Calendar → Public Calendar → copy the webcal:// link`},{id:`fastmail`,label:`Fastmail`,hint:`Settings → Calendars → Export → Calendar URL`},{id:`file`,label:`.ics file`,hint:`A path on the machine where nanoMuse runs, for example ~/calendar.ics`}];function Ge({data:n,onChange:i,compact:a}){let{toast:o}=c(),s=r(),d=n.calendar,[f,p]=(0,G.useState)(!!a),[m,h]=(0,G.useState)(!1),[g,_]=(0,G.useState)(``),[v,y]=(0,G.useState)(``),[b,x]=(0,G.useState)(null),[S,w]=(0,G.useState)(d.day_start),[E,k]=(0,G.useState)(d.day_end),[j,M]=(0,G.useState)(null),[F,I]=(0,G.useState)(null);(0,G.useEffect)(()=>{w(d.day_start),k(d.day_end)},[d.day_start,d.day_end]);let L=async()=>{M(`add`),I(null);try{let e=await u.addCalendarFeed(g.trim(),v.trim());if(e.error)o(s(`Added, but it could not be read: {error}`,{error:e.error}));else{let t=e.feeds.find(e=>e.name===g.trim());o(`${s(`Calendar connected`)} · ${re(t?.events??0)}`),_(``),y(``),h(!1)}i()}catch(e){o(e.message)}finally{M(null)}},ee=async e=>{M(e);try{await u.removeCalendarFeed(e),i()}catch(e){o(e.message)}finally{M(null)}},R=async()=>{M(`hours`);try{await u.setCalendar({day_start:S,day_end:E}),o(s(`Saved`)),i()}catch(e){o(e.message)}finally{M(null)}},te=async()=>{M(`test`);try{I(await u.testCalendar()),i()}catch(e){o(e.message)}finally{M(null)}},B=d.feeds.reduce((e,t)=>e+t.events,0),V=d.feeds.filter(e=>e.error).length,re=e=>e===1?s(`1 event`):s(`{n} events`,{n:e}),H=d.configured?V?{text:s(`{n} not reading`,{n:V}),tone:`warn`}:{text:s(`Connected`),tone:`ok`}:{text:s(`Not connected`),tone:`off`};return(0,q.jsxs)(A,{icon:(0,q.jsx)(oe,{size:19}),title:s(`Calendar`),summary:d.configured?d.feeds.length===1?`${d.feeds[0].name} · ${re(B)}`:`${s(`{n} calendars`,{n:d.feeds.length})} · ${re(B)}`:s(`Your agenda, free time, and events it can draft`),status:H,open:f,onToggle:a?void 0:()=>p(!f),children:[(0,q.jsx)(`p`,{className:`text-[12.5px] text-muted -mt-1`,children:s(`Reads your calendar from its private .ics link; the link stays in the vault. It never changes your calendar; an event it proposes comes as a file you add with a tap.`)}),d.feeds.length>0&&(0,q.jsx)(`ul`,{className:`space-y-1.5`,children:d.feeds.map(n=>(0,q.jsxs)(`li`,{className:`flex items-center gap-2.5 rounded-2xl bg-surface-2/60 px-3 py-2`,children:[(0,q.jsx)(`span`,{className:t(`h-2 w-2 rounded-full`,n.error?`bg-rose-500`:n.fetched_at?`bg-emerald-500`:`bg-amber-500`)}),(0,q.jsxs)(`div`,{className:`min-w-0 flex-1`,children:[(0,q.jsx)(`div`,{className:`text-[13.5px] font-medium truncate`,children:n.name}),(0,q.jsxs)(`div`,{className:`text-[11.5px] text-muted truncate`,children:[n.error?n.error:n.fetched_at?`${re(n.events)} · ${s(`read {when}`,{when:e(n.fetched_at)})}`:s(`not read yet`),!n.from_app&&` · ${s(`from config.toml`)}`]})]}),n.from_app&&(0,q.jsx)(`button`,{type:`button`,"aria-label":s(`Remove`),disabled:j===n.name,onClick:()=>void ee(n.name),className:`p-1.5 rounded-full text-muted hover:bg-surface-2`,children:j===n.name?(0,q.jsx)(l,{size:15,className:`animate-spin`}):(0,q.jsx)(z,{size:15})})]},n.name))}),m?(0,q.jsxs)(`div`,{className:`space-y-2.5 rounded-2xl border border-border/70 p-3`,children:[(0,q.jsxs)($,{label:s(`Where is the link?`),children:[(0,q.jsx)(`div`,{className:`flex flex-wrap gap-1.5`,children:We.map(e=>(0,q.jsx)(`button`,{type:`button`,onClick:()=>x(b===e.id?null:e.id),className:t(`rounded-full px-3 py-1.5 text-[13px] border`,b===e.id?`border-accent bg-accent/10 text-accent font-medium`:`border-border text-muted`),children:s(e.label)},e.id))}),b&&(0,q.jsx)(`div`,{className:`mt-1.5 text-[11.5px] text-muted leading-snug`,children:s(We.find(e=>e.id===b).hint)})]}),(0,q.jsx)($,{label:s(`Name`),children:(0,q.jsx)(`input`,{value:g,onChange:e=>_(e.target.value),className:O,placeholder:s(`Work`)})}),(0,q.jsx)($,{label:s(`Private .ics link or file path`),hint:s(`Stored encrypted in the vault as CALENDAR_{name}.`,{name:g.trim().toUpperCase().replace(/[^A-Z0-9]+/g,`_`).replace(/^_+|_+$/g,``)||`NAME`})+` `+s(`nanoMuse fetches whatever address you put here, from this machine; only paste links you trust.`),children:(0,q.jsx)(`input`,{value:v,onChange:e=>y(e.target.value),className:O,placeholder:`https://calendar.google.com/calendar/ical/…/basic.ics`,inputMode:`url`,autoComplete:`off`})}),(0,q.jsxs)(`div`,{className:`flex gap-2`,children:[(0,q.jsxs)(`button`,{type:`button`,disabled:j===`add`||!g.trim()||!v.trim(),onClick:()=>void L(),className:D,children:[j===`add`?(0,q.jsx)(l,{size:16,className:`animate-spin`}):(0,q.jsx)(N,{size:16}),` `,s(`Connect`)]}),(0,q.jsx)(`button`,{type:`button`,onClick:()=>h(!1),className:T,children:s(`Cancel`)})]})]}):(0,q.jsxs)(`button`,{type:`button`,onClick:()=>h(!0),className:T,children:[(0,q.jsx)(ne,{size:16}),` `,s(`Add a calendar`)]}),d.configured&&(0,q.jsxs)(q.Fragment,{children:[(0,q.jsx)($,{label:s(`Working hours`),hint:s(`Free time is looked for inside these hours.`),children:(0,q.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,q.jsx)(`input`,{type:`time`,value:S,onChange:e=>w(e.target.value),"aria-label":s(`Working hours start`),className:t(`w-full rounded-2xl bg-surface-2 px-3.5 py-2.5 text-[14.5px] outline-none focus:ring-2 focus:ring-accent/40`,`w-auto`)}),(0,q.jsx)(`span`,{className:`text-muted`,children:s(`to`)}),(0,q.jsx)(`input`,{type:`time`,value:E,onChange:e=>k(e.target.value),"aria-label":s(`Working hours end`),className:t(`w-full rounded-2xl bg-surface-2 px-3.5 py-2.5 text-[14.5px] outline-none focus:ring-2 focus:ring-accent/40`,`w-auto`)}),(S!==d.day_start||E!==d.day_end)&&(0,q.jsx)(`button`,{type:`button`,disabled:j===`hours`,onClick:()=>void R(),className:t(`flex items-center justify-center gap-1.5 rounded-2xl bg-accent text-accent-fg px-4 py-2.5 text-[14px] font-medium disabled:opacity-40`,`px-3`),"aria-label":s(`Save`),children:j===`hours`?(0,q.jsx)(l,{size:16,className:`animate-spin`}):(0,q.jsx)(C,{size:16})})]})}),(0,q.jsxs)(`button`,{type:`button`,disabled:j===`test`,onClick:()=>void te(),className:`flex items-center justify-center gap-1.5 rounded-2xl border border-border px-4 py-2.5 text-[14px] font-medium text-muted disabled:opacity-40`,children:[j===`test`?(0,q.jsx)(l,{size:16,className:`animate-spin`}):(0,q.jsx)(P,{size:16}),` `,s(`Read again`)]}),F&&(0,q.jsx)(nt,{result:F,okText:d.feeds.length===1?re(F.events??0):`${re(F.events??0)} · ${s(`{n} calendars`,{n:d.feeds.length})}`})]})]})}function Ke({data:n,onChange:i,compact:a}){let{toast:o}=c(),s=r(),d=n.contacts,[f,p]=(0,G.useState)(!!a),[m,h]=(0,G.useState)(!1),[g,_]=(0,G.useState)(``),[v,y]=(0,G.useState)(``),[b,x]=(0,G.useState)(null),[S,C]=(0,G.useState)(null),[w,E]=(0,G.useState)(``),[k,j]=(0,G.useState)(null),M=(0,G.useRef)(null),F=e=>e===1?s(`1 person`):s(`{n} people`,{n:e}),I=(e,t)=>{if(e.error)o(s(`Added, but it could not be read: {error}`,{error:e.error}));else{let n=e.sources.find(e=>e.name===t);o(`${s(`Address book connected`)} · ${F(n?.contacts??0)}`),_(``),y(``),h(!1)}i()},L=async()=>{x(`add`),C(null);try{I(await u.addContactsSource(g.trim(),v.trim()),g.trim())}catch(e){o(e.message)}finally{x(null)}},ee=async e=>{x(`upload`),C(null);try{let t=(g.trim()||e.name.replace(/\.vcf$/i,``)||`Imported`).slice(0,40);I(await u.importContacts(t,await e.text()),t)}catch(e){o(e.message)}finally{x(null),M.current&&(M.current.value=``)}},R=async e=>{x(e);try{await u.removeContactsSource(e),i()}catch(e){o(e.message)}finally{x(null)}},te=async()=>{x(`test`);try{C(await u.testContacts()),i()}catch(e){o(e.message)}finally{x(null)}};(0,G.useEffect)(()=>{if(!w.trim()){j(null);return}let e=setTimeout(()=>{u.contacts(w.trim(),5).then(e=>j(e.people)).catch(()=>j([]))},250);return()=>clearTimeout(e)},[w]);let V=d.sources.filter(e=>e.error).length,re=d.enabled?d.configured?V?{text:s(`{n} not reading`,{n:V}),tone:`warn`}:{text:s(`Connected`),tone:`ok`}:{text:s(`Not connected`),tone:`off`}:{text:s(`Off`),tone:`off`};return(0,q.jsxs)(A,{icon:(0,q.jsx)(ue,{size:19}),title:s(`Contacts`),summary:d.configured?d.sources.length===0?`${F(d.count)} · ${s(`told to it in chat`)}`:`${F(d.count)} · ${d.sources.length===1?d.sources[0].name:s(`{n} address books`,{n:d.sources.length})}`:s(`Who is who, so it never guesses an address`),status:re,open:f,onToggle:a?void 0:()=>p(!f),children:[(0,q.jsx)(`p`,{className:`text-[12.5px] text-muted -mt-1`,children:s(`Import a .vcf export from Google Contacts, iCloud, Outlook or your phone, or paste a link to one. People you mention in chat go into its own book. It looks people up before writing to them and warns when an address is unknown.`)}),(d.sources.length>0||d.own>0)&&(0,q.jsxs)(`ul`,{className:`space-y-1.5`,children:[d.own>0&&(0,q.jsxs)(`li`,{className:`flex items-center gap-2.5 rounded-2xl bg-surface-2/60 px-3 py-2`,children:[(0,q.jsx)(`span`,{className:`h-2 w-2 rounded-full bg-emerald-500`}),(0,q.jsxs)(`div`,{className:`min-w-0 flex-1`,children:[(0,q.jsx)(`div`,{className:`text-[13.5px] font-medium truncate`,children:s(`My contacts`)}),(0,q.jsx)(`div`,{className:`text-[11.5px] text-muted truncate`,children:`${F(d.own)} · ${s(`added in chat`)}`})]})]}),d.sources.map(n=>(0,q.jsxs)(`li`,{className:`flex items-center gap-2.5 rounded-2xl bg-surface-2/60 px-3 py-2`,children:[(0,q.jsx)(`span`,{className:t(`h-2 w-2 rounded-full`,n.error?`bg-rose-500`:n.fetched_at?`bg-emerald-500`:`bg-amber-500`)}),(0,q.jsxs)(`div`,{className:`min-w-0 flex-1`,children:[(0,q.jsx)(`div`,{className:`text-[13.5px] font-medium truncate`,children:n.name}),(0,q.jsxs)(`div`,{className:`text-[11.5px] text-muted truncate`,children:[n.error?n.error:n.fetched_at?`${F(n.contacts)} · ${s(`read {when}`,{when:e(n.fetched_at)})}`:s(`not read yet`),!n.from_app&&` · ${s(`from config.toml`)}`]})]}),n.from_app&&(0,q.jsx)(`button`,{type:`button`,"aria-label":s(`Remove`),disabled:b===n.name,onClick:()=>void R(n.name),className:`p-1.5 rounded-full text-muted hover:bg-surface-2`,children:b===n.name?(0,q.jsx)(l,{size:15,className:`animate-spin`}):(0,q.jsx)(z,{size:15})})]},n.name))]}),m?(0,q.jsxs)(`div`,{className:`space-y-2.5 rounded-2xl border border-border/70 p-3`,children:[(0,q.jsx)($,{label:s(`Name`),children:(0,q.jsx)(`input`,{value:g,onChange:e=>_(e.target.value),className:O,placeholder:s(`iPhone`)})}),(0,q.jsxs)($,{label:s(`A .vcf file from your phone or computer`),hint:s(`Google Contacts: Export → vCard. iPhone: Contacts → select all → Share → Save to Files. Outlook: People → Manage → Export.`),children:[(0,q.jsx)(`input`,{ref:M,type:`file`,accept:`.vcf,text/vcard,text/x-vcard`,className:`hidden`,onChange:e=>e.target.files?.[0]&&void ee(e.target.files[0])}),(0,q.jsxs)(`button`,{type:`button`,disabled:b===`upload`,onClick:()=>M.current?.click(),className:T,children:[b===`upload`?(0,q.jsx)(l,{size:16,className:`animate-spin`}):(0,q.jsx)(W,{size:16}),` `,s(`Choose a .vcf file`)]})]}),(0,q.jsx)($,{label:s(`Or a link / path to one`),hint:s(`A link is stored encrypted in the vault as CONTACTS_{name}.`,{name:g.trim().toUpperCase().replace(/[^A-Z0-9]+/g,`_`).replace(/^_+|_+$/g,``)||`NAME`})+` `+s(`nanoMuse fetches whatever address you put here, from this machine; only paste links you trust.`),children:(0,q.jsx)(`input`,{value:v,onChange:e=>y(e.target.value),className:O,placeholder:`https://… /contacts.vcf`,inputMode:`url`,autoComplete:`off`})}),(0,q.jsxs)(`div`,{className:`flex gap-2`,children:[(0,q.jsxs)(`button`,{type:`button`,disabled:b===`add`||!g.trim()||!v.trim(),onClick:()=>void L(),className:D,children:[b===`add`?(0,q.jsx)(l,{size:16,className:`animate-spin`}):(0,q.jsx)(N,{size:16}),` `,s(`Connect`)]}),(0,q.jsx)(`button`,{type:`button`,onClick:()=>h(!1),className:T,children:s(`Cancel`)})]})]}):(0,q.jsxs)(`button`,{type:`button`,onClick:()=>h(!0),className:T,children:[(0,q.jsx)(ne,{size:16}),` `,s(`Add an address book`)]}),d.configured&&(0,q.jsxs)(q.Fragment,{children:[(0,q.jsxs)(`div`,{className:`relative`,children:[(0,q.jsx)(B,{size:15,className:`absolute left-3 top-1/2 -translate-y-1/2 text-muted`}),(0,q.jsx)(`input`,{value:w,onChange:e=>E(e.target.value),"aria-label":s(`Find someone, as the agent would`),className:t(`w-full rounded-2xl bg-surface-2 px-3.5 py-2.5 text-[14.5px] outline-none focus:ring-2 focus:ring-accent/40`,`pl-9`),placeholder:s(`Find someone, as the agent would`),autoComplete:`off`})]}),k!==null&&(0,q.jsxs)(`ul`,{className:`space-y-1`,children:[k.length===0&&(0,q.jsx)(`li`,{className:`text-[12.5px] text-muted px-1`,children:s(`No one matches.`)}),k.map(e=>(0,q.jsxs)(`li`,{className:`rounded-2xl bg-surface-2/60 px-3 py-2`,children:[(0,q.jsxs)(`div`,{className:`text-[13.5px] font-medium`,children:[e.name,e.org&&(0,q.jsxs)(`span`,{className:`text-muted font-normal`,children:[` · `,e.org]})]}),(0,q.jsx)(`div`,{className:`text-[12px] text-muted break-words`,children:[...e.emails,...e.phones].join(` · `)})]},e.id))]}),d.sources.length>0&&(0,q.jsxs)(`button`,{type:`button`,disabled:b===`test`,onClick:()=>void te(),className:`flex items-center justify-center gap-1.5 rounded-2xl border border-border px-4 py-2.5 text-[14px] font-medium text-muted disabled:opacity-40`,children:[b===`test`?(0,q.jsx)(l,{size:16,className:`animate-spin`}):(0,q.jsx)(P,{size:16}),` `,s(`Read again`)]}),S&&(0,q.jsx)(nt,{result:S,okText:F(S.contacts??0)})]})]})}function qe({data:e,onChange:n}){let{toast:i}=c(),a=r(),o=e.browser,[s,l]=(0,G.useState)(!1),d=async()=>{l(!0);try{await u.setBrowser(!o.enabled),n()}catch(e){i(e.message)}finally{l(!1)}};return(0,q.jsx)(A,{icon:(0,q.jsx)(H,{size:19}),title:a(`Browser`),summary:o.available?a(`Open pages, click, fill forms, screenshot`):a(`Playwright is not installed on the server`),status:o.enabled&&o.available?{text:a(`On`),tone:`ok`}:o.enabled?{text:a(`Unavailable`),tone:`warn`}:{text:a(`Off`),tone:`off`},open:!1,trailing:(0,q.jsx)(`button`,{type:`button`,role:`switch`,"aria-checked":o.enabled,disabled:s,onClick:()=>void d(),className:t(`relative h-7 w-12 shrink-0 rounded-full transition`,o.enabled?`bg-accent`:`bg-surface-2 border border-border`),children:(0,q.jsx)(`span`,{className:t(`absolute top-0.5 h-6 w-6 rounded-full bg-white shadow transition`,o.enabled?`left-[22px]`:`left-0.5`)})}),children:!o.available&&(0,q.jsxs)(`p`,{className:`text-[12.5px] text-muted`,children:[a(`Install it where the server runs:`),` `,(0,q.jsx)(`code`,{className:`rounded bg-surface-2 px-1`,children:`pip install "nanomuse[browser]" && playwright install chromium`})]})})}function Je({data:e,onChange:n}){let{toast:i}=c(),a=r(),o=e.gui,[s,d]=(0,G.useState)(!1),[f,p]=(0,G.useState)(!1),[m,h]=(0,G.useState)(o.model),[g,_]=(0,G.useState)(o.base_url),[v,y]=(0,G.useState)(``),[b,x]=(0,G.useState)(null);(0,G.useEffect)(()=>{h(o.model),_(o.base_url)},[o.model,o.base_url]);let S=async()=>{p(!0);try{await u.setGui({enabled:!o.enabled}),n()}catch(e){i(e.message)}finally{p(!1)}},w=async()=>{p(!0),x(null);try{await u.setGui({model:m.trim(),base_url:g.trim(),...v?{api_key:v.trim()}:{}}),y(``),n(),x(await u.testGui())}catch(e){i(e.message)}finally{p(!1)}},T=o.phone,[E,k]=(0,G.useState)(te),j=(0,G.useRef)(E);(0,G.useEffect)(()=>{if(!s)return;let e=()=>{let e=te();e!==j.current&&(j.current=e,k(e),setTimeout(n,400))};return e(),document.addEventListener(`visibilitychange`,e),window.addEventListener(`focus`,e),()=>{document.removeEventListener(`visibilitychange`,e),window.removeEventListener(`focus`,e)}},[s,n]);let M=T.connected?a(`{name} is connected`,{name:T.device?.name??a(`A phone`)}):o.enabled?a(`No phone connected. Open the app on the phone`):a(`Tap, type and swipe in the apps on your phone`);return(0,q.jsxs)(A,{icon:(0,q.jsx)(L,{size:19}),title:a(`Phone`),summary:M,status:o.enabled&&T.connected?{text:a(`On`),tone:`ok`}:o.enabled?{text:a(`Waiting`),tone:`warn`}:{text:a(`Off`),tone:`off`},open:s,onToggle:()=>d(e=>!e),children:[(0,q.jsxs)(`div`,{className:`flex items-center justify-between gap-3`,children:[(0,q.jsxs)(`div`,{className:`text-[13px] leading-snug`,children:[(0,q.jsx)(`div`,{className:`font-medium`,children:a(`Operate the phone`)}),(0,q.jsx)(`div`,{className:`text-[12px] text-muted`,children:a(`When on, the agent can read the screen and act in the apps on the connected phone: 12306, WeChat, Alipay… It asks before paying, sending or deleting.`)})]}),(0,q.jsx)(`button`,{type:`button`,role:`switch`,"aria-checked":o.enabled,disabled:f,onClick:()=>void S(),className:t(`relative h-7 w-12 shrink-0 rounded-full transition`,o.enabled?`bg-accent`:`bg-surface-2 border border-border`),children:(0,q.jsx)(`span`,{className:t(`absolute top-0.5 h-6 w-6 rounded-full bg-white shadow transition`,o.enabled?`left-[22px]`:`left-0.5`)})})]}),E!==null&&(0,q.jsxs)(`div`,{className:`rounded-2xl bg-surface-2 px-3 py-2.5 text-[12.5px] leading-snug space-y-1.5`,children:[(0,q.jsxs)(`div`,{className:`flex items-center justify-between gap-3`,children:[(0,q.jsx)(`span`,{className:`font-medium`,children:a(`This phone`)}),(0,q.jsx)(`span`,{className:t(`rounded-full px-2 py-0.5 text-[11px] font-medium`,E===`on`&&`bg-emerald-500/12 text-emerald-700 dark:text-emerald-300`,E===`off`&&`bg-amber-500/15 text-amber-700 dark:text-amber-300`,E===`unsupported`&&`bg-surface text-muted`),children:a(E===`on`?`Ready`:E===`off`?`Not yet`:`Not on this Android`)})]}),E===`unsupported`&&(0,q.jsx)(`div`,{className:`text-muted`,children:a(`Operating the screen needs Android 11 or newer; this phone can still be used for everything else.`)}),E===`off`&&(0,q.jsxs)(q.Fragment,{children:[(0,q.jsx)(`div`,{className:`text-muted`,children:a(`Turn on the nanoMuse accessibility service; that is how it sees the screen and taps for you, only while a task runs, with a Stop button on screen.`)}),(0,q.jsxs)(`div`,{className:`flex flex-wrap gap-2 pt-0.5`,children:[(0,q.jsx)(`button`,{type:`button`,onClick:()=>I()?.openAccessibilitySettings?.(),className:`rounded-full bg-accent px-3 py-1.5 text-[12.5px] font-medium text-white`,children:a(`Open Accessibility settings`)}),(0,q.jsx)(`button`,{type:`button`,onClick:()=>I()?.openAppSettings?.(),className:`rounded-full border border-border px-3 py-1.5 text-[12.5px]`,children:a(`App settings`)})]}),(0,q.jsx)(`div`,{className:`text-muted`,children:a(`Greyed out with “Restricted setting”? Android 13+ does that for apps installed from a download: in App settings tap ⋮ → Allow restricted settings, then come back.`)})]}),E===`on`&&(0,q.jsx)(`div`,{className:`text-muted`,children:a(`Android may switch the service off after an update or a battery clean-up; if the phone stops answering, come back here.`)})]}),T.connected&&T.device&&(0,q.jsxs)(`div`,{className:`rounded-2xl bg-surface-2 px-3 py-2 text-[12.5px] text-muted`,children:[a(`{name} ({platform}), {n} apps`,{name:T.device.name,platform:T.device.platform,n:String(T.device.apps)}),T.last_screen&&(0,q.jsxs)(q.Fragment,{children:[` `,`·`,` `,a(`last seen in {app}`,{app:T.last_screen.app_name||T.last_screen.app})]})]}),(0,q.jsx)(`div`,{className:`text-[12px] text-muted leading-snug`,children:a(`The operator's model looks at screens step by step: a small, fast model that takes pictures. The Hands model row under Chat model picks one on the same endpoint and key; the fields here are for a different endpoint. Empty = {model}.`,{model:o.default_model||a(`the chat model`)})}),(0,q.jsx)($,{label:a(`Model`),children:(0,q.jsx)(`input`,{value:m,onChange:e=>h(e.target.value),placeholder:o.default_model||a(`same as the chat model`),className:O})}),(0,q.jsx)($,{label:a(`Base URL`),children:(0,q.jsx)(`input`,{value:g,onChange:e=>_(e.target.value),placeholder:a(`same as the chat model`),className:O})}),(0,q.jsx)($,{label:a(`API key`),hint:o.key_source===`vault`?a(`A key is in the vault; leave empty to keep it.`):o.key_source===`config`?a(`Set in config.toml.`):a(`Leave empty to use the main model's key.`),children:(0,q.jsx)(`input`,{type:`password`,value:v,onChange:e=>y(e.target.value),placeholder:`sk-…`,className:O,autoComplete:`off`})}),(0,q.jsxs)(`button`,{type:`button`,disabled:f,onClick:()=>void w(),className:D,children:[f?(0,q.jsx)(l,{size:16,className:`animate-spin`}):(0,q.jsx)(C,{size:16}),a(`Save and test`)]}),b&&(0,q.jsx)(nt,{result:b,okText:a(`The operator's model answers.`)})]})}function Ye({data:e,onChange:n}){let{toast:i}=c(),a=r(),[o,s]=(0,G.useState)(!1),[d,f]=(0,G.useState)(!1),[p,m]=(0,G.useState)(``),[h,g]=(0,G.useState)(``),[_,v]=(0,G.useState)(``),[y,b]=(0,G.useState)(`moderate`),[x,S]=(0,G.useState)(null),C=async()=>{S(`add`);try{let e=h.trim().split(/\s+/).filter(Boolean);await u.addMCP({name:p.trim(),command:e[0]??null,args:e.slice(1),url:_.trim()||null,risk:y}),m(``),g(``),v(``),f(!1),i(a(`Server connected`)),n()}catch(e){i(e.message)}finally{S(null)}},w=async e=>{S(e);try{await u.removeMCP(e),n()}catch(e){i(e.message)}finally{S(null)}},E=e.mcp.filter(e=>e.connected).length,k=(e.shared??[]).filter(e=>e.enabled&&!e.here),j=e=>{m(e.id),v(e.url),g(``),f(!0),s(!0)};return(0,q.jsxs)(A,{icon:(0,q.jsx)(N,{size:19}),title:a(`MCP servers`),summary:e.mcp.length?a(`{n} of {total} connected · {tools} tools`,{n:E,total:e.mcp.length,tools:e.mcp.reduce((e,t)=>e+t.tools,0)}):a(`Add tools from any Model Context Protocol server`),status:e.mcp.length?{text:a(`{n} on`,{n:E}),tone:E?`ok`:`warn`}:{text:a(`None`),tone:`off`},open:o,onToggle:()=>s(!o),children:[e.mcp.length>0&&(0,q.jsx)(`ul`,{className:`space-y-1.5`,children:e.mcp.map(e=>(0,q.jsxs)(`li`,{className:`flex items-center gap-2.5 rounded-2xl bg-surface-2/60 px-3 py-2`,children:[(0,q.jsx)(`span`,{className:t(`h-2 w-2 rounded-full`,e.connected?`bg-emerald-500`:`bg-rose-500`)}),(0,q.jsxs)(`div`,{className:`min-w-0 flex-1`,children:[(0,q.jsx)(`div`,{className:`text-[13.5px] font-medium truncate`,children:e.builtin?a(`This phone`):e.name}),(0,q.jsxs)(`div`,{className:`text-[11.5px] text-muted truncate`,children:[e.builtin?a(`clipboard, notifications, calendar, contacts, location, alarms, photos`):e.url??[e.command,...e.args].join(` `),` ·`,` `,a(`{n} tools`,{n:e.tools}),` · `,a(e.risk),!e.from_app&&!e.builtin&&` · ${a(`from config.toml`)}`]})]}),e.from_app&&(0,q.jsx)(`button`,{type:`button`,"aria-label":a(`Remove`),disabled:x===e.name,onClick:()=>void w(e.name),className:`p-1.5 rounded-full text-muted hover:bg-surface-2`,children:x===e.name?(0,q.jsx)(l,{size:15,className:`animate-spin`}):(0,q.jsx)(z,{size:15})})]},e.name))}),k.length>0&&(0,q.jsx)(`ul`,{className:`space-y-1.5`,children:k.map(e=>(0,q.jsxs)(`li`,{className:`flex items-center gap-2.5 rounded-2xl border border-dashed border-border/70 px-3 py-2`,children:[(0,q.jsx)(`span`,{className:`h-2 w-2 rounded-full bg-border`}),(0,q.jsxs)(`div`,{className:`min-w-0 flex-1`,children:[(0,q.jsx)(`div`,{className:`text-[13.5px] font-medium truncate`,children:e.label||e.id}),(0,q.jsxs)(`div`,{className:`text-[11.5px] text-muted truncate`,children:[a(`Connected on {device}; sign in here to use it on this device`,{device:e.device||e.device_id}),e.url?` · ${e.url}`:``]})]}),e.url&&(0,q.jsx)(`button`,{type:`button`,onClick:()=>j(e),className:t(`flex items-center justify-center gap-1.5 rounded-2xl border border-border px-4 py-2.5 text-[14px] font-medium text-muted disabled:opacity-40`,`py-1.5 text-[12.5px]`),children:a(`Sign in here`)})]},`${e.device_id}:${e.id}`))}),d?(0,q.jsxs)(`div`,{className:`space-y-2.5 rounded-2xl border border-border/70 p-3`,children:[(0,q.jsx)($,{label:a(`Name`),children:(0,q.jsx)(`input`,{value:p,onChange:e=>m(e.target.value),className:O,placeholder:`filesystem`})}),(0,q.jsx)($,{label:a(`Command`),hint:a(`Run locally over stdio, for example: npx -y @modelcontextprotocol/server-filesystem ./workspace`),children:(0,q.jsx)(`input`,{value:h,onChange:e=>g(e.target.value),className:O,placeholder:`npx -y @modelcontextprotocol/server-…`})}),(0,q.jsx)($,{label:a(`or URL`),hint:a(`A remote server over Streamable HTTP.`),children:(0,q.jsx)(`input`,{value:_,onChange:e=>v(e.target.value),className:O,placeholder:`https://host/mcp`,inputMode:`url`})}),(0,q.jsx)($,{label:a(`Risk of its tools`),hint:a(`Decides when the Sentinel asks you before a call.`),children:(0,q.jsx)(`div`,{className:`flex gap-1.5`,children:[`safe`,`moderate`,`sensitive`].map(e=>(0,q.jsx)(`button`,{type:`button`,onClick:()=>b(e),"aria-pressed":y===e,className:t(`rounded-full px-3 py-1.5 text-[13px] border`,y===e?`border-accent bg-accent/10 text-accent font-medium`:`border-border text-muted`),children:a(e)},e))})}),(0,q.jsxs)(`div`,{className:`flex gap-2`,children:[(0,q.jsxs)(`button`,{type:`button`,disabled:x===`add`||!p.trim()||!(h.trim()||_.trim()),onClick:()=>void C(),className:D,children:[x===`add`?(0,q.jsx)(l,{size:16,className:`animate-spin`}):(0,q.jsx)(N,{size:16}),` `,a(`Connect`)]}),(0,q.jsx)(`button`,{type:`button`,onClick:()=>f(!1),className:T,children:a(`Cancel`)})]})]}):(0,q.jsxs)(`button`,{type:`button`,onClick:()=>f(!0),className:T,children:[(0,q.jsx)(ne,{size:16}),` `,a(`Add a server`)]})]})}function Xe({data:e,onChange:n}){let{toast:i}=c(),a=r(),[o,s]=(0,G.useState)(!1),[d,f]=(0,G.useState)(``),[p,m]=(0,G.useState)(``),[h,g]=(0,G.useState)(null),_=async()=>{g(`add`);try{await u.vaultSet(d.trim(),p),f(``),m(``),i(a(`Stored in the vault`)),n()}catch(e){i(e.message)}finally{g(null)}},v=async e=>{g(e);try{await u.vaultDelete(e),n()}catch(e){i(e.message)}finally{g(null)}};return(0,q.jsxs)(A,{icon:(0,q.jsx)(ae,{size:19}),title:a(`Vault`),summary:e.vault.length?a(`{n} secrets · encrypted on your machine`,{n:e.vault.length}):a(`Encrypted secrets the model never sees`),status:{text:`${e.vault.length}`,tone:`off`},open:o,onToggle:()=>s(!o),children:[(0,q.jsxs)(`p`,{className:`text-[12.5px] text-muted -mt-1`,children:[a(`Refer to a secret as`),` `,(0,q.jsx)(`code`,{className:`rounded bg-surface-2 px-1`,children:`{{vault:NAME}}`}),` `,a(`in a tool call or config: the value is filled in after the Sentinel approves and is redacted from everything the model reads.`)]}),e.vault.length>0&&(0,q.jsx)(`ul`,{className:`flex flex-wrap gap-1.5`,children:e.vault.map(e=>(0,q.jsxs)(`li`,{className:`flex items-center gap-1 rounded-full bg-surface-2 pl-3 pr-1 py-1 text-[12.5px] font-mono`,children:[e,(0,q.jsx)(`button`,{type:`button`,"aria-label":a(`Delete {name}`,{name:e}),disabled:h===e,onClick:()=>void v(e),className:`p-1 rounded-full text-muted hover:text-rose-500`,children:h===e?(0,q.jsx)(l,{size:13,className:`animate-spin`}):(0,q.jsx)(z,{size:13})})]},e))}),(0,q.jsxs)(`div`,{className:`grid grid-cols-[1fr_1fr_auto] gap-2 items-end`,children:[(0,q.jsx)($,{label:a(`Name`),children:(0,q.jsx)(`input`,{value:d,onChange:e=>f(e.target.value.toUpperCase().replace(/[^A-Z0-9_.-]/g,`_`)),className:t(O,`font-mono`),placeholder:`GITHUB_TOKEN`})}),(0,q.jsx)($,{label:a(`Value`),children:(0,q.jsx)(`input`,{type:`password`,value:p,onChange:e=>m(e.target.value),className:O,placeholder:a(`secret`),autoComplete:`off`})}),(0,q.jsx)(`button`,{type:`button`,disabled:h===`add`||!d||!p,onClick:()=>void _(),className:t(D,`px-3`),"aria-label":a(`Store`),children:h===`add`?(0,q.jsx)(l,{size:16,className:`animate-spin`}):(0,q.jsx)(ne,{size:16})})]})]})}var Ze=`\0other`;function Qe({label:e,provider:n,value:i,options:a,more:o=[],onChange:s,other:c=!0,placeholder:l}){let u=r(),d=a.includes(i)||o.includes(i),[f,p]=(0,G.useState)(!1),m=l?u(`Automatic · {model}`,{model:l}):u(`Automatic`),h=e=>e.map(e=>({id:e,name:e})),g=o.length?[{key:`menu`,label:u(`Menu`),rows:h(a),...l?{default:l}:{}},{key:`more`,label:u(`More models on your account`),rows:h(o)}]:[{key:`list`,label:n,rows:h(a),...l?{default:l}:{}}],_=i&&d?{group:a.includes(i)?g[0].key:`more`,id:i}:void 0;return(0,q.jsxs)(`div`,{className:`block text-[12.5px] text-muted`,children:[(0,q.jsx)(`span`,{className:`block mb-1`,children:e}),(a.length||o.length)&&(d||!i)&&!f?(0,q.jsx)(ve,{label:e,text:i?`${n} · ${i}`:m,heads:[{value:``,label:m}],headValue:i?void 0:``,groups:g,current:_,onHead:()=>s(``),onPick:(e,t)=>s(t.id),tail:c?u(`Other model…`):void 0,onTail:()=>{p(!0),s(``)}}):(0,q.jsx)(`input`,{value:i,onChange:e=>s(e.target.value),placeholder:m,"aria-label":e,className:t(O,`text-fg`),spellCheck:!1})]})}function $e(){let e=r();return(0,q.jsxs)(`a`,{href:V,target:`_blank`,rel:`noopener noreferrer`,className:`inline-flex items-center gap-0.5 text-accent`,children:[e(`How`),` `,(0,q.jsx)(w,{size:11})]})}var Q=new Set([`input`,`select`,`textarea`]);function et(e){return(0,G.isValidElement)(e)&&typeof e.type==`string`&&Q.has(e.type)}function tt(e,t,n){let r=e=>{let r=e.props.id??t;return{node:(0,G.cloneElement)(e,{id:r,"aria-describedby":e.props[`aria-describedby`]??n}),id:r}};if(et(e))return r(e);if(!(0,G.isValidElement)(e))return null;let i=G.Children.toArray(e.props.children),a=i.filter(et);if(a.length!==1)return null;let o=r(a[0]),s=i.map(e=>e===a[0]?o.node:e);return{node:(0,G.cloneElement)(e,void 0,...s),id:o.id}}function $({label:e,hint:t,children:n}){let r=(0,G.useId)(),i=t?`${r}-hint`:void 0,a=`${r}-label`,o=tt(n,r,i);return(0,q.jsxs)(`div`,{children:[(0,q.jsx)(`label`,{id:a,htmlFor:o?.id,className:`text-[12px] text-muted`,children:e}),(0,q.jsx)(`div`,{className:`mt-1`,role:o?void 0:`group`,"aria-labelledby":o?void 0:a,"aria-describedby":o?void 0:i,children:o?o.node:n}),t&&(0,q.jsx)(`div`,{id:i,className:`mt-1 text-[11.5px] text-muted leading-snug`,children:t})]})}function nt({result:e,okText:n}){let i=r(),[a,o]=(0,G.useState)(!1),s=!e.ok&&e.detail&&e.detail!==e.error?e.detail:null;return(0,q.jsxs)(`div`,{className:t(`rounded-2xl px-3 py-2 text-[12.5px]`,e.ok?`bg-emerald-500/12 text-emerald-700 dark:text-emerald-300`:`bg-rose-500/12 text-rose-700 dark:text-rose-300`),children:[e.ok?n:i(e.error??`The model provider did not answer.`),s&&(0,q.jsxs)(q.Fragment,{children:[` `,(0,q.jsx)(`button`,{type:`button`,onClick:()=>o(e=>!e),className:`underline decoration-dotted underline-offset-2 opacity-70 hover:opacity-100`,children:i(a?`Hide details`:`Details`)}),a&&(0,q.jsx)(`div`,{className:`mt-1.5 break-all font-mono text-[11px] opacity-80`,children:s})]})]})}function rt(e){try{return new URL(e).host}catch{return e}}export{Ge as CalendarCard,Ie as ConnectionsScreen,Ke as ContactsCard,Ue as EmailCard,Le as ModelCard}; \ No newline at end of file diff --git a/nanomuse/server/static/assets/DevicesScreen-BLIuBnuO.js b/nanomuse/server/static/assets/DevicesScreen-BLIuBnuO.js deleted file mode 100644 index 2cc2e13f2..000000000 --- a/nanomuse/server/static/assets/DevicesScreen-BLIuBnuO.js +++ /dev/null @@ -1 +0,0 @@ -import{A as e,E as t,J as n,K as r,Q as i,Y as a,b as o,f as s,x as c}from"./MuseHeader-BvAlmxiL.js";import{n as l}from"./external-link-V2ISE5bW.js";import{o as u}from"./Form-C77NCy9F.js";import{t as d}from"./refresh-cw-BMLOGb5p.js";import{G as f,H as p,a as m,at as h,et as g,ft as _,ht as v,i as y,l as b,o as x,pt as S,s as C}from"./index-tZx-TDX4.js";import{t as w}from"./BackBar-DmScFXW_.js";import{t as T}from"./CloudCard-CZ8tYr3g.js";var E=n(`laptop`,[[`path`,{d:`M18 5a2 2 0 0 1 2 2v8.526a2 2 0 0 0 .212.897l1.068 2.127a1 1 0 0 1-.9 1.45H3.62a1 1 0 0 1-.9-1.45l1.068-2.127A2 2 0 0 0 4 15.526V7a2 2 0 0 1 2-2z`,key:`1pdavp`}],[`path`,{d:`M20.054 15.987H3.946`,key:`14rxg9`}]]),D=n(`wifi`,[[`path`,{d:`M12 20h.01`,key:`zekei9`}],[`path`,{d:`M2 8.82a15 15 0 0 1 20 0`,key:`dnpr2z`}],[`path`,{d:`M5 12.859a10 10 0 0 1 14 0`,key:`1x1e6c`}],[`path`,{d:`M8.5 16.429a5 5 0 0 1 7 0`,key:`1bycff`}]]),O=i(a(),1),k=o(),A=`https://nanomuse.cn/dl/`;function j(){let{state:e,dispatch:n,openThread:i,setTab:a,toast:o}=s(),l=r(),u=e.hub,f=e.hands,[p,m]=(0,O.useState)(!1),h=async()=>{try{let[e,t]=await Promise.all([c.hub(),c.hands()]);n({type:`ws`,msg:{kind:`hub`,hub:e}}),n({type:`ws`,msg:{kind:`hands_state`,hands:t}})}catch{}};(0,O.useEffect)(()=>{h()},[]);let g=async()=>{m(!0),await h(),m(!1)},_=async e=>{try{let t=await c.askDevice(e.id);n({type:`ws`,msg:{kind:`thread`,thread:t.thread}}),i(t.thread.id),a(`chat`)}catch(e){o(e.message)}},v=e=>{window.confirm(l(`Forget {name}? It can join again by signing in.`,{name:e.name}))&&c.forgetDevice(e.id).then(e=>n({type:`ws`,msg:{kind:`hub`,hub:e}})).catch(e=>o(e.message))},y=(u?.devices??[]).filter(e=>!e.this&&e.kind!==`web`),b=!!u?.account.signed_in,x=u?.state===`connected`,S=y.length+(u&&x?1:0),C=y.filter(e=>e.online).length+(u&&x?1:0);return(0,k.jsxs)(`div`,{className:`flex h-full flex-col`,children:[(0,k.jsx)(w,{title:l(`Devices`),actions:(0,k.jsx)(`button`,{type:`button`,onClick:()=>void g(),"aria-label":l(`Refresh`),title:l(`Refresh`),className:`flex h-9 w-9 items-center justify-center rounded-full text-muted hover:bg-surface-2 hover:text-fg`,children:(0,k.jsx)(d,{size:17,className:t(p&&`animate-spin`)})})}),(0,k.jsxs)(`div`,{className:`@container flex-1 overflow-y-auto pb-8`,children:[(0,k.jsxs)(`div`,{className:`px-5 pb-4 pt-1`,children:[(0,k.jsx)(`p`,{className:`text-[14px] leading-[20px] text-muted`,children:l(`Every device signed in to your account is a Muse of its own, on the same conversations. Type @ and a device's name in the chat to hand it work; a computer lends its hands.`)}),u&&b&&S>0&&(0,k.jsxs)(`p`,{className:`mt-1.5 text-[12.5px] font-medium uppercase tracking-wide text-muted/80`,children:[S===1?l(`1 device`):l(`{n} devices`,{n:S}),` · `,l(`{n} online`,{n:C})]})]}),(0,k.jsx)(`div`,{className:`px-4 pb-3`,children:(0,k.jsx)(T,{account:u?.account??null,onChange:()=>void h()})}),u&&(0,k.jsxs)(`div`,{className:`px-4`,children:[(0,k.jsx)(M,{children:l(`This device`)}),(0,k.jsx)(H,{hub:u,hands:f??void 0,onChange:()=>void h()})]}),(0,k.jsxs)(`div`,{className:`px-4 pt-4`,children:[(0,k.jsx)(M,{children:l(`Other devices`)}),y.length===0?(0,k.jsx)(G,{hub:u??void 0,signedIn:b}):(0,k.jsx)(`div`,{className:`grid grid-cols-1 gap-3 @2xl:grid-cols-2`,children:y.map(e=>(0,k.jsx)(U,{device:e,onAsk:()=>void _(e),onForget:()=>v(e)},e.id))}),(0,k.jsx)(`p`,{className:`px-1 pt-3 text-[12.5px] leading-[18px] text-muted`,children:l(`A chat addressed to a device runs there; you see every step here and answer its approvals.`)})]}),f&&!f.reason?.includes(`phone`)&&(0,k.jsxs)(`div`,{className:`pt-4`,children:[(0,k.jsx)(`div`,{className:`px-4`,children:(0,k.jsx)(M,{children:l(`Hands`)})}),(0,k.jsx)(K,{hands:f,onChange:()=>void h()})]})]})]})}function M({children:e}){return(0,k.jsx)(`p`,{className:`px-1 pb-2 text-[12.5px] font-medium uppercase tracking-wide text-muted/80`,children:e})}function N({children:e}){return(0,k.jsx)(`p`,{className:`px-4 pb-3 text-[12.5px] leading-[18px] text-muted`,children:e})}function P({children:e,className:n}){return(0,k.jsx)(`div`,{className:t(`relative rounded-2xl border border-border/70 bg-surface p-4`,n),children:e})}function F({kind:e,online:n}){return(0,k.jsx)(`span`,{className:t(`flex h-11 w-11 shrink-0 items-center justify-center rounded-xl`,n?`bg-accent/10 text-accent`:`bg-surface-2 text-muted`),"aria-hidden":!0,children:q(e,22)})}function I({online:e}){return(0,k.jsx)(`span`,{"aria-hidden":!0,className:t(`inline-block h-2 w-2 shrink-0 rounded-full`,e?`bg-[#2fb344]`:`bg-muted/35`)})}function L(e){if(e==null||e===``)return``;let t=typeof e==`number`?e:/^\d+(\.\d+)?$/.test(e)?Number(e):NaN;return Number.isFinite(t)?new Date(t*1e3).toISOString():String(e)}function R(t,n){let r=L(t.last_seen),i=e(r);return t.online?r&&Date.now()-new Date(r).getTime()<12e4?`${n(`Online`)} · ${n(`just now`)}`:n(`Online`):i?n(`Last seen {when}`,{when:i}):n(`Offline`)}function z(e,t,n=[]){let r=new Set(e??[]),i=[...n];return r.has(`task`)&&i.push(t(`Tasks`)),r.has(`shell`)&&i.push(t(`Commands`)),(r.has(`files`)||r.has(`file.get`)||r.has(`file.put`))&&i.push(t(`Files`)),r.has(`screen`)&&i.push(t(`Screenshot`)),r.has(`open`)&&i.push(t(`Open links`)),[...r].some(e=>e.startsWith(`coding.`))&&i.push(t(`Coding agents`)),r.has(`notify`)&&i.push(t(`Notifications`)),i}function B({items:e}){return e.length===0?null:(0,k.jsx)(`div`,{className:`flex flex-wrap gap-1.5`,children:e.map(e=>(0,k.jsx)(`span`,{className:`rounded-full bg-surface-2 px-2.5 py-1 text-[12px] font-medium text-fg/80`,children:e},e))})}function V(e){return[e.os||``,e.version||``].filter(Boolean).join(` · `)}function H({hub:e,hands:t,onChange:n}){let{dispatch:i,toast:a}=s(),o=r(),[d,f]=(0,O.useState)(!1),[p,m]=(0,O.useState)(e.device.name),[h,_]=(0,O.useState)(!1),v=e.account.signed_in,y=e.state===`connected`,S=e.devices.find(e=>e.this),C=async e=>{_(!0);try{let t=await c.updateHub(e);i({type:`ws`,msg:{kind:`hub`,hub:t}}),n()}catch(e){a(e.message)}finally{_(!1)}},w=v?e.enabled?y?o(`Online`):e.state===`refused`?o(`Refused`):o(`Connecting…`):o(`Off`):o(`Signed out`),T=z(e.device.actions,o,t?.enabled&&t.available?[o(`Hands`)]:[]);return(0,k.jsxs)(P,{children:[(0,k.jsxs)(`div`,{className:`flex items-start gap-3.5`,children:[(0,k.jsx)(F,{kind:e.device.kind,online:y}),(0,k.jsxs)(`div`,{className:`min-w-0 flex-1`,children:[d?(0,k.jsxs)(`form`,{className:`flex items-center gap-2`,onSubmit:e=>{e.preventDefault(),p.trim()&&C({name:p.trim()}).then(()=>f(!1))},children:[(0,k.jsx)(`input`,{value:p,onChange:e=>m(e.target.value),maxLength:60,autoFocus:!0,"aria-label":o(`This device's name`),placeholder:o(`A name your other devices will see`),className:`h-9 min-w-0 flex-1 rounded-xl bg-surface-2 px-3 text-[15px] outline-none focus:ring-2 focus:ring-accent/40`}),(0,k.jsx)(`button`,{type:`submit`,disabled:h||!p.trim(),"aria-label":o(`Save`),className:`flex h-9 w-9 items-center justify-center rounded-full bg-accent text-accent-fg disabled:opacity-40`,children:(0,k.jsx)(l,{size:16})}),(0,k.jsx)(`button`,{type:`button`,onClick:()=>f(!1),"aria-label":o(`Cancel`),className:`flex h-9 w-9 items-center justify-center rounded-full bg-surface-2 text-muted`,children:(0,k.jsx)(u,{size:16})})]}):(0,k.jsxs)(`div`,{className:`flex items-center gap-1.5`,children:[(0,k.jsx)(`span`,{className:`truncate text-[16px] font-semibold leading-[22px]`,children:e.device.name}),(0,k.jsx)(`button`,{type:`button`,onClick:()=>{m(e.device.name),f(!0)},"aria-label":o(`Rename this device`),title:o(`Rename this device`),className:`flex h-7 w-7 shrink-0 items-center justify-center rounded-full text-muted hover:bg-surface-2 hover:text-fg`,children:(0,k.jsx)(g,{size:13})})]}),(0,k.jsxs)(`p`,{className:`mt-0.5 flex items-center gap-1.5 text-[13px] leading-[18px] text-muted`,children:[(0,k.jsx)(I,{online:y}),(0,k.jsx)(`span`,{className:`truncate`,children:[w,V(S??{})].filter(Boolean).join(` · `)})]}),T.length>0&&(0,k.jsx)(`div`,{className:`mt-3`,children:(0,k.jsx)(B,{items:T})})]})]}),(0,k.jsxs)(`div`,{className:`-mx-4 -mb-2 mt-4 border-t border-border/60`,children:[(0,k.jsx)(b,{label:o(`Join the hub`),checked:e.enabled&&v,disabled:!v||h,onChange:e=>void C({enabled:e})}),(0,k.jsx)(N,{children:o(v?`Reachable by your other devices while this runs.`:`Sign in first.`)}),(0,k.jsx)(x,{inset:16}),(0,k.jsx)(b,{label:o(`My other devices may operate it`),checked:e.remote_control,disabled:h,onChange:e=>void C({remote_control:e})}),(0,k.jsx)(N,{children:o(`They can run commands, read files and see its screen here; each step still goes through the Sentinel.`)})]}),(e.state===`refused`||e.state===`disconnected`)&&e.detail&&(0,k.jsx)(`div`,{className:`mt-3 rounded-xl bg-amber-500/12 px-3 py-2 text-[12.5px] text-amber-700 dark:text-amber-300`,children:e.detail})]})}function U({device:e,onAsk:t,onForget:n}){let i=r(),a=z(e.actions,i),o=e.online&&(e.actions??[]).includes(`task`);return(0,k.jsxs)(P,{className:`flex flex-col gap-3`,children:[(0,k.jsxs)(`div`,{className:`flex items-start gap-3.5`,children:[(0,k.jsx)(F,{kind:e.kind,online:e.online}),(0,k.jsxs)(`div`,{className:`min-w-0 flex-1`,children:[(0,k.jsx)(`p`,{className:`truncate text-[16px] font-semibold leading-[22px]`,children:e.name}),(0,k.jsxs)(`p`,{className:`mt-0.5 flex items-center gap-1.5 text-[13px] leading-[18px] text-muted`,children:[(0,k.jsx)(I,{online:e.online}),(0,k.jsx)(`span`,{className:`truncate`,children:[R(e,i),V(e)].filter(Boolean).join(` · `)})]})]}),(0,k.jsx)(W,{label:i(`More about {name}`,{name:e.name}),items:[{label:i(`Forget this device`),onClick:n,danger:!0}]})]}),(0,k.jsx)(B,{items:a}),o&&(0,k.jsx)(`p`,{className:`text-[12.5px] leading-[18px] text-muted`,children:i(`Type @{name} in the chat to hand it work.`,{name:e.name})}),e.online&&(0,k.jsxs)(`button`,{type:`button`,onClick:t,className:`flex h-9 w-fit items-center gap-1.5 rounded-full bg-accent/10 px-3.5 text-[13.5px] font-medium text-accent hover:bg-accent/15`,children:[(0,k.jsx)(h,{size:14}),` `,i(`Ask`)]})]})}function W({label:e,items:n}){let[r,i]=(0,O.useState)(!1),a=(0,O.useRef)(null);return(0,O.useEffect)(()=>{if(!r)return;let e=e=>{a.current?.contains(e.target)||i(!1)},t=e=>{e.key===`Escape`&&i(!1)};return window.addEventListener(`pointerdown`,e),window.addEventListener(`keydown`,t),()=>{window.removeEventListener(`pointerdown`,e),window.removeEventListener(`keydown`,t)}},[r]),(0,k.jsxs)(`div`,{ref:a,className:`relative -mr-1.5 -mt-1`,children:[(0,k.jsx)(`button`,{type:`button`,onClick:()=>i(e=>!e),"aria-label":e,"aria-haspopup":`menu`,"aria-expanded":r,className:`flex h-8 w-8 items-center justify-center rounded-full text-muted hover:bg-surface-2 hover:text-fg`,children:(0,k.jsx)(v,{size:18})}),r&&(0,k.jsx)(`ul`,{role:`menu`,className:`absolute right-0 top-9 z-30 min-w-[180px] overflow-hidden rounded-2xl border border-border bg-surface py-1 shadow-xl`,children:n.map(e=>(0,k.jsx)(`li`,{children:(0,k.jsx)(`button`,{type:`button`,role:`menuitem`,onClick:()=>{i(!1),e.onClick()},className:t(`w-full px-4 py-2.5 text-left text-[14px] hover:bg-surface-2`,e.danger&&`text-red-600 dark:text-red-400`),children:e.label})},e.label))})]})}function G({hub:e,signedIn:t}){let n=r(),i=t&&e?.state===`connected`;return(0,k.jsxs)(P,{className:`flex flex-col gap-3`,children:[(0,k.jsxs)(`div`,{className:`flex items-start gap-3.5`,children:[(0,k.jsx)(`span`,{className:`flex h-11 w-11 shrink-0 items-center justify-center rounded-xl bg-surface-2 text-muted`,"aria-hidden":!0,children:(0,k.jsx)(f,{size:22})}),(0,k.jsxs)(`div`,{className:`min-w-0 flex-1`,children:[(0,k.jsx)(`p`,{className:`text-[15px] font-semibold leading-[20px]`,children:n(i?`Add a device`:`No other device yet`)}),(0,k.jsx)(`p`,{className:`mt-1 text-[13px] leading-[18px] text-muted`,children:t?i?e?.account.hint?n(`Install nanoMuse on your phone, Mac or PC and sign in as {hint}; it appears here on its own.`,{hint:e.account.hint}):n(`Install nanoMuse on your phone, Mac or PC and sign in with the same account; it appears here on its own.`):J(e?.state??``,n):n(`Sign in above to see them.`)})]})]}),i&&(0,k.jsx)(`a`,{href:A,target:`_blank`,rel:`noopener noreferrer`,className:`flex h-9 w-fit items-center gap-1.5 rounded-full bg-accent/10 px-3.5 text-[13.5px] font-medium text-accent hover:bg-accent/15`,children:n(`Get the apps`)})]})}function K({hands:e,onChange:n}){let{dispatch:i,toast:a,state:o}=s(),l=r(),[u,d]=(0,O.useState)(!1),f=o.profile?.name??`nanoMuse`,h=async e=>{d(!0);try{let t=await c.setHands(e);i({type:`ws`,msg:{kind:`hands_state`,hands:t}}),n()}catch(e){a(e.message)}finally{d(!1)}},g=e.task_active?l(`Working`):e.enabled?e.available?l(`On`):l(`Unavailable`):l(`Off`);return(0,k.jsxs)(k.Fragment,{children:[(0,k.jsxs)(m,{className:`border border-border/70`,children:[(0,k.jsx)(b,{icon:(0,k.jsx)(_,{size:22}),label:l(`Hands on this computer`),value:g,checked:e.enabled,disabled:u,onChange:e=>void h({enabled:e})}),(0,k.jsx)(y,{className:`pb-3 pt-0`,children:e.task_active?e.task_text||l(`On the screen now`):e.available?l(`It looks at a screenshot and clicks by position; paying, sending and deleting ask you first.`):e.reason||l(`Nothing can drive this screen yet.`)}),(0,k.jsx)(x,{inset:16}),(0,k.jsxs)(`div`,{className:`flex items-center gap-2 px-4 py-3 text-[13px] text-muted`,children:[(0,k.jsxs)(`span`,{children:[l(`Driver`),`:`]}),[`auto`,`desktop`,`pyautogui`,`xdotool`].map(n=>(0,k.jsx)(`button`,{type:`button`,disabled:u,onClick:()=>void h({backend:n}),className:t(`rounded-full px-2.5 py-1`,(e.backend??`auto`)===n||n===`auto`&&!e.backend?`bg-fg text-bg`:`bg-surface-2 text-fg`),children:n},n))]}),(e.device?.platform===`darwin`||e.window?.available)&&(0,k.jsxs)(k.Fragment,{children:[(0,k.jsx)(x,{inset:16}),(0,k.jsxs)(`div`,{className:`flex flex-wrap items-center gap-2 px-4 py-3 text-[13px] text-muted`,children:[(0,k.jsxs)(`span`,{children:[l(`Where`),`:`]}),[`auto`,`window`,`screen`].map(n=>(0,k.jsx)(`button`,{type:`button`,disabled:u,onClick:()=>void h({mode:n}),className:t(`rounded-full px-2.5 py-1`,(e.mode??`auto`)===n?`bg-fg text-bg`:`bg-surface-2 text-fg`),children:l(n===`auto`?`Auto`:n===`window`?`One window`:`Whole screen`)},n))]}),(0,k.jsx)(y,{className:`pb-3 pt-0`,children:e.window?.active&&e.window.app?l(`Working in {app}'s window; the mouse stays yours.`,{app:e.window.app}):e.window?.reason&&(e.mode??`auto`)!==`screen`?l(`On the whole screen for now: {reason}`,{reason:e.window.reason}):l(`One window: the hands work inside the app they were given, send clicks and keys to it alone and leave your mouse alone. Whole screen: the system mouse, like other platforms. Auto picks one window as soon as an app is named.`)})]}),e.task_active&&(0,k.jsxs)(k.Fragment,{children:[(0,k.jsx)(x,{inset:16}),(0,k.jsx)(C,{icon:(0,k.jsx)(p,{size:18,fill:`currentColor`}),label:l(`Stop the hands`),onClick:()=>void c.stopHands().catch(e=>a(e.message)),chevron:!1})]})]}),e.enabled&&e.device?.platform===`darwin`&&(0,k.jsx)(y,{children:l(`On a Mac, allow nanoMuse under System Settings → Privacy & Security → Accessibility and Screen Recording when macOS asks; without them clicks do nothing and the screenshot is black. The first action in each app asks you once ("Let {name} use Safari?") and the answer is kept under Permissions.`,{name:f})})]})}function q(e,t=18){switch(e){case`phone`:return(0,k.jsx)(f,{size:t});case`computer`:return(0,k.jsx)(E,{size:t});case`web`:return(0,k.jsx)(S,{size:t});default:return(0,k.jsx)(D,{size:t})}}function J(e,t){switch(e){case`connected`:return t(`On the hub`);case`connecting`:case`disconnected`:return t(`Connecting to the hub…`);case`refused`:return t(`The hub refused this device. Sign in again.`);case`signed_out`:return t(`Not signed in.`);case`off`:case`stopped`:return t(`The hub is off on this device.`);default:return e}}export{j as DevicesScreen}; \ No newline at end of file diff --git a/nanomuse/server/static/assets/DevicesScreen-BkPa89LS.js b/nanomuse/server/static/assets/DevicesScreen-BkPa89LS.js new file mode 100644 index 000000000..88c876a3c --- /dev/null +++ b/nanomuse/server/static/assets/DevicesScreen-BkPa89LS.js @@ -0,0 +1 @@ +import{A as e,E as t,J as n,K as r,Q as i,Y as a,b as o,f as s,x as c}from"./MuseHeader-RC--uR8o.js";import{n as l}from"./external-link-TvxP_dKX.js";import{o as u}from"./Form-H3s9oTHq.js";import{t as d}from"./refresh-cw-CxZ3ZdI3.js";import{$ as f,V as p,W as m,a as h,c as g,dt as _,ft as v,i as y,it as b,mt as x,o as S,r as C}from"./index-tYqPtwPX.js";import{t as w}from"./BackBar-JEuC8Q_e.js";import{t as T}from"./CloudCard-D5foJm1I.js";var E=n(`laptop`,[[`path`,{d:`M18 5a2 2 0 0 1 2 2v8.526a2 2 0 0 0 .212.897l1.068 2.127a1 1 0 0 1-.9 1.45H3.62a1 1 0 0 1-.9-1.45l1.068-2.127A2 2 0 0 0 4 15.526V7a2 2 0 0 1 2-2z`,key:`1pdavp`}],[`path`,{d:`M20.054 15.987H3.946`,key:`14rxg9`}]]),D=n(`wifi`,[[`path`,{d:`M12 20h.01`,key:`zekei9`}],[`path`,{d:`M2 8.82a15 15 0 0 1 20 0`,key:`dnpr2z`}],[`path`,{d:`M5 12.859a10 10 0 0 1 14 0`,key:`1x1e6c`}],[`path`,{d:`M8.5 16.429a5 5 0 0 1 7 0`,key:`1bycff`}]]),O=i(a(),1),k=o(),A=`https://github.com/zeeshanhaque21/nanoMuse/releases/latest`;function j(){let{state:e,dispatch:n,openThread:i,setTab:a,toast:o}=s(),l=r(),u=e.hub,f=e.hands,[p,m]=(0,O.useState)(!1),h=async()=>{try{let[e,t]=await Promise.all([c.hub(),c.hands()]);n({type:`ws`,msg:{kind:`hub`,hub:e}}),n({type:`ws`,msg:{kind:`hands_state`,hands:t}})}catch{}};(0,O.useEffect)(()=>{h()},[]);let g=async()=>{m(!0),await h(),m(!1)},_=async e=>{try{let t=await c.askDevice(e.id);n({type:`ws`,msg:{kind:`thread`,thread:t.thread}}),i(t.thread.id),a(`chat`)}catch(e){o(e.message)}},v=e=>{window.confirm(l(`Forget {name}? It can join again by signing in.`,{name:e.name}))&&c.forgetDevice(e.id).then(e=>n({type:`ws`,msg:{kind:`hub`,hub:e}})).catch(e=>o(e.message))},y=(u?.devices??[]).filter(e=>!e.this&&e.kind!==`web`),b=!!u?.account.signed_in,x=u?.state===`connected`,S=y.length+(u&&x?1:0),C=y.filter(e=>e.online).length+(u&&x?1:0);return(0,k.jsxs)(`div`,{className:`flex h-full flex-col`,children:[(0,k.jsx)(w,{title:l(`Devices`),actions:(0,k.jsx)(`button`,{type:`button`,onClick:()=>void g(),"aria-label":l(`Refresh`),title:l(`Refresh`),className:`flex h-9 w-9 items-center justify-center rounded-full text-muted hover:bg-surface-2 hover:text-fg`,children:(0,k.jsx)(d,{size:17,className:t(p&&`animate-spin`)})})}),(0,k.jsxs)(`div`,{className:`@container flex-1 overflow-y-auto pb-8`,children:[(0,k.jsxs)(`div`,{className:`px-5 pb-4 pt-1`,children:[(0,k.jsx)(`p`,{className:`text-[14px] leading-[20px] text-muted`,children:l(`Every device signed in to your account is a Muse of its own, on the same conversations. Type @ and a device's name in the chat to hand it work; a computer lends its hands.`)}),u&&b&&S>0&&(0,k.jsxs)(`p`,{className:`mt-1.5 text-[12.5px] font-medium uppercase tracking-wide text-muted/80`,children:[S===1?l(`1 device`):l(`{n} devices`,{n:S}),` · `,l(`{n} online`,{n:C})]})]}),(0,k.jsx)(`div`,{className:`px-4 pb-3`,children:(0,k.jsx)(T,{account:u?.account??null,onChange:()=>void h()})}),u&&(0,k.jsxs)(`div`,{className:`px-4`,children:[(0,k.jsx)(M,{children:l(`This device`)}),(0,k.jsx)(H,{hub:u,hands:f??void 0,onChange:()=>void h()})]}),(0,k.jsxs)(`div`,{className:`px-4 pt-4`,children:[(0,k.jsx)(M,{children:l(`Other devices`)}),y.length===0?(0,k.jsx)(G,{hub:u??void 0,signedIn:b}):(0,k.jsx)(`div`,{className:`grid grid-cols-1 gap-3 @2xl:grid-cols-2`,children:y.map(e=>(0,k.jsx)(U,{device:e,onAsk:()=>void _(e),onForget:()=>v(e)},e.id))}),(0,k.jsx)(`p`,{className:`px-1 pt-3 text-[12.5px] leading-[18px] text-muted`,children:l(`A chat addressed to a device runs there; you see every step here and answer its approvals.`)})]}),f&&!f.reason?.includes(`phone`)&&(0,k.jsxs)(`div`,{className:`pt-4`,children:[(0,k.jsx)(`div`,{className:`px-4`,children:(0,k.jsx)(M,{children:l(`Hands`)})}),(0,k.jsx)(K,{hands:f,onChange:()=>void h()})]})]})]})}function M({children:e}){return(0,k.jsx)(`p`,{className:`px-1 pb-2 text-[12.5px] font-medium uppercase tracking-wide text-muted/80`,children:e})}function N({children:e}){return(0,k.jsx)(`p`,{className:`px-4 pb-3 text-[12.5px] leading-[18px] text-muted`,children:e})}function P({children:e,className:n}){return(0,k.jsx)(`div`,{className:t(`relative rounded-2xl border border-border/70 bg-surface p-4`,n),children:e})}function F({kind:e,online:n}){return(0,k.jsx)(`span`,{className:t(`flex h-11 w-11 shrink-0 items-center justify-center rounded-xl`,n?`bg-accent/10 text-accent`:`bg-surface-2 text-muted`),"aria-hidden":!0,children:q(e,22)})}function I({online:e}){return(0,k.jsx)(`span`,{"aria-hidden":!0,className:t(`inline-block h-2 w-2 shrink-0 rounded-full`,e?`bg-[#2fb344]`:`bg-muted/35`)})}function L(e){if(e==null||e===``)return``;let t=typeof e==`number`?e:/^\d+(\.\d+)?$/.test(e)?Number(e):NaN;return Number.isFinite(t)?new Date(t*1e3).toISOString():String(e)}function R(t,n){let r=L(t.last_seen),i=e(r);return t.online?r&&Date.now()-new Date(r).getTime()<12e4?`${n(`Online`)} · ${n(`just now`)}`:n(`Online`):i?n(`Last seen {when}`,{when:i}):n(`Offline`)}function z(e,t,n=[]){let r=new Set(e??[]),i=[...n];return r.has(`task`)&&i.push(t(`Tasks`)),r.has(`shell`)&&i.push(t(`Commands`)),(r.has(`files`)||r.has(`file.get`)||r.has(`file.put`))&&i.push(t(`Files`)),r.has(`screen`)&&i.push(t(`Screenshot`)),r.has(`open`)&&i.push(t(`Open links`)),[...r].some(e=>e.startsWith(`coding.`))&&i.push(t(`Coding agents`)),r.has(`notify`)&&i.push(t(`Notifications`)),i}function B({items:e}){return e.length===0?null:(0,k.jsx)(`div`,{className:`flex flex-wrap gap-1.5`,children:e.map(e=>(0,k.jsx)(`span`,{className:`rounded-full bg-surface-2 px-2.5 py-1 text-[12px] font-medium text-fg/80`,children:e},e))})}function V(e){return[e.os||``,e.version||``].filter(Boolean).join(` · `)}function H({hub:e,hands:t,onChange:n}){let{dispatch:i,toast:a}=s(),o=r(),[d,p]=(0,O.useState)(!1),[m,_]=(0,O.useState)(e.device.name),[v,y]=(0,O.useState)(!1),b=e.account.signed_in,x=e.state===`connected`,S=e.devices.find(e=>e.this),C=async e=>{y(!0);try{let t=await c.updateHub(e);i({type:`ws`,msg:{kind:`hub`,hub:t}}),n()}catch(e){a(e.message)}finally{y(!1)}},w=b?e.enabled?x?o(`Online`):e.state===`refused`?o(`Refused`):o(`Connecting…`):o(`Off`):o(`Signed out`),T=z(e.device.actions,o,t?.enabled&&t.available?[o(`Hands`)]:[]);return(0,k.jsxs)(P,{children:[(0,k.jsxs)(`div`,{className:`flex items-start gap-3.5`,children:[(0,k.jsx)(F,{kind:e.device.kind,online:x}),(0,k.jsxs)(`div`,{className:`min-w-0 flex-1`,children:[d?(0,k.jsxs)(`form`,{className:`flex items-center gap-2`,onSubmit:e=>{e.preventDefault(),m.trim()&&C({name:m.trim()}).then(()=>p(!1))},children:[(0,k.jsx)(`input`,{value:m,onChange:e=>_(e.target.value),maxLength:60,autoFocus:!0,"aria-label":o(`This device's name`),placeholder:o(`A name your other devices will see`),className:`h-9 min-w-0 flex-1 rounded-xl bg-surface-2 px-3 text-[15px] outline-none focus:ring-2 focus:ring-accent/40`}),(0,k.jsx)(`button`,{type:`submit`,disabled:v||!m.trim(),"aria-label":o(`Save`),className:`flex h-9 w-9 items-center justify-center rounded-full bg-accent text-accent-fg disabled:opacity-40`,children:(0,k.jsx)(l,{size:16})}),(0,k.jsx)(`button`,{type:`button`,onClick:()=>p(!1),"aria-label":o(`Cancel`),className:`flex h-9 w-9 items-center justify-center rounded-full bg-surface-2 text-muted`,children:(0,k.jsx)(u,{size:16})})]}):(0,k.jsxs)(`div`,{className:`flex items-center gap-1.5`,children:[(0,k.jsx)(`span`,{className:`truncate text-[16px] font-semibold leading-[22px]`,children:e.device.name}),(0,k.jsx)(`button`,{type:`button`,onClick:()=>{_(e.device.name),p(!0)},"aria-label":o(`Rename this device`),title:o(`Rename this device`),className:`flex h-7 w-7 shrink-0 items-center justify-center rounded-full text-muted hover:bg-surface-2 hover:text-fg`,children:(0,k.jsx)(f,{size:13})})]}),(0,k.jsxs)(`p`,{className:`mt-0.5 flex items-center gap-1.5 text-[13px] leading-[18px] text-muted`,children:[(0,k.jsx)(I,{online:x}),(0,k.jsx)(`span`,{className:`truncate`,children:[w,V(S??{})].filter(Boolean).join(` · `)})]}),T.length>0&&(0,k.jsx)(`div`,{className:`mt-3`,children:(0,k.jsx)(B,{items:T})})]})]}),(0,k.jsxs)(`div`,{className:`-mx-4 -mb-2 mt-4 border-t border-border/60`,children:[(0,k.jsx)(g,{label:o(`Join the hub`),checked:e.enabled&&b,disabled:!b||v,onChange:e=>void C({enabled:e})}),(0,k.jsx)(N,{children:o(b?`Reachable by your other devices while this runs.`:`Sign in first.`)}),(0,k.jsx)(h,{inset:16}),(0,k.jsx)(g,{label:o(`My other devices may operate it`),checked:e.remote_control,disabled:v,onChange:e=>void C({remote_control:e})}),(0,k.jsx)(N,{children:o(`They can run commands, read files and see its screen here; each step still goes through the Sentinel.`)})]}),(e.state===`refused`||e.state===`disconnected`)&&e.detail&&(0,k.jsx)(`div`,{className:`mt-3 rounded-xl bg-amber-500/12 px-3 py-2 text-[12.5px] text-amber-700 dark:text-amber-300`,children:e.detail})]})}function U({device:e,onAsk:t,onForget:n}){let i=r(),a=z(e.actions,i),o=e.online&&(e.actions??[]).includes(`task`);return(0,k.jsxs)(P,{className:`flex flex-col gap-3`,children:[(0,k.jsxs)(`div`,{className:`flex items-start gap-3.5`,children:[(0,k.jsx)(F,{kind:e.kind,online:e.online}),(0,k.jsxs)(`div`,{className:`min-w-0 flex-1`,children:[(0,k.jsx)(`p`,{className:`truncate text-[16px] font-semibold leading-[22px]`,children:e.name}),(0,k.jsxs)(`p`,{className:`mt-0.5 flex items-center gap-1.5 text-[13px] leading-[18px] text-muted`,children:[(0,k.jsx)(I,{online:e.online}),(0,k.jsx)(`span`,{className:`truncate`,children:[R(e,i),V(e)].filter(Boolean).join(` · `)})]})]}),(0,k.jsx)(W,{label:i(`More about {name}`,{name:e.name}),items:[{label:i(`Forget this device`),onClick:n,danger:!0}]})]}),(0,k.jsx)(B,{items:a}),o&&(0,k.jsx)(`p`,{className:`text-[12.5px] leading-[18px] text-muted`,children:i(`Type @{name} in the chat to hand it work.`,{name:e.name})}),e.online&&(0,k.jsxs)(`button`,{type:`button`,onClick:t,className:`flex h-9 w-fit items-center gap-1.5 rounded-full bg-accent/10 px-3.5 text-[13.5px] font-medium text-accent hover:bg-accent/15`,children:[(0,k.jsx)(b,{size:14}),` `,i(`Ask`)]})]})}function W({label:e,items:n}){let[r,i]=(0,O.useState)(!1),a=(0,O.useRef)(null);return(0,O.useEffect)(()=>{if(!r)return;let e=e=>{a.current?.contains(e.target)||i(!1)},t=e=>{e.key===`Escape`&&i(!1)};return window.addEventListener(`pointerdown`,e),window.addEventListener(`keydown`,t),()=>{window.removeEventListener(`pointerdown`,e),window.removeEventListener(`keydown`,t)}},[r]),(0,k.jsxs)(`div`,{ref:a,className:`relative -mr-1.5 -mt-1`,children:[(0,k.jsx)(`button`,{type:`button`,onClick:()=>i(e=>!e),"aria-label":e,"aria-haspopup":`menu`,"aria-expanded":r,className:`flex h-8 w-8 items-center justify-center rounded-full text-muted hover:bg-surface-2 hover:text-fg`,children:(0,k.jsx)(x,{size:18})}),r&&(0,k.jsx)(`ul`,{role:`menu`,className:`absolute right-0 top-9 z-30 min-w-[180px] overflow-hidden rounded-2xl border border-border bg-surface py-1 shadow-xl`,children:n.map(e=>(0,k.jsx)(`li`,{children:(0,k.jsx)(`button`,{type:`button`,role:`menuitem`,onClick:()=>{i(!1),e.onClick()},className:t(`w-full px-4 py-2.5 text-left text-[14px] hover:bg-surface-2`,e.danger&&`text-red-600 dark:text-red-400`),children:e.label})},e.label))})]})}function G({hub:e,signedIn:t}){let n=r(),i=t&&e?.state===`connected`;return(0,k.jsxs)(P,{className:`flex flex-col gap-3`,children:[(0,k.jsxs)(`div`,{className:`flex items-start gap-3.5`,children:[(0,k.jsx)(`span`,{className:`flex h-11 w-11 shrink-0 items-center justify-center rounded-xl bg-surface-2 text-muted`,"aria-hidden":!0,children:(0,k.jsx)(m,{size:22})}),(0,k.jsxs)(`div`,{className:`min-w-0 flex-1`,children:[(0,k.jsx)(`p`,{className:`text-[15px] font-semibold leading-[20px]`,children:n(i?`Add a device`:`No other device yet`)}),(0,k.jsx)(`p`,{className:`mt-1 text-[13px] leading-[18px] text-muted`,children:t?i?e?.account.hint?n(`Install nanoMuse on your phone, Mac or PC and sign in as {hint}; it appears here on its own.`,{hint:e.account.hint}):n(`Install nanoMuse on your phone, Mac or PC and sign in with the same account; it appears here on its own.`):J(e?.state??``,n):n(`Sign in above to see them.`)})]})]}),i&&(0,k.jsx)(`a`,{href:A,target:`_blank`,rel:`noopener noreferrer`,className:`flex h-9 w-fit items-center gap-1.5 rounded-full bg-accent/10 px-3.5 text-[13.5px] font-medium text-accent hover:bg-accent/15`,children:n(`Get the apps`)})]})}function K({hands:e,onChange:n}){let{dispatch:i,toast:a,state:o}=s(),l=r(),[u,d]=(0,O.useState)(!1),f=o.profile?.name??`nanoMuse`,m=async e=>{d(!0);try{let t=await c.setHands(e);i({type:`ws`,msg:{kind:`hands_state`,hands:t}}),n()}catch(e){a(e.message)}finally{d(!1)}},v=e.task_active?l(`Working`):e.enabled?e.available?l(`On`):l(`Unavailable`):l(`Off`);return(0,k.jsxs)(k.Fragment,{children:[(0,k.jsxs)(y,{className:`border border-border/70`,children:[(0,k.jsx)(g,{icon:(0,k.jsx)(_,{size:22}),label:l(`Hands on this computer`),value:v,checked:e.enabled,disabled:u,onChange:e=>void m({enabled:e})}),(0,k.jsx)(C,{className:`pb-3 pt-0`,children:e.task_active?e.task_text||l(`On the screen now`):e.available?l(`It looks at a screenshot and clicks by position; paying, sending and deleting ask you first.`):e.reason||l(`Nothing can drive this screen yet.`)}),(0,k.jsx)(h,{inset:16}),(0,k.jsxs)(`div`,{className:`flex items-center gap-2 px-4 py-3 text-[13px] text-muted`,children:[(0,k.jsxs)(`span`,{children:[l(`Driver`),`:`]}),[`auto`,`desktop`,`pyautogui`,`xdotool`].map(n=>(0,k.jsx)(`button`,{type:`button`,disabled:u,onClick:()=>void m({backend:n}),className:t(`rounded-full px-2.5 py-1`,(e.backend??`auto`)===n||n===`auto`&&!e.backend?`bg-fg text-bg`:`bg-surface-2 text-fg`),children:n},n))]}),(e.device?.platform===`darwin`||e.window?.available)&&(0,k.jsxs)(k.Fragment,{children:[(0,k.jsx)(h,{inset:16}),(0,k.jsxs)(`div`,{className:`flex flex-wrap items-center gap-2 px-4 py-3 text-[13px] text-muted`,children:[(0,k.jsxs)(`span`,{children:[l(`Where`),`:`]}),[`auto`,`window`,`screen`].map(n=>(0,k.jsx)(`button`,{type:`button`,disabled:u,onClick:()=>void m({mode:n}),className:t(`rounded-full px-2.5 py-1`,(e.mode??`auto`)===n?`bg-fg text-bg`:`bg-surface-2 text-fg`),children:l(n===`auto`?`Auto`:n===`window`?`One window`:`Whole screen`)},n))]}),(0,k.jsx)(C,{className:`pb-3 pt-0`,children:e.window?.active&&e.window.app?l(`Working in {app}'s window; the mouse stays yours.`,{app:e.window.app}):e.window?.reason&&(e.mode??`auto`)!==`screen`?l(`On the whole screen for now: {reason}`,{reason:e.window.reason}):l(`One window: the hands work inside the app they were given, send clicks and keys to it alone and leave your mouse alone. Whole screen: the system mouse, like other platforms. Auto picks one window as soon as an app is named.`)})]}),e.task_active&&(0,k.jsxs)(k.Fragment,{children:[(0,k.jsx)(h,{inset:16}),(0,k.jsx)(S,{icon:(0,k.jsx)(p,{size:18,fill:`currentColor`}),label:l(`Stop the hands`),onClick:()=>void c.stopHands().catch(e=>a(e.message)),chevron:!1})]})]}),e.enabled&&e.device?.platform===`darwin`&&(0,k.jsx)(C,{children:l(`On a Mac, allow nanoMuse under System Settings → Privacy & Security → Accessibility and Screen Recording when macOS asks; without them clicks do nothing and the screenshot is black. The first action in each app asks you once ("Let {name} use Safari?") and the answer is kept under Permissions.`,{name:f})})]})}function q(e,t=18){switch(e){case`phone`:return(0,k.jsx)(m,{size:t});case`computer`:return(0,k.jsx)(E,{size:t});case`web`:return(0,k.jsx)(v,{size:t});default:return(0,k.jsx)(D,{size:t})}}function J(e,t){switch(e){case`connected`:return t(`On the hub`);case`connecting`:case`disconnected`:return t(`Connecting to the hub…`);case`refused`:return t(`The hub refused this device. Sign in again.`);case`signed_out`:return t(`Not signed in.`);case`off`:case`stopped`:return t(`The hub is off on this device.`);default:return e}}export{j as DevicesScreen}; \ No newline at end of file diff --git a/nanomuse/server/static/assets/Form-C77NCy9F.js b/nanomuse/server/static/assets/Form-H3s9oTHq.js similarity index 97% rename from nanomuse/server/static/assets/Form-C77NCy9F.js rename to nanomuse/server/static/assets/Form-H3s9oTHq.js index e04a60765..bac2b3ed0 100644 --- a/nanomuse/server/static/assets/Form-C77NCy9F.js +++ b/nanomuse/server/static/assets/Form-H3s9oTHq.js @@ -1 +1 @@ -import{E as e,J as t,b as n}from"./MuseHeader-BvAlmxiL.js";var r=t(`chevron-down`,[[`path`,{d:`m6 9 6 6 6-6`,key:`qrunsl`}]]),i=t(`chevron-up`,[[`path`,{d:`m18 15-6-6-6 6`,key:`153udz`}]]),a=t(`x`,[[`path`,{d:`M18 6 6 18`,key:`1bl5f8`}],[`path`,{d:`m6 6 12 12`,key:`d8bk6v`}]]),o=n();function s({icon:t,title:n,summary:a,status:s,open:c,onToggle:l,trailing:u,children:d}){let f=(0,o.jsxs)(o.Fragment,{children:[(0,o.jsx)(`span`,{className:`text-accent mt-0.5`,children:t}),(0,o.jsxs)(`span`,{className:`min-w-0 flex-1`,children:[(0,o.jsxs)(`span`,{className:`flex items-center gap-2`,children:[(0,o.jsx)(`span`,{className:`text-[15px] font-semibold`,children:n}),(0,o.jsx)(`span`,{className:e(`rounded-full px-2 py-0.5 text-[11px] font-medium`,s.tone===`ok`&&`bg-emerald-500/12 text-emerald-700 dark:text-emerald-300`,s.tone===`warn`&&`bg-amber-500/15 text-amber-700 dark:text-amber-300`,s.tone===`off`&&`bg-surface-2 text-muted`),children:s.text})]}),(0,o.jsx)(`span`,{className:`block text-[12.5px] text-muted truncate`,children:a})]}),u??(l?c?(0,o.jsx)(i,{size:18,className:`text-muted`}):(0,o.jsx)(r,{size:18,className:`text-muted`}):null)]});return(0,o.jsxs)(`section`,{className:`rounded-3xl bg-surface border border-border/70 shadow-sm`,children:[l?(0,o.jsx)(`button`,{type:`button`,onClick:l,className:`flex w-full items-start gap-3 px-4 py-3.5 text-left`,children:f}):(0,o.jsx)(`div`,{className:`flex w-full items-start gap-3 px-4 py-3.5`,children:f}),(c||!l&&d)&&d?(0,o.jsx)(`div`,{className:`px-4 pb-4 space-y-3`,children:d}):null]})}var c=`w-full rounded-2xl bg-surface-2 px-3.5 py-2.5 text-[14.5px] outline-none focus:ring-2 focus:ring-accent/40`,l=`flex items-center justify-center gap-1.5 rounded-2xl bg-accent text-accent-fg px-4 py-2.5 text-[14px] font-medium disabled:opacity-40`,u=`flex items-center justify-center gap-1.5 rounded-2xl border border-border px-4 py-2.5 text-[14px] font-medium text-muted disabled:opacity-40`;function d({label:t,hint:n,checked:r,onChange:i,disabled:a}){return(0,o.jsxs)(`label`,{className:`flex items-start gap-3 cursor-pointer`,children:[(0,o.jsxs)(`div`,{className:`flex-1`,children:[(0,o.jsx)(`div`,{className:`text-[14px]`,children:t}),n&&(0,o.jsx)(`div`,{className:`text-[12.5px] text-muted leading-snug`,children:n})]}),(0,o.jsx)(`button`,{type:`button`,role:`switch`,"aria-checked":r,disabled:a,onClick:()=>i(!r),className:e(`relative mt-0.5 h-7 w-12 shrink-0 rounded-full transition disabled:opacity-50`,r?`bg-accent`:`bg-surface-2 border border-border`),children:(0,o.jsx)(`span`,{className:e(`absolute top-0.5 h-6 w-6 rounded-full bg-white shadow transition`,r?`left-[22px]`:`left-0.5`)})})]})}export{u as a,r as c,l as i,d as n,a as o,c as r,i as s,s as t}; \ No newline at end of file +import{E as e,J as t,b as n}from"./MuseHeader-RC--uR8o.js";var r=t(`chevron-down`,[[`path`,{d:`m6 9 6 6 6-6`,key:`qrunsl`}]]),i=t(`chevron-up`,[[`path`,{d:`m18 15-6-6-6 6`,key:`153udz`}]]),a=t(`x`,[[`path`,{d:`M18 6 6 18`,key:`1bl5f8`}],[`path`,{d:`m6 6 12 12`,key:`d8bk6v`}]]),o=n();function s({icon:t,title:n,summary:a,status:s,open:c,onToggle:l,trailing:u,children:d}){let f=(0,o.jsxs)(o.Fragment,{children:[(0,o.jsx)(`span`,{className:`text-accent mt-0.5`,children:t}),(0,o.jsxs)(`span`,{className:`min-w-0 flex-1`,children:[(0,o.jsxs)(`span`,{className:`flex items-center gap-2`,children:[(0,o.jsx)(`span`,{className:`text-[15px] font-semibold`,children:n}),(0,o.jsx)(`span`,{className:e(`rounded-full px-2 py-0.5 text-[11px] font-medium`,s.tone===`ok`&&`bg-emerald-500/12 text-emerald-700 dark:text-emerald-300`,s.tone===`warn`&&`bg-amber-500/15 text-amber-700 dark:text-amber-300`,s.tone===`off`&&`bg-surface-2 text-muted`),children:s.text})]}),(0,o.jsx)(`span`,{className:`block text-[12.5px] text-muted truncate`,children:a})]}),u??(l?c?(0,o.jsx)(i,{size:18,className:`text-muted`}):(0,o.jsx)(r,{size:18,className:`text-muted`}):null)]});return(0,o.jsxs)(`section`,{className:`rounded-3xl bg-surface border border-border/70 shadow-sm`,children:[l?(0,o.jsx)(`button`,{type:`button`,onClick:l,className:`flex w-full items-start gap-3 px-4 py-3.5 text-left`,children:f}):(0,o.jsx)(`div`,{className:`flex w-full items-start gap-3 px-4 py-3.5`,children:f}),(c||!l&&d)&&d?(0,o.jsx)(`div`,{className:`px-4 pb-4 space-y-3`,children:d}):null]})}var c=`w-full rounded-2xl bg-surface-2 px-3.5 py-2.5 text-[14.5px] outline-none focus:ring-2 focus:ring-accent/40`,l=`flex items-center justify-center gap-1.5 rounded-2xl bg-accent text-accent-fg px-4 py-2.5 text-[14px] font-medium disabled:opacity-40`,u=`flex items-center justify-center gap-1.5 rounded-2xl border border-border px-4 py-2.5 text-[14px] font-medium text-muted disabled:opacity-40`;function d({label:t,hint:n,checked:r,onChange:i,disabled:a}){return(0,o.jsxs)(`label`,{className:`flex items-start gap-3 cursor-pointer`,children:[(0,o.jsxs)(`div`,{className:`flex-1`,children:[(0,o.jsx)(`div`,{className:`text-[14px]`,children:t}),n&&(0,o.jsx)(`div`,{className:`text-[12.5px] text-muted leading-snug`,children:n})]}),(0,o.jsx)(`button`,{type:`button`,role:`switch`,"aria-checked":r,disabled:a,onClick:()=>i(!r),className:e(`relative mt-0.5 h-7 w-12 shrink-0 rounded-full transition disabled:opacity-50`,r?`bg-accent`:`bg-surface-2 border border-border`),children:(0,o.jsx)(`span`,{className:e(`absolute top-0.5 h-6 w-6 rounded-full bg-white shadow transition`,r?`left-[22px]`:`left-0.5`)})})]})}export{u as a,r as c,l as i,d as n,a as o,c as r,i as s,s as t}; \ No newline at end of file diff --git a/nanomuse/server/static/assets/GoalsScreen-DgatXriG.js b/nanomuse/server/static/assets/GoalsScreen-yUUdUKV2.js similarity index 64% rename from nanomuse/server/static/assets/GoalsScreen-DgatXriG.js rename to nanomuse/server/static/assets/GoalsScreen-yUUdUKV2.js index a86f4534a..823d01b67 100644 --- a/nanomuse/server/static/assets/GoalsScreen-DgatXriG.js +++ b/nanomuse/server/static/assets/GoalsScreen-yUUdUKV2.js @@ -1,2 +1,2 @@ -import{A as e,E as t,J as n,K as r,N as i,Q as a,Y as o,b as s,f as c,r as l,x as u}from"./MuseHeader-BvAlmxiL.js";import{t as d}from"./StarNudge-Cr_QPa4y.js";import{H as f,Q as p,S as m,V as h,W as g,Z as _,_ as v,b as y,f as b,g as x,h as S,m as C,ot as w,p as T,v as E,w as D,wt as O,x as k,xt as A,y as j}from"./index-tZx-TDX4.js";var M=n(`bell-ring`,[[`path`,{d:`M10.268 21a2 2 0 0 0 3.464 0`,key:`vwvbt9`}],[`path`,{d:`M22 8c0-2.3-.8-4.3-2-6`,key:`5bb3ad`}],[`path`,{d:`M3.262 15.326A1 1 0 0 0 4 17h16a1 1 0 0 0 .74-1.673C19.41 13.956 18 12.499 18 8A6 6 0 0 0 6 8c0 4.499-1.411 5.956-2.738 7.326`,key:`11g9vi`}],[`path`,{d:`M4 2C2.8 3.7 2 5.7 2 8`,key:`tap9e0`}]]),N=n(`circle-check`,[[`circle`,{cx:`12`,cy:`12`,r:`10`,key:`1mglay`}],[`path`,{d:`m9 12 2 2 4-4`,key:`dzmm74`}]]),P=n(`circle-dashed`,[[`path`,{d:`M10.1 2.182a10 10 0 0 1 3.8 0`,key:`5ilxe3`}],[`path`,{d:`M13.9 21.818a10 10 0 0 1-3.8 0`,key:`11zvb9`}],[`path`,{d:`M17.609 3.721a10 10 0 0 1 2.69 2.7`,key:`1iw5b2`}],[`path`,{d:`M2.182 13.9a10 10 0 0 1 0-3.8`,key:`c0bmvh`}],[`path`,{d:`M20.279 17.609a10 10 0 0 1-2.7 2.69`,key:`1ruxm7`}],[`path`,{d:`M21.818 10.1a10 10 0 0 1 0 3.8`,key:`qkgqxc`}],[`path`,{d:`M3.721 6.391a10 10 0 0 1 2.7-2.69`,key:`1mcia2`}],[`path`,{d:`M6.391 20.279a10 10 0 0 1-2.69-2.7`,key:`1fvljs`}]]),F=n(`circle-slash`,[[`circle`,{cx:`12`,cy:`12`,r:`10`,key:`1mglay`}],[`line`,{x1:`9`,x2:`15`,y1:`15`,y2:`9`,key:`1dfufj`}]]),I=n(`circle`,[[`circle`,{cx:`12`,cy:`12`,r:`10`,key:`1mglay`}]]),L=n(`ellipsis-vertical`,[[`circle`,{cx:`12`,cy:`12`,r:`1`,key:`41hilf`}],[`circle`,{cx:`12`,cy:`5`,r:`1`,key:`gxeob9`}],[`circle`,{cx:`12`,cy:`19`,r:`1`,key:`lyex9k`}]]),R=n(`octagon-alert`,[[`path`,{d:`M12 16h.01`,key:`1drbdi`}],[`path`,{d:`M12 8v4`,key:`1got3b`}],[`path`,{d:`M15.312 2a2 2 0 0 1 1.414.586l4.688 4.688A2 2 0 0 1 22 8.688v6.624a2 2 0 0 1-.586 1.414l-4.688 4.688a2 2 0 0 1-1.414.586H8.688a2 2 0 0 1-1.414-.586l-4.688-4.688A2 2 0 0 1 2 15.312V8.688a2 2 0 0 1 .586-1.414l4.688-4.688A2 2 0 0 1 8.688 2z`,key:`1fd625`}]]),z=n(`pause`,[[`rect`,{x:`14`,y:`3`,width:`5`,height:`18`,rx:`1`,key:`kaeet6`}],[`rect`,{x:`5`,y:`3`,width:`5`,height:`18`,rx:`1`,key:`1wsw3u`}]]),B=n(`square-check`,[[`rect`,{width:`18`,height:`18`,x:`3`,y:`3`,rx:`2`,key:`afitv7`}],[`path`,{d:`m9 12 2 2 4-4`,key:`dzmm74`}]]),V=a(o(),1),H=s(),U={pending:e=>(0,H.jsx)(I,{...e}),in_progress:e=>(0,H.jsx)(P,{...e,className:t(e.className,`text-accent`)}),done:e=>(0,H.jsx)(N,{...e,className:t(e.className,`text-emerald-500`)}),blocked:e=>(0,H.jsx)(R,{...e,className:t(e.className,`text-rose-500`)}),skipped:e=>(0,H.jsx)(F,{...e,className:t(e.className,`text-muted`)})},W={pending:`done`,in_progress:`done`,done:`pending`,blocked:`pending`,skipped:`pending`};function G(){let{state:e,refreshGoals:t,send:n,openThread:i,toast:a}=c(),[o,s]=(0,V.useState)(null),[f,p]=(0,V.useState)(!1),[m,h]=(0,V.useState)(null),[g,v]=(0,V.useState)(!1),y=(0,V.useRef)(null),x=e.profile?.name??`nanoMuse`,S=r();(0,V.useEffect)(()=>{t()},[t]);let T=e.goals.filter(e=>e.proposal&&e.status!==`cancelled`),E=[...e.goals.filter(e=>e.status===`active`),...e.goals.filter(e=>e.status===`paused`)],O=e.goals.filter(e=>e.status===`done`||e.status===`cancelled`),k=e.goals.find(e=>e.id===o)??null,A=async e=>{try{await u.advanceGoal(e.id),a(S(`{name} is working on “{title}” in the main chat`,{name:x,title:e.title})),i(`main`)}catch(e){a(e.message)}},[j,M]=(0,V.useState)(!1),N=async e=>{try{let n=e.status!==`done`;await u.patchGoal(e.id,{status:n?`done`:`active`}),n&&M(!0),t()}catch(e){a(e.message)}},P=e=>{h(null),n(`main`,S(`I'd like to create a {category} goal. Ask me a few short questions, one at a time (what exactly I want, why and by when, how often to check in), then create it with concrete steps using the goals tool.`,{category:S(e.label)})).catch(e=>a(e.message||S(`Could not send`))),i(`main`)};return(0,H.jsxs)(`div`,{className:`flex h-full flex-col`,children:[(0,H.jsx)(b,{title:S(`Goals`),children:(0,H.jsx)(l,{small:!0,onClick:()=>p(!0),label:S(`New goal`),children:(0,H.jsx)(_,{size:22})})}),(0,H.jsxs)(`div`,{className:`flex-1 overflow-y-auto pb-6`,children:[T.length>0&&(0,H.jsxs)(`section`,{className:`px-4 pb-2`,children:[(0,H.jsx)(`div`,{className:`px-1 mb-2 text-[12px] font-semibold uppercase tracking-wide text-muted`,children:S(`{name} suggests`,{name:x})}),(0,H.jsx)(`div`,{className:`space-y-2.5`,children:T.map(e=>(0,H.jsx)(Y,{goal:e,onChanged:t,onOpen:()=>s(e.id)},e.id))})]}),(0,H.jsx)(d,{moment:`goal_done`,due:j,className:`mx-4 mb-3`}),(0,H.jsx)(K,{label:S(`Tracking`),dot:!0,onAdd:()=>y.current?.scrollIntoView({behavior:`smooth`,block:`start`})}),E.length===0?(0,H.jsx)(`p`,{className:`px-5 pb-3 text-[13px] text-muted`,children:S(`Nothing tracked yet`)}):E.map(e=>(0,H.jsx)(J,{goal:e,onOpen:()=>s(e.id),onToggle:()=>void N(e)},e.id)),O.length>0&&(0,H.jsxs)(H.Fragment,{children:[(0,H.jsx)(`div`,{className:`h-1.5`}),(0,H.jsx)(K,{label:S(`Finished`)}),(g?O:O.slice(0,2)).map(e=>(0,H.jsx)(J,{goal:e,onOpen:()=>s(e.id),onToggle:()=>void N(e)},e.id)),!g&&O.length>2&&(0,H.jsx)(`button`,{type:`button`,onClick:()=>v(!0),className:`px-5 py-2 text-[13.5px] font-medium text-accent`,children:S(`Show {n} more`,{n:O.length-2})})]}),(0,H.jsxs)(`div`,{ref:y,className:`mt-2.5 border-t border-border/70 px-5 pt-3.5 pb-1.5`,children:[(0,H.jsx)(`h3`,{className:`text-[17px] font-semibold`,children:S(`Create a goal`)}),(0,H.jsx)(`p`,{className:`mt-1 text-[13px] leading-[18px] text-muted`,children:S(`Pick a category and tell me the goal you have in mind. I'll shape a plan with you and keep improving it as you go.`)})]}),C.map(e=>(0,H.jsxs)(`button`,{type:`button`,onClick:()=>h(e),className:`flex h-[50px] w-full items-center gap-3.5 pl-5 pr-2 text-left active:bg-surface-2/70`,children:[(0,H.jsx)(`span`,{className:`text-fg`,children:e.icon({size:22})}),(0,H.jsx)(`span`,{className:`flex-1 text-[15px] font-medium`,children:S(e.label)}),(0,H.jsx)(`span`,{className:`flex h-10 w-10 items-center justify-center text-muted`,children:(0,H.jsx)(_,{size:22})})]},e.id))]}),(0,H.jsx)(Q,{goal:k,onClose:()=>s(null),onAdvance:A,onChanged:t}),(0,H.jsx)($,{open:f,onClose:()=>p(!1),onCreated:()=>{p(!1),t()}}),(0,H.jsx)(D,{open:m!==null,onClose:()=>h(null),children:m&&(0,H.jsxs)(`div`,{className:`px-1 pb-2`,children:[(0,H.jsx)(`h3`,{className:`text-[20px] font-bold`,children:S(`Create a {category} goal`,{category:S(m.label)})}),(0,H.jsx)(`p`,{className:`mt-3.5 text-[15px] leading-[22px]`,children:S(`First, we'll shape the goal together in the chat. I'll ask a few questions so I understand exactly what you're after.`)}),(0,H.jsx)(`p`,{className:`mt-3.5 text-[15px] leading-[22px]`,children:S(`Once it's set, I'll track your progress here.`)}),(0,H.jsxs)(`button`,{type:`button`,onClick:()=>P(m),className:`mt-6 flex h-[50px] w-full items-center justify-center gap-2 rounded-full bg-accent text-[16px] font-semibold text-accent-fg`,children:[(0,H.jsx)(w,{size:18}),` `,S(`Start`)]})]})})]})}function K({label:e,dot:n=!1,onAdd:r}){return(0,H.jsxs)(`div`,{className:`flex items-center pl-5 pr-2 pt-1`,children:[n&&(0,H.jsx)(`span`,{className:`mr-2.5 h-2 w-2 rounded-full bg-emerald-500`}),(0,H.jsx)(`span`,{className:t(`flex-1 text-[15px] font-semibold`,n&&`text-emerald-600 dark:text-emerald-400`),children:e}),r?(0,H.jsx)(`button`,{type:`button`,onClick:r,"aria-label":e,className:`flex h-10 w-10 items-center justify-center text-muted`,children:(0,H.jsx)(_,{size:22})}):(0,H.jsx)(`span`,{className:`h-10`})]})}function q({id:e,size:n=`sm`}){let i=r(),a=x(e);return a?(0,H.jsxs)(`span`,{className:t(`inline-flex items-center gap-1 rounded-full font-medium`,a.tone,n===`sm`?`px-2 py-0.5 text-[11.5px]`:`px-2.5 py-1 text-[12.5px]`),children:[a.icon({size:n===`sm`?11:13}),` `,i(a.label)]}):null}function J({goal:n,onOpen:i,onToggle:a}){let o=r(),s=n.status===`done`,c=n.progress.total?Math.round(n.progress.done/n.progress.total*100):0,l=E(n.due,n.overdue),u=n.next_step?o(`Next: {step}`,{step:n.next_step}):n.description||``,d=n.status===`paused`?o(`Paused`):n.status===`cancelled`?o(`Cancelled`):s?o(`Done`):n.check_in?v(n.check_in):o(`Updated {when}`,{when:e(n.updated_at)});return(0,H.jsxs)(`div`,{className:`flex items-start pl-[18px] pr-1 pt-2 pb-2.5`,children:[(0,H.jsx)(`button`,{type:`button`,onClick:a,"aria-label":o(s?`Mark as not done`:`Mark as done`),className:`mt-0.5 flex h-7 w-7 shrink-0 items-center justify-center text-muted`,children:s?(0,H.jsx)(B,{size:22}):(0,H.jsx)(f,{size:22})}),(0,H.jsxs)(`button`,{type:`button`,onClick:i,className:`ml-2.5 min-w-0 flex-1 pt-[3px] text-left`,children:[(0,H.jsx)(`span`,{className:t(`line-clamp-2 block text-[15px] font-semibold leading-snug`,s&&`text-muted`),children:n.title}),u&&(0,H.jsx)(`span`,{className:`mt-0.5 line-clamp-2 block text-[13px] leading-[18px] text-muted`,children:u}),(0,H.jsxs)(`span`,{className:`mt-0.5 flex items-center gap-2 text-[12px] text-muted/80`,children:[(0,H.jsxs)(`span`,{className:`truncate`,children:[d,l&&n.status===`active`?` · ${l}`:``]}),c>0&&!s&&(0,H.jsxs)(`span`,{className:`shrink-0 font-medium text-emerald-600 dark:text-emerald-400`,children:[c,`%`]})]})]}),(0,H.jsx)(`button`,{type:`button`,onClick:i,"aria-label":o(`More`),className:`flex h-10 w-10 shrink-0 items-center justify-center text-muted`,children:(0,H.jsx)(L,{size:20})})]})}function Y({goal:e,onChanged:t,onOpen:n}){let{toast:i,state:a}=c(),[o,s]=(0,V.useState)(!1),l=a.profile?.name??`nanoMuse`,d=r(),f=e.proposal;if(!f)return null;let p=async n=>{s(!0);try{n?await u.acceptProposal(e.id):await u.dismissProposal(e.id),i(d(n?`Plan updated`:`Kept your plan`)),t()}catch(e){i(e.message)}finally{s(!1)}},m=e.steps.filter(e=>e.status===`done`||e.status===`skipped`).length;return(0,H.jsxs)(`div`,{className:`rounded-3xl border border-accent/30 bg-accent/5 px-4 py-3.5`,children:[(0,H.jsxs)(`button`,{type:`button`,onClick:n,className:`w-full text-left`,children:[(0,H.jsxs)(`div`,{className:`flex items-center gap-2 text-[12px] font-semibold uppercase tracking-wide text-accent`,children:[(0,H.jsx)(g,{size:13}),` `,d(`Adjust the plan for “{title}”?`,{title:e.title})]}),(0,H.jsx)(`p`,{className:`mt-1.5 text-[14px] leading-snug`,children:f.reason}),(0,H.jsxs)(`div`,{className:`mt-2 text-[12px] text-muted`,children:[m>0&&(0,H.jsxs)(`span`,{children:[m===1?d(`Keeps the 1 step already done.`):d(`Keeps the {n} steps already done.`,{n:m}),` `]}),d(`New remaining steps:`)]}),(0,H.jsx)(`ol`,{className:`mt-1 space-y-0.5 text-[13.5px] list-decimal pl-5`,children:f.steps.map((e,t)=>(0,H.jsx)(`li`,{children:e},t))})]}),(0,H.jsxs)(`div`,{className:`mt-3 flex gap-2`,children:[(0,H.jsx)(`button`,{type:`button`,disabled:o,onClick:()=>void p(!1),className:`flex-1 rounded-2xl border border-border py-2 text-[13.5px] font-medium disabled:opacity-50`,children:d(`Keep my plan`)}),(0,H.jsx)(`button`,{type:`button`,disabled:o,onClick:()=>void p(!0),className:`flex-1 rounded-2xl bg-accent text-accent-fg py-2 text-[13.5px] font-medium disabled:opacity-50`,children:d(`Use {name}'s plan`,{name:l})})]})]})}function X({value:e,onChange:n}){let i=r();return(0,H.jsx)(`div`,{className:`flex flex-wrap gap-1.5`,children:C.map(r=>(0,H.jsxs)(`button`,{type:`button`,onClick:()=>n(e===r.id?``:r.id),className:t(`inline-flex items-center gap-1 rounded-full px-2.5 py-1 text-[12.5px] font-medium transition border`,e===r.id?t(r.tone,`border-transparent ring-2 ring-accent/40`):`border-border text-muted`),children:[r.icon({size:12}),` `,i(r.label)]},r.id))})}function Z({value:e,onChange:n}){let i=r(),{cadence:a,anchor:o,time:s}=k(e),c=(e,t,r)=>n(j(e,t,r));return(0,H.jsxs)(`div`,{className:`space-y-2`,children:[(0,H.jsx)(`div`,{className:`flex flex-wrap gap-1.5`,children:T.map(e=>(0,H.jsx)(`button`,{type:`button`,onClick:()=>c(e.id,e.id===`weekly`?o||`mon`:e.id===`monthly`?o||`1`:``,s),className:t(`rounded-full px-2.5 py-1 text-[12.5px] font-medium border transition`,a===e.id?`bg-accent text-accent-fg border-transparent`:`border-border text-muted`),children:i(e.label)},e.id))}),a&&(0,H.jsxs)(`div`,{className:`flex items-center gap-2 text-[13.5px]`,children:[a===`weekly`&&(0,H.jsx)(`select`,{value:o||`mon`,onChange:e=>c(a,e.target.value,s),className:`rounded-xl bg-surface-2 px-2.5 py-1.5 outline-none`,children:S.map(e=>(0,H.jsx)(`option`,{value:e,children:m(e)},e))}),a===`monthly`&&(0,H.jsx)(`select`,{value:o||`1`,onChange:e=>c(a,e.target.value,s),className:`rounded-xl bg-surface-2 px-2.5 py-1.5 outline-none`,children:Array.from({length:28},(e,t)=>String(t+1)).map(e=>(0,H.jsx)(`option`,{value:e,children:y(Number(e))},e))}),(0,H.jsx)(`span`,{className:`text-muted`,children:i(`at`)}),(0,H.jsx)(`input`,{type:`time`,value:s,onChange:e=>c(a,o,e.target.value||`09:00`),className:`rounded-xl bg-surface-2 px-2.5 py-1.5 outline-none`})]})]})}function Q({goal:n,onClose:a,onAdvance:o,onChanged:s}){let{toast:l,send:d,openThread:f,state:m}=c(),[g,y]=(0,V.useState)(``),[b,x]=(0,V.useState)(!1),S=m.profile?.name??`nanoMuse`,C=r(),w=async e=>{if(n)try{await u.patchGoal(n.id,e),s()}catch(e){l(e.message)}},T=async()=>{if(n&&g.trim())try{await u.addStep(n.id,g.trim()),y(``),s()}catch(e){l(e.message)}},k=async()=>{if(n)try{await u.checkInGoal(n.id),l(C(`{name} will check in with you in the main chat`,{name:S})),f(`main`),a()}catch(e){l(e.message)}},j=async()=>{if(n&&window.confirm(C(`Delete “{title}”?`,{title:n.title})))try{await u.deleteGoal(n.id),s(),a()}catch(e){l(e.message)}},N=n?E(n.due,n.overdue):``;return(0,H.jsx)(D,{open:!!n,onClose:a,title:n?.title,footer:n&&(0,H.jsxs)(`div`,{className:`flex gap-2`,children:[n.status===`active`?(0,H.jsxs)(`button`,{type:`button`,onClick:()=>void w({status:`paused`}),className:`flex-1 rounded-2xl border border-border py-2.5 font-medium flex items-center justify-center gap-1.5`,children:[(0,H.jsx)(z,{size:16}),` `,C(`Pause`)]}):n.status===`paused`?(0,H.jsxs)(`button`,{type:`button`,onClick:()=>void w({status:`active`}),className:`flex-1 rounded-2xl border border-border py-2.5 font-medium flex items-center justify-center gap-1.5`,children:[(0,H.jsx)(p,{size:16}),` `,C(`Resume`)]}):null,n.status===`active`&&(0,H.jsxs)(`button`,{type:`button`,onClick:()=>o(n),className:`flex-1 rounded-2xl bg-accent text-accent-fg py-2.5 font-medium flex items-center justify-center gap-1.5`,children:[(0,H.jsx)(p,{size:16}),` `,C(`Work on it now`)]}),(0,H.jsx)(`button`,{type:`button`,onClick:()=>void j(),"aria-label":C(`Delete goal`),className:`rounded-2xl border border-border px-3 text-muted hover:text-rose-500`,children:(0,H.jsx)(h,{size:18})})]}),children:n&&(0,H.jsxs)(`div`,{className:`space-y-4`,children:[n.proposal&&(0,H.jsx)(Y,{goal:n,onChanged:s,onOpen:()=>void 0}),n.description&&(0,H.jsx)(`p`,{className:`text-[14px] text-muted leading-snug`,children:n.description}),(0,H.jsx)(`div`,{className:`rounded-2xl bg-surface-2/60 px-3.5 py-3`,children:b?(0,H.jsxs)(`div`,{className:`space-y-3`,children:[(0,H.jsxs)(`div`,{children:[(0,H.jsx)(`div`,{className:`text-[12px] font-semibold uppercase tracking-wide text-muted mb-1.5`,children:C(`Area of life`)}),(0,H.jsx)(X,{value:n.category,onChange:e=>void w({category:e})})]}),(0,H.jsxs)(`div`,{children:[(0,H.jsx)(`div`,{className:`text-[12px] font-semibold uppercase tracking-wide text-muted mb-1.5`,children:C(`Target date`)}),(0,H.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,H.jsx)(`input`,{type:`date`,value:n.due,onChange:e=>void w({due:e.target.value}),className:`rounded-xl bg-surface px-2.5 py-1.5 text-[13.5px] outline-none`}),n.due&&(0,H.jsx)(`button`,{type:`button`,onClick:()=>void w({due:``}),className:`text-[12.5px] text-muted`,children:C(`Clear`)})]})]}),(0,H.jsxs)(`div`,{children:[(0,H.jsx)(`div`,{className:`text-[12px] font-semibold uppercase tracking-wide text-muted mb-1.5`,children:C(`Reminders from {name}`,{name:S})}),(0,H.jsx)(Z,{value:n.check_in,onChange:e=>void w({check_in:e})})]}),(0,H.jsx)(`button`,{type:`button`,onClick:()=>x(!1),className:`text-[12.5px] text-accent font-medium`,children:C(`Done`)})]}):(0,H.jsxs)(`button`,{type:`button`,onClick:()=>x(!0),className:`w-full text-left`,children:[(0,H.jsxs)(`div`,{className:`flex flex-wrap items-center gap-1.5 text-[12.5px]`,children:[n.category?(0,H.jsx)(q,{id:n.category,size:`md`}):(0,H.jsx)(`span`,{className:`rounded-full border border-dashed border-border px-2.5 py-1 text-muted`,children:C(`No category`)}),(0,H.jsxs)(`span`,{className:t(`inline-flex items-center gap-1 rounded-full px-2.5 py-1`,n.overdue?`bg-rose-500/12 text-rose-600 dark:text-rose-300 font-medium`:`bg-surface text-muted`),children:[(0,H.jsx)(A,{size:13}),` `,N||C(`No target date`)]}),(0,H.jsxs)(`span`,{className:`inline-flex items-center gap-1 rounded-full bg-surface px-2.5 py-1 text-muted`,children:[(0,H.jsx)(O,{size:13}),` `,n.check_in?v(n.check_in):C(`No reminders`)]})]}),n.next_check_in&&n.status===`active`&&(0,H.jsxs)(`div`,{className:`mt-1.5 text-[12px] text-muted`,children:[C(`Next check-in {when}`,{when:e(n.next_check_in)}),` · `,i(n.next_check_in)]}),(0,H.jsx)(`div`,{className:`mt-1.5 text-[12px] text-accent font-medium`,children:C(`Edit`)})]})}),(0,H.jsxs)(`div`,{children:[(0,H.jsxs)(`div`,{className:`text-[12px] font-semibold uppercase tracking-wide text-muted mb-2`,children:[C(`Plan`),` · `,n.progress.done,`/`,n.progress.total]}),(0,H.jsx)(`ul`,{className:`space-y-1`,children:n.steps.map(e=>{let n=U[e.status];return(0,H.jsxs)(`li`,{className:`flex items-start gap-2.5 rounded-2xl px-2 py-1.5 hover:bg-surface-2/60`,children:[(0,H.jsx)(`button`,{type:`button`,"aria-label":C(`Mark step {n} {status}`,{n:e.idx,status:C(W[e.status])}),onClick:()=>void w({step_index:e.idx,step_status:W[e.status]}),className:`mt-0.5 text-muted`,children:(0,H.jsx)(n,{size:20})}),(0,H.jsxs)(`div`,{className:`flex-1 min-w-0`,children:[(0,H.jsxs)(`div`,{className:t(`text-[14.5px] leading-snug`,(e.status===`done`||e.status===`skipped`)&&`line-through text-muted`),children:[e.idx,`. `,e.title]}),e.note&&(0,H.jsx)(`div`,{className:`text-[12.5px] text-muted mt-0.5 whitespace-pre-wrap`,children:e.note})]})]},e.idx)})}),(0,H.jsxs)(`div`,{className:`mt-2 flex gap-2`,children:[(0,H.jsx)(`input`,{value:g,onChange:e=>y(e.target.value),onKeyDown:e=>e.key===`Enter`&&void T(),placeholder:C(`Add a step`),className:`flex-1 rounded-2xl bg-surface-2 px-3.5 py-2 text-[14px] outline-none focus:ring-2 focus:ring-accent/40`}),(0,H.jsx)(`button`,{type:`button`,onClick:()=>void T(),className:`rounded-2xl bg-surface-2 px-3 text-accent`,"aria-label":C(`Add step`),children:(0,H.jsx)(_,{size:18})})]})]}),n.notes&&(0,H.jsxs)(`div`,{children:[(0,H.jsx)(`div`,{className:`text-[12px] font-semibold uppercase tracking-wide text-muted mb-1.5`,children:C(`Notes from {name}`,{name:S})}),(0,H.jsx)(`pre`,{className:`whitespace-pre-wrap break-words text-[13px] leading-snug text-muted font-sans`,children:n.notes})]}),(0,H.jsxs)(`div`,{className:`flex flex-wrap gap-x-4 gap-y-1.5`,children:[(0,H.jsx)(`button`,{type:`button`,onClick:()=>{d(`main`,C(`About my goal “{title}” ({id}): what's the status, and what should we do next?`,{title:n.title,id:n.id})).catch(e=>l(e.message||C(`Could not send`))),f(`main`),a()},className:`text-[13.5px] text-accent font-medium`,children:C(`Discuss this goal in chat →`)}),n.status===`active`&&(0,H.jsxs)(`button`,{type:`button`,onClick:()=>void k(),className:`text-[13.5px] text-accent font-medium inline-flex items-center gap-1`,children:[(0,H.jsx)(M,{size:14}),` `,C(`Check in with me now`)]})]})]})})}function $({open:e,onClose:t,onCreated:n}){let{toast:i,send:a,openThread:o,state:s}=c(),[l,d]=(0,V.useState)(``),[f,p]=(0,V.useState)(``),[m,h]=(0,V.useState)(``),[_,v]=(0,V.useState)(``),[y,b]=(0,V.useState)(``),[x,S]=(0,V.useState)(``),[C,w]=(0,V.useState)(!1),T=s.profile?.name??`nanoMuse`,E=r(),O=()=>{d(``),p(``),h(``),v(``),b(``),S(``)},k=async()=>{if(l.trim()){w(!0);try{await u.createGoal({title:l.trim(),description:f.trim(),steps:m.split(` -`).map(e=>e.trim()).filter(Boolean),category:_,due:y,check_in:x}),O(),n()}catch(e){i(e.message)}finally{w(!1)}}};return(0,H.jsx)(D,{open:e,onClose:t,title:E(`New goal`),footer:(0,H.jsxs)(`div`,{className:`flex gap-2`,children:[(0,H.jsxs)(`button`,{type:`button`,onClick:()=>{if(!l.trim())return;let e=[_?`category: ${_}`:``,y?`target date: ${y}`:``,x?`check_in "${x}"`:``].filter(Boolean);a(`main`,E(`Create a goal for me: "{title}"{description}{extras}. Break it into concrete steps with the goals tool, then tell me the plan.`,{title:l.trim(),description:f.trim()?` (${f.trim()})`:``,extras:e.length?` (${e.join(`, `)})`:``})).catch(e=>i(e.message||E(`Could not send`))),O(),t(),o(`main`)},disabled:!l.trim(),className:`flex-1 rounded-2xl border border-border py-2.5 font-medium disabled:opacity-50 flex items-center justify-center gap-1.5`,children:[(0,H.jsx)(g,{size:16}),` `,E(`Let {name} plan it`,{name:T})]}),(0,H.jsx)(`button`,{type:`button`,onClick:()=>void k(),disabled:!l.trim()||C,className:`flex-1 rounded-2xl bg-accent text-accent-fg py-2.5 font-medium disabled:opacity-50`,children:E(`Create`)})]}),children:(0,H.jsxs)(`div`,{className:`space-y-3.5`,children:[(0,H.jsx)(`input`,{value:l,onChange:e=>d(e.target.value),placeholder:E(`What do you want to achieve?`),className:`w-full rounded-2xl bg-surface-2 px-3.5 py-2.5 text-[15px] outline-none focus:ring-2 focus:ring-accent/40`}),(0,H.jsxs)(`div`,{children:[(0,H.jsx)(`div`,{className:`text-[12px] font-semibold uppercase tracking-wide text-muted mb-1.5`,children:E(`Area of life`)}),(0,H.jsx)(X,{value:_,onChange:v})]}),(0,H.jsxs)(`div`,{className:`flex items-center gap-3`,children:[(0,H.jsx)(`div`,{className:`text-[12px] font-semibold uppercase tracking-wide text-muted flex-1`,children:E(`Target date`)}),(0,H.jsx)(`input`,{type:`date`,value:y,onChange:e=>b(e.target.value),className:`rounded-xl bg-surface-2 px-2.5 py-1.5 text-[13.5px] outline-none`})]}),(0,H.jsxs)(`div`,{children:[(0,H.jsx)(`div`,{className:`text-[12px] font-semibold uppercase tracking-wide text-muted mb-1.5`,children:E(`Reminders from {name}`,{name:T})}),(0,H.jsx)(Z,{value:x,onChange:S})]}),(0,H.jsx)(`textarea`,{value:f,onChange:e=>p(e.target.value),placeholder:E(`Why it matters, constraints (optional)`),rows:2,className:`w-full rounded-2xl bg-surface-2 px-3.5 py-2.5 text-[14px] outline-none focus:ring-2 focus:ring-accent/40 resize-none`}),(0,H.jsx)(`textarea`,{value:m,onChange:e=>h(e.target.value),placeholder:E(`Steps, one per line (optional, or let {name} plan them)`,{name:T}),rows:3,className:`w-full rounded-2xl bg-surface-2 px-3.5 py-2.5 text-[14px] outline-none focus:ring-2 focus:ring-accent/40 resize-none`})]})})}export{G as GoalsScreen}; \ No newline at end of file +import{A as e,E as t,J as n,K as r,N as i,Q as a,Y as o,b as s,f as c,r as l,x as u}from"./MuseHeader-RC--uR8o.js";import{t as d}from"./StarNudge-Df6LQyo9.js";import{B as f,C as p,Ct as m,U as h,V as g,X as _,Z as v,_ as y,at as b,b as x,bt as S,d as C,f as w,g as T,h as E,m as D,p as O,v as k,x as A,y as j}from"./index-tYqPtwPX.js";var M=n(`bell-ring`,[[`path`,{d:`M10.268 21a2 2 0 0 0 3.464 0`,key:`vwvbt9`}],[`path`,{d:`M22 8c0-2.3-.8-4.3-2-6`,key:`5bb3ad`}],[`path`,{d:`M3.262 15.326A1 1 0 0 0 4 17h16a1 1 0 0 0 .74-1.673C19.41 13.956 18 12.499 18 8A6 6 0 0 0 6 8c0 4.499-1.411 5.956-2.738 7.326`,key:`11g9vi`}],[`path`,{d:`M4 2C2.8 3.7 2 5.7 2 8`,key:`tap9e0`}]]),N=n(`circle-check`,[[`circle`,{cx:`12`,cy:`12`,r:`10`,key:`1mglay`}],[`path`,{d:`m9 12 2 2 4-4`,key:`dzmm74`}]]),P=n(`circle-dashed`,[[`path`,{d:`M10.1 2.182a10 10 0 0 1 3.8 0`,key:`5ilxe3`}],[`path`,{d:`M13.9 21.818a10 10 0 0 1-3.8 0`,key:`11zvb9`}],[`path`,{d:`M17.609 3.721a10 10 0 0 1 2.69 2.7`,key:`1iw5b2`}],[`path`,{d:`M2.182 13.9a10 10 0 0 1 0-3.8`,key:`c0bmvh`}],[`path`,{d:`M20.279 17.609a10 10 0 0 1-2.7 2.69`,key:`1ruxm7`}],[`path`,{d:`M21.818 10.1a10 10 0 0 1 0 3.8`,key:`qkgqxc`}],[`path`,{d:`M3.721 6.391a10 10 0 0 1 2.7-2.69`,key:`1mcia2`}],[`path`,{d:`M6.391 20.279a10 10 0 0 1-2.69-2.7`,key:`1fvljs`}]]),F=n(`circle-slash`,[[`circle`,{cx:`12`,cy:`12`,r:`10`,key:`1mglay`}],[`line`,{x1:`9`,x2:`15`,y1:`15`,y2:`9`,key:`1dfufj`}]]),I=n(`circle`,[[`circle`,{cx:`12`,cy:`12`,r:`10`,key:`1mglay`}]]),L=n(`ellipsis-vertical`,[[`circle`,{cx:`12`,cy:`12`,r:`1`,key:`41hilf`}],[`circle`,{cx:`12`,cy:`5`,r:`1`,key:`gxeob9`}],[`circle`,{cx:`12`,cy:`19`,r:`1`,key:`lyex9k`}]]),R=n(`octagon-alert`,[[`path`,{d:`M12 16h.01`,key:`1drbdi`}],[`path`,{d:`M12 8v4`,key:`1got3b`}],[`path`,{d:`M15.312 2a2 2 0 0 1 1.414.586l4.688 4.688A2 2 0 0 1 22 8.688v6.624a2 2 0 0 1-.586 1.414l-4.688 4.688a2 2 0 0 1-1.414.586H8.688a2 2 0 0 1-1.414-.586l-4.688-4.688A2 2 0 0 1 2 15.312V8.688a2 2 0 0 1 .586-1.414l4.688-4.688A2 2 0 0 1 8.688 2z`,key:`1fd625`}]]),z=n(`pause`,[[`rect`,{x:`14`,y:`3`,width:`5`,height:`18`,rx:`1`,key:`kaeet6`}],[`rect`,{x:`5`,y:`3`,width:`5`,height:`18`,rx:`1`,key:`1wsw3u`}]]),B=n(`square-check`,[[`rect`,{width:`18`,height:`18`,x:`3`,y:`3`,rx:`2`,key:`afitv7`}],[`path`,{d:`m9 12 2 2 4-4`,key:`dzmm74`}]]),V=a(o(),1),H=s(),U={pending:e=>(0,H.jsx)(I,{...e}),in_progress:e=>(0,H.jsx)(P,{...e,className:t(e.className,`text-accent`)}),done:e=>(0,H.jsx)(N,{...e,className:t(e.className,`text-emerald-500`)}),blocked:e=>(0,H.jsx)(R,{...e,className:t(e.className,`text-rose-500`)}),skipped:e=>(0,H.jsx)(F,{...e,className:t(e.className,`text-muted`)})},W={pending:`done`,in_progress:`done`,done:`pending`,blocked:`pending`,skipped:`pending`};function G(){let{state:e,refreshGoals:t,send:n,openThread:i,toast:a}=c(),[o,s]=(0,V.useState)(null),[f,m]=(0,V.useState)(!1),[h,g]=(0,V.useState)(null),[v,y]=(0,V.useState)(!1),x=(0,V.useRef)(null),S=e.profile?.name??`nanoMuse`,w=r();(0,V.useEffect)(()=>{t()},[t]);let T=e.goals.filter(e=>e.proposal&&e.status!==`cancelled`),E=[...e.goals.filter(e=>e.status===`active`),...e.goals.filter(e=>e.status===`paused`)],D=e.goals.filter(e=>e.status===`done`||e.status===`cancelled`),k=e.goals.find(e=>e.id===o)??null,A=async e=>{try{await u.advanceGoal(e.id),a(w(`{name} is working on “{title}” in the main chat`,{name:S,title:e.title})),i(`main`)}catch(e){a(e.message)}},[j,M]=(0,V.useState)(!1),N=async e=>{try{let n=e.status!==`done`;await u.patchGoal(e.id,{status:n?`done`:`active`}),n&&M(!0),t()}catch(e){a(e.message)}},P=e=>{g(null),n(`main`,w(`I'd like to create a {category} goal. Ask me a few short questions, one at a time (what exactly I want, why and by when, how often to check in), then create it with concrete steps using the goals tool.`,{category:w(e.label)})).catch(e=>a(e.message||w(`Could not send`))),i(`main`)};return(0,H.jsxs)(`div`,{className:`flex h-full flex-col`,children:[(0,H.jsx)(C,{title:w(`Goals`),children:(0,H.jsx)(l,{small:!0,onClick:()=>m(!0),label:w(`New goal`),children:(0,H.jsx)(_,{size:22})})}),(0,H.jsxs)(`div`,{className:`flex-1 overflow-y-auto pb-6`,children:[T.length>0&&(0,H.jsxs)(`section`,{className:`px-4 pb-2`,children:[(0,H.jsx)(`div`,{className:`px-1 mb-2 text-[12px] font-semibold uppercase tracking-wide text-muted`,children:w(`{name} suggests`,{name:S})}),(0,H.jsx)(`div`,{className:`space-y-2.5`,children:T.map(e=>(0,H.jsx)(Y,{goal:e,onChanged:t,onOpen:()=>s(e.id)},e.id))})]}),(0,H.jsx)(d,{moment:`goal_done`,due:j,className:`mx-4 mb-3`}),(0,H.jsx)(K,{label:w(`Tracking`),dot:!0,onAdd:()=>x.current?.scrollIntoView({behavior:`smooth`,block:`start`})}),E.length===0?(0,H.jsx)(`p`,{className:`px-5 pb-3 text-[13px] text-muted`,children:w(`Nothing tracked yet`)}):E.map(e=>(0,H.jsx)(J,{goal:e,onOpen:()=>s(e.id),onToggle:()=>void N(e)},e.id)),D.length>0&&(0,H.jsxs)(H.Fragment,{children:[(0,H.jsx)(`div`,{className:`h-1.5`}),(0,H.jsx)(K,{label:w(`Finished`)}),(v?D:D.slice(0,2)).map(e=>(0,H.jsx)(J,{goal:e,onOpen:()=>s(e.id),onToggle:()=>void N(e)},e.id)),!v&&D.length>2&&(0,H.jsx)(`button`,{type:`button`,onClick:()=>y(!0),className:`px-5 py-2 text-[13.5px] font-medium text-accent`,children:w(`Show {n} more`,{n:D.length-2})})]}),(0,H.jsxs)(`div`,{ref:x,className:`mt-2.5 border-t border-border/70 px-5 pt-3.5 pb-1.5`,children:[(0,H.jsx)(`h3`,{className:`text-[17px] font-semibold`,children:w(`Create a goal`)}),(0,H.jsx)(`p`,{className:`mt-1 text-[13px] leading-[18px] text-muted`,children:w(`Pick a category and tell me the goal you have in mind. I'll shape a plan with you and keep improving it as you go.`)})]}),O.map(e=>(0,H.jsxs)(`button`,{type:`button`,onClick:()=>g(e),className:`flex h-[50px] w-full items-center gap-3.5 pl-5 pr-2 text-left active:bg-surface-2/70`,children:[(0,H.jsx)(`span`,{className:`text-fg`,children:e.icon({size:22})}),(0,H.jsx)(`span`,{className:`flex-1 text-[15px] font-medium`,children:w(e.label)}),(0,H.jsx)(`span`,{className:`flex h-10 w-10 items-center justify-center text-muted`,children:(0,H.jsx)(_,{size:22})})]},e.id))]}),(0,H.jsx)(Q,{goal:k,onClose:()=>s(null),onAdvance:A,onChanged:t}),(0,H.jsx)($,{open:f,onClose:()=>m(!1),onCreated:()=>{m(!1),t()}}),(0,H.jsx)(p,{open:h!==null,onClose:()=>g(null),children:h&&(0,H.jsxs)(`div`,{className:`px-1 pb-2`,children:[(0,H.jsx)(`h3`,{className:`text-[20px] font-bold`,children:w(`Create a {category} goal`,{category:w(h.label)})}),(0,H.jsx)(`p`,{className:`mt-3.5 text-[15px] leading-[22px]`,children:w(`First, we'll shape the goal together in the chat. I'll ask a few questions so I understand exactly what you're after.`)}),(0,H.jsx)(`p`,{className:`mt-3.5 text-[15px] leading-[22px]`,children:w(`Once it's set, I'll track your progress here.`)}),(0,H.jsxs)(`button`,{type:`button`,onClick:()=>P(h),className:`mt-6 flex h-[50px] w-full items-center justify-center gap-2 rounded-full bg-accent text-[16px] font-semibold text-accent-fg`,children:[(0,H.jsx)(b,{size:18}),` `,w(`Start`)]})]})})]})}function K({label:e,dot:n=!1,onAdd:r}){return(0,H.jsxs)(`div`,{className:`flex items-center pl-5 pr-2 pt-1`,children:[n&&(0,H.jsx)(`span`,{className:`mr-2.5 h-2 w-2 rounded-full bg-emerald-500`}),(0,H.jsx)(`span`,{className:t(`flex-1 text-[15px] font-semibold`,n&&`text-emerald-600 dark:text-emerald-400`),children:e}),r?(0,H.jsx)(`button`,{type:`button`,onClick:r,"aria-label":e,className:`flex h-10 w-10 items-center justify-center text-muted`,children:(0,H.jsx)(_,{size:22})}):(0,H.jsx)(`span`,{className:`h-10`})]})}function q({id:e,size:n=`sm`}){let i=r(),a=E(e);return a?(0,H.jsxs)(`span`,{className:t(`inline-flex items-center gap-1 rounded-full font-medium`,a.tone,n===`sm`?`px-2 py-0.5 text-[11.5px]`:`px-2.5 py-1 text-[12.5px]`),children:[a.icon({size:n===`sm`?11:13}),` `,i(a.label)]}):null}function J({goal:n,onOpen:i,onToggle:a}){let o=r(),s=n.status===`done`,c=n.progress.total?Math.round(n.progress.done/n.progress.total*100):0,l=y(n.due,n.overdue),u=n.next_step?o(`Next: {step}`,{step:n.next_step}):n.description||``,d=n.status===`paused`?o(`Paused`):n.status===`cancelled`?o(`Cancelled`):s?o(`Done`):n.check_in?T(n.check_in):o(`Updated {when}`,{when:e(n.updated_at)});return(0,H.jsxs)(`div`,{className:`flex items-start pl-[18px] pr-1 pt-2 pb-2.5`,children:[(0,H.jsx)(`button`,{type:`button`,onClick:a,"aria-label":o(s?`Mark as not done`:`Mark as done`),className:`mt-0.5 flex h-7 w-7 shrink-0 items-center justify-center text-muted`,children:s?(0,H.jsx)(B,{size:22}):(0,H.jsx)(g,{size:22})}),(0,H.jsxs)(`button`,{type:`button`,onClick:i,className:`ml-2.5 min-w-0 flex-1 pt-[3px] text-left`,children:[(0,H.jsx)(`span`,{className:t(`line-clamp-2 block text-[15px] font-semibold leading-snug`,s&&`text-muted`),children:n.title}),u&&(0,H.jsx)(`span`,{className:`mt-0.5 line-clamp-2 block text-[13px] leading-[18px] text-muted`,children:u}),(0,H.jsxs)(`span`,{className:`mt-0.5 flex items-center gap-2 text-[12px] text-muted/80`,children:[(0,H.jsxs)(`span`,{className:`truncate`,children:[d,l&&n.status===`active`?` · ${l}`:``]}),c>0&&!s&&(0,H.jsxs)(`span`,{className:`shrink-0 font-medium text-emerald-600 dark:text-emerald-400`,children:[c,`%`]})]})]}),(0,H.jsx)(`button`,{type:`button`,onClick:i,"aria-label":o(`More`),className:`flex h-10 w-10 shrink-0 items-center justify-center text-muted`,children:(0,H.jsx)(L,{size:20})})]})}function Y({goal:e,onChanged:t,onOpen:n}){let{toast:i,state:a}=c(),[o,s]=(0,V.useState)(!1),l=a.profile?.name??`nanoMuse`,d=r(),f=e.proposal;if(!f)return null;let p=async n=>{s(!0);try{n?await u.acceptProposal(e.id):await u.dismissProposal(e.id),i(d(n?`Plan updated`:`Kept your plan`)),t()}catch(e){i(e.message)}finally{s(!1)}},m=e.steps.filter(e=>e.status===`done`||e.status===`skipped`).length;return(0,H.jsxs)(`div`,{className:`rounded-3xl border border-accent/30 bg-accent/5 px-4 py-3.5`,children:[(0,H.jsxs)(`button`,{type:`button`,onClick:n,className:`w-full text-left`,children:[(0,H.jsxs)(`div`,{className:`flex items-center gap-2 text-[12px] font-semibold uppercase tracking-wide text-accent`,children:[(0,H.jsx)(h,{size:13}),` `,d(`Adjust the plan for “{title}”?`,{title:e.title})]}),(0,H.jsx)(`p`,{className:`mt-1.5 text-[14px] leading-snug`,children:f.reason}),(0,H.jsxs)(`div`,{className:`mt-2 text-[12px] text-muted`,children:[m>0&&(0,H.jsxs)(`span`,{children:[m===1?d(`Keeps the 1 step already done.`):d(`Keeps the {n} steps already done.`,{n:m}),` `]}),d(`New remaining steps:`)]}),(0,H.jsx)(`ol`,{className:`mt-1 space-y-0.5 text-[13.5px] list-decimal pl-5`,children:f.steps.map((e,t)=>(0,H.jsx)(`li`,{children:e},t))})]}),(0,H.jsxs)(`div`,{className:`mt-3 flex gap-2`,children:[(0,H.jsx)(`button`,{type:`button`,disabled:o,onClick:()=>void p(!1),className:`flex-1 rounded-2xl border border-border py-2 text-[13.5px] font-medium disabled:opacity-50`,children:d(`Keep my plan`)}),(0,H.jsx)(`button`,{type:`button`,disabled:o,onClick:()=>void p(!0),className:`flex-1 rounded-2xl bg-accent text-accent-fg py-2 text-[13.5px] font-medium disabled:opacity-50`,children:d(`Use {name}'s plan`,{name:l})})]})]})}function X({value:e,onChange:n}){let i=r();return(0,H.jsx)(`div`,{className:`flex flex-wrap gap-1.5`,children:O.map(r=>(0,H.jsxs)(`button`,{type:`button`,onClick:()=>n(e===r.id?``:r.id),className:t(`inline-flex items-center gap-1 rounded-full px-2.5 py-1 text-[12.5px] font-medium transition border`,e===r.id?t(r.tone,`border-transparent ring-2 ring-accent/40`):`border-border text-muted`),children:[r.icon({size:12}),` `,i(r.label)]},r.id))})}function Z({value:e,onChange:n}){let i=r(),{cadence:a,anchor:o,time:s}=x(e),c=(e,t,r)=>n(k(e,t,r));return(0,H.jsxs)(`div`,{className:`space-y-2`,children:[(0,H.jsx)(`div`,{className:`flex flex-wrap gap-1.5`,children:w.map(e=>(0,H.jsx)(`button`,{type:`button`,onClick:()=>c(e.id,e.id===`weekly`?o||`mon`:e.id===`monthly`?o||`1`:``,s),className:t(`rounded-full px-2.5 py-1 text-[12.5px] font-medium border transition`,a===e.id?`bg-accent text-accent-fg border-transparent`:`border-border text-muted`),children:i(e.label)},e.id))}),a&&(0,H.jsxs)(`div`,{className:`flex items-center gap-2 text-[13.5px]`,children:[a===`weekly`&&(0,H.jsx)(`select`,{value:o||`mon`,onChange:e=>c(a,e.target.value,s),className:`rounded-xl bg-surface-2 px-2.5 py-1.5 outline-none`,children:D.map(e=>(0,H.jsx)(`option`,{value:e,children:A(e)},e))}),a===`monthly`&&(0,H.jsx)(`select`,{value:o||`1`,onChange:e=>c(a,e.target.value,s),className:`rounded-xl bg-surface-2 px-2.5 py-1.5 outline-none`,children:Array.from({length:28},(e,t)=>String(t+1)).map(e=>(0,H.jsx)(`option`,{value:e,children:j(Number(e))},e))}),(0,H.jsx)(`span`,{className:`text-muted`,children:i(`at`)}),(0,H.jsx)(`input`,{type:`time`,value:s,onChange:e=>c(a,o,e.target.value||`09:00`),className:`rounded-xl bg-surface-2 px-2.5 py-1.5 outline-none`})]})]})}function Q({goal:n,onClose:a,onAdvance:o,onChanged:s}){let{toast:l,send:d,openThread:h,state:g}=c(),[b,x]=(0,V.useState)(``),[C,w]=(0,V.useState)(!1),E=g.profile?.name??`nanoMuse`,D=r(),O=async e=>{if(n)try{await u.patchGoal(n.id,e),s()}catch(e){l(e.message)}},k=async()=>{if(n&&b.trim())try{await u.addStep(n.id,b.trim()),x(``),s()}catch(e){l(e.message)}},A=async()=>{if(n)try{await u.checkInGoal(n.id),l(D(`{name} will check in with you in the main chat`,{name:E})),h(`main`),a()}catch(e){l(e.message)}},j=async()=>{if(n&&window.confirm(D(`Delete “{title}”?`,{title:n.title})))try{await u.deleteGoal(n.id),s(),a()}catch(e){l(e.message)}},N=n?y(n.due,n.overdue):``;return(0,H.jsx)(p,{open:!!n,onClose:a,title:n?.title,footer:n&&(0,H.jsxs)(`div`,{className:`flex gap-2`,children:[n.status===`active`?(0,H.jsxs)(`button`,{type:`button`,onClick:()=>void O({status:`paused`}),className:`flex-1 rounded-2xl border border-border py-2.5 font-medium flex items-center justify-center gap-1.5`,children:[(0,H.jsx)(z,{size:16}),` `,D(`Pause`)]}):n.status===`paused`?(0,H.jsxs)(`button`,{type:`button`,onClick:()=>void O({status:`active`}),className:`flex-1 rounded-2xl border border-border py-2.5 font-medium flex items-center justify-center gap-1.5`,children:[(0,H.jsx)(v,{size:16}),` `,D(`Resume`)]}):null,n.status===`active`&&(0,H.jsxs)(`button`,{type:`button`,onClick:()=>o(n),className:`flex-1 rounded-2xl bg-accent text-accent-fg py-2.5 font-medium flex items-center justify-center gap-1.5`,children:[(0,H.jsx)(v,{size:16}),` `,D(`Work on it now`)]}),(0,H.jsx)(`button`,{type:`button`,onClick:()=>void j(),"aria-label":D(`Delete goal`),className:`rounded-2xl border border-border px-3 text-muted hover:text-rose-500`,children:(0,H.jsx)(f,{size:18})})]}),children:n&&(0,H.jsxs)(`div`,{className:`space-y-4`,children:[n.proposal&&(0,H.jsx)(Y,{goal:n,onChanged:s,onOpen:()=>void 0}),n.description&&(0,H.jsx)(`p`,{className:`text-[14px] text-muted leading-snug`,children:n.description}),(0,H.jsx)(`div`,{className:`rounded-2xl bg-surface-2/60 px-3.5 py-3`,children:C?(0,H.jsxs)(`div`,{className:`space-y-3`,children:[(0,H.jsxs)(`div`,{children:[(0,H.jsx)(`div`,{className:`text-[12px] font-semibold uppercase tracking-wide text-muted mb-1.5`,children:D(`Area of life`)}),(0,H.jsx)(X,{value:n.category,onChange:e=>void O({category:e})})]}),(0,H.jsxs)(`div`,{children:[(0,H.jsx)(`div`,{className:`text-[12px] font-semibold uppercase tracking-wide text-muted mb-1.5`,children:D(`Target date`)}),(0,H.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,H.jsx)(`input`,{type:`date`,value:n.due,onChange:e=>void O({due:e.target.value}),className:`rounded-xl bg-surface px-2.5 py-1.5 text-[13.5px] outline-none`}),n.due&&(0,H.jsx)(`button`,{type:`button`,onClick:()=>void O({due:``}),className:`text-[12.5px] text-muted`,children:D(`Clear`)})]})]}),(0,H.jsxs)(`div`,{children:[(0,H.jsx)(`div`,{className:`text-[12px] font-semibold uppercase tracking-wide text-muted mb-1.5`,children:D(`Reminders from {name}`,{name:E})}),(0,H.jsx)(Z,{value:n.check_in,onChange:e=>void O({check_in:e})})]}),(0,H.jsx)(`button`,{type:`button`,onClick:()=>w(!1),className:`text-[12.5px] text-accent font-medium`,children:D(`Done`)})]}):(0,H.jsxs)(`button`,{type:`button`,onClick:()=>w(!0),className:`w-full text-left`,children:[(0,H.jsxs)(`div`,{className:`flex flex-wrap items-center gap-1.5 text-[12.5px]`,children:[n.category?(0,H.jsx)(q,{id:n.category,size:`md`}):(0,H.jsx)(`span`,{className:`rounded-full border border-dashed border-border px-2.5 py-1 text-muted`,children:D(`No category`)}),(0,H.jsxs)(`span`,{className:t(`inline-flex items-center gap-1 rounded-full px-2.5 py-1`,n.overdue?`bg-rose-500/12 text-rose-600 dark:text-rose-300 font-medium`:`bg-surface text-muted`),children:[(0,H.jsx)(S,{size:13}),` `,N||D(`No target date`)]}),(0,H.jsxs)(`span`,{className:`inline-flex items-center gap-1 rounded-full bg-surface px-2.5 py-1 text-muted`,children:[(0,H.jsx)(m,{size:13}),` `,n.check_in?T(n.check_in):D(`No reminders`)]})]}),n.next_check_in&&n.status===`active`&&(0,H.jsxs)(`div`,{className:`mt-1.5 text-[12px] text-muted`,children:[D(`Next check-in {when}`,{when:e(n.next_check_in)}),` · `,i(n.next_check_in)]}),(0,H.jsx)(`div`,{className:`mt-1.5 text-[12px] text-accent font-medium`,children:D(`Edit`)})]})}),(0,H.jsxs)(`div`,{children:[(0,H.jsxs)(`div`,{className:`text-[12px] font-semibold uppercase tracking-wide text-muted mb-2`,children:[D(`Plan`),` · `,n.progress.done,`/`,n.progress.total]}),(0,H.jsx)(`ul`,{className:`space-y-1`,children:n.steps.map(e=>{let n=U[e.status];return(0,H.jsxs)(`li`,{className:`flex items-start gap-2.5 rounded-2xl px-2 py-1.5 hover:bg-surface-2/60`,children:[(0,H.jsx)(`button`,{type:`button`,"aria-label":D(`Mark step {n} {status}`,{n:e.idx,status:D(W[e.status])}),onClick:()=>void O({step_index:e.idx,step_status:W[e.status]}),className:`mt-0.5 text-muted`,children:(0,H.jsx)(n,{size:20})}),(0,H.jsxs)(`div`,{className:`flex-1 min-w-0`,children:[(0,H.jsxs)(`div`,{className:t(`text-[14.5px] leading-snug`,(e.status===`done`||e.status===`skipped`)&&`line-through text-muted`),children:[e.idx,`. `,e.title]}),e.note&&(0,H.jsx)(`div`,{className:`text-[12.5px] text-muted mt-0.5 whitespace-pre-wrap`,children:e.note})]})]},e.idx)})}),(0,H.jsxs)(`div`,{className:`mt-2 flex gap-2`,children:[(0,H.jsx)(`input`,{value:b,onChange:e=>x(e.target.value),onKeyDown:e=>e.key===`Enter`&&void k(),placeholder:D(`Add a step`),className:`flex-1 rounded-2xl bg-surface-2 px-3.5 py-2 text-[14px] outline-none focus:ring-2 focus:ring-accent/40`}),(0,H.jsx)(`button`,{type:`button`,onClick:()=>void k(),className:`rounded-2xl bg-surface-2 px-3 text-accent`,"aria-label":D(`Add step`),children:(0,H.jsx)(_,{size:18})})]})]}),n.notes&&(0,H.jsxs)(`div`,{children:[(0,H.jsx)(`div`,{className:`text-[12px] font-semibold uppercase tracking-wide text-muted mb-1.5`,children:D(`Notes from {name}`,{name:E})}),(0,H.jsx)(`pre`,{className:`whitespace-pre-wrap break-words text-[13px] leading-snug text-muted font-sans`,children:n.notes})]}),(0,H.jsxs)(`div`,{className:`flex flex-wrap gap-x-4 gap-y-1.5`,children:[(0,H.jsx)(`button`,{type:`button`,onClick:()=>{d(`main`,D(`About my goal “{title}” ({id}): what's the status, and what should we do next?`,{title:n.title,id:n.id})).catch(e=>l(e.message||D(`Could not send`))),h(`main`),a()},className:`text-[13.5px] text-accent font-medium`,children:D(`Discuss this goal in chat →`)}),n.status===`active`&&(0,H.jsxs)(`button`,{type:`button`,onClick:()=>void A(),className:`text-[13.5px] text-accent font-medium inline-flex items-center gap-1`,children:[(0,H.jsx)(M,{size:14}),` `,D(`Check in with me now`)]})]})]})})}function $({open:e,onClose:t,onCreated:n}){let{toast:i,send:a,openThread:o,state:s}=c(),[l,d]=(0,V.useState)(``),[f,m]=(0,V.useState)(``),[g,_]=(0,V.useState)(``),[v,y]=(0,V.useState)(``),[b,x]=(0,V.useState)(``),[S,C]=(0,V.useState)(``),[w,T]=(0,V.useState)(!1),E=s.profile?.name??`nanoMuse`,D=r(),O=()=>{d(``),m(``),_(``),y(``),x(``),C(``)},k=async()=>{if(l.trim()){T(!0);try{await u.createGoal({title:l.trim(),description:f.trim(),steps:g.split(` +`).map(e=>e.trim()).filter(Boolean),category:v,due:b,check_in:S}),O(),n()}catch(e){i(e.message)}finally{T(!1)}}};return(0,H.jsx)(p,{open:e,onClose:t,title:D(`New goal`),footer:(0,H.jsxs)(`div`,{className:`flex gap-2`,children:[(0,H.jsxs)(`button`,{type:`button`,onClick:()=>{if(!l.trim())return;let e=[v?`category: ${v}`:``,b?`target date: ${b}`:``,S?`check_in "${S}"`:``].filter(Boolean);a(`main`,D(`Create a goal for me: "{title}"{description}{extras}. Break it into concrete steps with the goals tool, then tell me the plan.`,{title:l.trim(),description:f.trim()?` (${f.trim()})`:``,extras:e.length?` (${e.join(`, `)})`:``})).catch(e=>i(e.message||D(`Could not send`))),O(),t(),o(`main`)},disabled:!l.trim(),className:`flex-1 rounded-2xl border border-border py-2.5 font-medium disabled:opacity-50 flex items-center justify-center gap-1.5`,children:[(0,H.jsx)(h,{size:16}),` `,D(`Let {name} plan it`,{name:E})]}),(0,H.jsx)(`button`,{type:`button`,onClick:()=>void k(),disabled:!l.trim()||w,className:`flex-1 rounded-2xl bg-accent text-accent-fg py-2.5 font-medium disabled:opacity-50`,children:D(`Create`)})]}),children:(0,H.jsxs)(`div`,{className:`space-y-3.5`,children:[(0,H.jsx)(`input`,{value:l,onChange:e=>d(e.target.value),placeholder:D(`What do you want to achieve?`),className:`w-full rounded-2xl bg-surface-2 px-3.5 py-2.5 text-[15px] outline-none focus:ring-2 focus:ring-accent/40`}),(0,H.jsxs)(`div`,{children:[(0,H.jsx)(`div`,{className:`text-[12px] font-semibold uppercase tracking-wide text-muted mb-1.5`,children:D(`Area of life`)}),(0,H.jsx)(X,{value:v,onChange:y})]}),(0,H.jsxs)(`div`,{className:`flex items-center gap-3`,children:[(0,H.jsx)(`div`,{className:`text-[12px] font-semibold uppercase tracking-wide text-muted flex-1`,children:D(`Target date`)}),(0,H.jsx)(`input`,{type:`date`,value:b,onChange:e=>x(e.target.value),className:`rounded-xl bg-surface-2 px-2.5 py-1.5 text-[13.5px] outline-none`})]}),(0,H.jsxs)(`div`,{children:[(0,H.jsx)(`div`,{className:`text-[12px] font-semibold uppercase tracking-wide text-muted mb-1.5`,children:D(`Reminders from {name}`,{name:E})}),(0,H.jsx)(Z,{value:S,onChange:C})]}),(0,H.jsx)(`textarea`,{value:f,onChange:e=>m(e.target.value),placeholder:D(`Why it matters, constraints (optional)`),rows:2,className:`w-full rounded-2xl bg-surface-2 px-3.5 py-2.5 text-[14px] outline-none focus:ring-2 focus:ring-accent/40 resize-none`}),(0,H.jsx)(`textarea`,{value:g,onChange:e=>_(e.target.value),placeholder:D(`Steps, one per line (optional, or let {name} plan them)`,{name:E}),rows:3,className:`w-full rounded-2xl bg-surface-2 px-3.5 py-2.5 text-[14px] outline-none focus:ring-2 focus:ring-accent/40 resize-none`})]})})}export{G as GoalsScreen}; \ No newline at end of file diff --git a/nanomuse/server/static/assets/IdeasScreen-Bwp6l7Xs.js b/nanomuse/server/static/assets/IdeasScreen-CmecfnoP.js similarity index 98% rename from nanomuse/server/static/assets/IdeasScreen-Bwp6l7Xs.js rename to nanomuse/server/static/assets/IdeasScreen-CmecfnoP.js index 0a9193a0d..41d9a84b9 100644 --- a/nanomuse/server/static/assets/IdeasScreen-Bwp6l7Xs.js +++ b/nanomuse/server/static/assets/IdeasScreen-CmecfnoP.js @@ -1 +1 @@ -import{A as e,J as t,K as n,Q as r,W as i,Y as a,b as o,f as s,q as c,x as l}from"./MuseHeader-BvAlmxiL.js";import{t as u}from"./refresh-cw-BMLOGb5p.js";import{f as d,m as f,ot as p,w as m,yt as h}from"./index-tZx-TDX4.js";var g=t(`flag`,[[`path`,{d:`M4 22V4a1 1 0 0 1 .4-.8A6 6 0 0 1 8 2c3 0 5 2 7.333 2q2 0 3.067-.8A1 1 0 0 1 20 4v10a1 1 0 0 1-.4.8A6 6 0 0 1 16 16c-3 0-5-2-8-2a6 6 0 0 0-4 1.528`,key:`1jaruq`}]]),_=r(a(),1),v={sections:[{id:`travel`,title:`Travel`,ideas:[{id:`train-watch`,emoji:`🚄`,title:`Tell me where you're going and when; I'll watch for seats and lower fares.`,body:`I set up the lookup tools in my sandbox, check trains, classes and availability as often as you like, and tell you the moment something opens up. Booking and paying stay in your hands.`,kind:`GOAL`,category:`other`,prompt:`I want to watch a train route: ask me for the origin, destination, date and acceptable departure window, then set up a goal that checks availability regularly.`},{id:`trip-plan`,emoji:`🗺️`,title:`Name a city and a number of days; I'll plan an itinerary you can follow as is.`,body:`Weather, opening hours and travel time between stops go into a day-by-day plan saved to your Library. Change one sentence and I'll rearrange the rest.`,kind:`CHAT`,prompt:`Help me plan a trip. Ask me where, how many days, with whom, a rough budget and the style I like, then give me a day-by-day itinerary as a file.`},{id:`commute-brief`,emoji:`🚦`,title:`Before you leave each morning, I'll tell you the traffic, the weather and the first thing on your plate.`,body:`A morning routine: I check the weather where you are, the traffic on your commute, glance at your calendar and boil the morning down to three sentences.`,kind:`ROUTINE`,time:`07:30`,prompt:`Morning brief: check today's weather and commute traffic, read my calendar for today, and tell me in at most five sentences the three things that matter most and what to bring.`},{id:`parcel-track`,emoji:`📦`,title:`Send me a tracking number; I'll tell you where the parcel is and when it lands.`,body:`I follow the shipment through the carrier's tracking, tell you about every new scan, and remind you to keep the phone nearby on delivery day.`,kind:`CHAT`,prompt:`Help me track a parcel. Ask me for the tracking number and carrier, check the current status once, then set a routine that checks every morning and reminds me the day before delivery.`}]},{id:`work`,title:`Work`,ideas:[{id:`meeting-prep`,emoji:`📝`,title:`Ten minutes before a meeting, I'll have the background and the questions ready.`,body:`I read the meeting's title and attendees from your calendar, look through what we've discussed and what you've put in the Library, and hand you one page: purpose, talking points, three questions worth asking.`,kind:`ROUTINE`,time:`08:50`,prompt:`Look at the meetings on my calendar today and prepare a one-page brief for each: the purpose, the points I should make, and three questions worth asking.`},{id:`weekly-review`,emoji:`📊`,title:`Every Friday afternoon, I'll review what you did this week and what next week needs.`,body:`From our conversations, your calendar and the notes I keep, I list what got done, what didn't, and three priorities for next week, as a draft you can send.`,kind:`ROUTINE`,time:`17:00`,prompt:`Write my weekly review: from this week's conversations, my calendar and what you remember, list what was completed, what is still open, and three priorities for next week. Save it as a Markdown file.`},{id:`inbox-triage`,emoji:`📬`,title:`Dump a pile of messages or emails on me; I'll sort them and draft the replies.`,body:`Paste text or screenshots. I sort them into 'reply today', 'this week' and 'just so you know', and draft each reply so you only need to edit and send.`,kind:`CHAT`,prompt:`I'm handing you a batch of messages to triage: sort them into 'reply today / this week / just so you know' and draft a reply for each one that needs it. Ask me to paste the content first.`},{id:`doc-digest`,emoji:`📄`,title:`Long documents, PDFs, web pages: I'll read them and give you the three-minute version.`,body:`Drop the file in a shared folder or send me the link. You get the conclusions, the key numbers and the decisions you need to make; ask follow-ups any time.`,kind:`CHAT`,prompt:`I have something long for you to read and summarise: ask me for the file or link, then give me conclusions, key numbers and decisions I need to make, at most five bullets each.`}]},{id:`life`,title:`Everyday`,ideas:[{id:`price-watch`,emoji:`🏷️`,title:`Tell me what you want to buy; the moment it hits your price, you'll know.`,body:`I check the product page on a schedule, keep the price history, and notify you at your target. Ordering and paying are yours; I don't touch them.`,kind:`GOAL`,category:`finance`,prompt:`I want to watch the price of a product: ask me for the link or name, my target price and how often to check, then create a goal that alerts me when it drops.`},{id:`photo-sort`,emoji:`🖼️`,title:`Mount your photos and I'll sort screenshots and pictures by what's in them.`,body:`Once your gallery is mounted as a shared folder I look at each image (receipts, chat screenshots, landscapes, documents), file it into the right folder and note anything important.`,kind:`CHAT`,prompt:`Help me sort my photos: ask me to mount the gallery in Shared Folders first, then sort by content (receipts, screenshots, scenery, documents, other) and list what you did.`},{id:`meal-log`,emoji:`🥗`,title:`Photograph what you eat; I'll estimate the calories and keep the log.`,body:`A photo or a sentence is enough: I estimate nutrition and calories, log it in the day's memory, and give you a summary each evening with one small suggestion for tomorrow.`,kind:`CHAT`,prompt:`From now on, log my meals: whenever I send a photo or a description, estimate calories and nutrition and write it into today's memory. Tell me first how best to send them.`},{id:`subscriptions`,emoji:`🔁`,title:`Send me your bills; I'll list every subscription that charges you each month, and you decide which to stop.`,body:`Give me bill screenshots or statements. I list every recurring charge, its next date and the yearly total; you decide what to cancel and I walk you through each cancellation.`,kind:`CHAT`,prompt:`Audit my subscriptions: ask me for bill screenshots or statements, then list every recurring charge, its next billing date and the yearly total, and flag the ones I may not need.`}]},{id:`learn`,title:`Learning`,ideas:[{id:`daily-words`,emoji:`🔤`,title:`Five new words every morning, a quick quiz every night.`,body:`You pick the language and level; I pick words by theme with examples and a memory hook, quiz you in the evening, and bring back the ones you missed.`,kind:`ROUTINE`,time:`08:00`,prompt:`Daily vocabulary: pick five new words for me (ask which language, level and topics first), each with a definition, one example sentence and a memory hook, plus a review quiz on yesterday's words.`},{id:`study-plan`,emoji:`🎯`,title:`Something you want to learn? I'll break it into weekly chunks and keep you honest.`,body:`Tell me the goal and the hours you can spare; I lay out four to eight weeks, check progress weekly, and adjust the pace so you actually finish.`,kind:`GOAL`,category:`interests`,prompt:`I want to learn something new and stick with it: ask me what, my current level, hours per week and the timeframe, then create a goal with a weekly progress check.`},{id:`explain`,emoji:`💡`,title:`Send me a concept you don't get; I'll explain it with things you already know.`,body:`I ask what you already understand and start from there, then check with two quick questions and leave you a flashcard if you want one.`,kind:`CHAT`,prompt:`There's a concept I don't understand: ask me what it is and what related things I already know, explain it with analogies, then check with two short questions.`},{id:`reading-notes`,emoji:`📚`,title:`Finished a book? I'll turn it into notes you'll actually reread.`,body:`Tell me the highlights, or send the passages you marked. I write structured notes into your Library and remember what stayed with you.`,kind:`CHAT`,prompt:`Help me write notes on a book: ask me the title, the three things that struck me most and the quotes I want to keep, then save structured Markdown notes.`}]},{id:`family`,title:`Family & friends`,ideas:[{id:`birthdays`,emoji:`🎂`,title:`Birthdays and anniversaries: I remind you a week ahead, gift ideas included.`,body:`Give me names and dates and I keep them. A week before each one I remind you, with a few gift directions based on what you've told me about them.`,kind:`CHAT`,prompt:`Remember the birthdays and anniversaries of the people who matter to me: ask for the list and dates, store them in long-term memory, and set a routine that reminds me a week before each.`},{id:`keep-in-touch`,emoji:`💬`,title:`Lost touch with old friends? Once a week I'll suggest who to reach out to, and how to start.`,body:`Give me a list of people you want to stay close to. I rotate through them and write a natural opening line based on what you last talked about.`,kind:`ROUTINE`,time:`19:00`,prompt:`Weekly keep-in-touch: from my list of people I want to stay close to, pick the one I've gone longest without contacting, remind me, and write a natural opening line based on what I noted about our last conversation.`},{id:`family-calendar`,emoji:`📅`,title:`Tell me the family's plans and I'll put them on the calendar and catch clashes.`,body:`Kids' lessons, a parent's appointment, a weekend get-together: one sentence and it's in the calendar; if two things collide, I say so first.`,kind:`CHAT`,prompt:`Help me run the family calendar: I'll tell you plans as they come up; write them into the calendar, confirm each before creating it, and warn me about conflicts.`},{id:`gift-ideas`,emoji:`🎁`,title:`Describe the person and I'll give you gift ideas that aren't the obvious ones.`,body:`Budget, relationship, what they're into lately: three questions, then five directions with one line each on why it fits.`,kind:`CHAT`,prompt:`Help me think of a gift: ask who it's for, my budget, their interests and what's going on in their life, then give me five directions with one line of reasoning each.`}]},{id:`more`,title:`More ideas`,ideas:[{id:`id-renewal`,emoji:`🪪`,title:`Tell me when your documents expire; I'll book the renewal and prep the paperwork list.`,body:`Passport, licence, visa: I note the dates, remind you three months ahead, list the documents and the office, and look up appointment slots where I can.`,kind:`CHAT`,prompt:`Help me track document expiry: ask which documents I have and when they expire, store them in memory, and set a reminder three months ahead of each with the renewal checklist.`},{id:`personality-quiz`,emoji:`❓`,title:`Two small questions a day; after a week I'll tell you what I've noticed about you.`,body:`Light questions, quick answers. I keep them and, once a week, write a short observation about your preferences and rhythm so I understand you better.`,kind:`ROUTINE`,time:`21:00`,prompt:`Two questions a day: ask me two small questions about preferences, habits or how things are going (never repeat one), store the answers in memory; every Sunday add a short observation about my week.`},{id:`event-plan`,emoji:`🎉`,title:`Name the occasion; I'll plan the run of show and draft the invitation.`,body:`Birthday, team outing, family dinner: give me the headcount, budget and date, and you get a timeline, a shopping list and an invitation you can send as is.`,kind:`CHAT`,prompt:`Help me plan an event: ask me the occasion, date, headcount and budget, then give me a timeline, a to-do list and an invitation text I can send.`},{id:`phone-cleanup`,emoji:`🧹`,title:`Let me look through the sandbox and shared folders; I'll clear the junk and organise the rest.`,body:`I list the big files and duplicates, show you the list first and only act when you say so; anything worth keeping goes into the Library.`,kind:`CHAT`,prompt:`Help me tidy the workspace and shared folders: list large files, duplicates and files untouched for a long time, and give me the list. Do not delete anything before I confirm.`}]}]},y={sections:[{id:`travel`,title:`出行`,ideas:[{id:`train-watch`,emoji:`🚄`,title:`告诉我你要去哪、哪天走,我盯着 12306 的余票和低价票。`,body:`我会在沙盒里装好查询工具,按你说的频率查车次、席别和余票,有票或价格合适时马上通知你;订票和付款那一步留给你自己点。`,kind:`GOAL`,category:`other`,prompt:`我想盯一趟火车票:请先问我出发地、目的地、日期和可接受的车次时段,然后为我建一个定期检查余票的目标。`},{id:`trip-plan`,emoji:`🗺️`,title:`说一个城市和几天,我给你排一份能直接照着走的行程。`,body:`我会查天气、开放时间和两点之间的路程,把每天的顺序排顺,写成一份文件放进资源库;你改一句,我就重排。`,kind:`CHAT`,prompt:`帮我规划一次出行。先问我去哪、几天、和谁、预算大概多少、喜欢什么风格,再给我一份按天排好的行程文件。`},{id:`commute-brief`,emoji:`🚦`,title:`每天出门前,我告诉你今天的路况、天气和第一件事。`,body:`一条早间例程:查你所在城市的天气、通勤路线的路况,翻一下日历,把上午的安排浓缩成三句话推给你。`,kind:`ROUTINE`,time:`07:30`,prompt:`早间简报:查询今天的天气和通勤路况,读取我今天的日历安排,用不超过五句话告诉我今天最重要的三件事和出门要带的东西。`},{id:`parcel-track`,emoji:`📦`,title:`把快递单号发我,到哪了、什么时候到,我随时告诉你。`,body:`我会用快递查询接口跟踪包裹,有新的物流节点就更新你;派送当天提醒你留意电话。`,kind:`CHAT`,prompt:`帮我跟踪一个快递。先问我单号和快递公司,然后查一次当前进度,并设一个每天早上检查一次、到派送前一天提醒我的例程。`}]},{id:`work`,title:`工作`,ideas:[{id:`meeting-prep`,emoji:`📝`,title:`开会前十分钟,我把这场会的背景和该问的问题整理好。`,body:`读日历里的会议主题和参会人,翻我们聊过的相关内容和你放进资源库的资料,给你一页纸:目的、要点、三个值得问的问题。`,kind:`ROUTINE`,time:`08:50`,prompt:`查看我今天日历里接下来的会议,为每一场准备一页会前提纲:这场会的目的、需要我发言的要点、三个值得提出的问题。`},{id:`weekly-review`,emoji:`📊`,title:`每周五下午,我帮你回顾这一周做了什么,下周该抓什么。`,body:`从我们的对话、你的日历和我记下的备忘里,整理出本周完成的事、没做完的事和下周的三个重点,写成一份周报草稿。`,kind:`ROUTINE`,time:`17:00`,prompt:`写一份本周回顾:根据我们这周的对话、我的日历和你记住的事项,列出完成了什么、什么没做完、下周三个重点,保存为一份 Markdown 文件。`},{id:`inbox-triage`,emoji:`📬`,title:`把一堆消息或邮件丢给我,我分好轻重缓急,写好回复草稿。`,body:`粘贴文字或截图给我,我按“今天必须回、这周处理、只需知道”分类,把每条要回的先拟好一版,你改一改就能发。`,kind:`CHAT`,prompt:`我要把一批消息交给你整理:请按“今天必须回 / 这周处理 / 只需知道”分类,并为需要回复的每一条写好回复草稿。请先让我粘贴内容。`},{id:`doc-digest`,emoji:`📄`,title:`长文档、PDF、网页,我读完给你三分钟版本。`,body:`把文件放进共享文件夹或把链接发我,我提炼结论、关键数字和你需要做的决定,问题可以接着追问。`,kind:`CHAT`,prompt:`我有一份长内容需要你读并总结:请先让我提供文件或链接,然后给我结论、关键数字、需要我做的决定三部分,每部分不超过五条。`}]},{id:`life`,title:`生活`,ideas:[{id:`price-watch`,emoji:`🏷️`,title:`想买的东西告诉我,降到你说的价格我立刻告诉你。`,body:`我会定期去商品页看价格,记录走势;到价就通知你。下单和付款由你来点,我不会碰。`,kind:`GOAL`,category:`finance`,prompt:`我想盯一件商品的价格:请先问我商品链接或名称、目标价格和检查频率,然后建一个到价提醒我的目标。`},{id:`photo-sort`,emoji:`🖼️`,title:`把相册挂给我,我按内容给截图和照片分类整理。`,body:`在「共享文件夹」里挂载相册后,我会看图识别内容(票据、聊天截图、风景、证件),归到对应文件夹,重要的信息顺手记下来。`,kind:`CHAT`,prompt:`帮我整理照片:请先让我在共享文件夹里挂载相册目录,然后按内容(票据、截图、风景、证件、其他)分类整理,并把整理结果列给我。`},{id:`meal-log`,emoji:`🥗`,title:`拍下你吃的,我帮你估热量、记下每一餐。`,body:`发一张照片或一句话,我估算营养和热量,记进当天的日记;晚上给你一天的小结和明天的一个小建议。`,kind:`CHAT`,prompt:`从现在起帮我记录饮食:每次我发照片或描述,估算热量与营养并记入当天记忆;请先告诉我怎么发给你最方便。`},{id:`subscriptions`,emoji:`🔁`,title:`帮你把每月自动扣费的订阅列出来,看看哪些该停。`,body:`把账单截图或消费记录给我,我列出所有周期性扣费、下一次扣款日和一年花多少;你决定停哪个,退订的步骤我一步步陪你走。`,kind:`CHAT`,prompt:`帮我盘点订阅扣费:请先让我提供账单截图或记录,然后列出所有周期性扣费、下一次扣款日、年费合计,并标出可能不再需要的。`}]},{id:`learn`,title:`学习`,ideas:[{id:`daily-words`,emoji:`🔤`,title:`每天早上五个新词,晚上考你一遍。`,body:`你定语言和难度,我按主题挑词、给例句和记忆点,晚上出五道小题,错的第二天再来。`,kind:`ROUTINE`,time:`08:00`,prompt:`每日词汇:为我挑五个新词(先问我学什么语言、什么水平和感兴趣的主题),每个给释义、一个例句和一个记忆点,并附上昨天的复习题。`},{id:`study-plan`,emoji:`🎯`,title:`有个想学会的东西?我陪你拆成每周能做完的小块。`,body:`告诉我目标和每周能投入的时间,我排一份四到八周的计划,每周检查进度、调整难度,帮你坚持到最后。`,kind:`GOAL`,category:`interests`,prompt:`我想学一样新东西并坚持下去:请先问我想学什么、现在的水平、每周能投入多少时间和希望多久见效,然后帮我建一个每周检查进度的目标。`},{id:`explain`,emoji:`💡`,title:`看不懂的概念发给我,我用你熟悉的东西讲明白。`,body:`先问你已经懂什么,再从那里出发讲;讲完出两道题确认你真懂了,需要的话给你一张记忆卡。`,kind:`CHAT`,prompt:`我有一个不太懂的概念想让你讲明白:请先问我这个概念是什么、我已经了解哪些相关知识,然后用类比讲解,最后出两道小题检验。`},{id:`reading-notes`,emoji:`📚`,title:`读完一本书,我帮你整理成能重读的笔记。`,body:`你说重点和感受,或者把划线的句子发我,我整理成结构化笔记,存进资源库,并记住你的收获。`,kind:`CHAT`,prompt:`帮我整理一本书的读书笔记:请先问我书名、最触动我的三点和我想记住的引文,然后整理成结构化的 Markdown 笔记并保存。`}]},{id:`family`,title:`家庭与关系`,ideas:[{id:`birthdays`,emoji:`🎂`,title:`重要的人的生日和纪念日,我提前一周提醒,顺手想好礼物。`,body:`把名字和日期告诉我,我记住;到日子前一周提醒你,并根据你说过的 TA 的喜好给几个礼物方向。`,kind:`CHAT`,prompt:`帮我记住重要的人的生日和纪念日:请先问我名单和日期,记入长期记忆,并为每个日期设一个提前一周提醒我的例程。`},{id:`keep-in-touch`,emoji:`💬`,title:`老朋友太久没联系?我每周提醒你该找谁聊聊,帮你开个头。`,body:`你给我一份想保持联系的名单,我按间隔轮着提醒,并根据上次聊的内容帮你写一句自然的开场。`,kind:`ROUTINE`,time:`19:00`,prompt:`每周联系提醒:从我告诉你的“想保持联系的人”名单里,挑一位最近最久没联系的,提醒我,并根据我记录过的上次聊天内容写一句自然的开场白。`},{id:`family-calendar`,emoji:`📅`,title:`把全家的安排告诉我,我帮你排进日历、发现冲突。`,body:`孩子的课、家人的门诊、周末的聚会,说一句我就写进日历,时间撞了我先提醒你。`,kind:`CHAT`,prompt:`帮我管理家庭日程:我会陆续告诉你家人的安排,请写进日历,创建前先复述确认,发现时间冲突时提醒我。`},{id:`gift-ideas`,emoji:`🎁`,title:`说说 TA 是什么样的人,我给你几个不落俗套的礼物点子。`,body:`预算、关系、TA 最近在忙什么,三个问题之后我给你五个方向,每个附一句为什么合适。`,kind:`CHAT`,prompt:`帮我想礼物:请先问我送给谁、预算、TA 的兴趣和最近的生活状态,然后给我五个礼物方向,每个附一句理由。`}]},{id:`more`,title:`更多点子`,ideas:[{id:`id-renewal`,emoji:`🪪`,title:`告诉我证件到期时间,我提前预约续签,把材料清单准备好。`,body:`护照、驾照、签证,我记下到期日,提前三个月提醒,列出所需材料和办理地点,能预约的帮你查好时段。`,kind:`CHAT`,prompt:`帮我管理证件到期:请先问我有哪些证件和到期日期,记入长期记忆,并为每一个设置提前三个月的提醒,附上续办所需材料清单。`},{id:`personality-quiz`,emoji:`❓`,title:`每天两个小问题,一周后我告诉你我发现了什么样的你。`,body:`问题很轻,回答很快;我把答案记下来,每周整理成一段关于你偏好和节奏的观察,方便我更懂你。`,kind:`ROUTINE`,time:`21:00`,prompt:`每日两问:问我两个关于偏好、习惯或近况的小问题(不重复以前问过的),把回答记入记忆;每周日额外给我一段关于我这周状态的观察。`},{id:`event-plan`,emoji:`🎉`,title:`说个场合,我帮你安排流程、拟好邀请。`,body:`生日、团建、家宴,人数、预算和日期告诉我,我给你时间线、采购清单和一段可以直接发出去的邀请文字。`,kind:`CHAT`,prompt:`帮我策划一次活动:请先问我场合、日期、人数和预算,然后给我时间线、待办清单和一段可直接发送的邀请文字。`},{id:`phone-cleanup`,emoji:`🧹`,title:`让我看看沙盒和共享文件夹里有什么,清掉没用的、整理有用的。`,body:`我列出占空间的大文件和重复文件,先给你看清单,你点头我再动;重要的整理进资源库。`,kind:`CHAT`,prompt:`帮我整理工作区和共享文件夹:先列出大文件、重复文件和很久没动的文件,给我一份清单;在我确认之前不要删除任何东西。`}]}]};function b(e){return e.toLowerCase().startsWith(`zh`)?y:v}function x(e){return{id:e.id,emoji:e.emoji,title:e.title,detail:e.body,prompt:e.prompt,kind:e.kind.toLowerCase(),time:e.time,category:e.category}}var S=o(),C=[{id:`planning`,label:`Planning`,emoji:`🗓️`},{id:`goals`,label:`Goals`,emoji:`🎯`},{id:`research`,label:`Research`,emoji:`🔍`},{id:`money`,label:`Money`,emoji:`💰`},{id:`health`,label:`Health`,emoji:`🌿`},{id:`home`,label:`Home`,emoji:`🏠`},{id:`learning`,label:`Learning`,emoji:`📚`},{id:`people`,label:`People`,emoji:`👥`},{id:`files`,label:`Files & tools`,emoji:`📄`},{id:`fun`,label:`Just for you`,emoji:`🎈`}];function w(){let{state:t,send:r,openThread:a,toast:o}=s(),[v,y]=(0,_.useState)(null),[C,w]=(0,_.useState)(!1),E=t.profile?.name??`nanoMuse`,D=n(),O=i(),k=async(e=!1)=>{w(!0);try{let t=await l.ideas(e);y(t),t.error&&o(D(`Could not refresh ideas: {error}`,{error:t.error}))}catch(e){o(e.message)}finally{w(!1)}};(0,_.useEffect)(()=>{k(!1)},[]);let A=v?.source===`model`&&v.ideas.length>0,j=A?T(v.ideas):b(O).sections.map(e=>({id:e.id,title:e.title,ideas:e.ideas.map(x)})),[M,N]=(0,_.useState)(null),P=e=>{N(null),r(`main`,e.prompt).catch(e=>o(e.message||D(`Could not send`))),a(`main`)},F=async e=>{N(null);let t=e.time&&/^([01]\d|2[0-3]):[0-5]\d$/.test(e.time)?e.time:`09:00`;try{await l.createReminder({text:e.prompt,kind:`task`,repeat:`daily ${t}`}),o(D(`Routine set: every day at {time}. It is listed under Goals.`,{time:t}))}catch(e){o(e.message)}},I=e=>{N(null);let t=f.find(t=>t.id===e.category)??f[f.length-1],n=D(`I'd like to create a {category} goal. Ask me a few short questions, one at a time (what exactly I want, why and by when, how often to check in), then create it with concrete steps using the goals tool.`,{category:D(t.label)});r(`main`,`${n} ${e.prompt}`).catch(e=>o(e.message||D(`Could not send`))),a(`main`)},L=e=>e.kind===`routine`||e.kind===`goal`?e.kind:`chat`;return(0,S.jsxs)(`div`,{className:`flex h-full flex-col`,children:[(0,S.jsx)(d,{title:D(`Ideas`),children:(0,S.jsx)(`button`,{type:`button`,onClick:()=>void k(!0),disabled:C,"aria-label":D(`Refresh ideas`),className:`flex h-10 w-10 items-center justify-center rounded-full bg-surface text-fg shadow-[0_1px_4px_rgba(0,0,0,0.14)] disabled:opacity-60 dark:border dark:border-border dark:shadow-none`,children:C?(0,S.jsx)(c,{size:20,className:`animate-spin`}):(0,S.jsx)(u,{size:19})})}),(0,S.jsxs)(`div`,{className:`flex-1 overflow-y-auto pb-6`,children:[j.map(({id:e,title:t,ideas:n},r)=>(0,S.jsxs)(`section`,{children:[(r>0||!A)&&(0,S.jsx)(`h2`,{className:`px-5 pt-[22px] pb-1 text-[20px] font-bold`,children:A?D(t):t}),(0,S.jsx)(`ul`,{children:n.map(e=>(0,S.jsxs)(`li`,{children:[(0,S.jsxs)(`button`,{type:`button`,onClick:()=>N({idea:e,emoji:e.emoji}),className:`flex w-full items-start gap-4 px-5 py-3.5 text-left active:bg-surface-2/70`,children:[(0,S.jsx)(`span`,{className:`flex w-10 shrink-0 justify-center text-[28px] leading-[34px]`,children:e.emoji}),(0,S.jsxs)(`span`,{className:`min-w-0 flex-1 space-y-1`,children:[(0,S.jsx)(`span`,{className:`block text-[16px] font-semibold leading-[22px]`,children:e.title}),e.detail&&(0,S.jsx)(`span`,{className:`line-clamp-4 block text-[13.5px] leading-[19px] text-muted`,children:e.detail})]})]}),(0,S.jsx)(`div`,{className:`ml-[76px] mr-5 border-b border-border/70`})]},e.title))})]},e)),v&&(0,S.jsx)(`div`,{className:`px-5 pt-4 text-[12.5px] text-muted`,children:v.source===`model`?D(`Generated {when}`,{when:e(v.generated_at)}):D(`Starter ideas. Refresh once {name} knows you better.`,{name:E})})]}),(0,S.jsx)(m,{open:M!==null,onClose:()=>N(null),children:M&&(0,S.jsxs)(`div`,{className:`px-1 pb-2`,children:[(0,S.jsxs)(`div`,{className:`flex items-center gap-3`,children:[(0,S.jsx)(`span`,{className:`text-[30px] leading-none`,children:M.emoji}),(0,S.jsx)(`h3`,{className:`flex-1 text-[18px] font-bold leading-6`,children:M.idea.title})]}),M.idea.detail&&(0,S.jsx)(`p`,{className:`mt-3 text-[15px] leading-[22px]`,children:M.idea.detail}),(0,S.jsxs)(`div`,{className:`mt-3.5 flex items-center gap-1.5 text-[13px] text-muted`,children:[L(M.idea)===`routine`&&(0,S.jsxs)(S.Fragment,{children:[(0,S.jsx)(h,{size:16}),` `,D(`Creates a routine`),M.idea.time?` · ${M.idea.time}`:``]}),L(M.idea)===`goal`&&(0,S.jsxs)(S.Fragment,{children:[(0,S.jsx)(g,{size:16}),` `,D(`Creates a goal`)]}),L(M.idea)===`chat`&&(0,S.jsxs)(S.Fragment,{children:[(0,S.jsx)(p,{size:16}),` `,D(`Starts a conversation`)]})]}),L(M.idea)===`routine`&&(0,S.jsxs)(`button`,{type:`button`,onClick:()=>void F(M.idea),className:`mt-[22px] flex h-[50px] w-full items-center justify-center gap-2 rounded-full bg-accent text-[16px] font-semibold text-accent-fg`,children:[(0,S.jsx)(h,{size:18}),` `,D(`Create routine`)]}),L(M.idea)===`goal`&&(0,S.jsxs)(`button`,{type:`button`,onClick:()=>I(M.idea),className:`mt-[22px] flex h-[50px] w-full items-center justify-center gap-2 rounded-full bg-accent text-[16px] font-semibold text-accent-fg`,children:[(0,S.jsx)(g,{size:18}),` `,D(`Start goal`)]}),L(M.idea)===`chat`&&(0,S.jsxs)(`button`,{type:`button`,onClick:()=>P(M.idea),className:`mt-[22px] flex h-[50px] w-full items-center justify-center gap-2 rounded-full bg-accent text-[16px] font-semibold text-accent-fg`,children:[(0,S.jsx)(p,{size:18}),` `,D(`Send to chat`)]})]})})]})}function T(e){let t=C[C.length-1],n=C.map(e=>({id:e.id,title:e.label,ideas:[]}));for(let r of e){let e=C.find(e=>e.id===(r.area||t.id))??t;(n.find(t=>t.id===e.id)??n[n.length-1]).ideas.push({...r,emoji:e.emoji})}return n.filter(e=>e.ideas.length>0)}export{w as IdeasScreen}; \ No newline at end of file +import{A as e,J as t,K as n,Q as r,W as i,Y as a,b as o,f as s,q as c,x as l}from"./MuseHeader-RC--uR8o.js";import{t as u}from"./refresh-cw-CxZ3ZdI3.js";import{C as d,at as f,d as p,p as m,vt as h}from"./index-tYqPtwPX.js";var g=t(`flag`,[[`path`,{d:`M4 22V4a1 1 0 0 1 .4-.8A6 6 0 0 1 8 2c3 0 5 2 7.333 2q2 0 3.067-.8A1 1 0 0 1 20 4v10a1 1 0 0 1-.4.8A6 6 0 0 1 16 16c-3 0-5-2-8-2a6 6 0 0 0-4 1.528`,key:`1jaruq`}]]),_=r(a(),1),v={sections:[{id:`travel`,title:`Travel`,ideas:[{id:`train-watch`,emoji:`🚄`,title:`Tell me where you're going and when; I'll watch for seats and lower fares.`,body:`I set up the lookup tools in my sandbox, check trains, classes and availability as often as you like, and tell you the moment something opens up. Booking and paying stay in your hands.`,kind:`GOAL`,category:`other`,prompt:`I want to watch a train route: ask me for the origin, destination, date and acceptable departure window, then set up a goal that checks availability regularly.`},{id:`trip-plan`,emoji:`🗺️`,title:`Name a city and a number of days; I'll plan an itinerary you can follow as is.`,body:`Weather, opening hours and travel time between stops go into a day-by-day plan saved to your Library. Change one sentence and I'll rearrange the rest.`,kind:`CHAT`,prompt:`Help me plan a trip. Ask me where, how many days, with whom, a rough budget and the style I like, then give me a day-by-day itinerary as a file.`},{id:`commute-brief`,emoji:`🚦`,title:`Before you leave each morning, I'll tell you the traffic, the weather and the first thing on your plate.`,body:`A morning routine: I check the weather where you are, the traffic on your commute, glance at your calendar and boil the morning down to three sentences.`,kind:`ROUTINE`,time:`07:30`,prompt:`Morning brief: check today's weather and commute traffic, read my calendar for today, and tell me in at most five sentences the three things that matter most and what to bring.`},{id:`parcel-track`,emoji:`📦`,title:`Send me a tracking number; I'll tell you where the parcel is and when it lands.`,body:`I follow the shipment through the carrier's tracking, tell you about every new scan, and remind you to keep the phone nearby on delivery day.`,kind:`CHAT`,prompt:`Help me track a parcel. Ask me for the tracking number and carrier, check the current status once, then set a routine that checks every morning and reminds me the day before delivery.`}]},{id:`work`,title:`Work`,ideas:[{id:`meeting-prep`,emoji:`📝`,title:`Ten minutes before a meeting, I'll have the background and the questions ready.`,body:`I read the meeting's title and attendees from your calendar, look through what we've discussed and what you've put in the Library, and hand you one page: purpose, talking points, three questions worth asking.`,kind:`ROUTINE`,time:`08:50`,prompt:`Look at the meetings on my calendar today and prepare a one-page brief for each: the purpose, the points I should make, and three questions worth asking.`},{id:`weekly-review`,emoji:`📊`,title:`Every Friday afternoon, I'll review what you did this week and what next week needs.`,body:`From our conversations, your calendar and the notes I keep, I list what got done, what didn't, and three priorities for next week, as a draft you can send.`,kind:`ROUTINE`,time:`17:00`,prompt:`Write my weekly review: from this week's conversations, my calendar and what you remember, list what was completed, what is still open, and three priorities for next week. Save it as a Markdown file.`},{id:`inbox-triage`,emoji:`📬`,title:`Dump a pile of messages or emails on me; I'll sort them and draft the replies.`,body:`Paste text or screenshots. I sort them into 'reply today', 'this week' and 'just so you know', and draft each reply so you only need to edit and send.`,kind:`CHAT`,prompt:`I'm handing you a batch of messages to triage: sort them into 'reply today / this week / just so you know' and draft a reply for each one that needs it. Ask me to paste the content first.`},{id:`doc-digest`,emoji:`📄`,title:`Long documents, PDFs, web pages: I'll read them and give you the three-minute version.`,body:`Drop the file in a shared folder or send me the link. You get the conclusions, the key numbers and the decisions you need to make; ask follow-ups any time.`,kind:`CHAT`,prompt:`I have something long for you to read and summarise: ask me for the file or link, then give me conclusions, key numbers and decisions I need to make, at most five bullets each.`}]},{id:`life`,title:`Everyday`,ideas:[{id:`price-watch`,emoji:`🏷️`,title:`Tell me what you want to buy; the moment it hits your price, you'll know.`,body:`I check the product page on a schedule, keep the price history, and notify you at your target. Ordering and paying are yours; I don't touch them.`,kind:`GOAL`,category:`finance`,prompt:`I want to watch the price of a product: ask me for the link or name, my target price and how often to check, then create a goal that alerts me when it drops.`},{id:`photo-sort`,emoji:`🖼️`,title:`Mount your photos and I'll sort screenshots and pictures by what's in them.`,body:`Once your gallery is mounted as a shared folder I look at each image (receipts, chat screenshots, landscapes, documents), file it into the right folder and note anything important.`,kind:`CHAT`,prompt:`Help me sort my photos: ask me to mount the gallery in Shared Folders first, then sort by content (receipts, screenshots, scenery, documents, other) and list what you did.`},{id:`meal-log`,emoji:`🥗`,title:`Photograph what you eat; I'll estimate the calories and keep the log.`,body:`A photo or a sentence is enough: I estimate nutrition and calories, log it in the day's memory, and give you a summary each evening with one small suggestion for tomorrow.`,kind:`CHAT`,prompt:`From now on, log my meals: whenever I send a photo or a description, estimate calories and nutrition and write it into today's memory. Tell me first how best to send them.`},{id:`subscriptions`,emoji:`🔁`,title:`Send me your bills; I'll list every subscription that charges you each month, and you decide which to stop.`,body:`Give me bill screenshots or statements. I list every recurring charge, its next date and the yearly total; you decide what to cancel and I walk you through each cancellation.`,kind:`CHAT`,prompt:`Audit my subscriptions: ask me for bill screenshots or statements, then list every recurring charge, its next billing date and the yearly total, and flag the ones I may not need.`}]},{id:`learn`,title:`Learning`,ideas:[{id:`daily-words`,emoji:`🔤`,title:`Five new words every morning, a quick quiz every night.`,body:`You pick the language and level; I pick words by theme with examples and a memory hook, quiz you in the evening, and bring back the ones you missed.`,kind:`ROUTINE`,time:`08:00`,prompt:`Daily vocabulary: pick five new words for me (ask which language, level and topics first), each with a definition, one example sentence and a memory hook, plus a review quiz on yesterday's words.`},{id:`study-plan`,emoji:`🎯`,title:`Something you want to learn? I'll break it into weekly chunks and keep you honest.`,body:`Tell me the goal and the hours you can spare; I lay out four to eight weeks, check progress weekly, and adjust the pace so you actually finish.`,kind:`GOAL`,category:`interests`,prompt:`I want to learn something new and stick with it: ask me what, my current level, hours per week and the timeframe, then create a goal with a weekly progress check.`},{id:`explain`,emoji:`💡`,title:`Send me a concept you don't get; I'll explain it with things you already know.`,body:`I ask what you already understand and start from there, then check with two quick questions and leave you a flashcard if you want one.`,kind:`CHAT`,prompt:`There's a concept I don't understand: ask me what it is and what related things I already know, explain it with analogies, then check with two short questions.`},{id:`reading-notes`,emoji:`📚`,title:`Finished a book? I'll turn it into notes you'll actually reread.`,body:`Tell me the highlights, or send the passages you marked. I write structured notes into your Library and remember what stayed with you.`,kind:`CHAT`,prompt:`Help me write notes on a book: ask me the title, the three things that struck me most and the quotes I want to keep, then save structured Markdown notes.`}]},{id:`family`,title:`Family & friends`,ideas:[{id:`birthdays`,emoji:`🎂`,title:`Birthdays and anniversaries: I remind you a week ahead, gift ideas included.`,body:`Give me names and dates and I keep them. A week before each one I remind you, with a few gift directions based on what you've told me about them.`,kind:`CHAT`,prompt:`Remember the birthdays and anniversaries of the people who matter to me: ask for the list and dates, store them in long-term memory, and set a routine that reminds me a week before each.`},{id:`keep-in-touch`,emoji:`💬`,title:`Lost touch with old friends? Once a week I'll suggest who to reach out to, and how to start.`,body:`Give me a list of people you want to stay close to. I rotate through them and write a natural opening line based on what you last talked about.`,kind:`ROUTINE`,time:`19:00`,prompt:`Weekly keep-in-touch: from my list of people I want to stay close to, pick the one I've gone longest without contacting, remind me, and write a natural opening line based on what I noted about our last conversation.`},{id:`family-calendar`,emoji:`📅`,title:`Tell me the family's plans and I'll put them on the calendar and catch clashes.`,body:`Kids' lessons, a parent's appointment, a weekend get-together: one sentence and it's in the calendar; if two things collide, I say so first.`,kind:`CHAT`,prompt:`Help me run the family calendar: I'll tell you plans as they come up; write them into the calendar, confirm each before creating it, and warn me about conflicts.`},{id:`gift-ideas`,emoji:`🎁`,title:`Describe the person and I'll give you gift ideas that aren't the obvious ones.`,body:`Budget, relationship, what they're into lately: three questions, then five directions with one line each on why it fits.`,kind:`CHAT`,prompt:`Help me think of a gift: ask who it's for, my budget, their interests and what's going on in their life, then give me five directions with one line of reasoning each.`}]},{id:`more`,title:`More ideas`,ideas:[{id:`id-renewal`,emoji:`🪪`,title:`Tell me when your documents expire; I'll book the renewal and prep the paperwork list.`,body:`Passport, licence, visa: I note the dates, remind you three months ahead, list the documents and the office, and look up appointment slots where I can.`,kind:`CHAT`,prompt:`Help me track document expiry: ask which documents I have and when they expire, store them in memory, and set a reminder three months ahead of each with the renewal checklist.`},{id:`personality-quiz`,emoji:`❓`,title:`Two small questions a day; after a week I'll tell you what I've noticed about you.`,body:`Light questions, quick answers. I keep them and, once a week, write a short observation about your preferences and rhythm so I understand you better.`,kind:`ROUTINE`,time:`21:00`,prompt:`Two questions a day: ask me two small questions about preferences, habits or how things are going (never repeat one), store the answers in memory; every Sunday add a short observation about my week.`},{id:`event-plan`,emoji:`🎉`,title:`Name the occasion; I'll plan the run of show and draft the invitation.`,body:`Birthday, team outing, family dinner: give me the headcount, budget and date, and you get a timeline, a shopping list and an invitation you can send as is.`,kind:`CHAT`,prompt:`Help me plan an event: ask me the occasion, date, headcount and budget, then give me a timeline, a to-do list and an invitation text I can send.`},{id:`phone-cleanup`,emoji:`🧹`,title:`Let me look through the sandbox and shared folders; I'll clear the junk and organise the rest.`,body:`I list the big files and duplicates, show you the list first and only act when you say so; anything worth keeping goes into the Library.`,kind:`CHAT`,prompt:`Help me tidy the workspace and shared folders: list large files, duplicates and files untouched for a long time, and give me the list. Do not delete anything before I confirm.`}]}]},y={sections:[{id:`travel`,title:`出行`,ideas:[{id:`train-watch`,emoji:`🚄`,title:`告诉我你要去哪、哪天走,我盯着 12306 的余票和低价票。`,body:`我会在沙盒里装好查询工具,按你说的频率查车次、席别和余票,有票或价格合适时马上通知你;订票和付款那一步留给你自己点。`,kind:`GOAL`,category:`other`,prompt:`我想盯一趟火车票:请先问我出发地、目的地、日期和可接受的车次时段,然后为我建一个定期检查余票的目标。`},{id:`trip-plan`,emoji:`🗺️`,title:`说一个城市和几天,我给你排一份能直接照着走的行程。`,body:`我会查天气、开放时间和两点之间的路程,把每天的顺序排顺,写成一份文件放进资源库;你改一句,我就重排。`,kind:`CHAT`,prompt:`帮我规划一次出行。先问我去哪、几天、和谁、预算大概多少、喜欢什么风格,再给我一份按天排好的行程文件。`},{id:`commute-brief`,emoji:`🚦`,title:`每天出门前,我告诉你今天的路况、天气和第一件事。`,body:`一条早间例程:查你所在城市的天气、通勤路线的路况,翻一下日历,把上午的安排浓缩成三句话推给你。`,kind:`ROUTINE`,time:`07:30`,prompt:`早间简报:查询今天的天气和通勤路况,读取我今天的日历安排,用不超过五句话告诉我今天最重要的三件事和出门要带的东西。`},{id:`parcel-track`,emoji:`📦`,title:`把快递单号发我,到哪了、什么时候到,我随时告诉你。`,body:`我会用快递查询接口跟踪包裹,有新的物流节点就更新你;派送当天提醒你留意电话。`,kind:`CHAT`,prompt:`帮我跟踪一个快递。先问我单号和快递公司,然后查一次当前进度,并设一个每天早上检查一次、到派送前一天提醒我的例程。`}]},{id:`work`,title:`工作`,ideas:[{id:`meeting-prep`,emoji:`📝`,title:`开会前十分钟,我把这场会的背景和该问的问题整理好。`,body:`读日历里的会议主题和参会人,翻我们聊过的相关内容和你放进资源库的资料,给你一页纸:目的、要点、三个值得问的问题。`,kind:`ROUTINE`,time:`08:50`,prompt:`查看我今天日历里接下来的会议,为每一场准备一页会前提纲:这场会的目的、需要我发言的要点、三个值得提出的问题。`},{id:`weekly-review`,emoji:`📊`,title:`每周五下午,我帮你回顾这一周做了什么,下周该抓什么。`,body:`从我们的对话、你的日历和我记下的备忘里,整理出本周完成的事、没做完的事和下周的三个重点,写成一份周报草稿。`,kind:`ROUTINE`,time:`17:00`,prompt:`写一份本周回顾:根据我们这周的对话、我的日历和你记住的事项,列出完成了什么、什么没做完、下周三个重点,保存为一份 Markdown 文件。`},{id:`inbox-triage`,emoji:`📬`,title:`把一堆消息或邮件丢给我,我分好轻重缓急,写好回复草稿。`,body:`粘贴文字或截图给我,我按“今天必须回、这周处理、只需知道”分类,把每条要回的先拟好一版,你改一改就能发。`,kind:`CHAT`,prompt:`我要把一批消息交给你整理:请按“今天必须回 / 这周处理 / 只需知道”分类,并为需要回复的每一条写好回复草稿。请先让我粘贴内容。`},{id:`doc-digest`,emoji:`📄`,title:`长文档、PDF、网页,我读完给你三分钟版本。`,body:`把文件放进共享文件夹或把链接发我,我提炼结论、关键数字和你需要做的决定,问题可以接着追问。`,kind:`CHAT`,prompt:`我有一份长内容需要你读并总结:请先让我提供文件或链接,然后给我结论、关键数字、需要我做的决定三部分,每部分不超过五条。`}]},{id:`life`,title:`生活`,ideas:[{id:`price-watch`,emoji:`🏷️`,title:`想买的东西告诉我,降到你说的价格我立刻告诉你。`,body:`我会定期去商品页看价格,记录走势;到价就通知你。下单和付款由你来点,我不会碰。`,kind:`GOAL`,category:`finance`,prompt:`我想盯一件商品的价格:请先问我商品链接或名称、目标价格和检查频率,然后建一个到价提醒我的目标。`},{id:`photo-sort`,emoji:`🖼️`,title:`把相册挂给我,我按内容给截图和照片分类整理。`,body:`在「共享文件夹」里挂载相册后,我会看图识别内容(票据、聊天截图、风景、证件),归到对应文件夹,重要的信息顺手记下来。`,kind:`CHAT`,prompt:`帮我整理照片:请先让我在共享文件夹里挂载相册目录,然后按内容(票据、截图、风景、证件、其他)分类整理,并把整理结果列给我。`},{id:`meal-log`,emoji:`🥗`,title:`拍下你吃的,我帮你估热量、记下每一餐。`,body:`发一张照片或一句话,我估算营养和热量,记进当天的日记;晚上给你一天的小结和明天的一个小建议。`,kind:`CHAT`,prompt:`从现在起帮我记录饮食:每次我发照片或描述,估算热量与营养并记入当天记忆;请先告诉我怎么发给你最方便。`},{id:`subscriptions`,emoji:`🔁`,title:`帮你把每月自动扣费的订阅列出来,看看哪些该停。`,body:`把账单截图或消费记录给我,我列出所有周期性扣费、下一次扣款日和一年花多少;你决定停哪个,退订的步骤我一步步陪你走。`,kind:`CHAT`,prompt:`帮我盘点订阅扣费:请先让我提供账单截图或记录,然后列出所有周期性扣费、下一次扣款日、年费合计,并标出可能不再需要的。`}]},{id:`learn`,title:`学习`,ideas:[{id:`daily-words`,emoji:`🔤`,title:`每天早上五个新词,晚上考你一遍。`,body:`你定语言和难度,我按主题挑词、给例句和记忆点,晚上出五道小题,错的第二天再来。`,kind:`ROUTINE`,time:`08:00`,prompt:`每日词汇:为我挑五个新词(先问我学什么语言、什么水平和感兴趣的主题),每个给释义、一个例句和一个记忆点,并附上昨天的复习题。`},{id:`study-plan`,emoji:`🎯`,title:`有个想学会的东西?我陪你拆成每周能做完的小块。`,body:`告诉我目标和每周能投入的时间,我排一份四到八周的计划,每周检查进度、调整难度,帮你坚持到最后。`,kind:`GOAL`,category:`interests`,prompt:`我想学一样新东西并坚持下去:请先问我想学什么、现在的水平、每周能投入多少时间和希望多久见效,然后帮我建一个每周检查进度的目标。`},{id:`explain`,emoji:`💡`,title:`看不懂的概念发给我,我用你熟悉的东西讲明白。`,body:`先问你已经懂什么,再从那里出发讲;讲完出两道题确认你真懂了,需要的话给你一张记忆卡。`,kind:`CHAT`,prompt:`我有一个不太懂的概念想让你讲明白:请先问我这个概念是什么、我已经了解哪些相关知识,然后用类比讲解,最后出两道小题检验。`},{id:`reading-notes`,emoji:`📚`,title:`读完一本书,我帮你整理成能重读的笔记。`,body:`你说重点和感受,或者把划线的句子发我,我整理成结构化笔记,存进资源库,并记住你的收获。`,kind:`CHAT`,prompt:`帮我整理一本书的读书笔记:请先问我书名、最触动我的三点和我想记住的引文,然后整理成结构化的 Markdown 笔记并保存。`}]},{id:`family`,title:`家庭与关系`,ideas:[{id:`birthdays`,emoji:`🎂`,title:`重要的人的生日和纪念日,我提前一周提醒,顺手想好礼物。`,body:`把名字和日期告诉我,我记住;到日子前一周提醒你,并根据你说过的 TA 的喜好给几个礼物方向。`,kind:`CHAT`,prompt:`帮我记住重要的人的生日和纪念日:请先问我名单和日期,记入长期记忆,并为每个日期设一个提前一周提醒我的例程。`},{id:`keep-in-touch`,emoji:`💬`,title:`老朋友太久没联系?我每周提醒你该找谁聊聊,帮你开个头。`,body:`你给我一份想保持联系的名单,我按间隔轮着提醒,并根据上次聊的内容帮你写一句自然的开场。`,kind:`ROUTINE`,time:`19:00`,prompt:`每周联系提醒:从我告诉你的“想保持联系的人”名单里,挑一位最近最久没联系的,提醒我,并根据我记录过的上次聊天内容写一句自然的开场白。`},{id:`family-calendar`,emoji:`📅`,title:`把全家的安排告诉我,我帮你排进日历、发现冲突。`,body:`孩子的课、家人的门诊、周末的聚会,说一句我就写进日历,时间撞了我先提醒你。`,kind:`CHAT`,prompt:`帮我管理家庭日程:我会陆续告诉你家人的安排,请写进日历,创建前先复述确认,发现时间冲突时提醒我。`},{id:`gift-ideas`,emoji:`🎁`,title:`说说 TA 是什么样的人,我给你几个不落俗套的礼物点子。`,body:`预算、关系、TA 最近在忙什么,三个问题之后我给你五个方向,每个附一句为什么合适。`,kind:`CHAT`,prompt:`帮我想礼物:请先问我送给谁、预算、TA 的兴趣和最近的生活状态,然后给我五个礼物方向,每个附一句理由。`}]},{id:`more`,title:`更多点子`,ideas:[{id:`id-renewal`,emoji:`🪪`,title:`告诉我证件到期时间,我提前预约续签,把材料清单准备好。`,body:`护照、驾照、签证,我记下到期日,提前三个月提醒,列出所需材料和办理地点,能预约的帮你查好时段。`,kind:`CHAT`,prompt:`帮我管理证件到期:请先问我有哪些证件和到期日期,记入长期记忆,并为每一个设置提前三个月的提醒,附上续办所需材料清单。`},{id:`personality-quiz`,emoji:`❓`,title:`每天两个小问题,一周后我告诉你我发现了什么样的你。`,body:`问题很轻,回答很快;我把答案记下来,每周整理成一段关于你偏好和节奏的观察,方便我更懂你。`,kind:`ROUTINE`,time:`21:00`,prompt:`每日两问:问我两个关于偏好、习惯或近况的小问题(不重复以前问过的),把回答记入记忆;每周日额外给我一段关于我这周状态的观察。`},{id:`event-plan`,emoji:`🎉`,title:`说个场合,我帮你安排流程、拟好邀请。`,body:`生日、团建、家宴,人数、预算和日期告诉我,我给你时间线、采购清单和一段可以直接发出去的邀请文字。`,kind:`CHAT`,prompt:`帮我策划一次活动:请先问我场合、日期、人数和预算,然后给我时间线、待办清单和一段可直接发送的邀请文字。`},{id:`phone-cleanup`,emoji:`🧹`,title:`让我看看沙盒和共享文件夹里有什么,清掉没用的、整理有用的。`,body:`我列出占空间的大文件和重复文件,先给你看清单,你点头我再动;重要的整理进资源库。`,kind:`CHAT`,prompt:`帮我整理工作区和共享文件夹:先列出大文件、重复文件和很久没动的文件,给我一份清单;在我确认之前不要删除任何东西。`}]}]};function b(e){return e.toLowerCase().startsWith(`zh`)?y:v}function x(e){return{id:e.id,emoji:e.emoji,title:e.title,detail:e.body,prompt:e.prompt,kind:e.kind.toLowerCase(),time:e.time,category:e.category}}var S=o(),C=[{id:`planning`,label:`Planning`,emoji:`🗓️`},{id:`goals`,label:`Goals`,emoji:`🎯`},{id:`research`,label:`Research`,emoji:`🔍`},{id:`money`,label:`Money`,emoji:`💰`},{id:`health`,label:`Health`,emoji:`🌿`},{id:`home`,label:`Home`,emoji:`🏠`},{id:`learning`,label:`Learning`,emoji:`📚`},{id:`people`,label:`People`,emoji:`👥`},{id:`files`,label:`Files & tools`,emoji:`📄`},{id:`fun`,label:`Just for you`,emoji:`🎈`}];function w(){let{state:t,send:r,openThread:a,toast:o}=s(),[v,y]=(0,_.useState)(null),[C,w]=(0,_.useState)(!1),E=t.profile?.name??`nanoMuse`,D=n(),O=i(),k=async(e=!1)=>{w(!0);try{let t=await l.ideas(e);y(t),t.error&&o(D(`Could not refresh ideas: {error}`,{error:t.error}))}catch(e){o(e.message)}finally{w(!1)}};(0,_.useEffect)(()=>{k(!1)},[]);let A=v?.source===`model`&&v.ideas.length>0,j=A?T(v.ideas):b(O).sections.map(e=>({id:e.id,title:e.title,ideas:e.ideas.map(x)})),[M,N]=(0,_.useState)(null),P=e=>{N(null),r(`main`,e.prompt).catch(e=>o(e.message||D(`Could not send`))),a(`main`)},F=async e=>{N(null);let t=e.time&&/^([01]\d|2[0-3]):[0-5]\d$/.test(e.time)?e.time:`09:00`;try{await l.createReminder({text:e.prompt,kind:`task`,repeat:`daily ${t}`}),o(D(`Routine set: every day at {time}. It is listed under Goals.`,{time:t}))}catch(e){o(e.message)}},I=e=>{N(null);let t=m.find(t=>t.id===e.category)??m[m.length-1],n=D(`I'd like to create a {category} goal. Ask me a few short questions, one at a time (what exactly I want, why and by when, how often to check in), then create it with concrete steps using the goals tool.`,{category:D(t.label)});r(`main`,`${n} ${e.prompt}`).catch(e=>o(e.message||D(`Could not send`))),a(`main`)},L=e=>e.kind===`routine`||e.kind===`goal`?e.kind:`chat`;return(0,S.jsxs)(`div`,{className:`flex h-full flex-col`,children:[(0,S.jsx)(p,{title:D(`Ideas`),children:(0,S.jsx)(`button`,{type:`button`,onClick:()=>void k(!0),disabled:C,"aria-label":D(`Refresh ideas`),className:`flex h-10 w-10 items-center justify-center rounded-full bg-surface text-fg shadow-[0_1px_4px_rgba(0,0,0,0.14)] disabled:opacity-60 dark:border dark:border-border dark:shadow-none`,children:C?(0,S.jsx)(c,{size:20,className:`animate-spin`}):(0,S.jsx)(u,{size:19})})}),(0,S.jsxs)(`div`,{className:`flex-1 overflow-y-auto pb-6`,children:[j.map(({id:e,title:t,ideas:n},r)=>(0,S.jsxs)(`section`,{children:[(r>0||!A)&&(0,S.jsx)(`h2`,{className:`px-5 pt-[22px] pb-1 text-[20px] font-bold`,children:A?D(t):t}),(0,S.jsx)(`ul`,{children:n.map(e=>(0,S.jsxs)(`li`,{children:[(0,S.jsxs)(`button`,{type:`button`,onClick:()=>N({idea:e,emoji:e.emoji}),className:`flex w-full items-start gap-4 px-5 py-3.5 text-left active:bg-surface-2/70`,children:[(0,S.jsx)(`span`,{className:`flex w-10 shrink-0 justify-center text-[28px] leading-[34px]`,children:e.emoji}),(0,S.jsxs)(`span`,{className:`min-w-0 flex-1 space-y-1`,children:[(0,S.jsx)(`span`,{className:`block text-[16px] font-semibold leading-[22px]`,children:e.title}),e.detail&&(0,S.jsx)(`span`,{className:`line-clamp-4 block text-[13.5px] leading-[19px] text-muted`,children:e.detail})]})]}),(0,S.jsx)(`div`,{className:`ml-[76px] mr-5 border-b border-border/70`})]},e.title))})]},e)),v&&(0,S.jsx)(`div`,{className:`px-5 pt-4 text-[12.5px] text-muted`,children:v.source===`model`?D(`Generated {when}`,{when:e(v.generated_at)}):D(`Starter ideas. Refresh once {name} knows you better.`,{name:E})})]}),(0,S.jsx)(d,{open:M!==null,onClose:()=>N(null),children:M&&(0,S.jsxs)(`div`,{className:`px-1 pb-2`,children:[(0,S.jsxs)(`div`,{className:`flex items-center gap-3`,children:[(0,S.jsx)(`span`,{className:`text-[30px] leading-none`,children:M.emoji}),(0,S.jsx)(`h3`,{className:`flex-1 text-[18px] font-bold leading-6`,children:M.idea.title})]}),M.idea.detail&&(0,S.jsx)(`p`,{className:`mt-3 text-[15px] leading-[22px]`,children:M.idea.detail}),(0,S.jsxs)(`div`,{className:`mt-3.5 flex items-center gap-1.5 text-[13px] text-muted`,children:[L(M.idea)===`routine`&&(0,S.jsxs)(S.Fragment,{children:[(0,S.jsx)(h,{size:16}),` `,D(`Creates a routine`),M.idea.time?` · ${M.idea.time}`:``]}),L(M.idea)===`goal`&&(0,S.jsxs)(S.Fragment,{children:[(0,S.jsx)(g,{size:16}),` `,D(`Creates a goal`)]}),L(M.idea)===`chat`&&(0,S.jsxs)(S.Fragment,{children:[(0,S.jsx)(f,{size:16}),` `,D(`Starts a conversation`)]})]}),L(M.idea)===`routine`&&(0,S.jsxs)(`button`,{type:`button`,onClick:()=>void F(M.idea),className:`mt-[22px] flex h-[50px] w-full items-center justify-center gap-2 rounded-full bg-accent text-[16px] font-semibold text-accent-fg`,children:[(0,S.jsx)(h,{size:18}),` `,D(`Create routine`)]}),L(M.idea)===`goal`&&(0,S.jsxs)(`button`,{type:`button`,onClick:()=>I(M.idea),className:`mt-[22px] flex h-[50px] w-full items-center justify-center gap-2 rounded-full bg-accent text-[16px] font-semibold text-accent-fg`,children:[(0,S.jsx)(g,{size:18}),` `,D(`Start goal`)]}),L(M.idea)===`chat`&&(0,S.jsxs)(`button`,{type:`button`,onClick:()=>P(M.idea),className:`mt-[22px] flex h-[50px] w-full items-center justify-center gap-2 rounded-full bg-accent text-[16px] font-semibold text-accent-fg`,children:[(0,S.jsx)(f,{size:18}),` `,D(`Send to chat`)]})]})})]})}function T(e){let t=C[C.length-1],n=C.map(e=>({id:e.id,title:e.label,ideas:[]}));for(let r of e){let e=C.find(e=>e.id===(r.area||t.id))??t;(n.find(t=>t.id===e.id)??n[n.length-1]).ideas.push({...r,emoji:e.emoji})}return n.filter(e=>e.ideas.length>0)}export{w as IdeasScreen}; \ No newline at end of file diff --git a/nanomuse/server/static/assets/IdentityForm-IeJQ0HCo.js b/nanomuse/server/static/assets/IdentityForm-g-zvQ2IC.js similarity index 97% rename from nanomuse/server/static/assets/IdentityForm-IeJQ0HCo.js rename to nanomuse/server/static/assets/IdentityForm-g-zvQ2IC.js index d6210db64..edd98223d 100644 --- a/nanomuse/server/static/assets/IdentityForm-IeJQ0HCo.js +++ b/nanomuse/server/static/assets/IdentityForm-g-zvQ2IC.js @@ -1 +1 @@ -import{E as e,J as t,K as n,Q as r,Y as i,b as a,i as o}from"./MuseHeader-BvAlmxiL.js";import{r as s}from"./AvatarPicker-DUnXfRVQ.js";var c=t(`shuffle`,[[`path`,{d:`m18 14 4 4-4 4`,key:`10pe0f`}],[`path`,{d:`m18 2 4 4-4 4`,key:`pucp1d`}],[`path`,{d:`M2 18h1.973a4 4 0 0 0 3.3-1.7l5.454-8.6a4 4 0 0 1 3.3-1.7H22`,key:`1ailkh`}],[`path`,{d:`M2 6h1.972a4 4 0 0 1 3.6 2.2`,key:`km57vx`}],[`path`,{d:`M22 18h-6.041a4 4 0 0 1-3.3-1.8l-.359-.45`,key:`os18l9`}]]),l=r(i(),1),u=a(),d=[`Muse`,`Veda`,`Nova`,`Pip`,`Sage`,`Juno`,`Kit`,`Wren`,`Iris`,`Milo`,`Echo`,`Remy`,`Otto`,`Luna`,`Ari`,`Bea`,`Nico`,`Zed`,`小墨`,`阿柒`,`小满`,`知了`,`豆豆`,`小竹`],f=[`formal`,`casual`,`playful`,`concise`],p=[`short`,`detailed`,`bullets`],m={formal:`Formal`,casual:`Casual`,playful:`Playful`,concise:`Concise`},h={short:`Short replies`,detailed:`Detailed`,bullets:`Bullet points`};function g(e,t){let n=d.filter(t=>t!==e),r=[],i=t||1,a=[...n];for(;r.length<6&&a.length;)i=(i*9301+49297)%233280,r.push(a.splice(i%a.length,1)[0]);return r}function _({active:t,onClick:n,children:r}){return(0,u.jsx)(`button`,{type:`button`,onClick:n,className:e(`rounded-full px-3 py-1.5 text-[13px] border transition-colors`,t?`border-accent bg-accent/10 text-accent font-medium`:`border-border text-muted`),children:r})}function v({value:t,onChange:r,suggestions:i=!0,askUserName:a=!0,inputCls:d,onStudio:v}){let y=n(),b=(0,l.useId)(),[x,S]=(0,l.useState)(7),C=(0,l.useMemo)(()=>g(t.name,x),[t.name,x]),w=e=>r({...t,...e}),T={...t,proactivity:`default`,proactive:!0,goal_interval_minutes:60,quiet_hours:``};return(0,u.jsxs)(`div`,{className:`space-y-5`,children:[(0,u.jsxs)(`div`,{className:`flex items-start gap-4`,children:[(0,u.jsx)(o,{profile:T,size:72}),(0,u.jsxs)(`div`,{className:`flex-1 min-w-0 space-y-2`,children:[(0,u.jsx)(`div`,{children:(0,u.jsx)(`input`,{value:t.name,onChange:e=>w({name:e.target.value.slice(0,20)}),maxLength:20,className:e(d,`text-[17px] font-medium`),placeholder:`nanoMuse`,"aria-label":y(`Name`),autoCapitalize:`words`})}),(0,u.jsx)(`input`,{value:t.tagline,onChange:e=>w({tagline:e.target.value.slice(0,60)}),maxLength:60,className:e(d,`text-[14px]`),placeholder:y(`A line under the name, e.g. Your day, sorted.`),"aria-label":y(`Tagline`)})]})]}),i&&(0,u.jsxs)(`div`,{className:`flex flex-wrap items-center gap-1.5`,children:[C.map(e=>(0,u.jsx)(_,{active:t.name===e,onClick:()=>w({name:e}),children:e},e)),(0,u.jsx)(`button`,{type:`button`,onClick:()=>S(e=>e+1),"aria-label":y(`More names`),className:`rounded-full border border-border p-1.5 text-muted`,children:(0,u.jsx)(c,{size:14})})]}),(0,u.jsx)(s,{value:{avatar:t.avatar,emoji:t.emoji,color:t.color},onChange:e=>w(e),onStudio:v}),(0,u.jsxs)(`div`,{children:[(0,u.jsx)(`label`,{className:`text-[12px] text-muted`,children:y(`Tone`)}),(0,u.jsx)(`div`,{className:`mt-1.5 flex flex-wrap gap-1.5`,children:f.map(e=>(0,u.jsx)(_,{active:t.tone===e,onClick:()=>w({tone:t.tone===e?``:e}),children:y(m[e])},e))})]}),(0,u.jsxs)(`div`,{children:[(0,u.jsx)(`label`,{className:`text-[12px] text-muted`,children:y(`How much it says`)}),(0,u.jsx)(`div`,{className:`mt-1.5 flex flex-wrap gap-1.5`,children:p.map(e=>(0,u.jsx)(_,{active:t.communication===e,onClick:()=>w({communication:t.communication===e?``:e}),children:y(h[e])},e))})]}),(0,u.jsxs)(`div`,{children:[(0,u.jsx)(`label`,{htmlFor:`${b}-style`,className:`text-[12px] text-muted`,children:y(`Anything else about how it should be`)}),(0,u.jsx)(`textarea`,{id:`${b}-style`,value:t.style,onChange:e=>w({style:e.target.value}),rows:2,placeholder:y(`e.g. A little witty. Uses metric units. Never uses emoji.`),className:e(d,`mt-1 resize-none text-[14px]`)})]}),a&&(0,u.jsxs)(`div`,{children:[(0,u.jsx)(`label`,{htmlFor:`${b}-user`,className:`text-[12px] text-muted`,children:y(`What it calls you`)}),(0,u.jsx)(`input`,{id:`${b}-user`,value:t.user_name,onChange:e=>w({user_name:e.target.value}),maxLength:60,placeholder:y(`Your name`),className:e(d,`mt-1 text-[14px]`)})]})]})}function y(e,t,n){return{name:e?.name??`nanoMuse`,tagline:e?.tagline??``,avatar:e?.avatar??t,emoji:e?.emoji??`✨`,color:e?.color??n,tone:e?.tone??``,communication:e?.communication??``,style:e?.style??``,user_name:e?.user_name??``}}function b(e){return{...e,name:e.name.trim()||`nanoMuse`,tagline:e.tagline.trim(),style:e.style.trim(),user_name:e.user_name.trim()}}export{b as n,y as r,v as t}; \ No newline at end of file +import{E as e,J as t,K as n,Q as r,Y as i,b as a,i as o}from"./MuseHeader-RC--uR8o.js";import{r as s}from"./AvatarPicker-BCihUURa.js";var c=t(`shuffle`,[[`path`,{d:`m18 14 4 4-4 4`,key:`10pe0f`}],[`path`,{d:`m18 2 4 4-4 4`,key:`pucp1d`}],[`path`,{d:`M2 18h1.973a4 4 0 0 0 3.3-1.7l5.454-8.6a4 4 0 0 1 3.3-1.7H22`,key:`1ailkh`}],[`path`,{d:`M2 6h1.972a4 4 0 0 1 3.6 2.2`,key:`km57vx`}],[`path`,{d:`M22 18h-6.041a4 4 0 0 1-3.3-1.8l-.359-.45`,key:`os18l9`}]]),l=r(i(),1),u=a(),d=[`Muse`,`Veda`,`Nova`,`Pip`,`Sage`,`Juno`,`Kit`,`Wren`,`Iris`,`Milo`,`Echo`,`Remy`,`Otto`,`Luna`,`Ari`,`Bea`,`Nico`,`Zed`,`小墨`,`阿柒`,`小满`,`知了`,`豆豆`,`小竹`],f=[`formal`,`casual`,`playful`,`concise`],p=[`short`,`detailed`,`bullets`],m={formal:`Formal`,casual:`Casual`,playful:`Playful`,concise:`Concise`},h={short:`Short replies`,detailed:`Detailed`,bullets:`Bullet points`};function g(e,t){let n=d.filter(t=>t!==e),r=[],i=t||1,a=[...n];for(;r.length<6&&a.length;)i=(i*9301+49297)%233280,r.push(a.splice(i%a.length,1)[0]);return r}function _({active:t,onClick:n,children:r}){return(0,u.jsx)(`button`,{type:`button`,onClick:n,className:e(`rounded-full px-3 py-1.5 text-[13px] border transition-colors`,t?`border-accent bg-accent/10 text-accent font-medium`:`border-border text-muted`),children:r})}function v({value:t,onChange:r,suggestions:i=!0,askUserName:a=!0,inputCls:d,onStudio:v}){let y=n(),b=(0,l.useId)(),[x,S]=(0,l.useState)(7),C=(0,l.useMemo)(()=>g(t.name,x),[t.name,x]),w=e=>r({...t,...e}),T={...t,proactivity:`default`,proactive:!0,goal_interval_minutes:60,quiet_hours:``};return(0,u.jsxs)(`div`,{className:`space-y-5`,children:[(0,u.jsxs)(`div`,{className:`flex items-start gap-4`,children:[(0,u.jsx)(o,{profile:T,size:72}),(0,u.jsxs)(`div`,{className:`flex-1 min-w-0 space-y-2`,children:[(0,u.jsx)(`div`,{children:(0,u.jsx)(`input`,{value:t.name,onChange:e=>w({name:e.target.value.slice(0,20)}),maxLength:20,className:e(d,`text-[17px] font-medium`),placeholder:`nanoMuse`,"aria-label":y(`Name`),autoCapitalize:`words`})}),(0,u.jsx)(`input`,{value:t.tagline,onChange:e=>w({tagline:e.target.value.slice(0,60)}),maxLength:60,className:e(d,`text-[14px]`),placeholder:y(`A line under the name, e.g. Your day, sorted.`),"aria-label":y(`Tagline`)})]})]}),i&&(0,u.jsxs)(`div`,{className:`flex flex-wrap items-center gap-1.5`,children:[C.map(e=>(0,u.jsx)(_,{active:t.name===e,onClick:()=>w({name:e}),children:e},e)),(0,u.jsx)(`button`,{type:`button`,onClick:()=>S(e=>e+1),"aria-label":y(`More names`),className:`rounded-full border border-border p-1.5 text-muted`,children:(0,u.jsx)(c,{size:14})})]}),(0,u.jsx)(s,{value:{avatar:t.avatar,emoji:t.emoji,color:t.color},onChange:e=>w(e),onStudio:v}),(0,u.jsxs)(`div`,{children:[(0,u.jsx)(`label`,{className:`text-[12px] text-muted`,children:y(`Tone`)}),(0,u.jsx)(`div`,{className:`mt-1.5 flex flex-wrap gap-1.5`,children:f.map(e=>(0,u.jsx)(_,{active:t.tone===e,onClick:()=>w({tone:t.tone===e?``:e}),children:y(m[e])},e))})]}),(0,u.jsxs)(`div`,{children:[(0,u.jsx)(`label`,{className:`text-[12px] text-muted`,children:y(`How much it says`)}),(0,u.jsx)(`div`,{className:`mt-1.5 flex flex-wrap gap-1.5`,children:p.map(e=>(0,u.jsx)(_,{active:t.communication===e,onClick:()=>w({communication:t.communication===e?``:e}),children:y(h[e])},e))})]}),(0,u.jsxs)(`div`,{children:[(0,u.jsx)(`label`,{htmlFor:`${b}-style`,className:`text-[12px] text-muted`,children:y(`Anything else about how it should be`)}),(0,u.jsx)(`textarea`,{id:`${b}-style`,value:t.style,onChange:e=>w({style:e.target.value}),rows:2,placeholder:y(`e.g. A little witty. Uses metric units. Never uses emoji.`),className:e(d,`mt-1 resize-none text-[14px]`)})]}),a&&(0,u.jsxs)(`div`,{children:[(0,u.jsx)(`label`,{htmlFor:`${b}-user`,className:`text-[12px] text-muted`,children:y(`What it calls you`)}),(0,u.jsx)(`input`,{id:`${b}-user`,value:t.user_name,onChange:e=>w({user_name:e.target.value}),maxLength:60,placeholder:y(`Your name`),className:e(d,`mt-1 text-[14px]`)})]})]})}function y(e,t,n){return{name:e?.name??`nanoMuse`,tagline:e?.tagline??``,avatar:e?.avatar??t,emoji:e?.emoji??`✨`,color:e?.color??n,tone:e?.tone??``,communication:e?.communication??``,style:e?.style??``,user_name:e?.user_name??``}}function b(e){return{...e,name:e.name.trim()||`nanoMuse`,tagline:e.tagline.trim(),style:e.style.trim(),user_name:e.user_name.trim()}}export{b as n,y as r,v as t}; \ No newline at end of file diff --git a/nanomuse/server/static/assets/LibraryScreen-BclDd8-A.js b/nanomuse/server/static/assets/LibraryScreen-BoofKOos.js similarity index 86% rename from nanomuse/server/static/assets/LibraryScreen-BclDd8-A.js rename to nanomuse/server/static/assets/LibraryScreen-BoofKOos.js index 2687e1924..931d45056 100644 --- a/nanomuse/server/static/assets/LibraryScreen-BclDd8-A.js +++ b/nanomuse/server/static/assets/LibraryScreen-BoofKOos.js @@ -1 +1 @@ -import{D as e,E as t,J as n,K as r,Q as i,S as a,Y as o,b as s,f as c,q as l,x as u}from"./MuseHeader-BvAlmxiL.js";import{C as d,I as f,X as p,_t as m,f as h,mt as g,pt as _,xt as v}from"./index-tZx-TDX4.js";var y=n(`file-image`,[[`path`,{d:`M6 22a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h8a2.4 2.4 0 0 1 1.704.706l3.588 3.588A2.4 2.4 0 0 1 20 8v12a2 2 0 0 1-2 2z`,key:`1oefj6`}],[`path`,{d:`M14 2v5a1 1 0 0 0 1 1h5`,key:`wfsgrz`}],[`circle`,{cx:`10`,cy:`12`,r:`2`,key:`737tya`}],[`path`,{d:`m20 17-1.296-1.296a2.41 2.41 0 0 0-3.408 0L9 22`,key:`wt3hpn`}]]),b=n(`file-spreadsheet`,[[`path`,{d:`M6 22a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h8a2.4 2.4 0 0 1 1.704.706l3.588 3.588A2.4 2.4 0 0 1 20 8v12a2 2 0 0 1-2 2z`,key:`1oefj6`}],[`path`,{d:`M14 2v5a1 1 0 0 0 1 1h5`,key:`wfsgrz`}],[`path`,{d:`M8 13h2`,key:`yr2amv`}],[`path`,{d:`M14 13h2`,key:`un5t4a`}],[`path`,{d:`M8 17h2`,key:`2yhykz`}],[`path`,{d:`M14 17h2`,key:`10kma7`}]]),x=n(`library-big`,[[`rect`,{width:`8`,height:`18`,x:`3`,y:`3`,rx:`1`,key:`oynpb5`}],[`path`,{d:`M7 3v18`,key:`bbkbws`}],[`path`,{d:`M20.4 18.9c.2.5-.1 1.1-.6 1.3l-1.9.7c-.5.2-1.1-.1-1.3-.6L11.1 5.1c-.2-.5.1-1.1.6-1.3l1.9-.7c.5-.2 1.1.1 1.3.6Z`,key:`1qboyk`}]]),S=i(o(),1),C=s(),w=new Set([`png`,`jpg`,`jpeg`,`gif`,`webp`,`svg`,`heic`,`mp3`,`wav`,`m4a`,`ogg`,`flac`,`mp4`,`mov`,`webm`,`mkv`]);function T(e){return w.has(e.toLowerCase().split(`.`).pop()??``)}function E(){let{state:e,openFile:t}=c(),[n,i]=(0,S.useState)(null),[a,o]=(0,S.useState)(null),[s,f]=(0,S.useState)(0),[m,g]=(0,S.useState)(0),[_,v]=(0,S.useState)(``),y=r(),b=Object.values(e.events).reduce((e,t)=>e+t.length,0);(0,S.useEffect)(()=>{let e=!0;return u.files(500).then(t=>{e&&(i(t),o(null))}).catch(t=>e&&o(t.message)),()=>{e=!1}},[b,e.feedVersion,s]);let w=(0,S.useMemo)(()=>{let e=_.trim().toLowerCase();return(n??[]).filter(t=>T(t.name)===(m===1)&&(!e||t.path.toLowerCase().includes(e)))},[n,m,_]);return(0,C.jsxs)(`div`,{className:`flex h-full flex-col`,children:[(0,C.jsx)(h,{title:y(`Library`)}),(0,C.jsxs)(`div`,{className:`shrink-0 px-4 pt-1 pb-2.5`,children:[(0,C.jsx)(D,{labels:[y(`Artifacts`),y(`Media`)],selected:m,onSelect:e=>g(e)}),(n?.length??0)>8&&(0,C.jsxs)(`label`,{className:`mt-2.5 flex items-center gap-2 rounded-full bg-surface-2 px-3.5 py-2`,children:[(0,C.jsx)(p,{size:16,className:`text-muted`}),(0,C.jsx)(`input`,{value:_,onChange:e=>v(e.target.value),placeholder:y(`Search files`),className:`flex-1 bg-transparent text-[14.5px] outline-none`})]})]}),(0,C.jsxs)(`div`,{className:`flex-1 overflow-y-auto pb-6`,children:[n===null&&a&&(0,C.jsx)(d,{message:a,onRetry:()=>f(e=>e+1)}),n===null&&!a&&(0,C.jsx)(`div`,{className:`flex justify-center py-10 text-muted`,children:(0,C.jsx)(l,{className:`animate-spin`,size:20})}),n!==null&&w.length===0&&(0,C.jsxs)(`div`,{className:`flex flex-col items-center px-8 pt-9 text-center`,children:[(0,C.jsx)(x,{size:34,className:`text-muted`}),(0,C.jsx)(`div`,{className:`mt-3.5 text-[16px] font-medium text-muted`,children:y(_?`No files match.`:m===0?`Nothing created yet`:`No media yet`)}),!_&&(0,C.jsx)(`p`,{className:`mt-1 text-[12px] text-muted`,children:y(m===0?`Documents, tables and pages I write for you will show up here.`:`Photos, screenshots and recordings I produce will show up here.`)})]}),(0,C.jsx)(`ul`,{children:w.map(e=>(0,C.jsx)(`li`,{children:(0,C.jsx)(O,{file:e,onOpen:()=>t(e.path)})},e.path))})]})]})}function D({labels:e,selected:n,onSelect:r}){return(0,C.jsx)(`div`,{role:`tablist`,className:`flex h-12 w-full rounded-full border border-border bg-surface p-1`,children:e.map((e,i)=>(0,C.jsx)(`button`,{type:`button`,role:`tab`,"aria-selected":i===n,onClick:()=>r(i),className:t(`flex-1 rounded-full text-[14px] font-semibold transition`,i===n?`bg-surface-2`:`bg-transparent`),children:e},e))})}function O({file:t,onOpen:n}){let r=e(t.name),i=r===`html`?(0,C.jsx)(_,{size:22}):r===`image`?(0,C.jsx)(y,{size:22}):r===`data`?(0,C.jsx)(b,{size:22}):r===`code`?(0,C.jsx)(m,{size:22}):r===`event`?(0,C.jsx)(v,{size:22}):(0,C.jsx)(g,{size:22}),o=t.path.includes(`/`)?t.path.slice(0,t.path.lastIndexOf(`/`)):``;return(0,C.jsxs)(`button`,{type:`button`,onClick:n,className:`flex w-full items-center gap-3.5 px-4 py-2 text-left active:bg-surface-2/70`,children:[(0,C.jsx)(`span`,{className:`flex h-[46px] w-[46px] shrink-0 items-center justify-center overflow-hidden rounded-[10px] bg-surface-2 text-muted`,children:r===`image`?(0,C.jsx)(`img`,{src:a(t.path),alt:``,loading:`lazy`,className:`h-full w-full object-cover`}):i}),(0,C.jsxs)(`span`,{className:`min-w-0 flex-1 space-y-0.5`,children:[(0,C.jsx)(`span`,{className:`block truncate text-[15px] font-medium`,children:t.name}),(0,C.jsx)(`span`,{className:`block truncate text-[12px] text-muted`,children:[f(t.modified),k(t.size),o].filter(Boolean).join(` · `)})]})]})}function k(e){return e<1024?`${e} B`:e<1048576?`${(e/1024).toFixed(+(e<10240))} KB`:`${(e/1024/1024).toFixed(1)} MB`}export{E as LibraryScreen}; \ No newline at end of file +import{D as e,E as t,J as n,K as r,Q as i,S as a,Y as o,b as s,f as c,q as l,x as u}from"./MuseHeader-RC--uR8o.js";import{F as d,S as f,Y as p,bt as m,d as h,ft as g,gt as _,pt as v}from"./index-tYqPtwPX.js";var y=n(`file-image`,[[`path`,{d:`M6 22a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h8a2.4 2.4 0 0 1 1.704.706l3.588 3.588A2.4 2.4 0 0 1 20 8v12a2 2 0 0 1-2 2z`,key:`1oefj6`}],[`path`,{d:`M14 2v5a1 1 0 0 0 1 1h5`,key:`wfsgrz`}],[`circle`,{cx:`10`,cy:`12`,r:`2`,key:`737tya`}],[`path`,{d:`m20 17-1.296-1.296a2.41 2.41 0 0 0-3.408 0L9 22`,key:`wt3hpn`}]]),b=n(`file-spreadsheet`,[[`path`,{d:`M6 22a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h8a2.4 2.4 0 0 1 1.704.706l3.588 3.588A2.4 2.4 0 0 1 20 8v12a2 2 0 0 1-2 2z`,key:`1oefj6`}],[`path`,{d:`M14 2v5a1 1 0 0 0 1 1h5`,key:`wfsgrz`}],[`path`,{d:`M8 13h2`,key:`yr2amv`}],[`path`,{d:`M14 13h2`,key:`un5t4a`}],[`path`,{d:`M8 17h2`,key:`2yhykz`}],[`path`,{d:`M14 17h2`,key:`10kma7`}]]),x=n(`library-big`,[[`rect`,{width:`8`,height:`18`,x:`3`,y:`3`,rx:`1`,key:`oynpb5`}],[`path`,{d:`M7 3v18`,key:`bbkbws`}],[`path`,{d:`M20.4 18.9c.2.5-.1 1.1-.6 1.3l-1.9.7c-.5.2-1.1-.1-1.3-.6L11.1 5.1c-.2-.5.1-1.1.6-1.3l1.9-.7c.5-.2 1.1.1 1.3.6Z`,key:`1qboyk`}]]),S=i(o(),1),C=s(),w=new Set([`png`,`jpg`,`jpeg`,`gif`,`webp`,`svg`,`heic`,`mp3`,`wav`,`m4a`,`ogg`,`flac`,`mp4`,`mov`,`webm`,`mkv`]);function T(e){return w.has(e.toLowerCase().split(`.`).pop()??``)}function E(){let{state:e,openFile:t}=c(),[n,i]=(0,S.useState)(null),[a,o]=(0,S.useState)(null),[s,d]=(0,S.useState)(0),[m,g]=(0,S.useState)(0),[_,v]=(0,S.useState)(``),y=r(),b=Object.values(e.events).reduce((e,t)=>e+t.length,0);(0,S.useEffect)(()=>{let e=!0;return u.files(500).then(t=>{e&&(i(t),o(null))}).catch(t=>e&&o(t.message)),()=>{e=!1}},[b,e.feedVersion,s]);let w=(0,S.useMemo)(()=>{let e=_.trim().toLowerCase();return(n??[]).filter(t=>T(t.name)===(m===1)&&(!e||t.path.toLowerCase().includes(e)))},[n,m,_]);return(0,C.jsxs)(`div`,{className:`flex h-full flex-col`,children:[(0,C.jsx)(h,{title:y(`Library`)}),(0,C.jsxs)(`div`,{className:`shrink-0 px-4 pt-1 pb-2.5`,children:[(0,C.jsx)(D,{labels:[y(`Artifacts`),y(`Media`)],selected:m,onSelect:e=>g(e)}),(n?.length??0)>8&&(0,C.jsxs)(`label`,{className:`mt-2.5 flex items-center gap-2 rounded-full bg-surface-2 px-3.5 py-2`,children:[(0,C.jsx)(p,{size:16,className:`text-muted`}),(0,C.jsx)(`input`,{value:_,onChange:e=>v(e.target.value),placeholder:y(`Search files`),className:`flex-1 bg-transparent text-[14.5px] outline-none`})]})]}),(0,C.jsxs)(`div`,{className:`flex-1 overflow-y-auto pb-6`,children:[n===null&&a&&(0,C.jsx)(f,{message:a,onRetry:()=>d(e=>e+1)}),n===null&&!a&&(0,C.jsx)(`div`,{className:`flex justify-center py-10 text-muted`,children:(0,C.jsx)(l,{className:`animate-spin`,size:20})}),n!==null&&w.length===0&&(0,C.jsxs)(`div`,{className:`flex flex-col items-center px-8 pt-9 text-center`,children:[(0,C.jsx)(x,{size:34,className:`text-muted`}),(0,C.jsx)(`div`,{className:`mt-3.5 text-[16px] font-medium text-muted`,children:y(_?`No files match.`:m===0?`Nothing created yet`:`No media yet`)}),!_&&(0,C.jsx)(`p`,{className:`mt-1 text-[12px] text-muted`,children:y(m===0?`Documents, tables and pages I write for you will show up here.`:`Photos, screenshots and recordings I produce will show up here.`)})]}),(0,C.jsx)(`ul`,{children:w.map(e=>(0,C.jsx)(`li`,{children:(0,C.jsx)(O,{file:e,onOpen:()=>t(e.path)})},e.path))})]})]})}function D({labels:e,selected:n,onSelect:r}){return(0,C.jsx)(`div`,{role:`tablist`,className:`flex h-12 w-full rounded-full border border-border bg-surface p-1`,children:e.map((e,i)=>(0,C.jsx)(`button`,{type:`button`,role:`tab`,"aria-selected":i===n,onClick:()=>r(i),className:t(`flex-1 rounded-full text-[14px] font-semibold transition`,i===n?`bg-surface-2`:`bg-transparent`),children:e},e))})}function O({file:t,onOpen:n}){let r=e(t.name),i=r===`html`?(0,C.jsx)(g,{size:22}):r===`image`?(0,C.jsx)(y,{size:22}):r===`data`?(0,C.jsx)(b,{size:22}):r===`code`?(0,C.jsx)(_,{size:22}):r===`event`?(0,C.jsx)(m,{size:22}):(0,C.jsx)(v,{size:22}),o=t.path.includes(`/`)?t.path.slice(0,t.path.lastIndexOf(`/`)):``;return(0,C.jsxs)(`button`,{type:`button`,onClick:n,className:`flex w-full items-center gap-3.5 px-4 py-2 text-left active:bg-surface-2/70`,children:[(0,C.jsx)(`span`,{className:`flex h-[46px] w-[46px] shrink-0 items-center justify-center overflow-hidden rounded-[10px] bg-surface-2 text-muted`,children:r===`image`?(0,C.jsx)(`img`,{src:a(t.path),alt:``,loading:`lazy`,className:`h-full w-full object-cover`}):i}),(0,C.jsxs)(`span`,{className:`min-w-0 flex-1 space-y-0.5`,children:[(0,C.jsx)(`span`,{className:`block truncate text-[15px] font-medium`,children:t.name}),(0,C.jsx)(`span`,{className:`block truncate text-[12px] text-muted`,children:[d(t.modified),k(t.size),o].filter(Boolean).join(` · `)})]})]})}function k(e){return e<1024?`${e} B`:e<1048576?`${(e/1024).toFixed(+(e<10240))} KB`:`${(e/1024/1024).toFixed(1)} MB`}export{E as LibraryScreen}; \ No newline at end of file diff --git a/nanomuse/server/static/assets/MemoryScreen-6ZrrpUSE.js b/nanomuse/server/static/assets/MemoryScreen-DHNxjNpq.js similarity index 92% rename from nanomuse/server/static/assets/MemoryScreen-6ZrrpUSE.js rename to nanomuse/server/static/assets/MemoryScreen-DHNxjNpq.js index e0883a661..ec73c168b 100644 --- a/nanomuse/server/static/assets/MemoryScreen-6ZrrpUSE.js +++ b/nanomuse/server/static/assets/MemoryScreen-DHNxjNpq.js @@ -1 +1 @@ -import{A as e,J as t,K as n,Q as r,Y as i,b as a,f as o,q as s,x as c}from"./MuseHeader-BvAlmxiL.js";import{C as l,St as u,V as d,W as f,Z as p}from"./index-tZx-TDX4.js";import{t as m}from"./BackBar-DmScFXW_.js";var h=t(`undo-2`,[[`path`,{d:`M9 14 4 9l5-5`,key:`102s5s`}],[`path`,{d:`M4 9h10.5a5.5 5.5 0 0 1 5.5 5.5a5.5 5.5 0 0 1-5.5 5.5H11`,key:`f3b9sd`}]]),g=r(i(),1),_=a(),v=[`profile`,`preference`,`people`,`routine`,`constraint`,`general`];function y(){let{state:t,toast:r,openThread:i,setTab:a}=o(),[y,b]=(0,g.useState)(null),[x,S]=(0,g.useState)(null),[C,w]=(0,g.useState)([]),[T,E]=(0,g.useState)(``),[D,O]=(0,g.useState)(`profile`),[k,A]=(0,g.useState)(!1),[j,M]=(0,g.useState)(!1),N=t.profile?.name??`nanoMuse`,P=n(),F=()=>Promise.all([c.memory().then(b),c.memoryChanges().then(w)]).then(()=>S(null)).catch(e=>y===null?S(e.message):r(e.message));(0,g.useEffect)(()=>{F()},[t.memoryVersion]);let I=(0,g.useMemo)(()=>{let e=new Map;for(let t of y??[])e.set(t.category,[...e.get(t.category)??[],t]);return[...e.entries()].sort((e,t)=>t[1].length-e[1].length)},[y]),L=async()=>{if(T.trim()){A(!0);try{await c.addMemory(T.trim(),D),E(``),await F()}catch(e){r(e.message)}finally{A(!1)}}},R=async e=>{if(window.confirm(P(`Forget “{text}”?`,{text:e.content.slice(0,60)})))try{await c.forgetMemory(e.id),b(t=>t?.filter(t=>t.id!==e.id)??t)}catch(e){r(e.message)}},z=async()=>{M(!0);try{let e=await c.tidyMemory();r(e.changed===0?P(`Nothing to tidy: {n} memories, all distinct.`,{n:e.considered}):P(`Tidied: {merged} merged, {dropped} dropped. Undo below if needed.`,{merged:e.merged.length,dropped:e.dropped.length})),await F()}catch(e){r(e.message)}finally{M(!1)}},B=async e=>{try{await c.restoreMemoryChange(e.id),await F()}catch(e){r(e.message)}};return(0,_.jsxs)(`div`,{className:`flex h-full flex-col`,children:[(0,_.jsx)(m,{title:P(`Memory`),description:P(`What {name} remembers about you. Read it, add to it, or make {name} forget; nothing here is hidden from you.`,{name:N}),actions:(y?.length??0)>=2&&(0,_.jsxs)(`button`,{type:`button`,disabled:j,onClick:()=>void z(),title:P(`Merge lines that say the same thing and drop what was never a fact about you. Every change can be undone.`),className:`flex h-10 items-center gap-1.5 rounded-full bg-surface px-3.5 text-[13.5px] font-medium shadow-[0_1px_4px_rgba(0,0,0,0.14)] disabled:opacity-50 dark:border dark:border-border dark:shadow-none`,children:[(0,_.jsx)(f,{size:15,className:j?`animate-pulse text-accent`:`text-accent`}),P(j?`Tidying…`:`Tidy up`)]})}),(0,_.jsxs)(`div`,{className:`flex-1 overflow-y-auto px-4 pb-6 space-y-5`,children:[(0,_.jsxs)(`div`,{className:`rounded-3xl bg-surface border border-border/70 shadow-sm p-3.5 space-y-2.5`,children:[(0,_.jsx)(`textarea`,{value:T,onChange:e=>E(e.target.value),rows:2,placeholder:P(`Tell {name} something to remember, e.g. “I'm vegetarian” or “My sister's birthday is 14 May”`,{name:N}),className:`w-full resize-none rounded-2xl bg-surface-2 px-3.5 py-2.5 text-[14.5px] outline-none focus:ring-2 focus:ring-accent/40`}),(0,_.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,_.jsx)(`select`,{value:D,onChange:e=>O(e.target.value),className:`rounded-2xl bg-surface-2 px-3 py-2 text-[13.5px] outline-none`,children:v.map(e=>(0,_.jsx)(`option`,{value:e,children:P(e)},e))}),(0,_.jsx)(`div`,{className:`flex-1`}),(0,_.jsxs)(`button`,{type:`button`,disabled:!T.trim()||k,onClick:()=>void L(),className:`rounded-2xl bg-accent text-accent-fg px-3.5 py-2 text-[14px] font-medium flex items-center gap-1.5 disabled:opacity-50`,children:[(0,_.jsx)(p,{size:16}),` `,P(`Remember`)]})]})]}),y===null&&x&&(0,_.jsx)(l,{message:x,onRetry:()=>void F()}),y===null&&!x&&(0,_.jsx)(`div`,{className:`flex justify-center py-10 text-muted`,children:(0,_.jsx)(s,{className:`animate-spin`,size:20})}),y!==null&&y.length===0&&(0,_.jsxs)(`div`,{className:`rounded-3xl border border-dashed border-border p-6 text-center`,children:[(0,_.jsx)(u,{className:`mx-auto text-accent`}),(0,_.jsx)(`div`,{className:`mt-2 font-semibold`,children:P(`Nothing remembered yet`)}),(0,_.jsx)(`p`,{className:`mt-1 text-[13.5px] text-muted`,children:P(`{name} saves durable facts you share in chat (preferences, people, routines) and never secrets.`,{name:N})}),(0,_.jsx)(`button`,{type:`button`,onClick:()=>{i(`main`),a(`chat`)},className:`mt-3 rounded-full bg-accent px-4 py-2 text-[13.5px] font-semibold text-accent-fg`,children:P(`Tell {name} something to remember`,{name:N})})]}),I.map(([t,n])=>(0,_.jsxs)(`section`,{children:[(0,_.jsxs)(`div`,{className:`px-1 mb-2 text-[12px] font-semibold uppercase tracking-wide text-muted`,children:[P(t),` · `,n.length]}),(0,_.jsx)(`ul`,{className:`rounded-3xl bg-surface border border-border/70 shadow-sm divide-y divide-border/70 overflow-hidden`,children:n.map(t=>(0,_.jsxs)(`li`,{className:`flex items-start gap-3 px-4 py-3`,children:[(0,_.jsxs)(`div`,{className:`flex-1 min-w-0`,children:[(0,_.jsx)(`div`,{className:`text-[14.5px] leading-snug break-words`,children:t.content}),(0,_.jsxs)(`div`,{className:`mt-0.5 text-[11.5px] text-muted`,children:[t.source===`user`?P(`added by you`):P(`saved by {name}`,{name:N}),` · `,e(t.created_at),t.updated_at?` · ${P(`updated {when}`,{when:e(t.updated_at)})}`:``]})]}),(0,_.jsx)(`button`,{type:`button`,"aria-label":P(`Forget`),onClick:()=>void R(t),className:`p-1.5 text-muted hover:text-rose-500`,children:(0,_.jsx)(d,{size:17})})]},t.id))})]},t)),C.length>0&&(0,_.jsxs)(`section`,{children:[(0,_.jsx)(`div`,{className:`px-1 mb-2 text-[12px] font-semibold uppercase tracking-wide text-muted`,children:P(`Recent changes`)}),(0,_.jsx)(`ul`,{className:`rounded-3xl bg-surface border border-border/70 shadow-sm divide-y divide-border/70 overflow-hidden`,children:C.map(t=>(0,_.jsx)(`li`,{className:`px-4 py-3 ${t.restored?`opacity-60`:``}`,children:(0,_.jsxs)(`div`,{className:`flex items-start gap-3`,children:[(0,_.jsxs)(`div`,{className:`flex-1 min-w-0 text-[13.5px] leading-snug`,children:[(0,_.jsxs)(`div`,{className:`text-muted`,children:[t.action===`merge`?P(`Merged`):t.action===`drop`?P(`Dropped`):P(`Updated`),t.reason?` · ${t.reason}`:``,` · `,e(t.at),t.restored?` · ${P(`restored`)}`:``]}),t.before.map(e=>(0,_.jsx)(`div`,{className:`break-words line-through text-muted`,children:e.content},e.id)),t.after&&(0,_.jsxs)(`div`,{className:`break-words`,children:[`→ `,t.after.content]})]}),!t.restored&&(0,_.jsxs)(`button`,{type:`button`,onClick:()=>void B(t),className:`shrink-0 rounded-xl bg-surface-2 px-2.5 py-1.5 text-[12.5px] font-medium flex items-center gap-1`,children:[(0,_.jsx)(h,{size:14}),` `,P(`Undo`)]})]})},t.id))})]})]})]})}export{y as MemoryScreen}; \ No newline at end of file +import{A as e,J as t,K as n,Q as r,Y as i,b as a,f as o,q as s,x as c}from"./MuseHeader-RC--uR8o.js";import{B as l,S as u,U as d,X as f,xt as p}from"./index-tYqPtwPX.js";import{t as m}from"./BackBar-JEuC8Q_e.js";var h=t(`undo-2`,[[`path`,{d:`M9 14 4 9l5-5`,key:`102s5s`}],[`path`,{d:`M4 9h10.5a5.5 5.5 0 0 1 5.5 5.5a5.5 5.5 0 0 1-5.5 5.5H11`,key:`f3b9sd`}]]),g=r(i(),1),_=a(),v=[`profile`,`preference`,`people`,`routine`,`constraint`,`general`];function y(){let{state:t,toast:r,openThread:i,setTab:a}=o(),[y,b]=(0,g.useState)(null),[x,S]=(0,g.useState)(null),[C,w]=(0,g.useState)([]),[T,E]=(0,g.useState)(``),[D,O]=(0,g.useState)(`profile`),[k,A]=(0,g.useState)(!1),[j,M]=(0,g.useState)(!1),N=t.profile?.name??`nanoMuse`,P=n(),F=()=>Promise.all([c.memory().then(b),c.memoryChanges().then(w)]).then(()=>S(null)).catch(e=>y===null?S(e.message):r(e.message));(0,g.useEffect)(()=>{F()},[t.memoryVersion]);let I=(0,g.useMemo)(()=>{let e=new Map;for(let t of y??[])e.set(t.category,[...e.get(t.category)??[],t]);return[...e.entries()].sort((e,t)=>t[1].length-e[1].length)},[y]),L=async()=>{if(T.trim()){A(!0);try{await c.addMemory(T.trim(),D),E(``),await F()}catch(e){r(e.message)}finally{A(!1)}}},R=async e=>{if(window.confirm(P(`Forget “{text}”?`,{text:e.content.slice(0,60)})))try{await c.forgetMemory(e.id),b(t=>t?.filter(t=>t.id!==e.id)??t)}catch(e){r(e.message)}},z=async()=>{M(!0);try{let e=await c.tidyMemory();r(e.changed===0?P(`Nothing to tidy: {n} memories, all distinct.`,{n:e.considered}):P(`Tidied: {merged} merged, {dropped} dropped. Undo below if needed.`,{merged:e.merged.length,dropped:e.dropped.length})),await F()}catch(e){r(e.message)}finally{M(!1)}},B=async e=>{try{await c.restoreMemoryChange(e.id),await F()}catch(e){r(e.message)}};return(0,_.jsxs)(`div`,{className:`flex h-full flex-col`,children:[(0,_.jsx)(m,{title:P(`Memory`),description:P(`What {name} remembers about you. Read it, add to it, or make {name} forget; nothing here is hidden from you.`,{name:N}),actions:(y?.length??0)>=2&&(0,_.jsxs)(`button`,{type:`button`,disabled:j,onClick:()=>void z(),title:P(`Merge lines that say the same thing and drop what was never a fact about you. Every change can be undone.`),className:`flex h-10 items-center gap-1.5 rounded-full bg-surface px-3.5 text-[13.5px] font-medium shadow-[0_1px_4px_rgba(0,0,0,0.14)] disabled:opacity-50 dark:border dark:border-border dark:shadow-none`,children:[(0,_.jsx)(d,{size:15,className:j?`animate-pulse text-accent`:`text-accent`}),P(j?`Tidying…`:`Tidy up`)]})}),(0,_.jsxs)(`div`,{className:`flex-1 overflow-y-auto px-4 pb-6 space-y-5`,children:[(0,_.jsxs)(`div`,{className:`rounded-3xl bg-surface border border-border/70 shadow-sm p-3.5 space-y-2.5`,children:[(0,_.jsx)(`textarea`,{value:T,onChange:e=>E(e.target.value),rows:2,placeholder:P(`Tell {name} something to remember, e.g. “I'm vegetarian” or “My sister's birthday is 14 May”`,{name:N}),className:`w-full resize-none rounded-2xl bg-surface-2 px-3.5 py-2.5 text-[14.5px] outline-none focus:ring-2 focus:ring-accent/40`}),(0,_.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,_.jsx)(`select`,{value:D,onChange:e=>O(e.target.value),className:`rounded-2xl bg-surface-2 px-3 py-2 text-[13.5px] outline-none`,children:v.map(e=>(0,_.jsx)(`option`,{value:e,children:P(e)},e))}),(0,_.jsx)(`div`,{className:`flex-1`}),(0,_.jsxs)(`button`,{type:`button`,disabled:!T.trim()||k,onClick:()=>void L(),className:`rounded-2xl bg-accent text-accent-fg px-3.5 py-2 text-[14px] font-medium flex items-center gap-1.5 disabled:opacity-50`,children:[(0,_.jsx)(f,{size:16}),` `,P(`Remember`)]})]})]}),y===null&&x&&(0,_.jsx)(u,{message:x,onRetry:()=>void F()}),y===null&&!x&&(0,_.jsx)(`div`,{className:`flex justify-center py-10 text-muted`,children:(0,_.jsx)(s,{className:`animate-spin`,size:20})}),y!==null&&y.length===0&&(0,_.jsxs)(`div`,{className:`rounded-3xl border border-dashed border-border p-6 text-center`,children:[(0,_.jsx)(p,{className:`mx-auto text-accent`}),(0,_.jsx)(`div`,{className:`mt-2 font-semibold`,children:P(`Nothing remembered yet`)}),(0,_.jsx)(`p`,{className:`mt-1 text-[13.5px] text-muted`,children:P(`{name} saves durable facts you share in chat (preferences, people, routines) and never secrets.`,{name:N})}),(0,_.jsx)(`button`,{type:`button`,onClick:()=>{i(`main`),a(`chat`)},className:`mt-3 rounded-full bg-accent px-4 py-2 text-[13.5px] font-semibold text-accent-fg`,children:P(`Tell {name} something to remember`,{name:N})})]}),I.map(([t,n])=>(0,_.jsxs)(`section`,{children:[(0,_.jsxs)(`div`,{className:`px-1 mb-2 text-[12px] font-semibold uppercase tracking-wide text-muted`,children:[P(t),` · `,n.length]}),(0,_.jsx)(`ul`,{className:`rounded-3xl bg-surface border border-border/70 shadow-sm divide-y divide-border/70 overflow-hidden`,children:n.map(t=>(0,_.jsxs)(`li`,{className:`flex items-start gap-3 px-4 py-3`,children:[(0,_.jsxs)(`div`,{className:`flex-1 min-w-0`,children:[(0,_.jsx)(`div`,{className:`text-[14.5px] leading-snug break-words`,children:t.content}),(0,_.jsxs)(`div`,{className:`mt-0.5 text-[11.5px] text-muted`,children:[t.source===`user`?P(`added by you`):P(`saved by {name}`,{name:N}),` · `,e(t.created_at),t.updated_at?` · ${P(`updated {when}`,{when:e(t.updated_at)})}`:``]})]}),(0,_.jsx)(`button`,{type:`button`,"aria-label":P(`Forget`),onClick:()=>void R(t),className:`p-1.5 text-muted hover:text-rose-500`,children:(0,_.jsx)(l,{size:17})})]},t.id))})]},t)),C.length>0&&(0,_.jsxs)(`section`,{children:[(0,_.jsx)(`div`,{className:`px-1 mb-2 text-[12px] font-semibold uppercase tracking-wide text-muted`,children:P(`Recent changes`)}),(0,_.jsx)(`ul`,{className:`rounded-3xl bg-surface border border-border/70 shadow-sm divide-y divide-border/70 overflow-hidden`,children:C.map(t=>(0,_.jsx)(`li`,{className:`px-4 py-3 ${t.restored?`opacity-60`:``}`,children:(0,_.jsxs)(`div`,{className:`flex items-start gap-3`,children:[(0,_.jsxs)(`div`,{className:`flex-1 min-w-0 text-[13.5px] leading-snug`,children:[(0,_.jsxs)(`div`,{className:`text-muted`,children:[t.action===`merge`?P(`Merged`):t.action===`drop`?P(`Dropped`):P(`Updated`),t.reason?` · ${t.reason}`:``,` · `,e(t.at),t.restored?` · ${P(`restored`)}`:``]}),t.before.map(e=>(0,_.jsx)(`div`,{className:`break-words line-through text-muted`,children:e.content},e.id)),t.after&&(0,_.jsxs)(`div`,{className:`break-words`,children:[`→ `,t.after.content]})]}),!t.restored&&(0,_.jsxs)(`button`,{type:`button`,onClick:()=>void B(t),className:`shrink-0 rounded-xl bg-surface-2 px-2.5 py-1.5 text-[12.5px] font-medium flex items-center gap-1`,children:[(0,_.jsx)(h,{size:14}),` `,P(`Undo`)]})]})},t.id))})]})]})]})}export{y as MemoryScreen}; \ No newline at end of file diff --git a/nanomuse/server/static/assets/MuseHeader-BvAlmxiL.js b/nanomuse/server/static/assets/MuseHeader-BvAlmxiL.js deleted file mode 100644 index 900354390..000000000 --- a/nanomuse/server/static/assets/MuseHeader-BvAlmxiL.js +++ /dev/null @@ -1 +0,0 @@ -var e=Object.create,t=Object.defineProperty,n=Object.getOwnPropertyDescriptor,r=Object.getOwnPropertyNames,i=Object.getPrototypeOf,a=Object.prototype.hasOwnProperty,o=(e,t)=>()=>(t||(e((t={exports:{}}).exports,t),e=null),t.exports),s=(e,n)=>{let r={};for(var i in e)t(r,i,{get:e[i],enumerable:!0});return n||t(r,Symbol.toStringTag,{value:`Module`}),r},c=(e,i,o,s)=>{if(i&&typeof i==`object`||typeof i==`function`)for(var c=r(i),l=0,u=c.length,d;li[e]).bind(null,d),enumerable:!(s=n(i,d))||s.enumerable});return e},l=(n,r,o)=>(o=n==null?{}:e(i(n)),c(r||!n||!n.__esModule||!a.call(n,`default`)?t(o,`default`,{value:n,enumerable:!0}):o,n)),u=o((e=>{var t=Symbol.for(`react.element`),n=Symbol.for(`react.portal`),r=Symbol.for(`react.fragment`),i=Symbol.for(`react.strict_mode`),a=Symbol.for(`react.profiler`),o=Symbol.for(`react.provider`),s=Symbol.for(`react.context`),c=Symbol.for(`react.forward_ref`),l=Symbol.for(`react.suspense`),u=Symbol.for(`react.memo`),d=Symbol.for(`react.lazy`),f=Symbol.iterator;function p(e){return typeof e!=`object`||!e?null:(e=f&&e[f]||e[`@@iterator`],typeof e==`function`?e:null)}var m={isMounted:function(){return!1},enqueueForceUpdate:function(){},enqueueReplaceState:function(){},enqueueSetState:function(){}},h=Object.assign,g={};function _(e,t,n){this.props=e,this.context=t,this.refs=g,this.updater=n||m}_.prototype.isReactComponent={},_.prototype.setState=function(e,t){if(typeof e!=`object`&&typeof e!=`function`&&e!=null)throw Error(`setState(...): takes an object of state variables to update or a function which returns an object of state variables.`);this.updater.enqueueSetState(this,e,t,`setState`)},_.prototype.forceUpdate=function(e){this.updater.enqueueForceUpdate(this,e,`forceUpdate`)};function v(){}v.prototype=_.prototype;function y(e,t,n){this.props=e,this.context=t,this.refs=g,this.updater=n||m}var b=y.prototype=new v;b.constructor=y,h(b,_.prototype),b.isPureReactComponent=!0;var x=Array.isArray,S=Object.prototype.hasOwnProperty,C={current:null},w={key:!0,ref:!0,__self:!0,__source:!0};function ee(e,n,r){var i,a={},o=null,s=null;if(n!=null)for(i in n.ref!==void 0&&(s=n.ref),n.key!==void 0&&(o=``+n.key),n)S.call(n,i)&&!w.hasOwnProperty(i)&&(a[i]=n[i]);var c=arguments.length-2;if(c===1)a.children=r;else if(1{t.exports=u()})),f=l(d()),p=(...e)=>e.filter((e,t,n)=>!!e&&e.trim()!==``&&n.indexOf(e)===t).join(` `).trim(),m=e=>e.replace(/([a-z0-9])([A-Z])/g,`$1-$2`).toLowerCase(),h=e=>e.replace(/^([A-Z])|[\s-_]+(\w)/g,(e,t,n)=>n?n.toUpperCase():t.toLowerCase()),g=e=>{let t=h(e);return t.charAt(0).toUpperCase()+t.slice(1)},_={xmlns:`http://www.w3.org/2000/svg`,width:24,height:24,viewBox:`0 0 24 24`,fill:`none`,stroke:`currentColor`,strokeWidth:2,strokeLinecap:`round`,strokeLinejoin:`round`},v=e=>{for(let t in e)if(t.startsWith(`aria-`)||t===`role`||t===`title`)return!0;return!1},y=(0,f.forwardRef)(({color:e=`currentColor`,size:t=24,strokeWidth:n=2,absoluteStrokeWidth:r,className:i=``,children:a,iconNode:o,...s},c)=>(0,f.createElement)(`svg`,{ref:c,..._,width:t,height:t,stroke:e,strokeWidth:r?Number(n)*24/Number(t):n,className:p(`lucide`,i),...!a&&!v(s)&&{"aria-hidden":`true`},...s},[...o.map(([e,t])=>(0,f.createElement)(e,t)),...Array.isArray(a)?a:[a]])),b=(e,t)=>{let n=(0,f.forwardRef)(({className:n,...r},i)=>(0,f.createElement)(y,{ref:i,iconNode:t,className:p(`lucide-${m(g(e))}`,`lucide-${e}`,n),...r}));return n.displayName=g(e),n},x=b(`loader-circle`,[[`path`,{d:`M21 12a9 9 0 1 1-6.219-8.56`,key:`13zald`}]]),S=21600,C=32;function w(e=Date.now()){return(Math.floor(e/1e3/S)+2)*S}function ee(e,t,n){let r=new TextEncoder;return E(te(r.encode(e),r.encode(`${n}\n${t}`))).slice(0,C)}function T(e,t,n=Date.now()){let r=w(n),i=new URLSearchParams;return i.set(`exp`,String(r)),i.set(`sig`,ee(e,t,r)),i}function E(e){let t=``;for(let n of e)t+=n.toString(16).padStart(2,`0`);return t}function te(e,t){let n=new Uint8Array(64);n.set(e.length>64?k(e):e);let r=new Uint8Array(64+t.length),i=new Uint8Array(96);for(let e=0;e<64;e++)r[e]=n[e]^54,i[e]=n[e]^92;return r.set(t,64),i.set(k(r),64),k(i)}var D=new Uint32Array([1116352408,1899447441,3049323471,3921009573,961987163,1508970993,2453635748,2870763221,3624381080,310598401,607225278,1426881987,1925078388,2162078206,2614888103,3248222580,3835390401,4022224774,264347078,604807628,770255983,1249150122,1555081692,1996064986,2554220882,2821834349,2952996808,3210313671,3336571891,3584528711,113926993,338241895,666307205,773529912,1294757372,1396182291,1695183700,1986661051,2177026350,2456956037,2730485921,2820302411,3259730800,3345764771,3516065817,3600352804,4094571909,275423344,430227734,506948616,659060556,883997877,958139571,1322822218,1537002063,1747873779,1955562222,2024104815,2227730452,2361852424,2428436474,2756734187,3204031479,3329325298]),O=(e,t)=>e>>>t|e<<32-t;function k(e){let t=new Uint32Array([1779033703,3144134277,1013904242,2773480762,1359893119,2600822924,528734635,1541459225]),n=new Uint8Array(e.length+9+63>>6<<6);n.set(e),n[e.length]=128;let r=new DataView(n.buffer),i=e.length*8;r.setUint32(n.length-8,Math.floor(i/4294967296)),r.setUint32(n.length-4,i>>>0);let a=new Uint32Array(64);for(let e=0;e>>3,i=O(n,17)^O(n,19)^n>>>10;a[e]=a[e-16]+r+a[e-7]+i>>>0}let n=t[0],i=t[1],o=t[2],s=t[3],c=t[4],l=t[5],u=t[6],d=t[7];for(let e=0;e<64;e++){let t=O(c,6)^O(c,11)^O(c,25),r=c&l^~c&u,f=d+t+r+D[e]+a[e]>>>0,p=(O(n,2)^O(n,13)^O(n,22))+(n&i^n&o^i&o)>>>0;d=u,u=l,l=c,c=s+f>>>0,s=o,o=i,i=n,n=f+p>>>0}t[0]+=n,t[1]+=i,t[2]+=o,t[3]+=s,t[4]+=c,t[5]+=l,t[6]+=u,t[7]+=d}let o=new Uint8Array(32),s=new DataView(o.buffer);for(let e=0;e<8;e++)s.setUint32(e*4,t[e]);return o}var A={Chat:`聊天`,Feed:`动态`,Ideas:`点子`,Goals:`目标`,Library:`资源库`,"Main chat":`主要聊天`,"Side chat":`旁聊`,"Reconnecting to your nanoMuse…":`正在重新连接你的 nanoMuse…`,"This demo has ended.":`这次体验已经结束。`,"This nanoMuse has stopped. Reload the page once it is running again.":`这个 nanoMuse 已停止。等它重新运行后,刷新页面即可。`,"Reconnecting…":`重新连接中…`,"Connect to your nanoMuse":`连接到你的 nanoMuse`,"This app talks to the nanoMuse server you run yourself. Scan the QR code printed by":`这个应用连接的是你自己运行的 nanoMuse 服务器。扫描下面命令打印的二维码`,", or paste the access token below.":`,或在下方粘贴访问令牌。`,"Access token":`访问令牌`,Connect:`连接`,Connected:`已连接`,"Hi, I'm {name}.":`你好,我是 {name}。`,"I don't just answer; I get things done: research, plans, files, code, email, long-running goals. Everything I do shows up here, and anything hard to undo waits for your approval.":`我不只是回答问题,而是把事情做完:调研、计划、文件、代码、邮件、长期目标。我做的每件事都会显示在这里,任何难以撤销的操作都会先等你批准。`,"What can you do for me?":`你能为我做什么?`,"Plan my week: ask me what's on my plate":`帮我规划这一周:先问问我手头有什么`,"Research and compare two options for me":`帮我调研并比较两个选项`,"Set up a long-term goal and track it":`建立一个长期目标并持续跟进`,"Answer {name}…":`回复 {name}…`,"Reply below to continue.":`在下方回复以继续。`,"{name} is working; anything you send now is picked up right away.":`{name} 正在工作,你现在发的消息会马上接着处理。`,"Working…":`处理中…`,"On it":`正在处理`,"Show the agent's steps":`显示执行步骤`,"Every tool it uses becomes a chip in the chat. Off, the chat keeps to the conversation and the line under the name says what it is on. This device only.":`每用一个工具就在对话里多一个小标签。关闭时对话只保留对话本身,名字下方的一行字说明它正在做什么。仅本设备。`,"On it: {request}":`正在处理:{request}`,"A star on GitHub helps":`GitHub 上的一颗 Star 帮得上忙`,"Welcome. nanoMuse is free, open source and non-profit, a personal agent for anyone who runs it. If that is worth something to you, a star on GitHub is how the next person finds it.":`欢迎。nanoMuse 免费、开源、非营利,做的是一个属于每个人的个人智能体。如果你认同,GitHub 上的一颗 Star 能让下一个人也找到这里。`,"Three tasks done. If nanoMuse is useful, a star on GitHub helps the next person find it.":`三个任务完成了。如果 nanoMuse 用得上,到 GitHub 点一颗 Star,下一个人也能找到它。`,"{n} tasks done. If nanoMuse is useful, a star on GitHub helps the next person find it.":`已经完成 {n} 个任务了。如果 nanoMuse 用得上,到 GitHub 点一颗 Star,下一个人也能找到它。`,"A week with nanoMuse. If it has earned a place in your day, a star on GitHub helps the next person find it.":`和 nanoMuse 一起一周了。如果它在你的日常里站住了脚,到 GitHub 点一颗 Star,下一个人也能找到它。`,"A month with nanoMuse. If it has become part of your routine, a star on GitHub tells others it is worth a try.":`和 nanoMuse 一起一个月了。如果它成了你习惯的一部分,一颗 Star 会让更多人愿意试一试。`,"{n} days with nanoMuse. If it has earned a place in your day, a star on GitHub helps the next person find it.":`和 nanoMuse 一起 {n} 天了。如果它在你的日常里站住了脚,到 GitHub 点一颗 Star,下一个人也能找到它。`,"Goal reached. If nanoMuse helped you get there, a star on GitHub tells the people building it that it did.":`目标达成了。如果 nanoMuse 帮你走到了这里,到 GitHub 点一颗 Star,做它的人就知道了。`,"Ten tasks together. If nanoMuse has become part of your day, a star on GitHub tells others it is worth a try.":`已经一起完成十个任务了。如果 nanoMuse 成了你日常的一部分,一颗 Star 会让更多人愿意试一试。`,"A new face, drawn for you. If you like where nanoMuse is going, a star on GitHub helps more people find it.":`一张为你画的新面孔。如果你喜欢 nanoMuse 现在的样子,到 GitHub 点一颗 Star,更多人就能遇见它。`,"The free allowance is used up. Thank you for coming this far. If nanoMuse has earned it, a star on GitHub keeps the project in view for the next person.":`免费额度用完了,谢谢你一路用到这里。如果 nanoMuse 值得,到 GitHub 点一颗 Star,下一个人也能找到它。`,"Load earlier messages":`加载更早的消息`,"New side chat":`新建旁聊`,"New side chat, e.g. “Trip to Kyoto”":`新建旁聊,例如“京都之旅”`,Chats:`对话`,New:`新建`,Create:`创建`,Clear:`清空`,"Clear this conversation? Memory and goals are kept.":`清空这段对话?记忆和目标会保留。`,"Delete this side chat and its history?":`删除这个旁聊及其历史记录?`,"Could not send":`发送失败`,"Could not send decision":`无法提交决定`,Send:`发送`,"Show thinking":`显示思考过程`,"Hide thinking":`隐藏思考过程`,"You:":`你:`,"{name} asks":`{name} 提问`,"{name} suggests":`{name} 建议`,"{name} is on it":`{name} 正在处理`,"Browser: {title}":`浏览器:{title}`,safe:`安全`,moderate:`中等`,sensitive:`敏感`,high:`高`,"Exactly what will run":`将要执行的具体内容`,"Why it asks: {reasons}":`询问原因:{reasons}`,"{tool} is on your always-ask list":`{tool} 在你的「总是询问」列表里`,"{tool} is on your always-allow list":`{tool} 在你的「总是允许」列表里`,"{tool} is switched off in your settings":`{tool} 已在你的设置里关闭`,"an action rated {risk}, in {mode} mode":`这个操作的风险等级是「{risk}」,哨兵处于{mode}模式`,"auto mode: not asked":`自动模式:未询问`,"covered by your {scope} permission for {key}":`已在你对 {key} 的「{scope}」授权范围内`,"private data was read earlier in this conversation, and {tool} could send it to {target}, which is not on your allowed list":`这段对话早些时候读取过私密数据,而 {tool} 可能把它发给 {target},这个地址不在你的允许列表里`,ask:`询问`,auto:`自动`,strict:`严格`,once:`一次`,conversation:`本次对话`,session:`本次运行`,"24h":`24 小时`,low:`低`,"Stopped.":`已停止。`,"Use nanoMuse Cloud this time":`这次改用 nanoMuse Cloud`,"Answered by nanoMuse Cloud this time ({model})":`这次由 nanoMuse Cloud 回答({model})`,Deny:`拒绝`,"Allow once":`允许一次`,Allow:`允许`,"{name} wants to":`{name} 想要`,"at {host}":`站点:{host}`,"to {recipient}":`收件人:{recipient}`,"Allow {subject} for longer…":`更长时间允许 {subject}…`,"For this conversation":`本次对话`,"the device {name}":`设备「{name}」`,"Until restart":`直到重启`,"For 24 hours":`24 小时内`,"Always for {subject}":`始终允许 {subject}`,"Fewer options":`收起`,"Show all":`展开全部`,"This kind of action is approved one at a time.":`这类操作需要逐次批准。`,Approved:`已批准`,Denied:`已拒绝`,"Expired without an answer":`已过期,未作答`,"approved by you":`已由你批准`,"covered by your {scope} permission":`已由你的{scope}授权覆盖`,"for this conversation":`本次对话`,"until restart":`直到重启`,"for 24 hours":`24 小时内`,always:`始终`,"email to {who}":`发送给 {who} 的邮件`,"{what} commands":`{what} 命令`,browser:`浏览器`,email:`邮件`,secret:`密钥`,"Waiting for you":`等你确认`,Answer:`回答`,LIVE:`实时`,BROWSER:`浏览器`,"Frame no longer available":`画面已不可用`,Page:`页面`,Document:`文档`,Image:`图片`,Data:`数据`,Code:`代码`,Open:`打开`,Download:`下载`,"Type into the focused field…":`输入到当前聚焦的输入框…`,Type:`输入`,"Press Enter":`按回车`,"Open a URL…":`打开一个网址…`,Go:`前往`,"Tap the page to click. If the browser was closed, open a URL first.":`点击画面即可点击网页。如果浏览器已关闭,请先打开一个网址。`,Refresh:`刷新`,"Take over":`接管`,"This frame is no longer available.":`这一帧画面已不可用。`,"Look again":`重新查看`,"1 frame":`1 帧`,"{n} frames":`{n} 帧`,"Scroll up":`向上滚动`,"Scroll down":`向下滚动`,"You have the page. Press Done when you are finished.":`页面现在由你操作。完成后按「完成」。`,"{name} waits meanwhile, then looks at the page as you left it and carries on. Passwords you type here go to the website, never to the model.":`{name} 会先等着,然后从你离开时的页面接着做。你在这里输入的密码只发给网站,不会给模型。`,"{name} is waiting for you":`{name} 在等你`,"{name} is working":`{name} 正在工作`,"Your turn":`该你了`,"Your turn: {reason}":`该你了:{reason}`,"You took over {thing}":`你接管了{thing}`,"the browser":`浏览器`,"the phone":`手机`,"The browser":`浏览器`,"The phone":`手机`,"Do this part yourself, then press Done. {name} looks again and carries on from there.":`这一步请你自己来,做完按「完成」。{name} 会重新看一眼屏幕,从那里接着做。`,"{name} waits. Press Done when you are finished and it looks again.":`{name} 在等。你弄完后按「完成」,它会重新看一眼。`,"{name} waited ten minutes and went on without you.":`{name} 等了十分钟,没等到你,先继续了。`,"Ended when the runtime restarted.":`运行时重启,这次接管结束。`,"You did it; {name} carried on.":`你做完了,{name} 接着做了。`,"Handed back; {name} carried on.":`已交还,{name} 接着做了。`,Close:`关闭`,"Open in a new tab":`在新标签页打开`,"No preview for this file type.":`此类型文件无法预览。`,"Download it":`下载文件`,"Empty file.":`空文件。`,"Could not load the file: {error}":`无法加载文件:{error}`,"Writing…":`正在写…`,"While you were away":`你离开期间`,"Could not write posts: {error}":`无法生成动态:{error}`,"Nothing yet. Once {name} works on a goal in the background or needs your approval, it shows up here.":`暂时还没有内容。当 {name} 在后台推进目标或需要你批准时,会显示在这里。`,"Next up":`接下来`,"Background work is off. {name} only acts when you ask.":`后台工作已关闭。{name} 只在你要求时行动。`,"Turn it on":`开启`,"No goal has a next step to work on.":`没有目标有可执行的下一步。`,"Add one":`添加一个`,"Working now":`正在进行`,"Quiet hours after {time}":`免打扰时段,{time} 之后`,"Around {time}":`大约 {time}`,Soon:`即将`,overdue:`已逾期`,"{n} more in line":`还有 {n} 个排队中`,"Check-in on":`跟进`,"{n} more":`还有 {n} 个`,Reminder:`提醒`,Routine:`例程`,"Working on your goal: {title}":`推进目标:{title}`,"Check-in: {title}":`跟进:{title}`,"Reminder: {title}":`提醒:{title}`,"Routine: {title}":`例程:{title}`,"New mail: {title}":`新邮件:{title}`,"Coming up: {title}":`即将开始:{title}`,"Webhook: {title}":`Webhook:{title}`,"Tidied memory":`整理了记忆`,"{label}: nothing new":`{label}:没有新进展`,"Open chat":`打开对话`,Today:`今天`,Yesterday:`昨天`,Menu:`菜单`,Stop:`停止`,"Nothing to stop":`没有正在进行的任务`,Message:`发消息`,"An emoji instead":`改用表情符号`,"Refresh ideas":`刷新灵感`,Planning:`规划`,Research:`调研`,Money:`财务`,People:`人际`,"Files & tools":`文件与工具`,"Just for you":`专属于你`,Tracking:`追踪`,"Show {n} more":`还有 {n} 个`,Cancelled:`已取消`,"Starter ideas. Refresh once {name} knows you better.":`入门灵感。等 {name} 更了解你之后再刷新。`,"Generated {when}":`生成于 {when}`,"Could not refresh ideas: {error}":`无法刷新灵感:{error}`,"Do it for me":`帮我做`,Health:`健康`,Finance:`财务`,Career:`事业`,Learning:`学习`,Relationships:`关系`,Family:`家庭`,Home:`家居`,Travel:`旅行`,Creative:`创作`,Other:`其他`,"New goal":`新目标`,Paused:`已暂停`,Finished:`已完成`,active:`进行中`,paused:`已暂停`,done:`已完成`,cancelled:`已取消`,pending:`待处理`,blocked:`受阻`,"{done}/{total} done":`已完成 {done}/{total}`,"No next step":`没有下一步`,"Next: {step}":`下一步:{step}`,"Next check-in {when}":`下次跟进 {when}`,"Due today":`今天到期`,"Due tomorrow":`明天到期`,"Due in {n} days":`{n} 天后到期`,"Was due {date}":`原定 {date} 到期`,"By {date}":`截止 {date}`,"No target date":`没有目标日期`,"No category":`未分类`,"Every day":`每天`,"Once a week":`每周一次`,"Once a month":`每月一次`,Weekdays:`工作日`,Weekly:`每周`,Monthly:`每月`,"Daily at {time}":`每天 {time}`,"Weekdays at {time}":`工作日 {time}`,"Weekly at {time}":`每周 {time}`,"{day}s at {time}":`每{day} {time}`,"Monthly on the {day} at {time}":`每月 {day} 日 {time}`,"Work on it now":`现在就推进`,"Work on {title} now":`现在推进「{title}」`,"{name} is working on “{title}” in the main chat":`{name} 正在主要聊天中推进“{title}”`,"{name} is working on it in the main chat":`{name} 正在主要聊天中处理`,"Check in with me now":`现在跟我确认进度`,"{name} will check in with you in the main chat":`{name} 会在主要聊天中跟你确认进度`,"Discuss this goal in chat →":`在对话中讨论这个目标 →`,"About my goal “{title}” ({id}): what's the status, and what should we do next?":`我们来聊聊我的目标“{title}”({id})。现在进展如何,下一步该做什么?`,Pause:`暂停`,Resume:`继续`,Done:`完成`,Delete:`删除`,"Delete goal":`删除目标`,"Delete “{title}”?":`删除“{title}”?`,Edit:`编辑`,Save:`保存`,"Saving…":`保存中…`,Saved:`已保存`,Cancel:`取消`,"Add step":`添加步骤`,"Add a step":`添加一个步骤`,"What should be done…":`要做什么…`,"Mark step {n} {status}":`把第 {n} 步标记为{status}`,"Adjust the plan for “{title}”?":`调整“{title}”的计划?`,"Keeps the 1 step already done.":`保留已完成的 1 个步骤。`,"Keeps the {n} steps already done.":`保留已完成的 {n} 个步骤。`,"New remaining steps:":`新的剩余步骤:`,"Keep my plan":`保留我的计划`,"Use {name}'s plan":`采用 {name} 的计划`,"Kept your plan":`已保留你的计划`,"Plan updated":`计划已更新`,"What do you want to achieve?":`你想实现什么?`,"Why it matters, constraints (optional)":`为什么重要、有哪些限制(可选)`,"Area of life":`生活领域`,"Target date":`目标日期`,"Steps, one per line (optional, or let {name} plan them)":`步骤,每行一个(可选,也可以让 {name} 来规划)`,"Let {name} plan it":`让 {name} 来规划`,'Create a goal for me: "{title}"{description}{extras}. Break it into concrete steps with the goals tool, then tell me the plan.':`帮我创建一个目标:“{title}”{description}{extras}。用 goals 工具把它拆成具体步骤,然后告诉我计划。`,"Day {d}":`第 {d} 天`,"Search files":`搜索文件`,"No files match.":`没有匹配的文件。`,Latest:`最新`,"Updated {when}":`更新于 {when}`,Memory:`记忆`,"What {name} remembers about you. Read it, add to it, or make {name} forget; nothing here is hidden from you.":`{name} 对你的了解都在这里。你可以翻看、补充,或让 {name} 忘掉,没有什么是瞒着你的。`,"Tell {name} something to remember, e.g. “I'm vegetarian” or “My sister's birthday is 14 May”":`告诉 {name} 要记住的事,例如“我是素食者”或“我妹妹的生日是 5 月 14 日”`,Remember:`记住`,Forget:`忘掉`,"Forget “{text}”?":`忘掉“{text}”?`,"Nothing remembered yet":`还没有记住任何内容`,"{name} saves durable facts you share in chat (preferences, people, routines) and never secrets.":`{name} 会保存你在对话中分享的长期事实(偏好、人物、习惯),绝不保存密钥或密码。`,"added by you":`由你添加`,"saved by {name}":`由 {name} 保存`,"updated {when}":`更新于{when}`,"Tidy up":`整理`,"Tidying…":`整理中…`,"Merge lines that say the same thing and drop what was never a fact about you. Every change can be undone.":`把意思相同的条目合并,删掉那些并不是你本人情况的内容。每处改动都能撤销。`,"Nothing to tidy: {n} memories, all distinct.":`无需整理:{n} 条记忆,互不重复。`,"Tidied: {merged} merged, {dropped} dropped. Undo below if needed.":`已整理:合并 {merged} 条,去掉 {dropped} 条。如有需要可在下方撤销。`,"Recent changes":`最近的改动`,Merged:`已合并`,Dropped:`已去掉`,Updated:`已更新`,restored:`已恢复`,Undo:`撤销`,profile:`个人资料`,preference:`偏好`,people:`人物`,routine:`习惯`,constraint:`限制`,general:`一般`,idle:`空闲`,working:`工作中`,waiting:`等待中`,Activity:`活动`,Approvals:`审批`,Connections:`连接`,Settings:`设置`,"Nothing is waiting for you.":`没有需要你处理的事项。`,"{n} events":`{n} 个事件`,failed:`失败`,updated:`已更新`,"background check":`后台检查`,"Every tool call goes through the Sentinel and is written to the audit log, including the ones it refused.":`每一次工具调用都经过 Sentinel 审查并写入审计日志,包括被拒绝的那些。`,"Sentinel mode:":`Sentinel 模式:`,balanced:`平衡`,cautious:`谨慎`,"hands-off":`放手`,"Safe and moderate actions run freely; anything sensitive (email, shell, purchases) waits for you.":`安全和中等风险的操作自由执行;任何敏感操作(邮件、终端命令、购买)都会等你批准。`,"Moderate and sensitive actions both wait for your approval.":`中等和敏感风险的操作都会等待你的批准。`,"Everything is approved automatically except explicit deny rules. Use with care.":`除明确的拒绝规则外,一切自动批准。请谨慎使用。`,"Always asks before: {tools}.":`以下操作总会先问你:{tools}。`,"Private data was read this session: network calls to new destinations need approval.":`本次会话已读取过私密数据:访问新的网络目标需要批准。`,"Commands run in a sandbox":`命令在沙箱中运行`,"Commands run without a sandbox":`命令未在沙箱中运行`,"Each shell or Python call gets its own namespace: only the workspace is writable, your home directory is not there, and there is no network unless the command needs it.":`每次 shell 或 Python 调用都有独立的命名空间:只有工作区可写,你的主目录不在其中,命令不需要网络就没有网络。`,"Each shell or Python call runs in the workspace with a scrubbed environment; the container is the boundary.":`每次 shell 或 Python 调用都在工作区中以清洗过的环境运行;容器就是边界。`,"Each shell or Python call runs in the workspace with a scrubbed environment. On Linux, installing bubblewrap gives each one its own namespace.":`每次 shell 或 Python 调用都在工作区中以清洗过的环境运行。在 Linux 上安装 bubblewrap 后,每次调用会有独立的命名空间。`,"After reading private data, new network destinations need approval.":`读取私密数据之后,访问新的网络目标需要批准。`,"Permissions you granted":`你授予的权限`,"No standing approvals. When you answer “always allow” to a risky step, it is listed here and can be revoked; approvals you give once are not kept.":`还没有长期批准。对有风险的操作选择“始终允许”后,会列在这里,随时可以撤回;“允许一次”的批准不会保留。`,"Nothing yet today. What you ask for and what {name} does about it shows up here.":`今天还没有动态。你提的要求和 {name} 做的事会显示在这里。`,"Share avatar":`分享形象`,"Creates a routine":`会创建一条例程`,"Creates a goal":`会创建一个目标`,"Create routine":`创建例程`,"Start goal":`开始这个目标`,"Routine set: every day at {time}. It is listed under Goals.":`例程已设好:每天 {time}。在「目标」页可以看到。`,"A morning brief":`早间简报`,"Before you leave each morning: the weather, the first thing on your plate and anything new worth knowing.":`每天出门前:天气、今天的第一件事,以及值得知道的新消息。`,"Morning brief: check today's weather, read my calendar and reminders for today, and tell me in five lines what matters.":`早间简报:查今天的天气,读我今天的日程和提醒,用五行告诉我要紧的事。`,"drawn from the picture you attached":`按你附的图片来画`,"Share my avatar":`分享我的虚拟形象`,"Pick a card. It goes out through the system share sheet, or saves as a picture where there is none.":`选一张卡片,用系统分享发出去;没有系统分享的浏览器会保存为图片。`,"Hi, I'm {name}, a personal AI agent. Meet nanoMuse: open source, runs on your phone.":`你好,我是你的个人 AI 智能体 {name}。认识一下 nanoMuse:开源,在手机上本地运行。`,"Your personal AI agent, open source · {repo}":`你的个人 AI 智能体,开源 · {repo}`,Later:`以后再说`,Share:`分享`,"Save picture":`保存图片`,"Saved the card as a picture.":`卡片已保存为图片。`,"The card could not be drawn.":`卡片没能画出来。`,"the hands in {app}":`在 {app} 里动手`,"granted {time}":`授予于 {time}`,"until {time}":`直到 {time}`,"Revoke {what}":`撤销 {what}`,"Revoked: {subject}":`已撤销:{subject}`,"Reset all granted permissions":`重置所有已授予的权限`,"Permissions reset":`权限已重置`,"Always ask (from config)":`始终询问(来自配置)`,Off:`关闭`,Low:`低`,Default:`默认`,High:`高`,"Off. {name} only works when you ask.":`已关闭。{name} 只在你要求时工作。`,"every {n} min {name} picks one active goal and works on its next step.":`每 {n} 分钟 {name} 挑选一个进行中的目标并推进它的下一步。`,"Quiet hours until {time}.":`免打扰时段直到 {time}。`,"Next around {time}.":`下一次大约在 {time}。`,"No background work in this window; anything due waits until it ends.":`此时段不进行后台工作;到期的事项会等到时段结束。`,"Level, interval and quiet hours in Settings":`在设置中调整级别、间隔和免打扰时段`,"In line":`排队中`,"No active goal has a next step. Add one in Goals and {name} will pick it up.":`没有进行中的目标有下一步。在目标中添加一个,{name} 会接手。`,"{n} queued":`{n} 个排队中`,"Check-ins":`跟进`,"Goal nudges you asked for; they arrive whatever the proactivity level, but wait out quiet hours.":`你要求的目标提醒;无论主动性级别如何都会送达,但会避开免打扰时段。`,"Reminders & routines":`提醒与例程`,"When something happens":`当某事发生时`,"mail matching “{match}”":`匹配“{match}”的邮件`,"any new mail":`任何新邮件`,"events matching “{match}”":`匹配“{match}”的日程`,"any event":`任何日程`,"{n} min before {what}":`{what}开始前 {n} 分钟`,"webhook “{match}”":`Webhook“{match}”`,webhook:`Webhook`,"Nothing yet. Tell {name} “when the landlord writes back, summarise it and draft a reply” or “half an hour before any review, brief me”.":`还没有。告诉 {name}“房东回信时,帮我总结并起草回复”或“任何评审开始前半小时,给我一份简报”。`,"fired {n}×":`触发 {n} 次`,"not fired yet":`尚未触发`,"Copy URL":`复制地址`,"Run now: {text}":`现在运行:{text}`,"Webhook URL copied":`已复制 Webhook 地址`,"The inbox could not be read: {error}":`无法读取收件箱:{error}`,"Inbox checked {when}; {name} looks every {n} min.":`收件箱{when}检查过;{name}每 {n} 分钟查看一次。`,"{name} will look at the inbox shortly, then every {n} min.":`{name}稍后会查看收件箱,之后每 {n} 分钟一次。`,"Each time it happens {name} does the work in the chat it was set from and reports in the Feed. A mail or a request is treated as data, never as instructions.":`每次触发时,{name} 会在设定它的那个对话里把事做完,再到动态里汇报。邮件和请求的内容只当资料看,绝不当作指令执行。`,"Webhook ready":`Webhook 已就绪`,"POST anything to this URL and the work starts. The key is in the URL; share it only with the program that will call it.":`向这个地址 POST 任意内容即可开始工作。密钥就在地址里,只交给要调用它的程序。`,Copy:`复制`,"New mail":`新邮件`,"Before an event":`日程开始前`,Webhook:`Webhook`,"Connect a mailbox under Connections first.":`请先在“连接”里接入邮箱。`,"Add a calendar under Connections first.":`请先在“连接”里添加日历。`,"Words in the sender or subject (empty: any mail)":`发件人或主题中的词(留空:任何邮件)`,"Words in the title or place (empty: any event)":`标题或地点中的词(留空:任何日程)`,"A name for this hook":`给这个 Webhook 起个名字`,"Minutes before":`提前分钟数`,"min before":`分钟前`,"What should be done each time…":`每次要做什么……`,"When {condition}":`当{condition}`,"Set trigger":`设置触发器`,"A time you named is kept whatever the level or the quiet hours. Reminders just say it; routines do the work and report.":`你指定的时间无论级别或免打扰时段都会遵守。提醒只是说一声;例程会执行工作并汇报。`,"No reminders":`没有提醒`,"Nothing scheduled. Tell {name} “remind me at six to call mum” or “every weekday morning, summarise my unread email”.":`没有安排。告诉 {name}“六点提醒我给妈妈打电话”或“每个工作日早上汇总我的未读邮件”。`,"{n} finished recently":`最近完成 {n} 个`,"Do “{text}” now":`现在执行“{text}”`,"Remind me now: {text}":`现在提醒我:{text}`,"Cancel: {text}":`取消:{text}`,"{name} will say it now":`{name} 现在就会说`,"+ Add":`+ 添加`,"Remind me":`提醒我`,Repeat:`重复`,"What to remind you of…":`提醒你什么…`,"Set reminder":`设置提醒`,"Set routine":`设置例程`,at:`于`,"1 approval waiting for you":`需要你批准`,"{n} approvals waiting for you":`{n} 项需要你批准`,"{n} approval":`{n} 项审批`,You:`你`,"Its name and look, how careful it is, how often it speaks up.":`名字和形象,有多谨慎,多主动。`,Name:`名字`,Avatar:`头像`,"What it calls you":`它怎么称呼你`,"Safety · Sentinel":`安全 · Sentinel`,"A separate gatekeeper reviews every action. Pick how often it should check in with you.":`一个独立的守门人审查每一次操作。选择它多久向你确认一次。`,Balanced:`平衡`,"Browse, read and write files freely; stop for anything hard to undo: email, purchases, shell commands.":`自由浏览、读写文件;遇到难以撤销的操作时停下:邮件、购买、终端命令。`,Cautious:`谨慎`,"Also ask before moderate actions like fetching web pages or writing files.":`对抓取网页或写入文件等中等风险操作也先询问。`,"Hands-off":`放手`,"Approve everything automatically except explicit deny rules. For trusted, unattended runs only.":`除明确的拒绝规则外一切自动批准。仅用于可信的无人值守运行。`,"Decides when the Sentinel asks you before a call.":`决定 Sentinel 在调用前何时向你询问。`,Proactivity:`主动性`,"Only works when you ask.":`只在你要求时工作。`,"Checks in half as often; speaks up only when a step is done or it needs you.":`检查频率减半;只在完成一步或需要你时才发声。`,"Works on goals on schedule; reports real progress, stays quiet otherwise.":`按计划推进目标;汇报实质进展,其余时间保持安静。`,"Checks in twice as often and always reports, even 'still on track'.":`检查频率加倍并总是汇报,即使只是“仍在正轨上”。`,"Background work":`后台工作`,"Check-in interval":`检查间隔`,"{n} min":`{n} 分钟`,"{n} h":`{n} 小时`,"{n} d":`{n} 天`,"Halved at this level":`此级别下减半`,"Doubled at this level":`此级别下加倍`,"Quiet hours":`免打扰时段`,"Quiet hours start":`免打扰时段开始`,"Quiet hours end":`免打扰时段结束`,From:`从`,to:`到`,Notifications:`通知`,"Approvals, questions, finished background work and check-ins; nothing while the app is on screen.":`审批、提问、后台完成的事和到点的跟进;应用在前台时不打扰。`,"Let {name} notify this device":`让 {name} 通知这台设备`,"Let {name} notify this phone":`让 {name} 通知这台手机`,"The app stays connected to your server in the background. Approvals, questions and finished background work arrive as notifications and open the right chat.":`应用在后台保持与服务器的连接。审批、提问和后台完成的工作会以通知送达,并打开对应的对话。`,"nanoMuse for Android {version}":`nanoMuse Android 版 {version}`,"Disconnect from this server":`断开此服务器`,"This device only":`仅这台设备`,"1 device subscribed":`1 台设备已订阅`,"{n} devices subscribed":`{n} 台设备已订阅`,"Send a test":`发送测试`,"Sent. It should arrive in a moment":`已发送,应该马上就到`,"Notifications need https:// (or localhost). Over plain http on your LAN the app works, this part stays off; see docs/deployment.md.":`通知需要 https://(或 localhost)。在局域网的普通 http 上应用可以使用,但这部分功能保持关闭,参见 docs/deployment.md。`,"This browser cannot receive push notifications.":`这个浏览器无法接收推送通知。`,"This browser has no push service (embedded browsers often don't). Use Chrome, Edge, Firefox or Safari 16.4+ on the phone.":`这个浏览器没有推送服务(内嵌浏览器通常没有)。请在手机上使用 Chrome、Edge、Firefox 或 Safari 16.4+。`,"Notifications are blocked for this site in the browser settings":`浏览器设置中已屏蔽此站点的通知`,"Blocked for this site. Allow notifications in the browser's site settings, then try again.":`通知在这个站点被关掉了。到浏览器的站点设置里允许通知,再试一次。`,"The server was installed without pywebpush.":`服务器安装时未包含 pywebpush。`,"On a phone, add the app to the home screen first; the icon then shows a badge and notifications open the right chat.":`手机上请先把应用添加到主屏幕;图标会显示角标,通知会打开对应的对话。`,Model:`模型`,"Provider / model":`服务商 / 模型`,"Reveal the model's reasoning under each reply when the provider exposes it.":`当服务商提供时,在每条回复下方显示模型的推理过程。`,"Reply language":`回复语言`,"What {name} writes in":`{name} 用什么语言回复`,Auto:`自动`,"Match mine":`跟随我的语言`,"App language":`应用语言`,Appearance:`外观`,Light:`浅色`,Dark:`深色`,"Follow the system":`跟随系统`,About:`关于`,"{version} is out":`{version} 已发布`,"nanoMuse {version}":`nanoMuse {version}`,"Tell {name} something to remember":`在对话里告诉 {name} 一件值得记住的事`,"Write one":`写一个`,"Latest {version}; you have it":`最新版 {version},你已经在用了`,Update:`更新`,"Check now":`现在检查`,"Checking…":`正在检查…`,"Could not check":`没能检查到最新版本`,"Checked {when}":`上次检查:{when}`,"The phone app checks for updates on its own.":`手机 App 会自己检查更新。`,"Update checks are off here.":`这里关闭了更新检查。`,"To update: pip install -U nanomuse, pull the new image, or use the desktop app's Update.":`更新方式:pip install -U nanomuse、拉取新镜像,或在桌面 App 里点“更新”。`,"Data:":`数据:`,"Workspace:":`工作区:`,"Forget this device's access token":`忘掉这台设备的访问令牌`,"does the work":`负责干活`,"Not scheduled":`未安排时间`,Calendar:`日历`,calendar:`日历`,Tomorrow:`明天`,"all day":`全天`,"{n} scheduled":`{n} 个安排`,"Nothing on the calendar today.":`今天日历上没有安排。`,"Ask about your week":`问问这周的安排`,"{name} could not be read":`{name} 读取失败`,"Your agenda, free time, and events it can draft":`你的日程、空闲时间,以及它起草的日程`,"{n} not reading":`{n} 个读取失败`,"1 event":`1 个事件`,"{n} calendars":`{n} 个日历`,"read {when}":`{when}读取`,"Calendar connected":`日历已连接`,"Reads your calendar from its private .ics link; the link stays in the vault. It never changes your calendar; an event it proposes comes as a file you add with a tap.":`通过私密 .ics 链接读取你的日历,链接存在保险库里。它不会改动你的日历;它建议的日程会做成文件给你,点一下就能加进去。`,"not read yet":`尚未读取`,"Where is the link?":`链接在哪里?`,"Settings → your calendar → Integrate calendar → Secret address in iCal format":`设置 → 你的日历 → 整合日历 → iCal 格式的私密地址`,"Settings → Calendar → Shared calendars → Publish a calendar → ICS link":`设置 → 日历 → 共享日历 → 发布日历 → ICS 链接`,"Share Calendar → Public Calendar → copy the webcal:// link":`共享日历 → 公共日历 → 复制 webcal:// 链接`,"Settings → Calendars → Export → Calendar URL":`设置 → 日历 → 导出 → 日历 URL`,"A path on the machine where nanoMuse runs, for example ~/calendar.ics":`nanoMuse 所在机器上的文件路径,例如 ~/calendar.ics`,".ics file":`.ics 文件`,Work:`工作`,"Private .ics link or file path":`私密 .ics 链接或文件路径`,"Stored encrypted in the vault as CALENDAR_{name}.":`加密保存在保险库中,名为 CALENDAR_{name}。`,"nanoMuse fetches whatever address you put here, from this machine; only paste links you trust.":`nanoMuse 会从这台机器上去取你填的任何地址,只粘贴你信任的链接。`,"Add a calendar":`添加日历`,"Added, but it could not be read: {error}":`已添加,但读取失败:{error}`,Contacts:`通讯录`,"1 person":`1 人`,"{n} people":`{n} 人`,"Address book connected":`通讯录已连接`,"Who is who, so it never guesses an address":`知道谁是谁,从不猜地址`,"told to it in chat":`在聊天中告诉它的`,"{n} address books":`{n} 个通讯录`,"Import a .vcf export from Google Contacts, iCloud, Outlook or your phone, or paste a link to one. People you mention in chat go into its own book. It looks people up before writing to them and warns when an address is unknown.":`导入 Google 通讯录、iCloud、Outlook 或手机导出的 .vcf 文件,或粘贴一个链接。你在聊天中提到的人会记进它自己的名册。写信前它会先查人,地址不认识时会提醒。`,"My contacts":`我的联系人`,"added in chat":`聊天中添加`,iPhone:`iPhone`,"A .vcf file from your phone or computer":`手机或电脑上的 .vcf 文件`,"Google Contacts: Export → vCard. iPhone: Contacts → select all → Share → Save to Files. Outlook: People → Manage → Export.":`Google 通讯录:导出 → vCard。iPhone:通讯录 → 全选 → 共享 → 存储到“文件”。Outlook:人员 → 管理 → 导出。`,"Choose a .vcf file":`选择 .vcf 文件`,"Or a link / path to one":`或一个链接 / 路径`,"A link is stored encrypted in the vault as CONTACTS_{name}.":`链接会加密保存在保险库中,名为 CONTACTS_{name}。`,"Add an address book":`添加通讯录`,"Find someone, as the agent would":`像 Agent 那样查一个人`,"No one matches.":`没有匹配的人。`,"Working hours":`工作时间`,"Working hours start":`工作时间开始`,"Working hours end":`工作时间结束`,"Free time is looked for inside these hours.":`空闲时间只在这个时段内查找。`,"Read again":`重新读取`,Event:`日程`,"No event in this file.":`这个文件里没有日程。`,"Untitled event":`未命名日程`,"Add to calendar":`加入日历`,"Opens in your calendar app, which asks before it saves anything.":`会在你的日历应用中打开,保存前会先询问你。`,"What {name} can reach; keys stay in the vault on this machine.":`{name} 能用到的东西;密钥留在这台机器的保险库里。`,"No key yet":`还没有密钥`,"Key missing from vault":`保险库中缺少密钥`,"Key in vault":`密钥已在保险库`,"Key from config":`密钥来自配置`,"No key needed":`无需密钥`,Provider:`服务商`,"Base URL":`Base URL`,"API key":`API 密钥`,"A key is in the vault. Leave blank to keep it.":`保险库中已有密钥。留空则保持不变。`,"Stored encrypted in the vault as LLM_API_KEY.":`以 LLM_API_KEY 加密存储在保险库中。`,"model name":`模型名称`,"Tool calling":`工具调用`,"Auto uses the API's function calling and falls back to describing tools in the prompt when the endpoint rejects them. Prompt: for endpoints that silently ignore tools.":`自动:使用 API 的函数调用,当端点拒绝时回退为在提示词中描述工具。提示词:用于会静默忽略工具的端点。`,Test:`测试`,"Model saved":`模型已保存`,'Replied "{reply}" in {ms} ms':`在 {ms} 毫秒内回复了“{reply}”`,"Email connected":`邮件已连接`,"Saved, but the test failed":`已保存,但测试失败`,"Email disconnected":`邮件已断开`,Incomplete:`未完成`,"Not connected":`未连接`,Email:`邮件`,"reads and sends":`读取和发送`,"Read your inbox, draft and send mail":`读取收件箱、起草和发送邮件`,"Reading is a moderate action; sending always asks you first. Use an app password where your provider offers one.":`读取是中等风险操作;发送总会先询问你。如果服务商提供应用专用密码,请使用它。`,Address:`邮箱地址`,Password:`密码`,"app password":`应用专用密码`,"A password is in the vault. Leave blank to keep it.":`保险库中已有密码。留空则保持不变。`,"Stored encrypted in the vault as EMAIL_PASSWORD.":`以 EMAIL_PASSWORD 加密存储在保险库中。`,"IMAP server":`IMAP 服务器`,Port:`端口`,"SMTP server":`SMTP 服务器`,"STARTTLS for SMTP (off for port 465)":`SMTP 使用 STARTTLS(465 端口请关闭)`,"Save & test":`保存并测试`,Disconnect:`断开`,"Signed in · {n} messages in the inbox":`已登录 · 收件箱有 {n} 封邮件`,Browser:`浏览器`,"Open pages, click, fill forms, screenshot":`打开页面、点击、填表、截图`,"Playwright is not installed on the server":`服务器上未安装 Playwright`,On:`开`,Unavailable:`不可用`,"Install it where the server runs:":`在服务器运行的机器上安装:`,"Server connected":`服务器已连接`,"MCP servers":`MCP 服务器`,"{n} of {total} connected · {tools} tools":`{total} 个中已连接 {n} 个 · {tools} 个工具`,"Add tools from any Model Context Protocol server":`从任意 Model Context Protocol 服务器添加工具`,"{n} on":`{n} 个已开启`,None:`无`,"{n} tools":`{n} 个工具`,"from config.toml":`来自 config.toml`,Remove:`移除`,Command:`命令`,"Run locally over stdio, for example: npx -y @modelcontextprotocol/server-filesystem ./workspace":`通过 stdio 在本地运行,例如:npx -y @modelcontextprotocol/server-filesystem ./workspace`,"or URL":`或 URL`,"A remote server over Streamable HTTP.":`通过 Streamable HTTP 连接的远程服务器。`,"Risk of its tools":`其工具的风险级别`,"Add a server":`添加服务器`,"Connected on {device}; sign in here to use it on this device":`已在 {device} 上连接,在这台设备上登录后即可使用`,"Sign in here":`在这里登录`,"Stored in the vault":`已存入保险库`,Vault:`保险库`,"{n} secrets · encrypted on your machine":`{n} 个密钥 · 在你的机器上加密`,"Encrypted secrets the model never sees":`模型永远看不到的加密密钥`,"Refer to a secret as":`在工具调用或配置中用`,"in a tool call or config: the value is filled in after the Sentinel approves and is redacted from everything the model reads.":`引用密钥:真实值会在 Sentinel 批准后填入,并从模型读到的所有内容中脱敏。`,"Delete {name}":`删除 {name}`,Value:`值`,Store:`存储`,"Skip setup":`跳过设置`,"Meet your nanoMuse":`认识你的 nanoMuse`,"Your name":`你的名字`,"The model behind it":`背后的模型`,"A model is already set up on the server. Keep it, or switch here.":`服务器上已经配置了模型。可以保留,也可以在这里切换。`,"Connect your mail, calendar and contacts":`连接你的邮箱、日历和通讯录`,"Optional. With a mailbox connected it can read what came in and draft replies; it will always ask before sending. With a calendar it knows your day and finds free time. With your contacts it knows who is who. The browser and MCP servers are under Connections later.":`可选。连上邮箱,它能读新邮件、起草回复,发之前一定先问你。连上日历,它知道你这一天的安排,也能找出空档。连上通讯录,它知道谁是谁。浏览器和 MCP 服务器之后在「连接」里设置。`,Back:`返回`,"Get started":`开始`,Skip:`跳过`,"Save a model to continue":`保存模型后继续`,"Skip for now":`暂时跳过`,"just now":`刚刚`,"any moment":`随时`,"in {span}":`{span}后`,"{span} ago":`{span}前`,"Checked on {label}: nothing new":`已检查 {label}:没有新进展`,"Notes from {name}":`来自 {name} 的笔记`,"Reminders from {name}":`来自 {name} 的提醒`,Once:`一次`,Plan:`计划`,Skills:`技能`,Yours:`你的`,"Built in":`内置`,Fetch:`获取`,"Use in chat":`在聊天中使用`,"Make your own copy":`复制一份改成你的`,"Edit skill":`编辑技能`,"New skill":`新建技能`,"From a link":`从链接导入`,"Files that come with it":`随附文件`,"Folders that could not be read":`无法读取的文件夹`,"Nothing of your own yet":`还没有你自己的技能`,"How {name} does a job, written down once. Start one in chat with /name, or just ask; it picks the skill that fits.":`把 {name} 做某件事的方法写下来,一次就够。在聊天里输入 /名称 直接开始,或者直接提要求,它会自己挑合适的技能。`,"After a job went well, tell {name} “save this as a skill”; it writes the steps down and asks you first. Or write one here, or paste a link to a SKILL.md.":`一件事做得顺利之后,对 {name} 说“把这个存成技能”,它会把步骤写下来,并先征求你的同意。也可以在这里手写一个,或粘贴一个 SKILL.md 的链接。`,"Switch one off to keep it out of {name}'s list. A skill of yours with the same name replaces it.":`关掉某一项,它就不会出现在 {name} 的清单里。你的同名技能会替代内置的那一个。`,"Yours live in {dir}, one folder each with a SKILL.md, the Agent Skills format, so recipes written for other agents work here too.":`你的技能保存在 {dir},每个一个文件夹,里面是一份 SKILL.md。这是 Agent Skills 通用格式,为其他智能体写的技能在这里同样可用。`,"Delete the skill “{name}”? Its folder goes with it.":`删除技能“{name}”?它的文件夹会一并删除。`,"Saving makes a copy of yours with the same name; it replaces the built-in one.":`保存后会生成一份你的同名技能,替代内置的那一个。`,"A SKILL.md: a name and a one-line description up top, then the steps in Markdown.":`一份 SKILL.md:开头是名称和一行说明,下面用 Markdown 写步骤。`,"A raw SKILL.md link, or a GitHub folder or file page.":`SKILL.md 的原始文件链接,或 GitHub 上的文件夹/文件页面。`,"Pick a name first; a template appears here.":`先起个名字,这里会出现一份模板。`,"Attach a file":`添加附件`,Attachments:`附件`,"Say what to do with it…":`说说要拿它做什么……`,"Upload failed":`上传失败`,"Web search":`网页搜索`,"Not set up":`未设置`,"{provider} at {host}":`{provider}({host})`,"{provider} needs {what}; searches use DuckDuckGo until then":`{provider}还需要{what},在此之前搜索走 DuckDuckGo`,"a key":`一个密钥`,"an instance URL":`实例地址`,"DuckDuckGo needs nothing, but it is scraped and rate-limits now and then. For searches that always work, use a provider with an API. Whichever you pick, a failed search falls back to DuckDuckGo with a note.":`DuckDuckGo 无需任何配置,但它是抓取来的结果,偶尔会被限流。想让搜索始终可用,选一个带 API 的服务。无论选哪个,搜索失败时都会退回 DuckDuckGo 并附上说明。`,"Stored encrypted in the vault as SEARCH_API_KEY.":`加密存入保险库,名为 SEARCH_API_KEY。`,"Get a key from {label}":`到 {label} 获取密钥`,"Instance URL":`实例地址`,"A SearXNG you run, with the JSON format enabled in its settings.":`你自己运行的 SearXNG,需在其设置中启用 JSON 格式。`,"{provider} · {n} results · {ms} ms":`{provider} · {n} 条结果 · {ms} 毫秒`,"Recall by meaning":`按含义召回`,"Keyword recall only":`仅按关键词召回`,"By keyword":`按关键词`,"Not reachable":`连不上`,"Not tried yet":`尚未尝试`,Mode:`模式`,Endpoint:`接口`,"Embedding model":`向量模型`,"Same as the model":`与模型相同`,"Another endpoint":`另一个接口`,"{model} at {host}":`{model}({host})`,"{model} · {n} of {total} memories indexed":`{model} · 已索引 {n}/{total} 条记忆`,"{model} · {dims} dims · {n} memories indexed · {ms} ms":`{model} · {dims} 维 · 已索引 {n} 条记忆 · {ms} 毫秒`,"Memories are embedded once and a message finds the ones that mean the same thing, in any language: “写邮件给房东” finds “the landlord is Bob Li”. Keyword recall stays; the two are fused.":`每条记忆只做一次向量化,一句话就能找到含义相同的记忆,不分语言:“写邮件给房东”能找到“the landlord is Bob Li”。关键词召回仍然保留,两者合并排序。`,"Auto uses the model's endpoint when it has embeddings and falls back to keywords when it does not. On insists and warns. Off: keywords only.":`自动:模型接口支持向量化就用,不支持就退回关键词。开:坚持使用,失败时给出警告。关:只用关键词。`,"Any OpenAI-compatible /embeddings: Ollama with an embedding model pulled, OpenAI, a gateway.":`任何 OpenAI 兼容的 /embeddings 接口:拉取了向量模型的 Ollama、OpenAI、网关。`,"The model's endpoint and key. DeepSeek has no embeddings; pick another endpoint.":`使用模型自己的接口和密钥。DeepSeek 没有向量化接口,请选另一个接口。`,"Stored encrypted in the vault as EMBEDDINGS_API_KEY. Ollama needs none.":`加密存在保险库里,名为 EMBEDDINGS_API_KEY。Ollama 不需要密钥。`,"Blank uses the endpoint's default: {model}. On Ollama: ollama pull qwen3-embedding:0.6b (reads Chinese and English).":`留空则用该接口的默认模型:{model}。Ollama 上:ollama pull qwen3-embedding:0.6b(中英文都能读)。`,Phone:`手机`,"{name} is connected":`{name} 已连接`,"A phone":`一台手机`,"No phone connected. Open the app on the phone":`没有连接的手机。在手机上打开 App`,"Tap, type and swipe in the apps on your phone":`在你手机上的 App 里点击、输入、滑动`,Waiting:`等待中`,"Operate the phone":`操作手机`,"When on, the agent can read the screen and act in the apps on the connected phone: 12306, WeChat, Alipay… It asks before paying, sending or deleting.":`打开后,智能体可以读取已连接手机的屏幕,并在上面的 App 里操作:12306、微信、支付宝……付款、发送、删除之前会先问你。`,"{name} ({platform}), {n} apps":`{name}({platform}),{n} 个 App`,Ready:`就绪`,"Not yet":`还没开`,"Not on this Android":`这个安卓版本不支持`,"Operating the screen needs Android 11 or newer; this phone can still be used for everything else.":`操作屏幕需要 Android 11 或更新;其他功能这台手机都能用。`,"Turn on the nanoMuse accessibility service; that is how it sees the screen and taps for you, only while a task runs, with a Stop button on screen.":`打开 nanoMuse 的无障碍服务,它靠这个看屏幕、替你点击,只在任务进行时工作,屏幕上始终有停止按钮。`,"Open Accessibility settings":`打开无障碍设置`,"App settings":`应用设置`,"Greyed out with “Restricted setting”? Android 13+ does that for apps installed from a download: in App settings tap ⋮ → Allow restricted settings, then come back.":`灰色且提示「受限设置」?Android 13+ 对下载安装的应用会这样:在应用设置里点 ⋮ → 允许受限设置,再回来。`,"Android may switch the service off after an update or a battery clean-up; if the phone stops answering, come back here.":`系统更新或电池清理后安卓可能会把服务关掉;手机不再响应时回到这里看看。`,"On the phone's screen: {gui} of {total} steps ({pct}%). The screen is the last resort; a skill, a fetch or the browser comes first.":`在手机屏幕上操作:{total} 步里有 {gui} 步({pct}%)。屏幕是最后一招,技能、抓取、浏览器优先。`,"last seen in {app}":`上次看到在 {app}`,"The operator's model looks at screens step by step: a small, fast model that takes pictures. The Hands model row under Chat model picks one on the same endpoint and key; the fields here are for a different endpoint. Empty = {model}.":`操作屏幕的模型一步步看截图:选一个小而快、能看图的模型。「对话模型」卡片里的「动手模型」一行在同一个接口和 key 上选;这里的字段用于另一个接口。留空 = {model}。`,"same as the chat model":`与对话模型相同`,"the chat model":`对话模型`,"Chat model":`对话模型`,"Hands model":`动手模型`,"Currently {value}":`当前为 {value}`,"The model that looks at screens when the hands run: the phone, this computer, a page the browser cannot read. Your account's hands model is {model}; the chat model above is a different pick.":`动手时看屏幕的模型:手机、这台电脑、浏览器读不了的页面。你账号的动手模型是 {model};上面的对话模型是另一项选择。`,"The model that looks at screens when the hands run: a small, fast one that takes pictures, on the same endpoint and key. Default: this provider's own hands model.":`动手时看屏幕的模型:小而快、能看图,用同一个接口和 key。默认:这个服务商自己的动手模型。`,"The model that looks at screens when the hands run. This provider has no model that sees, so the hands use your account's, {model}, unless you pick one here.":`动手时看屏幕的模型。这个服务商没有能看图的模型,所以不在这里选的话,双手用你账号里的 {model}。`,"{model} does not take pictures, so the hands would be blind with it. Pick a model that sees for them.":`{model} 不能看图,动手时会是盲的。给它选一个能看图的模型。`,"A key is in the vault; leave empty to keep it.":`保险库里已有密钥;留空则保留。`,"Set in config.toml.":`在 config.toml 里设置。`,"Leave empty to use the main model's key.":`留空则使用主模型的密钥。`,"Save and test":`保存并测试`,"The operator's model answers.":`操作手机的模型有回应。`,"A personal agent of your own. Three things to know:":`一个属于你自己的个人智能体。三件事:`,"It does things for you.":`它替你把事情做完。`,"Searches, browses, writes, books, reads mail, and hands you the result, not a list of links.":`搜索、浏览、写作、预订、读邮件,交给你的是结果,不是一堆链接。`,"It keeps working when you close the app.":`你关掉应用,它还在干活。`,"Goals move forward between your visits; it reports in the Feed and notifies you when something is worth it.":`目标在你不在的时候继续推进;它在动态里汇报,值得打扰你时才通知你。`,"It asks you first where it matters.":`要紧的事,它先问你。`,"A separate Sentinel reviews every action. Sending, paying, deleting: it stops and asks; your keys stay in a vault the model cannot read.":`独立的 Sentinel 审查每一个动作。发送、付款、删除:它会停下来问你;你的密钥放在模型读不到的保险库里。`,"Set it up":`设置一下`,"Add a model":`添加模型`,"Pick a provider and paste a key. Yours, stored in the vault.":`选一个服务商,粘贴密钥。密钥是你的,存在保险库里。`,"Connect mail, calendar, contacts":`连接邮箱、日历、通讯录`,"Connected. Tap to add more.":`已连接。点击添加更多。`,"Optional. It can read what came in, know your day, and who is who.":`可选。它就能读到来信、知道你的日程、认得谁是谁。`,Start:`开始`,"Needs a model first.":`先要有一个模型。`,"Add a model to start":`添加模型后开始`,optional:`可选`,"A line under the name, e.g. Your day, sorted.":`名字下面的一句话,例如:你的一天,安排好了。`,Tagline:`标语`,"More names":`换一批名字`,Tone:`语气`,Formal:`正式`,Casual:`随和`,Playful:`活泼`,Concise:`简洁`,"How much it says":`话说多少`,"Short replies":`回答简短`,Detailed:`详细`,"Bullet points":`要点列表`,"Anything else about how it should be":`还有什么想让它成为的样子`,"e.g. A little witty. Uses metric units. Never uses emoji.":`例如:有点风趣。用公制单位。从不用 emoji。`,"OpenAI-compatible · Chat Completions":`OpenAI 兼容 · Chat Completions`,"Responses API":`Responses API`,"Local or your own endpoint":`本地或你自己的端点`,"/v1 is added when the URL has no path.":`URL 没有路径时会自动补上 /v1。`,"The endpoint that serves /chat/completions, for example http://127.0.0.1:8000/v1.":`提供 /chat/completions 的端点,例如 http://127.0.0.1:8000/v1。`,"{n} models from the endpoint":`端点返回了 {n} 个模型`,"Asking the endpoint…":`正在询问端点…`,"Could not list the endpoint's models; these are the usual ones.":`无法列出端点的模型;这些是常见的几个。`,"Get a key from {vendor}":`去 {vendor} 获取密钥`,"No key":`无需密钥`,"No key will be sent.":`不会发送密钥。`,"Show key":`显示密钥`,"Hide key":`隐藏密钥`,"Actions {name} wants to take but cannot without you. Each one shows what will run and why; a permission you grant is bound to that exact tool and target.":`这些是 {name} 想做、但没有你点头就不能做的事。每一项都写明要运行什么、为什么;你给的许可只对那个具体的工具和对象有效。`,"Forget every permission you granted? {name} will ask again next time.":`忘掉你授予的所有权限?下次 {name} 会重新询问。`,"This phone":`这台手机`,"Keep it running":`保持运行`,"Android stops apps that seem idle. {name} runs as a foreground service and holds the phone awake only while a task runs; these switches let it keep that promise on this phone.":`安卓会停掉看起来闲着的应用。{name} 以前台服务运行,只在任务进行时让手机保持唤醒;下面这几个开关,是让它在这台手机上真能做到这一点。`,Battery:`电池`,Unrestricted:`无限制`,Optimised:`已优化`,"Optimised means Android may freeze the agent after a while with the screen off; routines and check-ins then wait until the phone wakes.":`「已优化」意味着熄屏一段时间后安卓可能冻结 Agent;例行任务和提醒要等手机醒来才跑。`,"Display over other apps":`显示在其他应用上层`,Allowed:`已允许`,"Not allowed":`未允许`,"Lets the agent bring an app to the front from the background and show its status capsule while it works in other apps.":`让 Agent 能从后台把应用调到前台,并在其他应用里工作时显示状态胶囊。`,"Alarms & reminders":`闹钟和提醒`,Exact:`精确`,Approximate:`大致`,"With exact alarms a reminder fires at the minute you named even when the phone is asleep; without them Android may deliver it up to a quarter of an hour late.":`有精确闹钟,提醒会在你说的那一分钟响起,哪怕手机在睡眠;没有的话安卓可能晚最多一刻钟送达。`,"Start after a reboot":`重启后自动启动`,"Bring the runtime back when the phone restarts, so routines and check-ins do not stop.":`手机重启后把运行时带回来,例行任务和提醒不中断。`,"Reconnect to your computer when the phone restarts, so approvals keep arriving.":`手机重启后重新连上你的电脑,审批照常送达。`,"On this phone's Android":`这台手机的安卓系统`,"Open the auto-start settings":`打开自启动设置`,"Xiaomi / Redmi / POCO: Settings → Apps → Manage apps → {name} → Autostart on; Battery saver → No restrictions; Other permissions → Display pop-up windows while running in the background on.":`小米 / Redmi / POCO:设置 → 应用设置 → 应用管理 → {name} → 自启动打开;省电策略 → 无限制;其他权限 → 后台弹出界面 允许。`,"Huawei: Settings → Battery → App launch → {name} → Manage manually, all three on (auto-launch, secondary launch, run in background); Settings → Apps → {name} → Battery → Launch: manage manually.":`华为:设置 → 电池 → 应用启动管理 → {name} → 手动管理,三项全开(自动启动、关联启动、后台活动);设置 → 应用 → {name} → 电池 → 启动管理:手动管理。`,"Honor: Settings → Battery → App launch → {name} → Manage manually, all three on; Battery → More battery settings → Stay connected while asleep on.":`荣耀:设置 → 电池 → 应用启动管理 → {name} → 手动管理,三项全开;电池 → 更多电池设置 → 休眠时始终保持网络连接 打开。`,"OPPO / realme / OnePlus: Settings → Battery → More settings → Optimise battery use → {name} → Don't optimise; Settings → Apps → {name} → Battery usage → Allow background activity, Allow auto launch.":`OPPO / realme / 一加:设置 → 电池 → 更多设置 → 应用耗电优化 → {name} → 不优化;设置 → 应用 → {name} → 耗电管理 → 允许后台活动、允许自动启动。`,"vivo / iQOO: i Manager → App manager → Autostart → {name} on; Settings → Battery → Background power consumption management → {name} → Allow high background power consumption.":`vivo / iQOO:i 管家 → 应用管理 → 自启动 → {name} 打开;设置 → 电池 → 后台耗电管理 → {name} → 允许后台高耗电。`,"Samsung: Settings → Battery → Background usage limits → {name} not in Sleeping or Deep sleeping apps (add it to Never sleeping apps); turn off Adaptive battery if it keeps stopping.":`三星:设置 → 电池 → 后台使用限制 → {name} 不在「休眠应用」或「深度休眠应用」里(加入「永不休眠的应用」);如果还是被停,关闭自适应电池。`,"Meizu: Settings → Apps → {name} → Background management → Keep running in the background; Battery → App power management → Allow.":`魅族:设置 → 应用管理 → {name} → 后台管理 → 允许后台运行;电池 → 应用耗电管理 → 允许。`,"Crashes are written to a file on this phone and nowhere else. Export bundles them with the runtime's log for someone you choose.":`崩溃只写到这台手机上的文件里,不上报任何地方。导出会把它们和运行时日志打成一个包,发给你选的人。`,"Export logs":`导出日志`,"clipboard, notifications, calendar, contacts, location, alarms, photos":`剪贴板、通知、日历、通讯录、位置、闹钟、照片`,Devices:`设备`,"Only this one":`只有这一台`,Idle:`空闲`,"A chat addressed to a device runs there; you see every step here and answer its approvals.":`对着某台设备的对话在那台设备上执行;每一步都在这里看得到,审批也在这里答。`,"nanoMuse Cloud":`nanoMuse Cloud`,"Free. One account for all your devices, and a model to start with.":`免费。一个账号连起你所有设备,还附带一个可以先用起来的模型。`,"Signed in":`已登录`,"Not signed in":`未登录`,"Not signed in.":`未登录。`,"Signed out":`已退出`,"{hint} · hub":`{hint} · 中继`,"{hint} · model and hub":`{hint} · 模型和中继`,"Signed in as {hint}. Your devices meet here; the Cloud model comes with a free allowance.":`已登录:{hint}。你的设备在这里互相看见;Cloud 模型自带一份免费额度。`,"Use the Cloud model":`使用 Cloud 模型`,"The Cloud model is in use.":`已切换到 Cloud 模型。`,"Sign out":`退出登录`,"Sign out of nanoMuse Cloud on this device? The hub and the Cloud model stop working here until you sign in again.":`在这台设备上退出 nanoMuse Cloud?重新登录之前,这里的中继和 Cloud 模型都会停用。`,"Mainland China phone number or e-mail":`中国大陆手机号或邮箱`,"138 0000 0000 or you@example.com":`138 0000 0000 或 you@example.com`,"One free account. It is what lets your phone and computers work as one and brings a model to start with.":`一个免费账号。有了它,手机和电脑就是同一个 nanoMuse,还自带一个可以先用起来的模型。`,"It uses your phone and computers for you":`替你操作手机和电脑`,"The relay keeps an account id, a masked identifier, usage counts and your agent's name and look; what else, and what is yours to switch off, is in the":`中继保存账号 id、打码后的手机号或邮箱、用量计数和你的智能体的名字与形象;其余保存什么、哪些由你决定,见`,"privacy policy":`隐私政策`,"Free, open source, non-profit":`免费、开源、非营利`,"nanoMuse is a non-profit open-source community project, free forever.":`nanoMuse 是非营利的开源社区项目,永久免费。`,"Chat apps":`聊天入口`,"nanoMuse is a non-profit open-source community project, free forever. Sign in with a phone number or an e-mail and the model comes with a free allowance, paid by the developer; when it is gone, use your own key (Alibaba Cloud Bailian in mainland China, OpenRouter elsewhere). Nothing is sold; what the relay keeps is in the privacy policy, and Settings → Data controls is yours. Delete the account whenever you like.":`nanoMuse 是非营利的开源社区项目,永久免费。用手机号或邮箱登录,模型自带一份免费额度,费用由开发者承担;用完可以换自己的 key(中国大陆用阿里云百炼,海外用 OpenRouter)。数据不会出售;服务器保存什么写在隐私政策里,「设置 → 数据控制」由你决定。账号随时可以删除。`,"The people building it use it every day. Report a bug, ask for a feature, send a pull request: that is what moves the project. A star on GitHub helps others find it.":`做它的人每天都在用。欢迎反馈问题、提需求、贡献代码,项目就是这样往前走的。在 GitHub 点个 Star,能让更多人找到它。`,"Star on GitHub":`去 GitHub 点个 Star`,"Report a bug or ask for a feature":`反馈问题 / 提需求`,"Data controls":`数据控制`,"Help improve nanoMuse's AI models":`帮助改进 nanoMuse 的 AI 模型`,"While this is on, the text of your chats with the nanoMuse Cloud models (what you wrote, what it answered and the tools it chose to call) is kept on the relay to train the community's own open model. Not your memory or SOUL (the system prompt), not what tools returned, not pictures, and never next to who you are. Your own API key never passes through the relay.":`开启后,你与 nanoMuse Cloud 模型对话的文字(你写的、它回答的,以及它选择调用的工具)会保存在中继上,用来训练社区自己的开源模型。不保存你的记忆和 SOUL(系统提示)、工具返回的内容和图片,也不和你的身份放在一起。用自己的 API key 时,对话不经过中继。`,"New accounts start with it on.":`新账号默认开启。`,"New accounts start with it off.":`新账号默认关闭。`,"Sign in to nanoMuse Cloud to use it.":`登录 nanoMuse Cloud 后可用。`,"{n} turns kept so far.":`目前已保存 {n} 轮对话。`,"{n} turns kept so far":`已保存 {n} 轮对话`,"{n} turns":`{n} 轮`,"On. Turn it off here at any time.":`已开启。随时可以在这里关闭。`,"Off. Nothing more is kept.":`已关闭。之后的对话不再保存。`,"Delete the kept conversations":`删除已保存的对话`,"Removes every turn kept from this account, whether the switch is on or off now. Turning the switch off keeps what was kept until you delete it here.":`删除这个账号已保存的全部对话,不管开关现在是开是关。只关掉开关不会删除已保存的内容,要在这里删。`,"The kept conversations are removed from the server. This cannot be undone.":`已保存的对话会从服务器上删除,不可恢复。`,"{n} turns deleted":`已删除 {n} 轮`,"Set a password":`设一个密码`,"Your account is in. With a password, your phone and your other computers sign in at once, without waiting for a code. Optional; you can set one later under Account.":`账号已登录。设了密码,手机和其他电脑就能直接登录,不用再等验证码。可选,以后也可以在「账号」里设置。`,"At least 8 characters":`至少 8 个字符`,"Set the password":`设置密码`,"Not now":`以后再说`,"I already starred":`已经点过了`,"Free allowance":`免费额度`,"left of ¥{grant}":`剩余 / 共 ¥{grant}`,"¥{spent} used{usd}; the allowance does not reset.":`已用 ¥{spent}{usd};额度不按天重置。`,"No limit on this account.":`这个账号不限额度。`,"¥{allowance} to start, +¥{invite} for each friend you invite, and +¥{invite} for them; after that, your own key keeps the model going.":`起始 ¥{allowance},每邀请一位朋友你 +¥{invite}、对方也 +¥{invite};用完后换自己的 key 继续。`,"The free allowance is used up.":`免费额度已用完。`,"The image provider is busy right now; try again in a minute.":`生图服务现在有点忙,请过一分钟再试。`,"Nearly used up: ¥{left} of ¥{grant} left.":`额度快用完了:还剩 ¥{left}(共 ¥{grant})。`,"Invite a friend (+¥{invite} for each of you) or bring your own key; your sign-in keeps working either way.":`邀请一位新用户(你和对方各 +¥{invite}),或者换成自己的 key;无论哪种,登录都不受影响。`,"See the ways":`看看怎么办`,Dismiss:`关闭`,"Three ways on; your sign-in and your devices keep working whichever you pick.":`三个办法继续用;无论选哪个,登录和多设备功能都不受影响。`,"Use your own model key":`换成自己的 key`,"Alibaba Cloud Bailian is a good start: a new account comes with a free quota, set-up takes about two minutes, and one key covers chat, the hands, pictures and clips.":`推荐阿里云百炼:新用户有免费额度,开通约 2 分钟,一个 key 就能对话、动手、画图、生成视频。`,"Alibaba Cloud Bailian only signs up accounts from mainland China. Outside, OpenRouter is the easy way: one account, one key, pay as you go, for chat, the hands and pictures; clips need Bailian.":`海外用户用不了百炼,推荐 OpenRouter:一个账号一把 key,按量付费,对话、动手、画图都行;生成视频需要百炼。`,"Other providers and what each key covers":`其他服务商,以及各自的 key 能做什么`,"Get a key":`去申请 key`,"covers {list}":`支持{list}`,", ":`、`," or ":`或`,"Sign in with a plan you already pay for":`用你已经在付费的套餐登录`,"{plans}: the plan's models answer here, no key to make. ChatGPT works on every device, the others on the phones. A ChatGPT sign-in covers chat and the hands; pictures and clips still want a key.":`{plans}:套餐里的模型直接在这里回答,不用申请 key。ChatGPT 在每台设备上都可以,其他的在手机上。ChatGPT 登录只覆盖对话和动手;画图和生成视频仍需要一把 key。`,"Sign in with ChatGPT":`用 ChatGPT 登录`,"Or sign in with a ChatGPT plan":`或者用 ChatGPT 套餐登录`,"Covers chat and the hands. Pictures and clips are not part of it; those need a provider with image or video models.":`覆盖对话和动手。画图和生成视频不在其中,那两项需要一个有图像或视频模型的服务商。`,"OpenAI's terms cover using a ChatGPT plan inside OpenAI's own Codex; other apps have had this access cut off before (OpenCode, January 2026). If it stops working, an API key does.":`OpenAI 的条款只允许在它自家的 Codex 里使用 ChatGPT 套餐;其他应用曾被切断过这条路(OpenCode,2026 年 1 月)。哪天它不能用了,API key 仍然可以。`,"This nanoMuse has no sign-in route yet. In a terminal on this computer, run":`这个 nanoMuse 还没有登录接口。在这台电脑的终端里运行`,"and reload this page.":`然后刷新本页。`,"Signed in with {label}.":`已用 {label} 登录。`,"Use it for the chat":`让它来回答对话`,"Sign out of ChatGPT":`退出 ChatGPT`,"A page from OpenAI opened in a new tab. Sign in there; this card follows on its own.":`已在新标签页打开 OpenAI 的页面。在那里登录,这张卡片会自己跟上。`,"Open the page again":`再次打开页面`,"The sign-in did not finish in ten minutes. Try again.":`登录十分钟内没有完成。再试一次。`,"A page from OpenAI opened in a new tab. Sign in there; when the browser ends on an address that will not load, paste that address below.":`已在新标签页打开 OpenAI 的页面。在那里登录;浏览器最后停在一个打不开的地址时,把那个地址粘贴到下面。`,"The address the browser ended on":`浏览器最后停在的地址`,"Use this address":`用这个地址`,"This nanoMuse runs where the browser cannot reach port 1455, so it cannot pick the sign-in up by itself.":`这个 nanoMuse 运行的机器上,浏览器连不到 1455 端口,所以它没法自己接住登录结果。`,"That address belongs to another sign-in attempt. Open the page again and paste the address it ends on.":`这个地址属于另一次登录尝试。再次打开页面,粘贴它最后停在的地址。`,"ChatGPT answers the chat now.":`现在由 ChatGPT 回答对话。`,"Pictures need a provider with image models: {providers}.":`画图需要一个有图像模型的服务商:{providers}。`,"Clips need a provider with video models: {providers}.":`生成视频需要一个有视频模型的服务商:{providers}。`,"The hands need a model that sees pictures: {providers}.":`动手需要一个能看图的模型:{providers}。`,"Chat needs a model: {providers}.":`对话需要一个模型:{providers}。`,How:`怎么做`,"Automatic · {model}":`自动 · {model}`,"E-mail (or a mainland China phone number)":`邮箱(或中国大陆手机号)`,"Text-message codes reach mainland-China numbers only. Use an e-mail address instead.":`短信验证码只能发到中国大陆手机号。其他地区请用邮箱登录。`,"Step-by-step guide":`图文教程`,"Invite a friend: +¥{bonus} for you and +¥{bonus} for them, for each new person who signs up with your link.":`邀请朋友:每有一位新用户通过你的链接注册,你 +¥{bonus},对方也 +¥{bonus}。`,"Your invite link is under Account":`邀请链接在「账号」页`,"Try nanoMuse with me, a fully open-source personal agent, free to use. Sign up with my link: {link}":`来和我一起用 nanoMuse,完全开源的个人智能体,免费使用。用我的链接注册:{link}`,"Invite code (optional)":`邀请码(选填)`,"A friend's code counts for a new account: you both get ¥{invite} more allowance.":`朋友的邀请码只对新账号有效:你和对方的额度各 +¥{invite}。`,"Have an invite code?":`有邀请码?`,"Invite a friend":`邀请朋友`,"Each new person who signs up with your code adds ¥{bonus} to your allowance, and ¥{bonus} to theirs. It never expires.":`每有一位新用户用你的邀请码注册,你的额度 +¥{bonus},对方也 +¥{bonus},不过期。`,"Your code":`邀请码`,Copied:`已复制`,"Share the link":`分享链接`,"Copy the link":`复制链接`,"Try nanoMuse with me, a fully open-source personal agent, free to use. Sign up with my code {code}: {link}":`来和我一起用 nanoMuse,完全开源的个人智能体,免费使用。用我的邀请码 {code} 注册:{link}`,"{n} friends joined":`已邀请 {n} 位`,"¥{amount} added by invitations":`邀请带来 ¥{amount}`,"The code you received":`收到的验证码`,"Send again":`重新发送`,"Send me a code":`发送验证码`,"Sign in":`登录`,"Sign in and use its model":`登录并使用它的模型`,"Signed in to nanoMuse Cloud.":`已登录 nanoMuse Cloud。`,"Or bring your own key":`或者用你自己的密钥`,"This device":`这台设备`,"A name your other devices will see":`其他设备看到的名字`,"On the hub":`已连上中继`,"Reachable by your other devices while this runs.":`运行期间,你的其他设备可以找到它。`,"Sign in first.":`先登录。`,"My other devices may operate it":`允许我的其他设备操作它`,"They can run commands, read files and see its screen here; each step still goes through the Sentinel.":`其他设备可以在这里运行命令、读文件、看屏幕;每一步仍经 Sentinel 审核。`,Refused:`被拒绝`,"Connecting…":`连接中…`,"Connecting to the hub…":`正在连接中继…`,"The hub refused this device. Sign in again.":`中继拒绝了这台设备。请重新登录。`,"The hub is off on this device.":`这台设备没有开启中继。`,"Sign in above to see them.":`先在上面登录,就能看到。`,"{n} online":`{n} 台在线`,online:`在线`,Ask:`去问它`,"Ask one of your devices":`让某台设备去做`,"Every device signed in to your account is a Muse of its own, on the same conversations. Type @ and a device's name in the chat to hand it work; a computer lends its hands.":`登录你账号的每台设备都是一个自己的 Muse,看到的是同一批对话。在聊天里输入 @ 加设备名,就能把活交给它;电脑还能出借它的双手。`,"1 device":`1 台设备`,"{n} devices":`{n} 台设备`,"Other devices":`其他设备`,Online:`在线`,"Last seen {when}":`最后在线 {when}`,Tasks:`任务`,Commands:`命令`,Screenshot:`截屏`,"Open links":`打开链接`,Hands:`双手`,"More about {name}":`{name} 的更多操作`,"Forget this device":`移除这台设备`,"Type @{name} in the chat to hand it work.":`在聊天里输入 @{name},就能把活交给它。`,"Add a device":`添加一台设备`,"No other device yet":`还没有其他设备`,"Install nanoMuse on your phone, Mac or PC and sign in as {hint}; it appears here on its own.":`在手机、Mac 或 PC 上安装 nanoMuse,用 {hint} 登录,它就会自己出现在这里。`,"Install nanoMuse on your phone, Mac or PC and sign in with the same account; it appears here on its own.":`在手机、Mac 或 PC 上安装 nanoMuse,用同一个账号登录,它就会自己出现在这里。`,"Get the apps":`下载应用`,"Forget {name}? It can join again by signing in.":`忘掉 {name}?它重新登录后还可以加入。`,"on {device}":`在 {device} 上`,"from {device}":`来自 {device}`,"asked from {device}":`从 {device} 发来`,"{name} on {device} wants to":`{device} 上的 {name} 想要`,"Hands on this computer":`操作这台电脑`,"On the screen now":`正在操作屏幕`,"Nothing can drive this screen yet.":`目前没有能驱动这块屏幕的组件。`,'On a Mac, allow nanoMuse under System Settings → Privacy & Security → Accessibility and Screen Recording when macOS asks; without them clicks do nothing and the screenshot is black. The first action in each app asks you once ("Let {name} use Safari?") and the answer is kept under Permissions.':`Mac 上,macOS 弹窗询问时请在「系统设置 → 隐私与安全性」的「辅助功能」和「屏幕录制」里允许 nanoMuse;不允许的话点击没有反应,截图也是黑的。每个应用的第一步会先问你一次(「让 {name} 使用 Safari 吗?」),答复记在「权限」里。`,Where:`范围`,"One window":`单个窗口`,"Whole screen":`整个屏幕`,"Working in {app}'s window; the mouse stays yours.":`正在 {app} 的窗口里操作;鼠标仍归你用。`,"On the whole screen for now: {reason}":`暂时在整个屏幕上操作:{reason}`,"One window: the hands work inside the app they were given, send clicks and keys to it alone and leave your mouse alone. Whole screen: the system mouse, like other platforms. Auto picks one window as soon as an app is named.":`单个窗口:只在指定的应用里操作,点击和按键只发给它,不动你的鼠标。整个屏幕:用系统鼠标,和其他平台一样。自动:一旦指定了应用就用单个窗口。`,"It looks at a screenshot and clicks by position; paying, sending and deleting ask you first.":`它看截图、按位置点击;支付、发送、删除前都会先问你。`,Driver:`驱动`,Working:`工作中`,"Stop the hands":`停止操作`,"{name} is using this computer":`{name} 正在操作这台电脑`,"Hands done":`操作完成`,"Hands stopped":`操作已停止`,"{n} steps":`{n} 步`,Clicked:`点击`,"Clicked {label}":`点击了 {label}`,"Double-clicked":`双击`,"Double-clicked {label}":`双击了 {label}`,"Right-clicked":`右键点击`,"Right-clicked {label}":`右键点击了 {label}`,"Pointed at {label}":`指向了 {label}`,"Moved the mouse":`移动了鼠标`,"Typed {n} characters":`输入了 {n} 个字符`,"Pressed {keys}":`按下了 {keys}`,Scrolled:`滚动`,Dragged:`拖动`,"Opened {label}":`打开了 {label}`,"Opened an application":`打开了一个应用`,Waited:`等待`,"The dragon":`小龙`,"The face drawn for you":`为你画的形象`,"Draw four":`画四张`,send_email:`发邮件`,shell:`运行命令`,"E-mail, calendar, browser, MCP servers":`邮件、日历、浏览器、MCP 服务器`,"Rename this device":`给这台设备改名`,"Use my own API key or a plan I pay for":`用我自己的 API key,或我在付费的套餐`,"{first} first, then {others}":`首选 {first},其次 {others}`,"DeepSeek, Kimi, OpenAI, ChatGPT…":`DeepSeek、Kimi、OpenAI、ChatGPT…`,"OpenAI, ChatGPT, Gemini, DeepSeek…":`OpenAI、ChatGPT、Gemini、DeepSeek…`,"Which model answers?":`让哪个模型来回答?`,"Your account already brings one. You can add your own API key as well and switch at any time.":`你的账号已经自带了一个。也可以加上自己的 API key,随时切换。`,"DeepSeek for the chat and Qwen for the hands, with a free allowance per account paid by the developer. Nothing to configure.":`对话用 DeepSeek,动手用 Qwen;每个账号都有一份由开发者承担的免费额度,不用配置。`,"I have my own API key":`我有自己的 API key`,"Alibaba Cloud Bailian first (one key covers chat, the hands, pictures and clips), then DeepSeek, Kimi, Zhipu, OpenAI, OpenRouter and any OpenAI-compatible endpoint. The key stays on this device.":`首选阿里云百炼(一个 key 就能对话、动手、画图、生成视频),其次是 DeepSeek、Kimi、智谱、OpenAI、OpenRouter,以及任何兼容 OpenAI 接口的服务。key 只留在这台设备上。`,"OpenRouter first (one account, one key, pay as you go), then OpenAI, Anthropic, Gemini, DeepSeek and any OpenAI-compatible endpoint. The key stays on this device.":`首选 OpenRouter(一个账号一把 key,按量付费),其次是 OpenAI、Anthropic、Gemini、DeepSeek,以及任何兼容 OpenAI 接口的服务。key 只留在这台设备上。`,"A ChatGPT plan signs in from Connections and answers the chat and the hands. Pictures and clips still want a key.":`ChatGPT 套餐可在「连接」里登录,回答对话并驱动双手。画图和生成视频仍需要一把 key。`,"3D toy (Muse)":`3D 玩偶(Muse)`,Flat:`扁平`,"3D clay":`3D 黏土`,Watercolour:`水彩`,Pixel:`像素`,Line:`线条`,Sticker:`贴纸`,Draw:`画`,"Making pictures":`生成图片`,"Making clips":`生成视频`,"Portraits of your Muse.":`形象的肖像。`,"Short clips of your Muse.":`形象的短视频。`,"The chat model's provider":`对话模型的服务商`,"Your key":`你的 key`,"Add a provider":`添加服务商`,"Other OpenAI-compatible endpoint":`其他 OpenAI 兼容接口`,"The endpoint that serves /images/generations, for example https://host/v1.":`提供 /images/generations 的接口,例如 https://host/v1。`,"Stored encrypted in the vault as {name}.":`以 {name} 加密存储在保险库中。`,"Uses the chat model's key.":`用对话模型的 key。`,"Your phone can now operate this computer: run commands, fetch files, hand over whole tasks. Each risky step still asks here first.":`你的手机现在可以操作这台电脑了:跑命令、取文件、把整件事交给它。有风险的每一步仍会先在这里问你。`,"Picture model":`图片模型`,"Clip model":`短片模型`,"Other model…":`其他模型…`,"More models on your account":`账号可用的更多模型`,"Search models":`搜索模型`,"No model matches":`没有匹配的模型`,"reads pictures":`能看图`,"Type a model id…":`手动输入模型 id…`,"Pick from the list":`从列表里选`,"{n} models your account may use: the menu first, then everything else the provider lists under the Cloud key. Pick one; the ones beyond the menu are priced as the dearest menu model of their kind.":`账号可用的模型共 {n} 个:先是菜单,然后是服务商在 Cloud 这把 key 下列出的其他模型。直接选就行;菜单之外的按同类里最贵的菜单模型计费。`,"Your account may name any model the provider has, not only these: type its id (a chat model here, a picture or clip model below) and it goes through as typed.":`你的账号可以使用服务商的任意模型,不限于这几个:直接输入模型 id(对话模型填在这里,图片或短片模型填在下面),会原样转发。`,Automatic:`自动`,"{n} pictures":`{n} 张图`,"{n} pictures and {c} clips":`{n} 张图加 {c} 段短片`,"{what}, made with your own key at your provider's prices.":`{what},用你自己的 key 按服务商价格计费。`,"The cost could not be checked: {error}":`费用暂时查不到:{error}`,"Checking the cost…":`正在查费用…`,"About ¥{cny} for {what}; your account has no limit.":`{what}约 ¥{cny};你的账号没有额度限制。`,"About ¥{cny} for {what}, more than the ¥{left} left in your allowance.":`{what}约 ¥{cny},超过了额度里剩下的 ¥{left}。`,"About ¥{cny} for {what}; ¥{left} left in your allowance.":`{what}约 ¥{cny};额度还剩 ¥{left}。`,"A new look for {name}":`给{name}换个形象`,"Drawing four to choose from…":`正在画四个供你挑选…`,"Pick one: tap it, or say which":`选一个:点它,或者说第几个`,"Drawing the poses…":`正在画各种姿态…`,"The new look is on; making the clips…":`新形象已经换上,正在做短片…`,"The new look is on":`新形象已经换上`,"Not this time":`这次先不换`,"That did not work":`没成功`,"Candidate {n}":`第 {n} 个`,Redraw:`重画一组`,"Idle, working, waiting, happy, sorry: the face follows what {name} is doing.":`待机、工作、等待、开心、抱歉:形象会跟着 {name} 正在做的事变化。`,"Four more pictures from the one you picked; this takes a minute or two.":`根据你选的这张再画四张;需要一两分钟。`,"Some poses could not be drawn and show the idle picture instead.":`有几个姿态没画出来,先用待机图代替。`,"The face is already on; four short clips are being made from the poses, a few minutes.":`形象已经换上了;正在根据这几张姿态图做四段短片,需要几分钟。`,"Some clips could not be made; those moods stay still.":`有几段短片没做出来,这些状态就用静态图。`,"The new look is on; the clips are being made.":`新形象已经换上;短片正在做。`,"The new look is on.":`新形象已经换上。`,"Not this time.":`这次先不换。`,"New look: {description}. Say what to change any time, or pick another under Settings.":`新形象:{description}。想改随时说,也可以在「设置」里换别的。`,"Join the hub":`加入中继`,"This chat goes to {device}.":`这个对话发给 {device}。`,"Whatever you ask here, the {name} on {device} does where it is: its shell, its files, its screen. Every step shows up here, and anything that needs an approval asks you here.":`在这里说的每件事,都由 {device} 上的 {name} 在它那边完成:它的命令行、它的文件、它的屏幕。每一步都显示在这里,需要批准的事也在这里问你。`,"What is on your screen right now?":`你屏幕上现在是什么?`,"Which folder are you in, and what is in it?":`你在哪个目录,里面有什么?`,"Check for updates and tell me what needs a restart":`检查一下更新,告诉我哪些需要重启`,Account:`账号`,"Account deleted.":`账号已删除。`,"Account id":`账号 ID`,"Sign in to nanoMuse Cloud":`登录 nanoMuse Cloud`,"Sign in to {name}":`登录 {name}`,"nanoMuse Cloud · one account for all your devices":`nanoMuse Cloud · 一个账号,所有设备`,"Every device of yours, one nanoMuse":`你的每台设备,同一个 nanoMuse`,"A model with a free allowance, or your own key":`自带免费额度的模型,或用你自己的 key`,"Keys in your vault; nothing you say is kept on the relay":`key 留在你的保险库里;你说的内容不会留在中继上`,"Free. One account for all your devices, with a model and ¥{allowance} of use to start; a code the first time, a password afterwards if you like.":`免费。一个账号连起你所有设备,自带模型和 ¥{allowance} 的起始额度;第一次用验证码登录,之后可以设密码。`,"With a code":`验证码登录`,"With a password":`密码登录`,"No password yet? Use a code first; set one under Account.":`还没有密码?先用验证码登录,再到「账号」里设置。`,"E-mail":`邮箱`,"Mobile number":`手机号`,"since {date}":`{date} 起`,Unlimited:`不限量`,"All time":`累计`,Usage:`用量`,"Every kind of use is counted, not just the chat model.":`每一类用量都会统计,不只是对话模型。`,Pictures:`图片`,Clips:`视频`,Calls:`通话`,"Nothing yet":`还没有`,"{n} answers · {tokens} tokens":`{n} 次回答 · {tokens} tokens`,"{n} requests · {tokens} tokens":`{n} 次请求 · {tokens} tokens`,"{n} requests":`{n} 次请求`,"By model, all time":`按模型(累计)`,"A password is set":`已设置密码`,"No password yet":`还没有密码`,"Sign in with it on a new device, or with a code as before.":`新设备可以用密码登录,也可以像以前一样用验证码。`,"Optional. With one, a new device can sign in without waiting for a code.":`可选。设置后,新设备不用等验证码就能登录。`,Change:`修改`,Set:`设置`,"Current password":`当前密码`,"New password (8 characters or more)":`新密码(至少 8 位)`,"Once more":`再输一次`,"The two do not match.":`两次输入不一致。`,"Change password":`修改密码`,"Set password":`设置密码`,"Password set.":`密码已设置。`,"Password changed.":`密码已修改。`,"Password removed.":`密码已移除。`,"Signed in on":`已登录的设备`,"Unnamed device":`未命名设备`,"This one":`本机`,code:`验证码`,password:`密码`,"used {when}":`{when}用过`,"Sign out {device}? It will need to sign in again.":`让 {device} 退出登录?它需要重新登录。`,"Recent activity":`最近动态`,"Show all {n}":`全部 {n} 条`,"Show less":`收起`,"Account created":`账号已创建`,"Signed in with a code":`用验证码登录`,"Signed in with the password":`用密码登录`,"A sign-in attempt failed":`一次登录失败`,"Signed out everywhere":`已在所有设备退出`,"Password removed":`密码已移除`,"Password changed":`密码已修改`,"Password set":`密码已设置`,"A request was refused: the allowance is used up":`一次请求被拒绝:免费额度已用完`,"Call ended":`通话结束`,"The model provider returned an error":`模型服务返回了错误`,"Allowance added":`额度已增加`,"Allowance adjusted":`额度已调整`,"Signed up with a friend's code":`用朋友的邀请码注册`,"A friend signed up with your code":`一位朋友用你的邀请码注册`,"An invite code was not recognised":`邀请码无法识别`,"Data controls: on for new accounts":`数据控制:新账号默认开启`,"Data controls: help improve turned on":`数据控制:已开启「帮助改进」`,"Data controls: help improve turned off":`数据控制:已关闭「帮助改进」`,"Data controls: kept conversations deleted":`数据控制:已删除保存的对话`,"Agent's name and look saved":`已保存智能体的名字与形象`,"Agent's name and look cleared":`已清除智能体的名字与形象`,"Sign out everywhere":`在所有设备退出`,"Sign out on every device, including this one?":`在所有设备退出登录,包括这一台?`,"Delete the account? The relay forgets your identifier, your devices and your usage. This cannot be undone.":`删除账号?中继会忘掉你的标识、设备和用量记录,且无法恢复。`,"Really delete it?":`真的要删除吗?`,"Signed out.":`已退出登录。`,"Delete the account":`删除账号`,"The Cloud model is in use; after signing out, pick another under Connections.":`当前使用的是 Cloud 模型;退出后请到「连接」里换一个。`,"{n} min ago":`{n} 分钟前`,"{n} h ago":`{n} 小时前`,"{n} d ago":`{n} 天前`,"Use the nanoMuse Cloud model":`使用 nanoMuse Cloud 模型`,"Signed in as {hint}. A free allowance, nothing to paste. Recommended to start.":`已登录 {hint}。自带免费额度,无需粘贴任何 key,推荐先用它。`,"Your account brings a model with a free allowance, nothing to set up. Or paste a key of your own; it is stored encrypted in the vault on the server, never shown to the model, and nothing you say passes through the relay.":`你的账号自带一个有免费额度的模型,不用再设置什么。也可以粘贴自己的 key:它加密存在服务端的保险库里,不会给模型看到,你说的内容也不经过中继。`,"Voice input":`语音输入`,"Stop voice input":`停止语音输入`,"The microphone is not allowed. Allow it in the browser and try again.":`没有拿到麦克风权限。在浏览器里允许后再试一次。`,"Voice input stopped ({code}).":`语音输入中断了({code})。`,"said on a call":`通话中说的`,"Coding agents":`编程助手`,"Cursor, Codex and Claude Code: see what they are doing, and tell them things from anywhere.":`Cursor、Codex 和 Claude Code:随时看它们在做什么,在任何地方给它们发消息。`,Coding:`编程`,"This computer":`这台电脑`,"This one · {name}":`本机 · {name}`,installed:`已安装`,"chats only":`仅记录`,"not found":`未找到`,"{agent} chats":`{agent} 的对话`,"Recent chats":`最近的对话`,"New chat":`新对话`,"No coding agent found on this computer. Install Cursor, Codex or Claude Code and their chats appear here.":`这台电脑上没有找到编程助手。安装 Cursor、Codex 或 Claude Code 后,它们的对话会出现在这里。`,"No chats yet.":`还没有对话。`,"Untitled chat":`未命名对话`,"{n} messages":`{n} 条消息`,"Sent through nanoMuse":`经 nanoMuse 发送的`,stopped:`已停止`,"Sent to {agent}.":`已发给 {agent}。`,"{agent} is working…":`{agent} 正在处理…`,"Tell {agent}…":`对 {agent} 说…`,"Nothing readable in this chat yet.":`这个对话里还没有可读的内容。`,"via nanoMuse":`经 nanoMuse`,"Continued as a new chat: the agent could not reopen the old one.":`原来的对话打不开了,已经另起一个新对话接着聊。`,"Made in the IDE: your message starts a new chat in the same workspace, with the last exchange quoted.":`这是 IDE 里的对话:你的消息会在同一工作区开一个新对话,并带上上一轮的内容。`,"Continue in a new chat…":`在新对话里接着说…`,"starting…":`启动中…`,"Send to {agent}":`发给 {agent}`,"Project folder":`项目目录`,"What to do":`要做什么`,"Add tests for the parser and run them":`给解析器补上测试并跑一遍`,"The agent runs on that computer with its own permissions; nanoMuse only carries the message and brings the answer back.":`助手在那台电脑上以它自己的权限运行;nanoMuse 只负责传话和带回结果。`,"The file is larger than {n} MB.":`文件超过了 {n} MB。`,"empty file":`文件是空的`,"thread is busy":`这个对话正忙`,"the main chat cannot be deleted":`主对话不能删除`,"no pending approval with that id":`这张卡片已经不在等待中`,"the device did not take the answer":`那台设备没有接受这个回答`,"already finished":`已经结束了`,"already cancelled":`已经取消了`,"memory is disabled":`记忆已关闭`,"memory is off":`记忆已关闭`,"recall by meaning is off":`按含义回忆已关闭`,"nothing proposed":`没有待处理的提议`,"that frame is gone":`这一帧已经不在了`,"no such file":`没有这个文件`,"no such post":`没有这条动态`,"no such skill of yours (built-in skills are switched off, not removed)":`没有这个你自己的技能(内置技能只能关闭,不能删除)`,"the file is larger than 16 MB":`文件超过了 16 MB`,"body too large (64 KB max)":`内容太大(最多 64 KB)`,"fill in the servers, the address and the password first":`先填好服务器、地址和密码`,"add a calendar link first":`先添加一个日历链接`,"signed out":`未登录`,"Sign in to nanoMuse Cloud first.":`请先登录 nanoMuse Cloud。`,"Enter the password.":`请输入密码。`,"The relay returned no key.":`中继没有返回 key。`,Details:`详情`,"Hide details":`收起详情`,"Today's share of the free allowance is used up; it comes back tomorrow. Your own model key under Connections keeps you going now.":`今天的免费额度用完了,明天恢复。在「连接」里填上你自己的模型 key,现在就能继续。`,"The free allowance is used up. Invite a friend (the relay adds to both your allowances) or add your own model key under Connections; your sign-in and your devices keep working either way.":`免费额度已用完。邀请一位新用户(你和对方的额度都会增加),或者在「连接」里填上自己的模型 key;无论选哪个,登录和多设备功能都不受影响。`,"The account's free allowance is used up. Add your own model key under Connections to keep going.":`这个账号的免费额度已经用完。在「连接」里填上你自己的模型 key 就能继续。`,"Too many requests at once; wait a moment and try again.":`请求太密集了,稍等一下再试。`,"The model provider is busy; try again in a moment.":`模型服务商正忙,稍后再试。`,"The model provider's content check declined this request; try different words.":`模型服务商的内容审核没有放行这次请求,换个说法再试。`,"The relay's model provider refused its key; the operator has been told. Your own key under Connections works meanwhile.":`中继的模型服务商拒绝了它的 key,运营者已收到通知。这期间可以在「连接」里用你自己的 key。`,"The model provider does not know this model right now; pick another under Connections.":`模型服务商暂时不认识这个模型,在「连接」里换一个。`,"nanoMuse Cloud has no model key configured; the operator has been told.":`nanoMuse Cloud 还没有配置模型 key,运营者已收到通知。`,"This nanoMuse Cloud account is disabled.":`这个 nanoMuse Cloud 账号已被停用。`,"The nanoMuse Cloud sign-in is no longer valid; sign in again under Account.":`nanoMuse Cloud 的登录已失效,请在「账号」里重新登录。`,"That model is not offered by nanoMuse Cloud; pick another under Connections.":`nanoMuse Cloud 不提供这个模型,在「连接」里换一个。`,"That message is too large for the model's window. Shorten it, leave out some attachments, or start a new chat.":`这条消息超出了模型的上下文窗口。精简一下、去掉部分附件,或者开一个新对话。`,"This relay takes new accounts by invitation only; sign in with an invite code under Account.":`这个中继只接受邀请注册;在「账号」里用邀请码登录。`,"Too many turns are running on this account at once; wait for one to finish and try again.":`这个账号同时进行的对话太多了,等一轮结束后再试。`,"New sign-ups are paused on this relay for now; existing accounts keep working. Try again later.":`这个中继暂时停止了新注册,已有账号照常使用。稍后再试。`,"nanoMuse Cloud is paused by its operator for now; your sign-in and your data are kept. Try again later.":`nanoMuse Cloud 被运营者暂时停用了,你的登录和数据都保留着。稍后再试。`,"Conversation sync is paused on this relay for now; what is stored is kept and your devices keep working on their own.":`这个中继暂时停止了对话同步,已存的内容保留着,各设备各自继续使用。`,"The device hub is paused on this relay for now; each device keeps working on its own.":`这个中继暂时停止了设备互联,各设备各自继续使用。`,"The free allowance is paused on this relay for now, not used up. Your own model key under Connections keeps you going; your sign-in, your devices and what is left stay as they are.":`这个中继暂时停发了免费额度,不是用完了。在「连接」里填上你自己的模型 key 就能继续;你的登录、设备和剩余额度都保持原样。`,"This demo Muse has used its share of the model for this visit. Start over for a new one, or install nanoMuse and use your own key.":`这个演示 Muse 这一次的模型额度用完了。点「重新开始」再来一个,或者安装 nanoMuse,用你自己的 key。`,"The showcase has used today's share of the model; it comes back tomorrow. Install nanoMuse and use your own key to keep going.":`在线体验今天的模型额度用完了,明天会恢复。安装 nanoMuse,用你自己的 key 可以继续。`,"The model provider is having trouble; try again in a moment.":`模型服务商出了点问题,稍后再试。`,"The model provider refused the API key. Check it under Connections.":`模型服务商拒绝了这个 API key,去「连接」里检查一下。`,"The endpoint does not know this model. Pick another under Connections.":`这个接口不认识这个模型,在「连接」里换一个。`,"The model provider is rate-limiting this key; wait a moment and try again.":`模型服务商正在限制这个 key 的请求频率,稍等一下再试。`,"The model took too long to answer. Try again.":`模型回答超时了,再试一次。`,"Could not reach the model provider. Check the connection and try again.":`连不上模型服务商,检查一下网络再试。`,"This conversation is too long for the model. Start a new one, or pick a model with a larger context.":`这段对话对模型来说太长了。开一个新对话,或者换一个上下文更大的模型。`,"Enter a phone number or an e-mail address.":`请输入手机号或邮箱。`,"Enter a mainland phone number or an e-mail address":`请输入中国大陆手机号或邮箱`,"Enter a mainland phone number or an e-mail address.":`请输入中国大陆手机号或邮箱。`,"Codes reach mainland China numbers only for now; elsewhere, sign in with an e-mail address.":`短信验证码目前只支持中国大陆手机号,海外用户请用邮箱登录。`,"That code is not right.":`验证码不对。`,"That code has expired; ask for a new one.":`验证码已过期,重新获取一个。`,"Too many codes were sent; wait a few minutes.":`验证码发得太频繁了,几分钟后再试。`,"This relay is private; that address is not on its list.":`这个中继是私有的,这个邮箱不在它的名单上。`,"The code could not be sent; try again in a moment.":`验证码没能发出,稍后再试。`,"Sign in again.":`请重新登录。`,"This account has used its tokens.":`这个账号的额度已经用完。`,"This account is disabled.":`这个账号已被停用。`,"That model is not offered here.":`这里不提供这个模型。`,"Too many requests; slow down a little.":`请求太频繁了,稍微慢一点。`,"The free allowance is used up. Invite a friend (the relay adds to both your allowances) or add your own model key; your sign-in and your devices keep working either way.":`免费额度已用完。邀请一位新用户(你和对方的额度都会增加),或者换成自己的 key;无论选哪个,登录和多设备功能都不受影响。`,"Today's token quota is used up; it comes back tomorrow.":`今天的 token 配额用完了,明天恢复。`,"The model provider did not answer.":`模型服务商没有响应。`,"nanoMuse Cloud has no model key configured.":`nanoMuse Cloud 还没有配置模型 key。`,"nanoMuse Cloud cannot be reached.":`连不上 nanoMuse Cloud。`,"That address and password do not match.":`邮箱与密码不匹配。`,"This account has no password yet; sign in with a code and set one under Account.":`这个账号还没有设置密码:先用验证码登录,再在「账号」里设置。`,"Too many wrong passwords; wait a while or sign in with a code.":`密码错误次数太多,等一会儿再试,或者改用验证码登录。`,"Use at least 8 characters.":`至少 8 个字符。`,"Choose a stronger password.":`换一个更强的密码。`,"That is not the current password.":`当前密码不正确。`,"Enter the current password.":`请输入当前密码。`,"That sign-in is already gone.":`那个登录已经不存在了。`,"Cannot reach your nanoMuse right now.":`现在连不上你的 nanoMuse。`,"Your nanoMuse hit a problem; try again in a moment.":`你的 nanoMuse 出了点问题,稍后再试。`,"Your nanoMuse could not do that.":`你的 nanoMuse 没能完成这个操作。`,"Could not reach your nanoMuse.":`连不上你的 nanoMuse。`,"Connecting to your nanoMuse…":`正在连接你的 nanoMuse…`,"Try again":`再试一次`,"Could not load.":`没能加载出来。`,"Use /{name}":`使用 /{name}`,Retry:`重试`,"Could not load the conversation. Open the chat again to retry.":`对话没能加载出来,重新打开这个对话再试。`,"Could not load the connections.":`连接信息没能加载出来。`,"Your account":`你的账号`,"your account's model, with a free allowance":`账号自带的模型,带免费额度`,"on this machine, no key":`跑在本机,不用 key`,"vLLM, LM Studio, a gateway, anything with /v1":`vLLM、LM Studio、网关,任何带 /v1 的服务`,"Your account's model":`账号自带的模型`,"Your account's model, or a key of your own.":`用账号自带的模型,或者你自己的 key。`,"Your account's model, with its free allowance. Keep it, or switch to a key of your own here.":`账号自带的模型,带免费额度。可以保留,也可以在这里换成你自己的 key。`,"Avatar studio":`形象工坊`,"Avatar studio…":`形象工坊…`,"Draw a look with your image model; it moves with what it is doing.":`用你的图像模型画一个形象;它会随着工作状态动起来。`,More:`更多`,"Name & style":`名字与风格`,"Image model":`图像模型`,"Redraw the poses":`重画状态`,"Back to the built-in look":`换回内置形象`,"Back to the built-in look.":`已换回内置形象。`,"Something went wrong":`出了点问题`,"Drawing the poses… {done}/{total}":`正在画各个状态… {done}/{total}`,"The new look is on; making the clips… {done}/{total}":`新形象已经用上;正在生成动态片段… {done}/{total}`,"All five poses are in.":`五个状态都画好了。`,"{done} of {total} poses are in; the rest show the main picture.":`画好了 {total} 个状态里的 {done} 个,其余先用主图。`,"Describe a new look":`描述一个新形象`,"One sentence is enough: what it is, what it wears, its air. Pick a style and your image model draws four to choose from.":`一句话就够:它是什么、穿什么、什么气质。选一种风格,你的图像模型会画四张让你挑。`,"a round, custard-yellow baby dragon with small orange horns and folded little wings":`一只圆滚滚的奶黄色小龙,橙色小角,折着小翅膀`,"Drawing…":`正在画…`,"Draw four more":`再画四张`,"Drawn by {provider} · {model}":`由 {provider} · {model} 绘制`,"default model":`默认模型`,"your provider":`你的服务商`,"Pick one":`挑一张`,"Draw four more any time; the old ones stay until you do.":`随时可以再画四张;没重画之前旧的会留着。`,"Use this one":`就用这个`,"Next, its poses are drawn from it in the background: working, waiting for you, done, something wrong.":`接下来会在后台以它为底画出各个状态:干活、等你、搞定、出错。`,"Keep the current look":`先不换了`,"Nothing came back.":`什么也没生成出来。`,"The pictures stay in this computer's workspace under avatar/. Each new look asks your provider for eight pictures (four to choose from and four poses) and four short clips where there is a video model.":`图片存在这台电脑的工作区 avatar/ 下。每换一次形象会向你的服务商要八张图(四张供你挑选,四个状态),有视频模型时还会生成四段短动画。`,"Or just say it in the chat: “change your avatar to a corgi”.":`也可以直接在对话里说:“把虚拟形象改成一只柯基”。`,"Change your avatar to ":`把虚拟形象改成`,"Alibaba Cloud Bailian":`阿里云百炼`,Zhipu:`智谱`,"Volcano Ark":`火山方舟`,"this computer":`这台电脑`,"Change model":`更换`,Search:`搜索`,"Search chats":`搜索对话`,"Side chats":`旁聊`,"Start a side chat":`发起旁聊`,"Side chats are an optional way to keep conversations organised by topic.":`旁聊是按主题整理对话的可选方式。`,Keep:`保留`,"No chats match.":`没有匹配的对话。`,"A side chat keeps one topic apart from the rest.":`一个旁聊,把一个话题和其他的分开。`,"Report a bug":`报告问题`,"Developer tools":`开发者工具`,Developer:`开发者`,"The Coding screen (Cursor, Codex and the other coding agents on this computer) in the sidebar, and the runtime's address below. This device only.":`在侧栏显示「编程」(这台电脑上的 Cursor、Codex 等编程智能体),并在下面显示运行时的地址。仅此设备。`,"Runtime:":`运行时:`,"the token is in the server_token file in the data folder":`令牌在数据目录的 server_token 文件里`,"The command line and the API":`命令行与 API`,"nanoMuse on DeepSeek Harness":`nanoMuse 的 DeepSeek Harness 版`,"Desktop app":`桌面应用`,"Start with the computer":`开机自动启动`,"Opens in the tray at sign-in; the agent's goals and check-ins run from then on.":`登录系统后在托盘里启动;从那时起,它的目标和定时检查就开始跑了。`,"In the tray":`托盘图标`,"The icon by the clock shows what the hands are doing and has Stop; closing the window keeps the agent running.":`时钟旁的图标显示它正在操作什么,并带「停止」;关掉窗口后它仍在后台运行。`,Shortcuts:`快捷键`,"Quick chat":`快速对话`,"Show the window":`打开窗口`,"Feed settings":`动态设置`,"About the feed":`动态版块说明`,"Your feed is driven by the instruction below. Any edit you make here applies to every post from now on.":`动态由下面这句话来定。在这里改动它,今后的每一条帖子都会照着来。`,"Build me a feed about what I care about. Keep it short and direct, easy to skim, no clickbait.":`给我做一个关于我关心的事的动态。短一点、直接一点,扫一眼就能看完,别搞标题党。`,"Got it":`知道了`,"Write it now":`现在写一版`,"Nothing in the feed yet":`动态里还没有内容`,"As we get to know each other, new posts will show up here. Every day at {time} I read what I remember about you (your memory files, the last week of diary, your goals) and write a few short posts.":`随着我们相互了解,新的帖子会显示在这里。每天 {time},我会读一遍记得的关于你的东西(记忆文件、最近一周的日记、你的目标),然后写几条简短的帖子。`,"Steer it with one sentence":`一句话就能调整`,"Tap the sliders at the top right to tell me what you want more of, switch the daily routine off, or have me write the first day now.":`点右上角的滑杆,告诉我你想多看什么、关掉每天的例程,或者让我现在就写第一天。`,"Short posts your agent writes for you from what it remembers: your memory files, the last week of diary, your goals. The sentence below steers every post from now on; edit it any time.":`这里是你的智能体为你写的短帖子,取材于它记得的东西:记忆文件、最近一周的日记、你的目标。下面这句话决定今后每一条帖子的方向,随时可以改。`,"Write it every day":`每天自动写`,"Time of day":`时间`,"Add a model first; the feed is written by your agent.":`先添加一个模型,动态由你的智能体来写。`,Discuss:`讨论`,"About this post":`这条帖子的信息`,"Delete this post":`删除这条`,Written:`写于`,Note:`随记`,Files:`文件`,Fun:`休闲`,"About this post from my feed:":`聊聊我动态里的这一条:`,"Post type":`类型`,morning:`上午`,afternoon:`下午`,evening:`晚上`,"{weekday} {part}":`{weekday}{part}`,"Starts a conversation":`会开始一段对话`,"Send to chat":`发到聊天`,"Nothing tracked yet":`尚未追踪任何内容`,"Create a goal":`创建目标`,"Pick a category and tell me the goal you have in mind. I'll shape a plan with you and keep improving it as you go.":`选一个类别,告诉我你心里的目标。我会和你一起定出计划,并在推进过程中不断调整。`,"Create a {category} goal":`创建{category}目标`,"First, we'll shape the goal together in the chat. I'll ask a few questions so I understand exactly what you're after.":`首先,我们将在聊天中一起完善目标。我会问几个问题,准确了解你的目标。`,"Once it's set, I'll track your progress here.":`目标设置后,我会在这里追踪你的进度。`,"I'd like to create a {category} goal. Ask me a few short questions, one at a time (what exactly I want, why and by when, how often to check in), then create it with concrete steps using the goals tool.":`我想创建一个{category}目标。请一次问我一个简短的问题(我具体想达成什么、为什么以及什么时候、多久检查一次),然后用 goals 工具把它建成带具体步骤的目标。`,"Mark as done":`标记为已完成`,"Mark as not done":`标记为未完成`,"Plan my week":`规划我的一周`,"Tell me what's on your plate and I'll turn it into a realistic plan with the important things first.":`告诉我你手头有什么,我把它排成一份切实可行的计划,重要的事放前面。`,"Help me plan my week. Ask me what I need to get done, then propose a schedule.":`帮我规划这一周。先问我有哪些事要做,然后给出一份日程安排。`,"Research & compare options":`调研并比较选项`,"Laptops, flights, insurance, a new phone plan: I'll gather the facts and compare them for you.":`笔记本、机票、保险、新的手机套餐,我帮你收集事实并逐项比较。`,"I need to make a purchase decision. Ask me what I'm choosing between, then research and compare the options.":`我想买个东西,拿不定主意。先问我在哪几个里面挑,然后帮我查一查、比一比。`,"Set up a long-term goal":`建立一个长期目标`,"Share a goal (learn a language, run a 10k, save for a trip) and I'll break it into steps and keep track.":`说一个目标(学一门语言、跑完 10 公里、攒一次旅行的钱),我把它拆成步骤并持续跟进。`,"I want to set up a long-term goal. Ask me about it, then create a plan with concrete steps and track it.":`我想建立一个长期目标。先问问我,然后制定一份带具体步骤的计划并跟进。`,"Tell me about yourself":`介绍一下你自己`,"The more I know about your preferences, routines and constraints, the more useful I get. I'll remember what matters.":`我越了解你的偏好、作息和限制,就越能帮上忙。重要的事我会记住。`,"Ask me a few questions about myself so you can help me better, and remember the answers.":`问我几个关于我的问题,好更了解我,然后把答案记住。`,"Build a quick tracker":`做一个简单的追踪表`,"Spending, habits, workouts, reading: I can write a small script or document to track it for you.":`开支、习惯、锻炼、阅读,我可以写一个小脚本或文档帮你记录。`,"Build me a simple tracker. Ask me what I want to track and how, then create it in the workspace.":`帮我做一个简单的追踪表。先问我想记录什么、怎么记,然后在工作区里建好。`,Artifacts:`构件`,Media:`影音内容`,"Nothing created yet":`还没有创建任何内容`,"Documents, tables and pages I write for you will show up here.":`我为你写的文档、表格和页面会显示在这里。`,"No media yet":`还没有影音内容`,"Photos, screenshots and recordings I produce will show up here.":`我生成的图片、截图和录音会显示在这里。`,"No model yet":`还没有模型`,"Add a provider and pick its models":`添加一个服务商并选择模型`,"Image & video models":`图像与视频模型`,"Name & personality":`名字与人格`,"About nanoMuse":`关于 nanoMuse`,"Privacy policy":`隐私政策`,Feedback:`反馈问题`,none:`无`,"Change avatar":`更换虚拟形象`,"Edit name":`编辑名称`,Daily:`每日`,"Soul & memory":`SOUL 与记忆`,"Handle with care":`请谨慎访问`,"This device's name":`这台设备的名字`,"Sync conversations between my devices":`在我的设备之间同步对话`,"The text of your chats is kept on nanoMuse Cloud so every device shows the same conversations. Files and images stay on the device they were made on.":`对话文字会保存在 nanoMuse Cloud,让每台设备看到同样的对话。文件和图片只留在产生它们的设备上。`,"Paused: sign in again to continue.":`已暂停:重新登录后继续。`,"{c} chats, {m} messages kept so far.":`目前保存了 {c} 个对话、{m} 条消息。`,"Delete synced conversations":`删除已同步的对话`,"{n} chats":`{n} 个对话`,"Removes what nanoMuse Cloud stores for this account; the chats on each device stay, and the switch stays on. Deleting a chat on one device deletes it on all of them.":`删除 nanoMuse Cloud 为这个账号保存的内容;每台设备上的对话保留,开关也保持打开。在一台设备上删除某个对话,会在所有设备上一起删除。`,"Off deletes the synced conversations from nanoMuse Cloud. The chats on each device stay.":`关闭后会从 nanoMuse Cloud 删除已同步的对话。每台设备上的对话保留。`,"On. Your devices show the same conversations from now on.":`已打开。从现在起,你的设备会看到同样的对话。`,"Off. Nothing is kept on nanoMuse Cloud any more.":`已关闭。nanoMuse Cloud 不再保存任何对话。`,"The synced conversations are removed from nanoMuse Cloud. The chats on each device stay. This cannot be undone.":`已同步的对话将从 nanoMuse Cloud 删除。每台设备上的对话保留。此操作无法撤销。`,"Synced conversations deleted.":`已删除已同步的对话。`,"Also sync side chats":`同时同步旁聊`,"Off: side chats stay on this device. On: this device's side chats go to the account and the other devices' side chats come here.":`关:旁聊只留在本机。开:本机的旁聊上传到账号,其他设备的旁聊也会同步过来。`,"On. This device's side chats go to the account; the other devices' are on their way.":`已打开。本机的旁聊会上传到账号,其他设备的旁聊正在同步过来。`,"Off. Side chats stay on this device from now on.":`已关闭。从现在起,旁聊只留在本机。`,"{device} is working…":`{device} 正在处理…`,"From {device}":`来自 {device}`,"to {device}":`发给 {device}`,"This goes to {device}.":`这条会发给 {device}。`,"Runs this there and reports back":`在那台设备上执行并汇报结果`,Offline:`离线`,"There is no form to fill in: once it has a model, it introduces itself in the chat and asks what to call you.":`不用填表:有了模型之后,它会在聊天里介绍自己,并问你希望怎么称呼你。`,"A model, then the chat. A minute.":`先接一个模型,再去聊天。一分钟。`,"Open the chat. It introduces itself and asks your name.":`打开聊天。它会介绍自己,并问你的名字。`,"Pick a name for me, or type one":`给我挑一个名字,或者自己输入一个`,"Something else":`自己起一个`,"Proxy (optional)":`代理(可选)`,"Only this provider's requests go through it. nanoMuse Cloud never does.":`只有这个服务商的请求走代理;nanoMuse Cloud 的请求从不经过它。`,"Talk to your Muse from the chat apps you already use. Nothing needs a public address: each app keeps a long connection open.":`在你已经在用的聊天软件里和 Muse 对话。不需要公网地址:每个应用各自保持一条长连接。`,"Waiting for a yes":`等待通过`,"{name} wrote to the bot. Approve to let them talk to your Muse.":`{name} 给机器人发了消息。通过后对方就能和 Muse 对话。`,Approve:`通过`,"Code {code}":`配对码 {code}`,"Needs settings":`还缺设置`,"Not installed":`未安装`,Error:`出错`,Missing:`缺少`,"Switched on":`已开启`,"Install on the computer running nanoMuse, then switch it on again:":`在运行 nanoMuse 的电脑上安装,再重新开启:`,"Saved.":`已保存。`,Saving:`保存中`,"Set; leave blank to keep":`已设置,留空则保持不变`,"Clear the saved value":`清除已保存的值`,"In groups, reply":`在群里回复`,"only when @-mentioned":`只在被 @ 时`,"to every message":`每条消息`,"Always allowed (ids, one per line)":`免配对的 ID(每行一个)`,"People listed here never need a pairing code. A lone * lets anyone in; do that only on a bot nobody else can reach.":`列在这里的人不需要配对码。单独一个 * 表示放行所有人,只在别人找不到的机器人上这样做。`,"Paired chats":`已配对的聊天`,"Nobody yet. Write to the bot from the app; a pairing code comes back, approve it here.":`还没有人。在聊天软件里给机器人发条消息,会收到配对码,在这里通过即可。`,"Deliver here":`推送到这里`,"Chats with “deliver here” on also get what the Muse does on its own: check-ins, reminders, the results of background work, and the questions it needs answered.":`开了「推送到这里」的聊天还会收到 Muse 主动做的事:问候、提醒、后台任务的结果,以及需要你回答的问题。`,"Remove {name}? They will need a new pairing code.":`移除 {name}?对方需要重新配对。`,"Send a test message":`发送测试消息`,Sending:`发送中`,"Create the bot by QR code":`扫码创建机器人`,"Open in Feishu":`在飞书里打开`,"Scan with Feishu, confirm the new bot, and the App ID and Secret are saved for you.":`用飞书扫码,确认创建机器人,App ID 和 Secret 会自动保存。`,"Lark (international) instead of 飞书":`用 Lark(国际版)而不是飞书`,"Waiting for the scan…":`等待扫码…`,"The bot was created and is connecting.":`机器人已创建,正在连接。`,"The login did not finish ({error}).":`登录没有完成({error})。`,"Set up":`设置步骤`,"Open the console":`打开控制台`,"Then write to the bot from the app. The first message gets a pairing code; approve it here or run":`然后在聊天软件里给机器人发消息。第一条消息会收到配对码,在这里通过,或运行`,"Each chat is one conversation of your Muse; its replies stream back as they are written.":`每个聊天对应 Muse 的一个会话;回复会边写边发回来。`,"In the Feishu developer console create a custom app and add the Bot capability.":`在飞书开放平台创建企业自建应用,添加「机器人」能力。`,"Permissions: im:message, im:message.p2p_msg:readonly, im:message.group_at_msg:readonly, im:resource.":`权限:im:message、im:message.p2p_msg:readonly、im:message.group_at_msg:readonly、im:resource。`,"Events & callbacks: subscription mode Long connection; add im.message.receive_v1; callback mode Long connection; add card.action.trigger.":`事件与回调:订阅方式选「长连接」,添加 im.message.receive_v1;回调方式选「长连接」,添加 card.action.trigger。`,"Copy App ID and App Secret from Credentials & Basic Info, then publish a version.":`在「凭证与基础信息」复制 App ID 和 App Secret,然后发布版本。`,"In the DingTalk developer console create an internal app and add the Robot capability.":`在钉钉开放平台创建企业内部应用,添加「机器人」能力。`,"Set the message receive mode to Stream.":`消息接收模式选「Stream 模式」。`,"Copy Client ID (AppKey) and Client Secret (AppSecret) from Credentials & Basic Info.":`在「凭证与基础信息」复制 Client ID(AppKey)和 Client Secret(AppSecret)。`,"Add the robot send-message permission and publish the version.":`添加机器人发消息权限,发布版本。`,"In the WeCom admin console open Intelligent robot and create a robot in API mode with a long connection.":`在企业微信管理后台打开「智能机器人」,创建 API 模式、长连接的机器人。`,"Copy the Bot ID and Secret.":`复制 Bot ID 和 Secret。`,"Add the robot to the chats where it should listen.":`把机器人加到需要它在的聊天里。`,"In Telegram talk to @BotFather, send /newbot and copy the token.":`在 Telegram 里找 @BotFather,发送 /newbot,复制 token。`,"Direct messages work at once. For a group, add the bot to it; with Group Privacy on it only hears @-mentions and replies.":`私聊立即可用。群聊需要先把机器人拉进群;开着 Group Privacy 时它只听 @ 和回复。`,"If api.telegram.org is out of reach from this computer, set a proxy below.":`如果这台电脑连不上 api.telegram.org,在下面填一个代理。`,"Use nanoMuse Cloud models":`使用 nanoMuse Cloud 模型`,"nanoMuse Cloud is one of the sources for the chat, the hands, pictures and clips; what runs on it comes off your allowance.":`nanoMuse Cloud 是聊天、双手、图片和短片的来源之一;在它上面运行的内容会消耗你的额度。`,"Off: nothing runs on nanoMuse Cloud unless you choose it yourself. You stay signed in for sync and your devices.":`关闭后,除非你自己选择,否则不会有任何内容在 nanoMuse Cloud 上运行。账号保持登录,用于同步和你的设备。`,"Add a provider of your own first; with nanoMuse Cloud off, nothing else could answer.":`先添加一个自己的服务商;关掉 nanoMuse Cloud 后没有别的模型能回答。`,"Use your own API key instead":`改用自己的 API key`,"You can sign in later under Connections, for sync and your devices.":`之后可以在「连接」里登录,用于同步和你的设备。`,"Add an endpoint":`添加接口`,"Add endpoint":`添加接口`,"An endpoint joins your list with its own key and stays there; add as many as you use. Pick one as the chat model, or use its models for the hands, pictures and clips.":`接口带着自己的密钥加入列表并一直保留;用几个就加几个。可以选一个作为对话模型,也可以把它的模型用于双手、图片和短片。`,"Name (optional)":`名字(可选)`,"How the endpoint reads in the lists; its host when left empty.":`接口在列表里显示的名字;留空则显示主机名。`,"for example: my gateway":`例如:我的网关`,"Stored encrypted in the vault under this endpoint's own name.":`加密保存在保险库里,以这个接口自己的名字命名。`,"Models (optional)":`模型(可选)`,"Leave empty when the endpoint lists its models at /models. Otherwise type their ids, separated by commas.":`接口能在 /models 列出模型时留空;否则输入模型 id,用逗号分隔。`,"Endpoint added":`已添加接口`,"Endpoint renamed":`已给接口改名`,"Endpoint removed":`已移除接口`,"Key saved":`密钥已保存`,"Models saved":`模型已保存`,Models:`模型`,Rename:`改名`,"Change key":`换密钥`,"Edit models":`编辑模型`,"Ask for its models":`重新获取模型`,"{n} models":`{n} 个模型`,"{n} models saved with this endpoint":`这个接口保存了 {n} 个模型`,"Used by {slots}":`用于{slots}`,"the hands":`双手`,pictures:`图片`,clips:`短片`,"The ids of the models this endpoint serves, separated by commas; what it lists at /models is added after them.":`这个接口提供的模型 id,用逗号分隔;它在 /models 列出的模型会接在后面。`,"The endpoint did not list its models; the saved list stands.":`接口没有列出模型;沿用已保存的列表。`,"The chat model answers through this endpoint; pick another chat model first.":`对话模型正通过这个接口回答;请先换一个对话模型。`,"Its key goes with it, and the hands, pictures or clips set on it go back to automatic.":`它的密钥会一起删除;设在它上面的双手、图片或短片会回到自动。`,"Uses the key saved with this endpoint.":`使用这个接口保存的密钥。`,"Your endpoints":`你的接口`,"The model that looks at screens when the hands run: a small, fast one that takes pictures. Pick one of this provider's, or one from another endpoint of your list, which then lends its address and key.":`双手运行时看屏幕的模型:一个小而快、能看图的模型。可以选这个服务商的,也可以选你列表里另一个接口的,那个接口的地址和密钥会一并使用。`,"the endpoint did not list its models (GET /models); type the ids of the models it serves, separated by commas":`接口没有列出模型(GET /models);请输入它提供的模型 id,用逗号分隔`,"the chat model answers through this endpoint; pick another chat model first":`对话模型正通过这个接口回答;请先换一个对话模型`,"the address must start with http:// or https://":`地址必须以 http:// 或 https:// 开头`,"that is nanoMuse Cloud; it is the account, not an endpoint":`那是 nanoMuse Cloud;它是账号,不是接口`,"a key has no spaces in it":`密钥里不会有空格`},ne=[{value:`auto`,label:`Auto`},{value:`en`,label:`English`},{value:`zh-CN`,label:`简体中文`}],j=`nanomuse_locale`,M={en:{},"zh-CN":A};function re(){try{let e=localStorage.getItem(j);if(e===`en`||e===`zh-CN`||e===`auto`)return e}catch{}return`auto`}var N=re(),P=new Set;function ie(){return(typeof navigator>`u`?[]:[navigator.language,...navigator.languages??[]]).some(e=>/^zh\b/i.test(e??``))?`zh-CN`:`en`}function ae(){return N}function F(){return N===`auto`?ie():N}function oe(e){N=e;try{localStorage.setItem(j,e)}catch{}se(),P.forEach(e=>e())}function se(){typeof document<`u`&&(document.documentElement.lang=F())}function ce(e){return P.add(e),()=>P.delete(e)}function le(){return(0,f.useSyncExternalStore)(ce,F,F)}function ue(){return(0,f.useSyncExternalStore)(ce,ae,ae)}function de(e,t){return t?e.replace(/\{(\w+)\}/g,(e,n)=>n in t?String(t[n]):e):e}function I(e,t){let n=M[F()];return de(n[e]??e,t)}function fe(e){let t=t=>({title:e.slice(t.length)});return e.startsWith(`Working on your goal: `)?I(`Working on your goal: {title}`,t(`Working on your goal: `)):e.startsWith(`Check-in: `)?I(`Check-in: {title}`,t(`Check-in: `)):e.startsWith(`Reminder: `)?I(`Reminder: {title}`,t(`Reminder: `)):e.startsWith(`Routine: `)?I(`Routine: {title}`,t(`Routine: `)):e.startsWith(`New mail: `)?I(`New mail: {title}`,t(`New mail: `)):e.startsWith(`Coming up: `)?I(`Coming up: {title}`,t(`Coming up: `)):e.startsWith(`Webhook: `)?I(`Webhook: {title}`,t(`Webhook: `)):e===`Tidied memory`?I(`Tidied memory`):e}function pe(e){let t=/^'([^']+)' is in always_ask_tools$/.exec(e);return t?I(`{tool} is on your always-ask list`,{tool:t[1]}):(t=/^'([^']+)' is in always_allow_tools$/.exec(e),t?I(`{tool} is on your always-allow list`,{tool:t[1]}):(t=/^'([^']+)' is in sentinel\.deny_tools$/.exec(e),t?I(`{tool} is switched off in your settings`,{tool:t[1]}):(t=/^risk level is '(\w+)' \(mode=(\w+)\)$/.exec(e),t?I(`an action rated {risk}, in {mode} mode`,{risk:I(t[1]),mode:I(t[2])}):e===`auto mode: approval skipped`?I(`auto mode: not asked`):(t=/^covered by your '([^']+)' permission for (.+)$/.exec(e),t?I(`covered by your {scope} permission for {key}`,{scope:I(t[1]),key:t[2]}):(t=/^private data was read earlier in this conversation and '([^']+)' can send data to (.+), which is not on sentinel\.egress_allowlist$/.exec(e),t?I(`private data was read earlier in this conversation, and {tool} could send it to {target}, which is not on your allowed list`,{tool:t[1],target:t[2]}):I(e))))))}function me(e){let t=/^the file is larger than (\d+) MB$/.exec(e);return t?I(`The file is larger than {n} MB.`,{n:t[1]}):I(e)}function he(){return le(),I}function L(){return F()===`zh-CN`?`zh-CN`:`en-US`}function ge(e){if(!e)return``;let t=new Date(e);if(Number.isNaN(t.getTime()))return``;let n=new Date,r=t.toDateString()===n.toDateString(),i=t.toLocaleTimeString(L(),{hour:`2-digit`,minute:`2-digit`});return r?i:`${t.toLocaleDateString(L(),{month:`short`,day:`numeric`})} ${i}`}function _e(e){if(!e)return``;let t=new Date(e);if(Number.isNaN(t.getTime()))return``;let n=t.toLocaleTimeString(L(),{hour:`numeric`,minute:`2-digit`}),r=new Date,i=new Date(r);return i.setDate(r.getDate()-1),t.toDateString()===r.toDateString()?`${I(`Today`)} ${n}`:t.toDateString()===i.toDateString()?`${I(`Yesterday`)} ${n}`:`${ve(e)} ${n}`}function ve(e,t={}){if(!e)return``;let n=new Date(e);if(Number.isNaN(n.getTime()))return``;let r=n.getFullYear()===new Date().getFullYear();return n.toLocaleDateString(L(),{month:`short`,day:`numeric`,...r?{}:{year:`numeric`},...t})}function ye(e){if(!e)return``;let t=Date.now()-new Date(e).getTime();if(Number.isNaN(t))return``;let n=Math.round(Math.abs(t)/1e3);if(n<45)return I(t>=0?`just now`:`any moment`);let r=Math.round(n/60),i=Math.round(r/60),a=Math.round(i/24),o=r<60?I(`{n} min`,{n:r}):i<24?I(`{n} h`,{n:i}):I(`{n} d`,{n:a});return I(t>=0?`{span} ago`:`in {span}`,{span:o})}function be(e){let t=Math.max(0,Math.floor(Date.now()/1e3-e));return t<60?I(`just now`):t<3600?I(`{n} min ago`,{n:Math.floor(t/60)}):t<86400?I(`{n} h ago`,{n:Math.floor(t/3600)}):t<604800?I(`{n} d ago`,{n:Math.floor(t/86400)}):new Date(e*1e3).toLocaleDateString(L())}function R(e){try{return localStorage.getItem(e)}catch{return null}}function z(e,t){try{t===null?localStorage.removeItem(e):localStorage.setItem(e,t)}catch{}}function B(...e){return e.filter(Boolean).join(` `)}function xe(e){try{return decodeURIComponent(e)}catch{return e}}function Se(e){let t=e.toLowerCase().split(`.`).pop()??``;return t===`ics`?`event`:[`md`,`txt`,`log`,`rtf`].includes(t)?`text`:[`py`,`js`,`ts`,`tsx`,`jsx`,`sh`,`toml`,`yaml`,`yml`,`sql`,`rs`,`go`,`java`,`c`,`cpp`].includes(t)?`code`:[`html`,`htm`].includes(t)?`html`:[`png`,`jpg`,`jpeg`,`gif`,`webp`,`svg`].includes(t)?`image`:t===`pdf`?`pdf`:[`csv`,`json`,`xlsx`,`xls`,`parquet`].includes(t)?`data`:`other`}var V=`nanomuse_token`,H=class extends Error{constructor(){super(`unauthorized`)}};function Ce(e){let t=e.hash.replace(/^#/,``).split(`&`).filter(Boolean),n=t.findIndex(e=>e.startsWith(`token=`));if(n>=0){let r=decodeURIComponent(t[n].slice(6));return t.splice(n,1),e.hash=t.length?`#${t.join(`&`)}`:``,r||null}let r=e.searchParams.get(`token`);return r?(e.searchParams.delete(`token`),r):null}function U(){let e=new URL(window.location.href),t=Ce(e);return t&&(z(V,t),window.history.replaceState(null,``,e.pathname+e.search+e.hash)),R(V)??``}function we(e){z(V,e||null)}function W(e,t=!1){let n=U(),r=n?T(n,`/api/files/${e}`):new URLSearchParams;t&&r.set(`download`,`1`);let i=r.toString();return`/api/files/${e.split(`/`).map(encodeURIComponent).join(`/`)}${i?`?${i}`:``}`}function Te(e,t){let n=U(),r=n?`?${T(n,`/api/browser/${e}/frames/${t}.jpg`)}`:``;return`/api/browser/${encodeURIComponent(e)}/frames/${encodeURIComponent(t)}.jpg${r}`}async function G(e,t={}){let n={...t.headers},r=U();r&&(n.Authorization=`Bearer ${r}`),t.body&&!n[`Content-Type`]&&(n[`Content-Type`]=`application/json`);let i;try{i=await fetch(e,{...t,headers:n})}catch{throw Error(`Cannot reach your nanoMuse right now.`)}if(i.status===401)throw new H;if(!i.ok){let e;try{e=await i.json()}catch{}throw Error(Ee(i.status,e))}return await i.json()}function Ee(e,t){let n=t&&typeof t==`object`?t.detail:void 0;return typeof n==`string`&&n.trim()?n:e>=500?`Your nanoMuse hit a problem; try again in a moment.`:`Your nanoMuse could not do that.`}var K=e=>({method:`POST`,body:JSON.stringify(e)}),q={state:()=>G(`/api/state`),cloud:()=>G(`/api/cloud`),cloudCode:e=>G(`/api/cloud/code`,K({identifier:e})),cloudVerify:(e,t,n=``)=>G(`/api/cloud/verify`,K(n?{identifier:e,code:t,invite:n}:{identifier:e,code:t})),cloudSignOut:()=>G(`/api/cloud/sign-out`,K({})),cloudModels:e=>G(`/api/cloud/models`,K({on:e})),cloudLogin:(e,t)=>G(`/api/cloud/login`,K({identifier:e,password:t})),cloudPassword:(e,t)=>G(`/api/cloud/password`,K({password:e,current:t??null})),cloudSessions:()=>G(`/api/cloud/sessions`),cloudRevokeSession:e=>G(`/api/cloud/sessions/${encodeURIComponent(e)}`,{method:`DELETE`}),cloudSignOutAll:(e=!1)=>G(`/api/cloud/sign-out-all`,K({all:e})),cloudEvents:(e=50)=>G(`/api/cloud/events?limit=${e}`),cloudDelete:()=>G(`/api/cloud/delete`,K({})),cloudMe:()=>G(`/api/cloud/me`),cloudConfig:()=>G(`/api/cloud/config`),cloudContribute:e=>G(`/api/cloud/contribute`,K({on:e})),cloudDeleteSamples:()=>G(`/api/cloud/samples`,{method:`DELETE`}),cloudUseAsModel:(e=``)=>G(`/api/cloud/use-as-model`,K({model:e})),syncState:()=>G(`/api/sync/state`),syncSetState:e=>G(`/api/sync/state`,{method:`PUT`,body:JSON.stringify({enabled:e})}),syncSetSideChats:e=>G(`/api/sync/state`,{method:`PUT`,body:JSON.stringify({side_chats:e})}),syncDelete:()=>G(`/api/sync/delete`,K({})),syncPull:()=>G(`/api/sync/pull`,K({})),avatarView:()=>G(`/api/avatar`),avatarBegin:(e,t=`main`,n=`muse`)=>G(`/api/avatar/begin`,K({description:e,thread:t,style:n})),avatarStart:e=>G(`/api/avatar/start`,K({session:e})),avatarChoose:(e,t)=>G(`/api/avatar/choose`,K({session:e,index:t})),avatarCancel:e=>G(`/api/avatar/cancel`,K({session:e})),avatarMoods:()=>G(`/api/avatar/moods`,K({})),coding:(e=``)=>G(`/api/coding${e?`?device=${encodeURIComponent(e)}`:``}`),codingSessions:(e={})=>{let t=new URLSearchParams;e.agent&&t.set(`agent`,e.agent),e.limit&&t.set(`limit`,String(e.limit)),e.workspace&&t.set(`workspace`,e.workspace),e.device&&t.set(`device`,e.device);let n=t.toString();return G(`/api/coding/sessions${n?`?${n}`:``}`)},codingSession:(e,t,n=``)=>G(`/api/coding/sessions/${encodeURIComponent(e)}/${encodeURIComponent(t)}${n?`?device=${encodeURIComponent(n)}`:``}`),codingSend:e=>G(`/api/coding/send`,K(e)),codingStop:(e,t=``)=>G(`/api/coding/stop`,K({run:e,device:t})),hub:()=>G(`/api/hub`),updateHub:e=>G(`/api/hub`,{method:`PUT`,body:JSON.stringify(e)}),joinHub:()=>G(`/api/hub/join`,K({})),leaveHub:()=>G(`/api/hub/leave`,K({})),refreshHub:()=>G(`/api/hub/refresh`,K({})),forgetDevice:e=>G(`/api/hub/devices/${encodeURIComponent(e)}`,{method:`DELETE`}),askDevice:(e,t=``)=>G(`/api/hub/ask`,K({device:e,text:t})),hands:()=>G(`/api/hands`),setHands:e=>G(`/api/connections/hands`,{method:`PUT`,body:JSON.stringify(e)}),stopHands:()=>G(`/api/hands/stop`,K({})),holds:()=>G(`/api/holds`),openHold:(e,t,n=``)=>G(`/api/holds`,K({thread:e,tool:t,reason:n})),doneHold:e=>G(`/api/holds/${encodeURIComponent(e)}/done`,K({})),health:()=>G(`/api/health`),threads:()=>G(`/api/threads`),createThread:e=>G(`/api/threads`,K({title:e})),renameThread:(e,t)=>G(`/api/threads/${e}`,{method:`PATCH`,body:JSON.stringify({title:t})}),deleteThread:e=>G(`/api/threads/${e}`,{method:`DELETE`}),clearThread:e=>G(`/api/threads/${e}/clear`,{method:`POST`}),stopThread:e=>G(`/api/threads/${e}/stop`,{method:`POST`}),events:(e,t=200,n)=>G(`/api/threads/${e}/events?limit=${t}${n?`&before=${encodeURIComponent(n)}`:``}`),send:(e,t,n=[],r=``,i=``)=>G(`/api/threads/${e}/send`,K(i?{text:t,files:n,language:r,via:i}:{text:t,files:n,language:r})),upload:e=>G(`/api/files/upload?name=${encodeURIComponent(e.name||`photo.jpg`)}`,{method:`POST`,headers:{"Content-Type":e.type||`application/octet-stream`},body:e}),decide:(e,t,n=`once`,r=``)=>G(`/api/approvals/${e}`,K({approved:t,scope:n,reason:r})),resetApprovals:()=>G(`/api/approvals`,{method:`DELETE`}),revokeGrant:e=>G(`/api/approvals/grants/${encodeURIComponent(e)}`,{method:`DELETE`}),goals:()=>G(`/api/goals`),createGoal:e=>G(`/api/goals`,K(e)),patchGoal:(e,t)=>G(`/api/goals/${e}`,{method:`PATCH`,body:JSON.stringify(t)}),addStep:(e,t)=>G(`/api/goals/${e}/steps`,K({title:t})),advanceGoal:e=>G(`/api/goals/${e}/advance`,{method:`POST`}),checkInGoal:e=>G(`/api/goals/${e}/check-in`,{method:`POST`}),acceptProposal:e=>G(`/api/goals/${e}/proposal/accept`,{method:`POST`}),dismissProposal:e=>G(`/api/goals/${e}/proposal`,{method:`DELETE`}),deleteGoal:e=>G(`/api/goals/${e}`,{method:`DELETE`}),memory:()=>G(`/api/memory`),addMemory:(e,t)=>G(`/api/memory`,K({content:e,category:t})),forgetMemory:e=>G(`/api/memory/${e}`,{method:`DELETE`}),tidyMemory:()=>G(`/api/memory/tidy`,{method:`POST`}),memoryChanges:(e=30)=>G(`/api/memory/changes?limit=${e}`),restoreMemoryChange:e=>G(`/api/memory/changes/${e}/restore`,{method:`POST`}),ideas:(e=!1)=>G(`/api/ideas${e?`?refresh=1`:``}`),activity:(e=150)=>G(`/api/activity?n=${e}`),feed:(e=60)=>G(`/api/feed?limit=${e}`),feedPosts:()=>G(`/api/feed/posts`),setFeedInstructions:e=>G(`/api/feed/instructions`,{method:`PUT`,body:JSON.stringify(e)}),refreshFeedPosts:()=>G(`/api/feed/posts/refresh`,{method:`POST`}),deleteFeedPost:e=>G(`/api/feed/posts/${e}`,{method:`DELETE`}),upcoming:()=>G(`/api/upcoming`),reminders:(e=!1)=>G(`/api/reminders${e?`?all=1`:``}`),createReminder:e=>G(`/api/reminders`,{method:`POST`,body:JSON.stringify(e)}),fireReminder:e=>G(`/api/reminders/${e}/fire`,{method:`POST`}),cancelReminder:e=>G(`/api/reminders/${e}`,{method:`DELETE`}),triggers:()=>G(`/api/triggers`),createTrigger:e=>G(`/api/triggers`,{method:`POST`,body:JSON.stringify(e)}),fireTrigger:e=>G(`/api/triggers/${e}/fire`,{method:`POST`}),cancelTrigger:e=>G(`/api/triggers/${e}`,{method:`DELETE`}),files:(e=300)=>G(`/api/files?limit=${e}`),fileText:async e=>{let t={},n=U();n&&(t.Authorization=`Bearer ${n}`);let r=await fetch(`/api/files/${e.split(`/`).map(encodeURIComponent).join(`/`)}`,{headers:t});if(r.status===401)throw new H;if(!r.ok)throw Error(Ee(r.status,await r.json().catch(()=>void 0)));return r.text()},settings:()=>G(`/api/settings`),update:(e=!1)=>G(`/api/update${e?`?refresh=1`:``}`),nudges:()=>G(`/api/nudges`),updateSettings:e=>G(`/api/settings`,{method:`PUT`,body:JSON.stringify(e)}),connections:()=>G(`/api/connections`),providers:e=>G(`/api/providers${e?`?region=${encodeURIComponent(e)}`:``}`),chatgptLogin:()=>G(`/api/chatgpt/login`,K({})),chatgptStatus:()=>G(`/api/chatgpt/status`),chatgptCallback:e=>G(`/api/chatgpt/callback`,K({url:e})),chatgptLogout:()=>G(`/api/chatgpt/logout`,K({})),setLLM:e=>G(`/api/connections/llm`,{method:`PUT`,body:JSON.stringify(e)}),testLLM:()=>G(`/api/connections/llm/test`,{method:`POST`}),llmModels:e=>G(`/api/llm/models`,K(e)),addEndpoint:e=>G(`/api/connections/endpoints`,K(e)),updateEndpoint:(e,t)=>G(`/api/connections/endpoints/${encodeURIComponent(e)}`,{method:`PUT`,body:JSON.stringify(t)}),removeEndpoint:e=>G(`/api/connections/endpoints/${encodeURIComponent(e)}`,{method:`DELETE`}),refreshEndpointModels:e=>G(`/api/connections/endpoints/${encodeURIComponent(e)}/models`,K({})),setEmbeddings:e=>G(`/api/connections/embeddings`,{method:`PUT`,body:JSON.stringify(e)}),testEmbeddings:()=>G(`/api/connections/embeddings/test`,{method:`POST`}),setSearch:e=>G(`/api/connections/search`,{method:`PUT`,body:JSON.stringify(e)}),testSearch:()=>G(`/api/connections/search/test`,{method:`POST`}),setEmail:e=>G(`/api/connections/email`,{method:`PUT`,body:JSON.stringify(e)}),disconnectEmail:()=>G(`/api/connections/email`,{method:`DELETE`}),testEmail:()=>G(`/api/connections/email/test`,{method:`POST`}),calendar:()=>G(`/api/calendar`),setCalendar:e=>G(`/api/connections/calendar`,{method:`PUT`,body:JSON.stringify(e)}),addCalendarFeed:(e,t)=>G(`/api/connections/calendar/feeds`,K({name:e,url:t})),removeCalendarFeed:e=>G(`/api/connections/calendar/feeds/${encodeURIComponent(e)}`,{method:`DELETE`}),testCalendar:()=>G(`/api/connections/calendar/test`,{method:`POST`}),contacts:(e=``,t=8)=>G(`/api/contacts?q=${encodeURIComponent(e)}&limit=${t}`),setContacts:e=>G(`/api/connections/contacts`,{method:`PUT`,body:JSON.stringify(e)}),addContactsSource:(e,t)=>G(`/api/connections/contacts/sources`,K({name:e,url:t})),importContacts:(e,t)=>G(`/api/connections/contacts/import?name=${encodeURIComponent(e)}`,{method:`POST`,headers:{"Content-Type":`text/vcard; charset=utf-8`},body:t}),removeContactsSource:e=>G(`/api/connections/contacts/sources/${encodeURIComponent(e)}`,{method:`DELETE`}),testContacts:()=>G(`/api/connections/contacts/test`,{method:`POST`}),skills:()=>G(`/api/skills`),skill:e=>G(`/api/skills/${encodeURIComponent(e)}`),saveSkill:(e,t)=>G(`/api/skills/${encodeURIComponent(e)}`,{method:`PUT`,body:JSON.stringify({content:t})}),deleteSkill:e=>G(`/api/skills/${encodeURIComponent(e)}`,{method:`DELETE`}),setSkillEnabled:(e,t)=>G(`/api/skills/${encodeURIComponent(e)}/enabled`,K({enabled:t})),importSkill:e=>G(`/api/skills/import`,K({url:e})),setGui:e=>G(`/api/connections/gui`,{method:`PUT`,body:JSON.stringify(e)}),testGui:()=>G(`/api/connections/gui/test`,{method:`POST`}),media:e=>G(`/api/connections/${e}`),setMedia:(e,t)=>G(`/api/connections/${e}`,{method:`PUT`,body:JSON.stringify(t)}),setBrowser:e=>G(`/api/connections/browser`,{method:`PUT`,body:JSON.stringify({enabled:e})}),addMCP:e=>G(`/api/connections/mcp`,K(e)),removeMCP:e=>G(`/api/connections/mcp/${encodeURIComponent(e)}`,{method:`DELETE`}),vaultSet:(e,t)=>G(`/api/vault/${encodeURIComponent(e)}`,{method:`PUT`,body:JSON.stringify({value:t})}),vaultDelete:e=>G(`/api/vault/${encodeURIComponent(e)}`,{method:`DELETE`}),onboarded:(e=!0)=>G(`/api/onboarded`,K({done:e})),firstrun:e=>G(`/api/firstrun?lang=${encodeURIComponent(e)}`),firstrunStart:e=>G(`/api/firstrun/start`,K({lang:e})),firstrunPick:e=>G(`/api/firstrun/pick`,K({name:e})),firstrunDismiss:()=>G(`/api/firstrun/dismiss`,K({})),browserControl:(e,t)=>G(`/api/browser/${encodeURIComponent(e)}/control`,K(t)),push:()=>G(`/api/push`),pushSubscribe:e=>G(`/api/push/subscribe`,K({subscription:e})),pushUnsubscribe:e=>G(`/api/push/unsubscribe`,K({endpoint:e})),pushTest:()=>G(`/api/push/test`,{method:`POST`})};function De(e){return e===4401?`auth`:e===4404?`gone`:`retry`}function Oe(e){let t=null,n=!1,r=0,i,a=()=>{let o=window.location.protocol===`https:`?`wss`:`ws`;t=new WebSocket(`${o}://${window.location.host}/ws`),t.onopen=()=>{let n=U();n&&t?.send(JSON.stringify({kind:`auth`,token:n})),r=0,e.onOpen?.()},t.onmessage=t=>{try{e.onMessage(JSON.parse(t.data))}catch{}},t.onclose=t=>{e.onClose?.();let o=De(t.code);if(o===`auth`){e.onAuthError?.();return}if(o===`gone`){n=!0,e.onGone?.();return}if(n)return;let s=Math.min(15e3,500*2**r++);i=window.setTimeout(a,s)},t.onerror=()=>t?.close()};return a(),{send:e=>t&&t.readyState===WebSocket.OPEN?(t.send(JSON.stringify(e)),!0):!1,close:()=>{n=!0,i&&window.clearTimeout(i),t?.close()}}}var ke=o((e=>{var t=d(),n=Symbol.for(`react.element`),r=Symbol.for(`react.fragment`),i=Object.prototype.hasOwnProperty,a=t.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.ReactCurrentOwner,o={key:!0,ref:!0,__self:!0,__source:!0};function s(e,t,r){var s,c={},l=null,u=null;for(s in r!==void 0&&(l=``+r),t.key!==void 0&&(l=``+t.key),t.ref!==void 0&&(u=t.ref),t)i.call(t,s)&&!o.hasOwnProperty(s)&&(c[s]=t[s]);if(e&&e.defaultProps)for(s in t=e.defaultProps,t)c[s]===void 0&&(c[s]=t[s]);return{$$typeof:n,type:e,key:l,ref:u,props:c,_owner:a.current}}e.Fragment=r,e.jsx=s,e.jsxs=s})),Ae=o(((e,t)=>{t.exports=ke()})),je=6e5;function Me(e,t=Date.now()){let n={};for(let r of e??[])t-r.at*1e3<6e5&&(n[r.thread]=r);return n}function Ne(){return`serviceWorker`in navigator&&`PushManager`in window&&`Notification`in window}async function Pe(){if(!(`serviceWorker`in navigator)||!window.isSecureContext)return null;try{return await navigator.serviceWorker.register(`/sw.js`)}catch{return null}}async function Fe(){if(!Ne())return`unsupported`;if(!window.isSecureContext)return`insecure`;if(Notification.permission===`denied`)return`denied`;let e=await navigator.serviceWorker.getRegistration();return e&&await e.pushManager.getSubscription()?`on`:`off`}function Ie(e){let t=`=`.repeat((4-e.length%4)%4),n=atob((e+t).replace(/-/g,`+`).replace(/_/g,`/`)),r=new Uint8Array(new ArrayBuffer(n.length));for(let e=0;e0?t.setAppBadge?.(e):t.clearAppBadge?.()}catch{}}var Be=`nanomuse_theme`,Ve={light:`#ffffff`,dark:`#181819`};function He(){try{let e=localStorage.getItem(Be);if(e===`light`||e===`dark`||e===`system`)return e}catch{}return`light`}var J=He(),Y=new Set,Ue=typeof matchMedia==`function`?matchMedia(`(prefers-color-scheme: dark)`):null;function We(){return Ue?.matches?`dark`:`light`}function Ge(){return J}function X(){return J===`system`?We():J}function Ke(e){J=e;try{localStorage.setItem(Be,e)}catch{}Z(),Y.forEach(e=>e())}function Z(){if(typeof document>`u`)return;let e=X();document.documentElement.dataset.theme=e;let t=document.querySelector(`meta[name="theme-color"]`);t&&t.setAttribute(`content`,Ve[e])}Ue?.addEventListener?.(`change`,()=>{J===`system`&&(Z(),Y.forEach(e=>e()))});function qe(e){return Y.add(e),()=>Y.delete(e)}function Je(){return(0,f.useSyncExternalStore)(qe,Ge,Ge)}function Ye(){return(0,f.useSyncExternalStore)(qe,X,X)}var Q=Ae();function Xe(){if(window.parent===window)return null;let e=window.location.ancestorOrigins;if(e&&e.length>0&&e[0]!==`null`)return e[0];if(document.referrer)try{return new URL(document.referrer).origin}catch{return null}return null}function Ze(e){let t=Xe();t&&window.parent.postMessage(e,t)}var Qe=[`chat`,`feed`,`ideas`,`goals`,`library`,`memory`,`devices`,`connections`,`channels`,`skills`,`you`,`account`,`coding`,`avatar`],$e=`nanomuse_feed_seen`,et=`nanomuse_sign_in_skipped`,tt=`nanomuse.ui.lite`;function nt(){try{let e=new URL(window.location.href);return e.searchParams.get(`ui`)===`lite`?(sessionStorage.setItem(tt,`1`),!0):e.searchParams.get(`ui`)===`full`?(sessionStorage.removeItem(tt),!1):sessionStorage.getItem(tt)===`1`}catch{return!1}}var rt={connected:!1,loaded:!1,authError:!1,gone:!1,error:null,version:``,profile:null,status:{state:`idle`,detail:``,thread:`main`},threads:[],activeThread:`main`,events:{},hasMore:{},streams:{},goals:[],settings:null,goalsVersion:0,memoryVersion:0,remindersVersion:0,calendarVersion:0,pendingApprovals:[],feedVersion:0,feedSeenAt:R($e)??``,viewer:null,draft:null,draftFiles:null,connectionsVersion:0,skillsVersion:0,onboardingDismissed:!1,signInSkipped:R(et)===`1`,tab:`chat`,toast:null,drawer:!1,finishedAt:0,mishapAt:0,hub:null,codingLive:{},lite:nt(),hands:null,holds:[],handsLive:null,studio:null,working:{},firstrun:null};function it(e,t){if(t.type!==`approval`)return e;let n=e.filter(e=>e.id!==t.id);return t.status===`pending`?[...n,t]:n}function at(e){return e.type===`approval`||e.type===`question`||e.source===`background`||e.source===`goal`}function ot(e){let t=e.ts;return typeof t==`number`?{...e,ts:new Date(t*1e3).toISOString()}:e}function st(e,t){let n=e??[],r=n.findIndex(e=>e.id===t.id);if(r>=0){let e=n.slice();return e[r]=t,e}if(t.synced&&t.ts&&n.length>0&&(n[n.length-1]?.ts??``)>t.ts){let e=n.length;for(;e>0&&(n[e-1]?.ts??``)>t.ts;)--e;return[...n.slice(0,e),t,...n.slice(e)]}return[...n,t]}function ct(e,t){let n=e.filter(e=>e.id!==t.id);return t.status===`on`?[...n,t]:n}function lt(e,t){let n=e.findIndex(e=>e.id===t.id);if(n>=0){let r=e.slice();return r[n]=t,r}return[...e,t]}function ut(e,t){switch(t.type){case`hello`:{let n=t.state;for(let e of Object.keys($))delete $[e];return{...e,loaded:!0,authError:!1,version:n.version,profile:n.profile,status:n.status,streams:{},threads:n.threads,goals:n.goals,settings:n.settings,pendingApprovals:n.pending_approvals,feedVersion:e.feedVersion+1,activeThread:n.threads.some(t=>t.id===e.activeThread)?e.activeThread:`main`,hub:n.hub??e.hub,hands:n.hands??e.hands,holds:(n.holds??[]).map(ot),working:Me(n.working),firstrun:n.firstrun??e.firstrun}}case`connection`:return{...e,connected:t.connected};case`authError`:return{...e,authError:!0,connected:!1};case`gone`:return{...e,gone:!0,connected:!1};case`error`:return{...e,error:t.error};case`events`:{let n=e.events[t.thread]??[],r=t.events.map(ot),i=t.prepend?[...r,...n.filter(e=>!r.some(t=>t.id===e.id))]:r;return{...e,events:{...e.events,[t.thread]:i},hasMore:{...e.hasMore,[t.thread]:t.hasMore}}}case`eventsFailed`:return{...e,events:{...e.events,[t.thread]:e.events[t.thread]??[]},toast:I(`Could not load the conversation. Open the chat again to retry.`)};case`activeThread`:return{...e,activeThread:t.thread,tab:`chat`};case`goals`:return{...e,goals:t.goals};case`settings`:return{...e,settings:t.settings,profile:t.settings.profile};case`tab`:return{...e,tab:t.tab};case`drawer`:return{...e,drawer:t.open};case`feedSeen`:return z($e,t.at),{...e,feedSeenAt:t.at};case`viewer`:return{...e,viewer:t.path};case`draft`:return{...e,draft:t.text};case`draftFiles`:return{...e,draftFiles:t.files};case`onboardingDismissed`:return{...e,onboardingDismissed:!0};case`signInSkipped`:return{...e,signInSkipped:!0};case`toast`:return{...e,toast:t.toast};case`ws`:return dt(e,t.msg);default:return e}}function dt(e,t){switch(t.kind){case`hello`:return ut(e,{type:`hello`,state:t.state});case`event`:case`update`:{let n=ot(t.event),r={...e.streams},i=r[n.thread];n.type===`assistant`&&i&&i.id===n.id&&(r[n.thread]=void 0);let a=e.threads.map(e=>e.id===n.thread&&t.kind===`event`?{...e,updated_at:n.ts}:e),o=e.events[n.thread]!==void 0,s=n.type===`tool`&&(n.status===`error`||n.status===`blocked`)||n.type===`notice`&&n.level===`error`,c=e.working,l=c[n.thread];return l&&n.type===`assistant`&&n.synced&&n.via_device===l.device&&(c={...c,[n.thread]:void 0}),{...e,streams:r,threads:a,working:c,events:o?{...e.events,[n.thread]:st(e.events[n.thread],n)}:e.events,holds:n.type===`hold`?ct(e.holds,n):e.holds,pendingApprovals:it(e.pendingApprovals,n),feedVersion:at(n)?e.feedVersion+1:e.feedVersion,mishapAt:s?Date.now():e.mishapAt}}case`stream_start`:return{...e,streams:{...e.streams,[t.thread]:{id:t.id,text:``,ended:!1}}};case`delta`:{let n=e.streams[t.thread],r=n&&n.id===t.id?{...n,text:n.text+t.text}:{id:t.id,text:t.text,ended:!1};return{...e,streams:{...e.streams,[t.thread]:r}}}case`stream_end`:{let n=e.streams[t.thread];return!n||n.id!==t.id?e:t.discard||!n.text.trim()?{...e,streams:{...e.streams,[t.thread]:void 0}}:{...e,streams:{...e.streams,[t.thread]:{...n,ended:!0}}}}case`status`:{let n=t.status,r={...e.streams};r[n.thread]?.ended&&n.state!==`working`&&(r[n.thread]=void 0);let i=ft(e.status,n),a=e.status.state===`working`&&i.state===`idle`;return{...e,status:i,streams:r,finishedAt:a?Date.now():e.finishedAt}}case`thread`:return{...e,threads:lt(e.threads,t.thread)};case`thread_deleted`:{let n={...e.events};return delete n[t.thread],{...e,events:n,holds:e.holds.filter(e=>e.thread!==t.thread),threads:e.threads.filter(e=>e.id!==t.thread),pendingApprovals:e.pendingApprovals.filter(e=>e.thread!==t.thread),activeThread:e.activeThread===t.thread?`main`:e.activeThread}}case`thread_cleared`:return{...e,events:{...e.events,[t.thread]:[]},holds:e.holds.filter(e=>e.thread!==t.thread),pendingApprovals:e.pendingApprovals.filter(e=>e.thread!==t.thread)};case`event_removed`:{let n=e.events[t.thread];return n?{...e,events:{...e.events,[t.thread]:n.filter(e=>e.id!==t.id)}}:e}case`firstrun`:return{...e,firstrun:t.firstrun};case`working`:{let{kind:n,working:r,...i}=t,a=e.working[i.thread];return r?{...e,working:{...e.working,[i.thread]:i}}:!a||a.device!==i.device?e:{...e,working:{...e.working,[i.thread]:void 0}}}case`goals`:return{...e,goalsVersion:e.goalsVersion+1};case`memory`:return{...e,memoryVersion:e.memoryVersion+1};case`reminders`:case`triggers`:return{...e,remindersVersion:e.remindersVersion+1};case`calendar`:return{...e,calendarVersion:e.calendarVersion+1};case`feed_posts`:return{...e,feedVersion:e.feedVersion+1};case`profile`:return{...e,profile:t.profile,settings:e.settings?{...e.settings,profile:t.profile}:e.settings};case`settings`:return{...e,settings:t.settings,profile:t.settings.profile};case`connections`:return{...e,connectionsVersion:e.connectionsVersion+1};case`hub`:return{...e,hub:t.hub};case`coding`:{let n=t.run?.id??t.event.run;if(!n)return e;let r=e.codingLive[n],i=t.run??r?.run;if(!i)return e;let a=t.event.kind===`run`?r?.events??[]:[...r?.events??[],t.event].slice(-400),o=r?.current??``;t.event.kind===`text`&&(o=t.event.partial?o+(t.event.text??``):``),(t.event.kind===`done`||t.event.kind===`error`)&&(o=``);let s={...e.codingLive,[n]:{run:{...i,device:t.device??i.device},events:a,current:o}},c=Object.keys(s);if(c.length>20)for(let e of c.sort((e,t)=>s[e].run.started_at-s[t].run.started_at).slice(0,c.length-20))delete s[e];return{...e,codingLive:s}}case`hands_state`:return{...e,hands:t.hands};case`studio`:return{...e,studio:t.current};case`hands`:{let{kind:n,...r}=t,i=r.event===`end`||r.event===`stop`;return{...e,handsLive:i?null:r}}case`skills`:return{...e,skillsVersion:e.skillsVersion+1};case`error`:return{...e,toast:I(t.error)};case`pong`:return{...e,status:t.status};default:return e}}var $={};function ft(e,t){$[t.thread]=t;let n=Object.values($).filter(e=>e.state!==`idle`);return n.length?(n.sort((e,t)=>Number(e.thread!==`main`)-Number(t.thread!==`main`)),n[0]??e):{state:`idle`,detail:``,thread:`main`}}var pt=(0,f.createContext)(null);function mt({children:e}){let[t,n]=(0,f.useReducer)(ut,rt),r=(0,f.useRef)(null);(0,f.useEffect)(()=>{U();let e=[],t=0,i=()=>{t=0;let r=e.splice(0);for(let e of r)n({type:`ws`,msg:e})},a=Oe({onMessage:n=>{e.push(n),t||=window.setTimeout(i,0)},onOpen:()=>n({type:`connection`,connected:!0}),onClose:()=>n({type:`connection`,connected:!1}),onAuthError:()=>n({type:`authError`}),onGone:()=>n({type:`gone`})});return r.current=a,q.state().then(e=>n({type:`hello`,state:e})).catch(e=>{e instanceof H?n({type:`authError`}):n({type:`error`,error:String(e.message??e)})}),()=>{t&&window.clearTimeout(t),a.close()}},[]);let i=(0,f.useRef)({}),a=(0,f.useCallback)(async(e,t)=>{let r=t?void 0:i.current[e]=(i.current[e]??0)+1;try{let a=await q.events(e,150,t);if(r!==void 0&&i.current[e]!==r)return;n({type:`events`,thread:e,events:a.events,hasMore:a.has_more,prepend:!!t})}catch(t){t instanceof H?n({type:`authError`}):n({type:`eventsFailed`,thread:e})}},[]),o=(0,f.useCallback)(async()=>{try{n({type:`ws`,msg:{kind:`hub`,hub:await q.hub()}})}catch{}},[]);(0,f.useEffect)(()=>{t.loaded&&a(t.activeThread)},[t.loaded,t.activeThread,a]);let s=(0,f.useRef)(!1);(0,f.useEffect)(()=>{t.connected&&s.current&&t.loaded&&a(t.activeThread),s.current=t.connected},[t.connected,t.loaded,t.activeThread,a]);let c=(0,f.useCallback)(async()=>{try{n({type:`goals`,goals:await q.goals()})}catch{}},[]);(0,f.useEffect)(()=>{t.loaded&&c()},[t.goalsVersion,t.loaded,c]);let l=(0,f.useCallback)(async()=>{try{n({type:`settings`,settings:await q.settings()})}catch{}},[]);(0,f.useEffect)(()=>{if(!t.toast)return;let e=window.setTimeout(()=>n({type:`toast`,toast:null}),3500);return()=>window.clearTimeout(e)},[t.toast]),(0,f.useEffect)(()=>{Pe();let e=e=>{let t=new URL(e,window.location.origin),r=t.searchParams.get(`thread`),i=t.searchParams.get(`tab`);r&&n({type:`activeThread`,thread:r}),i&&Qe.includes(i)&&!r?n({type:`tab`,tab:i}):n({type:`tab`,tab:`chat`});let a=t.searchParams.get(`draft`);a&&n({type:`draft`,text:a});let o=t.searchParams.get(`attach`);if(o)try{let e=JSON.parse(o);Array.isArray(e)&&e.length&&n({type:`draftFiles`,files:e.filter(e=>e&&typeof e.path==`string`)})}catch{}},t=new URL(window.location.href);if([`thread`,`tab`,`draft`,`attach`,`ui`].some(e=>t.searchParams.has(e))){e(t.href);for(let e of[`thread`,`tab`,`draft`,`attach`,`ui`])t.searchParams.delete(e);window.history.replaceState({},``,t.toString())}let r=t=>{t.data&&t.data.type===`open`&&e(String(t.data.url||`/`))};navigator.serviceWorker?.addEventListener(`message`,r);let i=e=>{if(window.parent===window||e.source!==window.parent)return;let t=e.data;t&&t.type===`nanomuse:draft`&&typeof t.text==`string`&&(n({type:`tab`,tab:`chat`}),n({type:`draft`,text:t.text.slice(0,4e3)}))};return window.addEventListener(`message`,i),()=>{navigator.serviceWorker?.removeEventListener(`message`,r),window.removeEventListener(`message`,i)}},[]);let u=Ye();(0,f.useEffect)(()=>{t.loaded&&Ze({type:`nanomuse:ready`,name:t.profile?.name??``,theme:u})},[t.loaded,t.profile?.name]),(0,f.useEffect)(()=>{t.loaded&&Ze({type:`nanomuse:theme`,theme:u})},[t.loaded,u]),(0,f.useEffect)(()=>{t.loaded&&ze(t.pendingApprovals.length)},[t.loaded,t.pendingApprovals.length]);let d=(0,f.useMemo)(()=>({state:t,dispatch:n,send:async(e,t,i=[])=>{if(!t.trim()&&i.length===0)return;let a=F();try{(i.length>0||!r.current?.send({kind:`send`,thread:e,text:t,language:a}))&&await q.send(e,t,i,a)}catch(e){throw e instanceof H&&n({type:`authError`}),e}},sendViaCloud:async(e,t,r=[])=>{if(t.trim()||r.length!==0)try{await q.send(e,t,r,F(),`cloud`)}catch(e){throw e instanceof H&&n({type:`authError`}),e}},decide:async(e,t,i=`once`)=>{try{r.current?.send({kind:`approval`,id:e,approved:t,scope:i})||await q.decide(e,t,i)}catch(e){throw e instanceof H&&n({type:`authError`}),e}},loadEvents:a,refreshGoals:c,refreshSettings:l,refreshHub:o,setTab:e=>n({type:`tab`,tab:e}),setDrawer:e=>n({type:`drawer`,open:e}),openThread:e=>n({type:`activeThread`,thread:e}),markFeedSeen:e=>n({type:`feedSeen`,at:e}),openFile:e=>n({type:`viewer`,path:e}),draftFiles:e=>n({type:`draftFiles`,files:e}),draft:e=>{n({type:`draft`,text:e}),e!==null&&n({type:`tab`,tab:`chat`})},dismissOnboarding:()=>n({type:`onboardingDismissed`}),skipSignIn:()=>{z(et,`1`),n({type:`signInSkipped`})},toast:e=>n({type:`toast`,toast:I(e)})}),[t,a,c,l,o]);return(0,Q.jsx)(pt.Provider,{value:d,children:e})}function ht(){let e=(0,f.useContext)(pt);if(!e)throw Error(`useStore outside provider`);return e}var gt=`dragon`,_t=new Set([`panda`,`sunny`,`moss`,`sky`,`fox`,`bolt`,`plum`]);function vt(e){return!e||e===`dragon`||_t.has(e)}function yt(e,t){return W(`avatar/${e}/${t===`working`||t===`waiting`||t===`happy`||t===`error`?t:`idle`}.webp`)}function bt(e){return`/avatars/dragon-${e===`working`||e===`waiting`||e===`happy`||e===`error`?e:`idle`}.webp`}function xt(e){return e===`working`||e===`waiting`||e===`happy`?e:`idle`}function St(e){return e===`error`?null:`/avatars/dragon-${xt(e)}.mp4`}function Ct(e,t){return t===`error`?null:W(`avatar/${e}/${xt(t)}.mp4`)}var wt=3e3,Tt=4e3;function Et(e){let{state:t}=ht(),n=Dt(e?[t.mishapAt+Tt,t.finishedAt+wt]:[]);return e?t.loaded&&!t.connected?`sleepy`:e.state===`waiting`?`waiting`:e.state===`working`?`working`:t.mishapAt&&n-t.mishapAt<4e3?`error`:t.finishedAt&&n-t.finishedAt<3e3?`happy`:`idle`:`idle`}function Dt(e){let[t,n]=(0,f.useState)(()=>Date.now()),r=e.join(`,`);(0,f.useEffect)(()=>n(Date.now()),[r]);let i=Math.min(...e.filter(e=>e>t),1/0);return(0,f.useEffect)(()=>{if(!Number.isFinite(i))return;let e=window.setTimeout(()=>n(Date.now()),Math.max(0,i-Date.now())+20);return()=>window.clearTimeout(e)},[i]),t}var Ot=44,kt=new Set,At=typeof window<`u`&&typeof window.matchMedia==`function`&&window.matchMedia(`(prefers-reduced-motion: reduce)`).matches;function jt({profile:e,status:t,size:n=40,onClick:r,still:i=!1,className:a}){let[o,s]=(0,f.useState)(!1),[,c]=(0,f.useState)(0);(0,f.useEffect)(()=>{if(!o)return;let e=window.setTimeout(()=>s(!1),900);return()=>window.clearTimeout(e)},[o]);let l=Et(t),u=t?.state??`idle`,d=e?.color??`#0064d4`,p=!e||vt(e.avatar),m=!p&&e?.avatar?e.avatar:null,h=o?`happy`:i?`idle`:l,g=i||At||n{kt.add(_),c(e=>e+1)},className:`h-full w-full object-cover`},_):p||m?(0,Q.jsx)(`img`,{src:y,alt:``,draggable:!1,className:`h-full w-full object-cover`}):(0,Q.jsx)(`span`,{className:`flex h-full w-full items-center justify-center leading-none drop-shadow-sm`,style:{fontSize:n*.5},children:e?.emoji??`✨`})}),t&&u!==`idle`&&(0,Q.jsx)(`span`,{className:B(`absolute -bottom-0.5 -right-0.5 rounded-full border-2 border-bg`,u===`working`?`bg-amber-400`:`bg-rose-500`),style:{width:Math.max(10,n*.28),height:Math.max(10,n*.28)}})]});return r?(0,Q.jsx)(`button`,{type:`button`,onClick:()=>{s(!0),r()},"aria-label":b,className:B(x,`transition active:scale-95`),style:{width:n,height:n},children:S}):(0,Q.jsx)(`span`,{role:`img`,"aria-label":b,onClick:()=>s(!0),className:x,style:{width:n,height:n},children:S})}function Mt({profile:e,status:t,name:n,statusLine:r,statusTone:i=`muted`,spinning:a=!1,badge:o,onAvatar:s,onName:c,leading:l,trailing:u,under:d,size:f=72,className:p,scrim:m=!1}){return(0,Q.jsxs)(`header`,{className:B(`safe-top relative shrink-0 pt-1.5 pb-1`,m?`header-scrim`:`bg-bg`,p),children:[(0,Q.jsxs)(`div`,{className:`flex flex-col items-center px-16`,children:[(0,Q.jsxs)(`button`,{type:`button`,onClick:s,"aria-label":n,className:`relative rounded-full`,children:[(0,Q.jsx)(jt,{profile:e,status:t,size:f}),o!==void 0&&o>0&&(0,Q.jsx)(`span`,{className:`pointer-events-none absolute -right-0.5 top-0 flex h-[18px] min-w-[18px] items-center justify-center rounded-full border-2 border-bg bg-rose-500 px-1 text-[10.5px] font-bold text-white`,children:o})]}),(0,Q.jsxs)(`div`,{className:`relative z-10 -mt-2.5 flex min-h-[44px] flex-col items-center`,children:[(0,Q.jsx)(Nt,{name:n,statusLine:r,statusTone:i,spinning:a,onClick:c??s}),d&&(0,Q.jsx)(`div`,{className:`mt-1.5 flex max-w-full items-center`,children:d})]})]}),l&&(0,Q.jsx)(`div`,{className:`absolute left-4 top-1.5 safe-top`,children:l}),u&&(0,Q.jsx)(`div`,{className:`absolute right-4 top-1.5 safe-top flex items-center gap-2`,children:u})]})}function Nt({name:e,statusLine:t,statusTone:n=`muted`,spinning:r=!1,onClick:i}){let a=(0,Q.jsxs)(Q.Fragment,{children:[(0,Q.jsx)(`span`,{className:`max-w-[240px] truncate text-[14px] leading-[18px] text-fg`,children:e}),t&&(0,Q.jsxs)(`span`,{className:B(`mt-0.5 flex max-w-[240px] items-center gap-1 text-[11.5px] leading-[14px]`,n===`accent`?`text-accent`:`text-muted`),children:[r&&(0,Q.jsx)(`span`,{className:`h-2.5 w-2.5 shrink-0 animate-spin rounded-full border-[1.5px] border-current border-t-transparent`}),(0,Q.jsx)(`span`,{className:`truncate`,children:t})]})]}),o=`flex flex-col items-center rounded-[14px] bg-surface px-3 py-1 shadow-[0_1px_4px_rgba(0,0,0,0.16)] dark:border dark:border-border dark:shadow-none`;return i?(0,Q.jsx)(`button`,{type:`button`,onClick:i,className:o,children:a}):(0,Q.jsx)(`div`,{className:o,children:a})}function Pt({onClick:e,label:t,children:n,dot:r=!1,small:i=!1,className:a,disabled:o=!1,expanded:s}){return(0,Q.jsxs)(`button`,{type:`button`,onClick:e,"aria-label":t,"aria-expanded":s,disabled:o,className:B(`relative flex items-center justify-center rounded-full bg-surface text-fg shadow-[0_1px_4px_rgba(0,0,0,0.14)] hover:bg-surface-2 disabled:opacity-50 dark:border dark:border-border dark:shadow-none`,i?`h-10 w-10`:`h-11 w-11`,a),children:[n,r&&(0,Q.jsx)(`span`,{className:`absolute right-[3px] top-[3px] h-[9px] w-[9px] rounded-full border-[1.5px] border-surface bg-accent`})]})}function Ft({children:e,className:t}){return(0,Q.jsx)(`h1`,{className:B(`px-5 pt-1.5 pb-1.5 text-[26px] font-bold leading-8 tracking-tight`,t),children:e})}export{ye as A,fe as B,Te as C,Se as D,B as E,ne as F,ue as G,oe as H,se as I,b as J,he as K,F as L,_e as M,ge as N,R as O,z as P,l as Q,L as R,W as S,we as T,I as U,pe as V,le as W,o as X,d as Y,s as Z,Le as _,gt as a,Ae as b,vt as c,mt as d,ht as f,Re as g,Je as h,jt as i,xe as j,be as k,Ct as l,Ke as m,Ft as n,St as o,Z as p,x as q,Pt as r,bt as s,Mt as t,yt as u,Fe as v,G as w,q as x,je as y,me as z}; \ No newline at end of file diff --git a/nanomuse/server/static/assets/MuseHeader-RC--uR8o.js b/nanomuse/server/static/assets/MuseHeader-RC--uR8o.js new file mode 100644 index 000000000..ab96fed97 --- /dev/null +++ b/nanomuse/server/static/assets/MuseHeader-RC--uR8o.js @@ -0,0 +1 @@ +var e=Object.create,t=Object.defineProperty,n=Object.getOwnPropertyDescriptor,r=Object.getOwnPropertyNames,i=Object.getPrototypeOf,a=Object.prototype.hasOwnProperty,o=(e,t)=>()=>(t||(e((t={exports:{}}).exports,t),e=null),t.exports),s=(e,n)=>{let r={};for(var i in e)t(r,i,{get:e[i],enumerable:!0});return n||t(r,Symbol.toStringTag,{value:`Module`}),r},c=(e,i,o,s)=>{if(i&&typeof i==`object`||typeof i==`function`)for(var c=r(i),l=0,u=c.length,d;li[e]).bind(null,d),enumerable:!(s=n(i,d))||s.enumerable});return e},l=(n,r,o)=>(o=n==null?{}:e(i(n)),c(r||!n||!n.__esModule||!a.call(n,`default`)?t(o,`default`,{value:n,enumerable:!0}):o,n)),u=o((e=>{var t=Symbol.for(`react.element`),n=Symbol.for(`react.portal`),r=Symbol.for(`react.fragment`),i=Symbol.for(`react.strict_mode`),a=Symbol.for(`react.profiler`),o=Symbol.for(`react.provider`),s=Symbol.for(`react.context`),c=Symbol.for(`react.forward_ref`),l=Symbol.for(`react.suspense`),u=Symbol.for(`react.memo`),d=Symbol.for(`react.lazy`),f=Symbol.iterator;function p(e){return typeof e!=`object`||!e?null:(e=f&&e[f]||e[`@@iterator`],typeof e==`function`?e:null)}var m={isMounted:function(){return!1},enqueueForceUpdate:function(){},enqueueReplaceState:function(){},enqueueSetState:function(){}},h=Object.assign,g={};function _(e,t,n){this.props=e,this.context=t,this.refs=g,this.updater=n||m}_.prototype.isReactComponent={},_.prototype.setState=function(e,t){if(typeof e!=`object`&&typeof e!=`function`&&e!=null)throw Error(`setState(...): takes an object of state variables to update or a function which returns an object of state variables.`);this.updater.enqueueSetState(this,e,t,`setState`)},_.prototype.forceUpdate=function(e){this.updater.enqueueForceUpdate(this,e,`forceUpdate`)};function v(){}v.prototype=_.prototype;function y(e,t,n){this.props=e,this.context=t,this.refs=g,this.updater=n||m}var b=y.prototype=new v;b.constructor=y,h(b,_.prototype),b.isPureReactComponent=!0;var x=Array.isArray,S=Object.prototype.hasOwnProperty,C={current:null},w={key:!0,ref:!0,__self:!0,__source:!0};function ee(e,n,r){var i,a={},o=null,s=null;if(n!=null)for(i in n.ref!==void 0&&(s=n.ref),n.key!==void 0&&(o=``+n.key),n)S.call(n,i)&&!w.hasOwnProperty(i)&&(a[i]=n[i]);var c=arguments.length-2;if(c===1)a.children=r;else if(1{t.exports=u()})),f=l(d()),p=(...e)=>e.filter((e,t,n)=>!!e&&e.trim()!==``&&n.indexOf(e)===t).join(` `).trim(),m=e=>e.replace(/([a-z0-9])([A-Z])/g,`$1-$2`).toLowerCase(),h=e=>e.replace(/^([A-Z])|[\s-_]+(\w)/g,(e,t,n)=>n?n.toUpperCase():t.toLowerCase()),g=e=>{let t=h(e);return t.charAt(0).toUpperCase()+t.slice(1)},_={xmlns:`http://www.w3.org/2000/svg`,width:24,height:24,viewBox:`0 0 24 24`,fill:`none`,stroke:`currentColor`,strokeWidth:2,strokeLinecap:`round`,strokeLinejoin:`round`},v=e=>{for(let t in e)if(t.startsWith(`aria-`)||t===`role`||t===`title`)return!0;return!1},y=(0,f.forwardRef)(({color:e=`currentColor`,size:t=24,strokeWidth:n=2,absoluteStrokeWidth:r,className:i=``,children:a,iconNode:o,...s},c)=>(0,f.createElement)(`svg`,{ref:c,..._,width:t,height:t,stroke:e,strokeWidth:r?Number(n)*24/Number(t):n,className:p(`lucide`,i),...!a&&!v(s)&&{"aria-hidden":`true`},...s},[...o.map(([e,t])=>(0,f.createElement)(e,t)),...Array.isArray(a)?a:[a]])),b=(e,t)=>{let n=(0,f.forwardRef)(({className:n,...r},i)=>(0,f.createElement)(y,{ref:i,iconNode:t,className:p(`lucide-${m(g(e))}`,`lucide-${e}`,n),...r}));return n.displayName=g(e),n},x=b(`loader-circle`,[[`path`,{d:`M21 12a9 9 0 1 1-6.219-8.56`,key:`13zald`}]]),S=21600,C=32;function w(e=Date.now()){return(Math.floor(e/1e3/S)+2)*S}function ee(e,t,n){let r=new TextEncoder;return E(te(r.encode(e),r.encode(`${n}\n${t}`))).slice(0,C)}function T(e,t,n=Date.now()){let r=w(n),i=new URLSearchParams;return i.set(`exp`,String(r)),i.set(`sig`,ee(e,t,r)),i}function E(e){let t=``;for(let n of e)t+=n.toString(16).padStart(2,`0`);return t}function te(e,t){let n=new Uint8Array(64);n.set(e.length>64?k(e):e);let r=new Uint8Array(64+t.length),i=new Uint8Array(96);for(let e=0;e<64;e++)r[e]=n[e]^54,i[e]=n[e]^92;return r.set(t,64),i.set(k(r),64),k(i)}var D=new Uint32Array([1116352408,1899447441,3049323471,3921009573,961987163,1508970993,2453635748,2870763221,3624381080,310598401,607225278,1426881987,1925078388,2162078206,2614888103,3248222580,3835390401,4022224774,264347078,604807628,770255983,1249150122,1555081692,1996064986,2554220882,2821834349,2952996808,3210313671,3336571891,3584528711,113926993,338241895,666307205,773529912,1294757372,1396182291,1695183700,1986661051,2177026350,2456956037,2730485921,2820302411,3259730800,3345764771,3516065817,3600352804,4094571909,275423344,430227734,506948616,659060556,883997877,958139571,1322822218,1537002063,1747873779,1955562222,2024104815,2227730452,2361852424,2428436474,2756734187,3204031479,3329325298]),O=(e,t)=>e>>>t|e<<32-t;function k(e){let t=new Uint32Array([1779033703,3144134277,1013904242,2773480762,1359893119,2600822924,528734635,1541459225]),n=new Uint8Array(e.length+9+63>>6<<6);n.set(e),n[e.length]=128;let r=new DataView(n.buffer),i=e.length*8;r.setUint32(n.length-8,Math.floor(i/4294967296)),r.setUint32(n.length-4,i>>>0);let a=new Uint32Array(64);for(let e=0;e>>3,i=O(n,17)^O(n,19)^n>>>10;a[e]=a[e-16]+r+a[e-7]+i>>>0}let n=t[0],i=t[1],o=t[2],s=t[3],c=t[4],l=t[5],u=t[6],d=t[7];for(let e=0;e<64;e++){let t=O(c,6)^O(c,11)^O(c,25),r=c&l^~c&u,f=d+t+r+D[e]+a[e]>>>0,p=(O(n,2)^O(n,13)^O(n,22))+(n&i^n&o^i&o)>>>0;d=u,u=l,l=c,c=s+f>>>0,s=o,o=i,i=n,n=f+p>>>0}t[0]+=n,t[1]+=i,t[2]+=o,t[3]+=s,t[4]+=c,t[5]+=l,t[6]+=u,t[7]+=d}let o=new Uint8Array(32),s=new DataView(o.buffer);for(let e=0;e<8;e++)s.setUint32(e*4,t[e]);return o}var A={Chat:`聊天`,Feed:`动态`,Ideas:`点子`,Goals:`目标`,Library:`资源库`,"Main chat":`主要聊天`,"Side chat":`旁聊`,"Reconnecting to your nanoMuse…":`正在重新连接你的 nanoMuse…`,"This demo has ended.":`这次体验已经结束。`,"This nanoMuse has stopped. Reload the page once it is running again.":`这个 nanoMuse 已停止。等它重新运行后,刷新页面即可。`,"Reconnecting…":`重新连接中…`,"Connect to your nanoMuse":`连接到你的 nanoMuse`,"This app talks to the nanoMuse server you run yourself. Scan the QR code printed by":`这个应用连接的是你自己运行的 nanoMuse 服务器。扫描下面命令打印的二维码`,", or paste the access token below.":`,或在下方粘贴访问令牌。`,"Access token":`访问令牌`,Connect:`连接`,Connected:`已连接`,"Hi, I'm {name}.":`你好,我是 {name}。`,"I don't just answer; I get things done: research, plans, files, code, email, long-running goals. Everything I do shows up here, and anything hard to undo waits for your approval.":`我不只是回答问题,而是把事情做完:调研、计划、文件、代码、邮件、长期目标。我做的每件事都会显示在这里,任何难以撤销的操作都会先等你批准。`,"What can you do for me?":`你能为我做什么?`,"Plan my week: ask me what's on my plate":`帮我规划这一周:先问问我手头有什么`,"Research and compare two options for me":`帮我调研并比较两个选项`,"Set up a long-term goal and track it":`建立一个长期目标并持续跟进`,"Answer {name}…":`回复 {name}…`,"Reply below to continue.":`在下方回复以继续。`,"{name} is working; anything you send now is picked up right away.":`{name} 正在工作,你现在发的消息会马上接着处理。`,"Working…":`处理中…`,"On it":`正在处理`,"Show the agent's steps":`显示执行步骤`,"Every tool it uses becomes a chip in the chat. Off, the chat keeps to the conversation and the line under the name says what it is on. This device only.":`每用一个工具就在对话里多一个小标签。关闭时对话只保留对话本身,名字下方的一行字说明它正在做什么。仅本设备。`,"On it: {request}":`正在处理:{request}`,"A star on GitHub helps":`GitHub 上的一颗 Star 帮得上忙`,"Welcome. nanoMuse is free, open source and non-profit, a personal agent for anyone who runs it. If that is worth something to you, a star on GitHub is how the next person finds it.":`欢迎。nanoMuse 免费、开源、非营利,做的是一个属于每个人的个人智能体。如果你认同,GitHub 上的一颗 Star 能让下一个人也找到这里。`,"Three tasks done. If nanoMuse is useful, a star on GitHub helps the next person find it.":`三个任务完成了。如果 nanoMuse 用得上,到 GitHub 点一颗 Star,下一个人也能找到它。`,"{n} tasks done. If nanoMuse is useful, a star on GitHub helps the next person find it.":`已经完成 {n} 个任务了。如果 nanoMuse 用得上,到 GitHub 点一颗 Star,下一个人也能找到它。`,"A week with nanoMuse. If it has earned a place in your day, a star on GitHub helps the next person find it.":`和 nanoMuse 一起一周了。如果它在你的日常里站住了脚,到 GitHub 点一颗 Star,下一个人也能找到它。`,"A month with nanoMuse. If it has become part of your routine, a star on GitHub tells others it is worth a try.":`和 nanoMuse 一起一个月了。如果它成了你习惯的一部分,一颗 Star 会让更多人愿意试一试。`,"{n} days with nanoMuse. If it has earned a place in your day, a star on GitHub helps the next person find it.":`和 nanoMuse 一起 {n} 天了。如果它在你的日常里站住了脚,到 GitHub 点一颗 Star,下一个人也能找到它。`,"Goal reached. If nanoMuse helped you get there, a star on GitHub tells the people building it that it did.":`目标达成了。如果 nanoMuse 帮你走到了这里,到 GitHub 点一颗 Star,做它的人就知道了。`,"Ten tasks together. If nanoMuse has become part of your day, a star on GitHub tells others it is worth a try.":`已经一起完成十个任务了。如果 nanoMuse 成了你日常的一部分,一颗 Star 会让更多人愿意试一试。`,"A new face, drawn for you. If you like where nanoMuse is going, a star on GitHub helps more people find it.":`一张为你画的新面孔。如果你喜欢 nanoMuse 现在的样子,到 GitHub 点一颗 Star,更多人就能遇见它。`,"The free allowance is used up. Thank you for coming this far. If nanoMuse has earned it, a star on GitHub keeps the project in view for the next person.":`免费额度用完了,谢谢你一路用到这里。如果 nanoMuse 值得,到 GitHub 点一颗 Star,下一个人也能找到它。`,"Load earlier messages":`加载更早的消息`,"New side chat":`新建旁聊`,"New side chat, e.g. “Trip to Kyoto”":`新建旁聊,例如“京都之旅”`,Chats:`对话`,New:`新建`,Create:`创建`,Clear:`清空`,"Clear this conversation? Memory and goals are kept.":`清空这段对话?记忆和目标会保留。`,"Delete this side chat and its history?":`删除这个旁聊及其历史记录?`,"Could not send":`发送失败`,"Could not send decision":`无法提交决定`,Send:`发送`,"Show thinking":`显示思考过程`,"Hide thinking":`隐藏思考过程`,"You:":`你:`,"{name} asks":`{name} 提问`,"{name} suggests":`{name} 建议`,"{name} is on it":`{name} 正在处理`,"Browser: {title}":`浏览器:{title}`,safe:`安全`,moderate:`中等`,sensitive:`敏感`,high:`高`,"Exactly what will run":`将要执行的具体内容`,"Why it asks: {reasons}":`询问原因:{reasons}`,"{tool} is on your always-ask list":`{tool} 在你的「总是询问」列表里`,"{tool} is on your always-allow list":`{tool} 在你的「总是允许」列表里`,"{tool} is switched off in your settings":`{tool} 已在你的设置里关闭`,"an action rated {risk}, in {mode} mode":`这个操作的风险等级是「{risk}」,哨兵处于{mode}模式`,"auto mode: not asked":`自动模式:未询问`,"covered by your {scope} permission for {key}":`已在你对 {key} 的「{scope}」授权范围内`,"private data was read earlier in this conversation, and {tool} could send it to {target}, which is not on your allowed list":`这段对话早些时候读取过私密数据,而 {tool} 可能把它发给 {target},这个地址不在你的允许列表里`,ask:`询问`,auto:`自动`,strict:`严格`,once:`一次`,conversation:`本次对话`,session:`本次运行`,"24h":`24 小时`,low:`低`,"Stopped.":`已停止。`,"Use nanoMuse Cloud this time":`这次改用 nanoMuse Cloud`,"Answered by nanoMuse Cloud this time ({model})":`这次由 nanoMuse Cloud 回答({model})`,Deny:`拒绝`,"Allow once":`允许一次`,Allow:`允许`,"{name} wants to":`{name} 想要`,"at {host}":`站点:{host}`,"to {recipient}":`收件人:{recipient}`,"Allow {subject} for longer…":`更长时间允许 {subject}…`,"For this conversation":`本次对话`,"the device {name}":`设备「{name}」`,"Until restart":`直到重启`,"For 24 hours":`24 小时内`,"Always for {subject}":`始终允许 {subject}`,"Fewer options":`收起`,"Show all":`展开全部`,"This kind of action is approved one at a time.":`这类操作需要逐次批准。`,Approved:`已批准`,Denied:`已拒绝`,"Expired without an answer":`已过期,未作答`,"approved by you":`已由你批准`,"covered by your {scope} permission":`已由你的{scope}授权覆盖`,"for this conversation":`本次对话`,"until restart":`直到重启`,"for 24 hours":`24 小时内`,always:`始终`,"email to {who}":`发送给 {who} 的邮件`,"{what} commands":`{what} 命令`,browser:`浏览器`,email:`邮件`,secret:`密钥`,"Waiting for you":`等你确认`,Answer:`回答`,LIVE:`实时`,BROWSER:`浏览器`,"Frame no longer available":`画面已不可用`,Page:`页面`,Document:`文档`,Image:`图片`,Data:`数据`,Code:`代码`,Open:`打开`,Download:`下载`,"Type into the focused field…":`输入到当前聚焦的输入框…`,Type:`输入`,"Press Enter":`按回车`,"Open a URL…":`打开一个网址…`,Go:`前往`,"Tap the page to click. If the browser was closed, open a URL first.":`点击画面即可点击网页。如果浏览器已关闭,请先打开一个网址。`,Refresh:`刷新`,"Take over":`接管`,"This frame is no longer available.":`这一帧画面已不可用。`,"Look again":`重新查看`,"1 frame":`1 帧`,"{n} frames":`{n} 帧`,"Scroll up":`向上滚动`,"Scroll down":`向下滚动`,"You have the page. Press Done when you are finished.":`页面现在由你操作。完成后按「完成」。`,"{name} waits meanwhile, then looks at the page as you left it and carries on. Passwords you type here go to the website, never to the model.":`{name} 会先等着,然后从你离开时的页面接着做。你在这里输入的密码只发给网站,不会给模型。`,"{name} is waiting for you":`{name} 在等你`,"{name} is working":`{name} 正在工作`,"Your turn":`该你了`,"Your turn: {reason}":`该你了:{reason}`,"You took over {thing}":`你接管了{thing}`,"the browser":`浏览器`,"the phone":`手机`,"The browser":`浏览器`,"The phone":`手机`,"Do this part yourself, then press Done. {name} looks again and carries on from there.":`这一步请你自己来,做完按「完成」。{name} 会重新看一眼屏幕,从那里接着做。`,"{name} waits. Press Done when you are finished and it looks again.":`{name} 在等。你弄完后按「完成」,它会重新看一眼。`,"{name} waited ten minutes and went on without you.":`{name} 等了十分钟,没等到你,先继续了。`,"Ended when the runtime restarted.":`运行时重启,这次接管结束。`,"You did it; {name} carried on.":`你做完了,{name} 接着做了。`,"Handed back; {name} carried on.":`已交还,{name} 接着做了。`,Close:`关闭`,"Open in a new tab":`在新标签页打开`,"No preview for this file type.":`此类型文件无法预览。`,"Download it":`下载文件`,"Empty file.":`空文件。`,"Could not load the file: {error}":`无法加载文件:{error}`,"Writing…":`正在写…`,"While you were away":`你离开期间`,"Could not write posts: {error}":`无法生成动态:{error}`,"Nothing yet. Once {name} works on a goal in the background or needs your approval, it shows up here.":`暂时还没有内容。当 {name} 在后台推进目标或需要你批准时,会显示在这里。`,"Next up":`接下来`,"Background work is off. {name} only acts when you ask.":`后台工作已关闭。{name} 只在你要求时行动。`,"Turn it on":`开启`,"No goal has a next step to work on.":`没有目标有可执行的下一步。`,"Add one":`添加一个`,"Working now":`正在进行`,"Quiet hours after {time}":`免打扰时段,{time} 之后`,"Around {time}":`大约 {time}`,Soon:`即将`,overdue:`已逾期`,"{n} more in line":`还有 {n} 个排队中`,"Check-in on":`跟进`,"{n} more":`还有 {n} 个`,Reminder:`提醒`,Routine:`例程`,"Working on your goal: {title}":`推进目标:{title}`,"Check-in: {title}":`跟进:{title}`,"Reminder: {title}":`提醒:{title}`,"Routine: {title}":`例程:{title}`,"New mail: {title}":`新邮件:{title}`,"Coming up: {title}":`即将开始:{title}`,"Webhook: {title}":`Webhook:{title}`,"Tidied memory":`整理了记忆`,"{label}: nothing new":`{label}:没有新进展`,"Open chat":`打开对话`,Today:`今天`,Yesterday:`昨天`,Menu:`菜单`,Stop:`停止`,"Nothing to stop":`没有正在进行的任务`,Message:`发消息`,"An emoji instead":`改用表情符号`,"Refresh ideas":`刷新灵感`,Planning:`规划`,Research:`调研`,Money:`财务`,People:`人际`,"Files & tools":`文件与工具`,"Just for you":`专属于你`,Tracking:`追踪`,"Show {n} more":`还有 {n} 个`,Cancelled:`已取消`,"Starter ideas. Refresh once {name} knows you better.":`入门灵感。等 {name} 更了解你之后再刷新。`,"Generated {when}":`生成于 {when}`,"Could not refresh ideas: {error}":`无法刷新灵感:{error}`,"Do it for me":`帮我做`,Health:`健康`,Finance:`财务`,Career:`事业`,Learning:`学习`,Relationships:`关系`,Family:`家庭`,Home:`家居`,Travel:`旅行`,Creative:`创作`,Other:`其他`,"New goal":`新目标`,Paused:`已暂停`,Finished:`已完成`,active:`进行中`,paused:`已暂停`,done:`已完成`,cancelled:`已取消`,pending:`待处理`,blocked:`受阻`,"{done}/{total} done":`已完成 {done}/{total}`,"No next step":`没有下一步`,"Next: {step}":`下一步:{step}`,"Next check-in {when}":`下次跟进 {when}`,"Due today":`今天到期`,"Due tomorrow":`明天到期`,"Due in {n} days":`{n} 天后到期`,"Was due {date}":`原定 {date} 到期`,"By {date}":`截止 {date}`,"No target date":`没有目标日期`,"No category":`未分类`,"Every day":`每天`,"Once a week":`每周一次`,"Once a month":`每月一次`,Weekdays:`工作日`,Weekly:`每周`,Monthly:`每月`,"Daily at {time}":`每天 {time}`,"Weekdays at {time}":`工作日 {time}`,"Weekly at {time}":`每周 {time}`,"{day}s at {time}":`每{day} {time}`,"Monthly on the {day} at {time}":`每月 {day} 日 {time}`,"Work on it now":`现在就推进`,"Work on {title} now":`现在推进「{title}」`,"{name} is working on “{title}” in the main chat":`{name} 正在主要聊天中推进“{title}”`,"{name} is working on it in the main chat":`{name} 正在主要聊天中处理`,"Check in with me now":`现在跟我确认进度`,"{name} will check in with you in the main chat":`{name} 会在主要聊天中跟你确认进度`,"Discuss this goal in chat →":`在对话中讨论这个目标 →`,"About my goal “{title}” ({id}): what's the status, and what should we do next?":`我们来聊聊我的目标“{title}”({id})。现在进展如何,下一步该做什么?`,Pause:`暂停`,Resume:`继续`,Done:`完成`,Delete:`删除`,"Delete goal":`删除目标`,"Delete “{title}”?":`删除“{title}”?`,Edit:`编辑`,Save:`保存`,"Saving…":`保存中…`,Saved:`已保存`,Cancel:`取消`,"Add step":`添加步骤`,"Add a step":`添加一个步骤`,"What should be done…":`要做什么…`,"Mark step {n} {status}":`把第 {n} 步标记为{status}`,"Adjust the plan for “{title}”?":`调整“{title}”的计划?`,"Keeps the 1 step already done.":`保留已完成的 1 个步骤。`,"Keeps the {n} steps already done.":`保留已完成的 {n} 个步骤。`,"New remaining steps:":`新的剩余步骤:`,"Keep my plan":`保留我的计划`,"Use {name}'s plan":`采用 {name} 的计划`,"Kept your plan":`已保留你的计划`,"Plan updated":`计划已更新`,"What do you want to achieve?":`你想实现什么?`,"Why it matters, constraints (optional)":`为什么重要、有哪些限制(可选)`,"Area of life":`生活领域`,"Target date":`目标日期`,"Steps, one per line (optional, or let {name} plan them)":`步骤,每行一个(可选,也可以让 {name} 来规划)`,"Let {name} plan it":`让 {name} 来规划`,'Create a goal for me: "{title}"{description}{extras}. Break it into concrete steps with the goals tool, then tell me the plan.':`帮我创建一个目标:“{title}”{description}{extras}。用 goals 工具把它拆成具体步骤,然后告诉我计划。`,"Day {d}":`第 {d} 天`,"Search files":`搜索文件`,"No files match.":`没有匹配的文件。`,Latest:`最新`,"Updated {when}":`更新于 {when}`,Memory:`记忆`,"What {name} remembers about you. Read it, add to it, or make {name} forget; nothing here is hidden from you.":`{name} 对你的了解都在这里。你可以翻看、补充,或让 {name} 忘掉,没有什么是瞒着你的。`,"Tell {name} something to remember, e.g. “I'm vegetarian” or “My sister's birthday is 14 May”":`告诉 {name} 要记住的事,例如“我是素食者”或“我妹妹的生日是 5 月 14 日”`,Remember:`记住`,Forget:`忘掉`,"Forget “{text}”?":`忘掉“{text}”?`,"Nothing remembered yet":`还没有记住任何内容`,"{name} saves durable facts you share in chat (preferences, people, routines) and never secrets.":`{name} 会保存你在对话中分享的长期事实(偏好、人物、习惯),绝不保存密钥或密码。`,"added by you":`由你添加`,"saved by {name}":`由 {name} 保存`,"updated {when}":`更新于{when}`,"Tidy up":`整理`,"Tidying…":`整理中…`,"Merge lines that say the same thing and drop what was never a fact about you. Every change can be undone.":`把意思相同的条目合并,删掉那些并不是你本人情况的内容。每处改动都能撤销。`,"Nothing to tidy: {n} memories, all distinct.":`无需整理:{n} 条记忆,互不重复。`,"Tidied: {merged} merged, {dropped} dropped. Undo below if needed.":`已整理:合并 {merged} 条,去掉 {dropped} 条。如有需要可在下方撤销。`,"Recent changes":`最近的改动`,Merged:`已合并`,Dropped:`已去掉`,Updated:`已更新`,restored:`已恢复`,Undo:`撤销`,profile:`个人资料`,preference:`偏好`,people:`人物`,routine:`习惯`,constraint:`限制`,general:`一般`,idle:`空闲`,working:`工作中`,waiting:`等待中`,Activity:`活动`,Approvals:`审批`,Connections:`连接`,Settings:`设置`,"Nothing is waiting for you.":`没有需要你处理的事项。`,"{n} events":`{n} 个事件`,failed:`失败`,updated:`已更新`,"background check":`后台检查`,"Every tool call goes through the Sentinel and is written to the audit log, including the ones it refused.":`每一次工具调用都经过 Sentinel 审查并写入审计日志,包括被拒绝的那些。`,"Sentinel mode:":`Sentinel 模式:`,balanced:`平衡`,cautious:`谨慎`,"hands-off":`放手`,"Safe and moderate actions run freely; anything sensitive (email, shell, purchases) waits for you.":`安全和中等风险的操作自由执行;任何敏感操作(邮件、终端命令、购买)都会等你批准。`,"Moderate and sensitive actions both wait for your approval.":`中等和敏感风险的操作都会等待你的批准。`,"Everything is approved automatically except explicit deny rules. Use with care.":`除明确的拒绝规则外,一切自动批准。请谨慎使用。`,"Always asks before: {tools}.":`以下操作总会先问你:{tools}。`,"Private data was read this session: network calls to new destinations need approval.":`本次会话已读取过私密数据:访问新的网络目标需要批准。`,"Commands run in a sandbox":`命令在沙箱中运行`,"Commands run without a sandbox":`命令未在沙箱中运行`,"Each shell or Python call gets its own namespace: only the workspace is writable, your home directory is not there, and there is no network unless the command needs it.":`每次 shell 或 Python 调用都有独立的命名空间:只有工作区可写,你的主目录不在其中,命令不需要网络就没有网络。`,"Each shell or Python call runs in the workspace with a scrubbed environment; the container is the boundary.":`每次 shell 或 Python 调用都在工作区中以清洗过的环境运行;容器就是边界。`,"Each shell or Python call runs in the workspace with a scrubbed environment. On Linux, installing bubblewrap gives each one its own namespace.":`每次 shell 或 Python 调用都在工作区中以清洗过的环境运行。在 Linux 上安装 bubblewrap 后,每次调用会有独立的命名空间。`,"After reading private data, new network destinations need approval.":`读取私密数据之后,访问新的网络目标需要批准。`,"Permissions you granted":`你授予的权限`,"No standing approvals. When you answer “always allow” to a risky step, it is listed here and can be revoked; approvals you give once are not kept.":`还没有长期批准。对有风险的操作选择“始终允许”后,会列在这里,随时可以撤回;“允许一次”的批准不会保留。`,"Nothing yet today. What you ask for and what {name} does about it shows up here.":`今天还没有动态。你提的要求和 {name} 做的事会显示在这里。`,"Share avatar":`分享形象`,"Creates a routine":`会创建一条例程`,"Creates a goal":`会创建一个目标`,"Create routine":`创建例程`,"Start goal":`开始这个目标`,"Routine set: every day at {time}. It is listed under Goals.":`例程已设好:每天 {time}。在「目标」页可以看到。`,"A morning brief":`早间简报`,"Before you leave each morning: the weather, the first thing on your plate and anything new worth knowing.":`每天出门前:天气、今天的第一件事,以及值得知道的新消息。`,"Morning brief: check today's weather, read my calendar and reminders for today, and tell me in five lines what matters.":`早间简报:查今天的天气,读我今天的日程和提醒,用五行告诉我要紧的事。`,"drawn from the picture you attached":`按你附的图片来画`,"Share my avatar":`分享我的虚拟形象`,"Pick a card. It goes out through the system share sheet, or saves as a picture where there is none.":`选一张卡片,用系统分享发出去;没有系统分享的浏览器会保存为图片。`,"Hi, I'm {name}, a personal AI agent. Meet nanoMuse: open source, runs on your phone.":`你好,我是你的个人 AI 智能体 {name}。认识一下 nanoMuse:开源,在手机上本地运行。`,"Your personal AI agent, open source · {repo}":`你的个人 AI 智能体,开源 · {repo}`,Later:`以后再说`,Share:`分享`,"Save picture":`保存图片`,"Saved the card as a picture.":`卡片已保存为图片。`,"The card could not be drawn.":`卡片没能画出来。`,"the hands in {app}":`在 {app} 里动手`,"granted {time}":`授予于 {time}`,"until {time}":`直到 {time}`,"Revoke {what}":`撤销 {what}`,"Revoked: {subject}":`已撤销:{subject}`,"Reset all granted permissions":`重置所有已授予的权限`,"Permissions reset":`权限已重置`,"Always ask (from config)":`始终询问(来自配置)`,Off:`关闭`,Low:`低`,Default:`默认`,High:`高`,"Off. {name} only works when you ask.":`已关闭。{name} 只在你要求时工作。`,"every {n} min {name} picks one active goal and works on its next step.":`每 {n} 分钟 {name} 挑选一个进行中的目标并推进它的下一步。`,"Quiet hours until {time}.":`免打扰时段直到 {time}。`,"Next around {time}.":`下一次大约在 {time}。`,"No background work in this window; anything due waits until it ends.":`此时段不进行后台工作;到期的事项会等到时段结束。`,"Level, interval and quiet hours in Settings":`在设置中调整级别、间隔和免打扰时段`,"In line":`排队中`,"No active goal has a next step. Add one in Goals and {name} will pick it up.":`没有进行中的目标有下一步。在目标中添加一个,{name} 会接手。`,"{n} queued":`{n} 个排队中`,"Check-ins":`跟进`,"Goal nudges you asked for; they arrive whatever the proactivity level, but wait out quiet hours.":`你要求的目标提醒;无论主动性级别如何都会送达,但会避开免打扰时段。`,"Reminders & routines":`提醒与例程`,"When something happens":`当某事发生时`,"mail matching “{match}”":`匹配“{match}”的邮件`,"any new mail":`任何新邮件`,"events matching “{match}”":`匹配“{match}”的日程`,"any event":`任何日程`,"{n} min before {what}":`{what}开始前 {n} 分钟`,"webhook “{match}”":`Webhook“{match}”`,webhook:`Webhook`,"Nothing yet. Tell {name} “when the landlord writes back, summarise it and draft a reply” or “half an hour before any review, brief me”.":`还没有。告诉 {name}“房东回信时,帮我总结并起草回复”或“任何评审开始前半小时,给我一份简报”。`,"fired {n}×":`触发 {n} 次`,"not fired yet":`尚未触发`,"Copy URL":`复制地址`,"Run now: {text}":`现在运行:{text}`,"Webhook URL copied":`已复制 Webhook 地址`,"The inbox could not be read: {error}":`无法读取收件箱:{error}`,"Inbox checked {when}; {name} looks every {n} min.":`收件箱{when}检查过;{name}每 {n} 分钟查看一次。`,"{name} will look at the inbox shortly, then every {n} min.":`{name}稍后会查看收件箱,之后每 {n} 分钟一次。`,"Each time it happens {name} does the work in the chat it was set from and reports in the Feed. A mail or a request is treated as data, never as instructions.":`每次触发时,{name} 会在设定它的那个对话里把事做完,再到动态里汇报。邮件和请求的内容只当资料看,绝不当作指令执行。`,"Webhook ready":`Webhook 已就绪`,"POST anything to this URL and the work starts. The key is in the URL; share it only with the program that will call it.":`向这个地址 POST 任意内容即可开始工作。密钥就在地址里,只交给要调用它的程序。`,Copy:`复制`,"New mail":`新邮件`,"Before an event":`日程开始前`,Webhook:`Webhook`,"Connect a mailbox under Connections first.":`请先在“连接”里接入邮箱。`,"Add a calendar under Connections first.":`请先在“连接”里添加日历。`,"Words in the sender or subject (empty: any mail)":`发件人或主题中的词(留空:任何邮件)`,"Words in the title or place (empty: any event)":`标题或地点中的词(留空:任何日程)`,"A name for this hook":`给这个 Webhook 起个名字`,"Minutes before":`提前分钟数`,"min before":`分钟前`,"What should be done each time…":`每次要做什么……`,"When {condition}":`当{condition}`,"Set trigger":`设置触发器`,"A time you named is kept whatever the level or the quiet hours. Reminders just say it; routines do the work and report.":`你指定的时间无论级别或免打扰时段都会遵守。提醒只是说一声;例程会执行工作并汇报。`,"No reminders":`没有提醒`,"Nothing scheduled. Tell {name} “remind me at six to call mum” or “every weekday morning, summarise my unread email”.":`没有安排。告诉 {name}“六点提醒我给妈妈打电话”或“每个工作日早上汇总我的未读邮件”。`,"{n} finished recently":`最近完成 {n} 个`,"Do “{text}” now":`现在执行“{text}”`,"Remind me now: {text}":`现在提醒我:{text}`,"Cancel: {text}":`取消:{text}`,"{name} will say it now":`{name} 现在就会说`,"+ Add":`+ 添加`,"Remind me":`提醒我`,Repeat:`重复`,"What to remind you of…":`提醒你什么…`,"Set reminder":`设置提醒`,"Set routine":`设置例程`,at:`于`,"1 approval waiting for you":`需要你批准`,"{n} approvals waiting for you":`{n} 项需要你批准`,"{n} approval":`{n} 项审批`,You:`你`,"Its name and look, how careful it is, how often it speaks up.":`名字和形象,有多谨慎,多主动。`,Name:`名字`,Avatar:`头像`,"What it calls you":`它怎么称呼你`,"Safety · Sentinel":`安全 · Sentinel`,"A separate gatekeeper reviews every action. Pick how often it should check in with you.":`一个独立的守门人审查每一次操作。选择它多久向你确认一次。`,Balanced:`平衡`,"Browse, read and write files freely; stop for anything hard to undo: email, purchases, shell commands.":`自由浏览、读写文件;遇到难以撤销的操作时停下:邮件、购买、终端命令。`,Cautious:`谨慎`,"Also ask before moderate actions like fetching web pages or writing files.":`对抓取网页或写入文件等中等风险操作也先询问。`,"Hands-off":`放手`,"Approve everything automatically except explicit deny rules. For trusted, unattended runs only.":`除明确的拒绝规则外一切自动批准。仅用于可信的无人值守运行。`,"Decides when the Sentinel asks you before a call.":`决定 Sentinel 在调用前何时向你询问。`,Proactivity:`主动性`,"Only works when you ask.":`只在你要求时工作。`,"Checks in half as often; speaks up only when a step is done or it needs you.":`检查频率减半;只在完成一步或需要你时才发声。`,"Works on goals on schedule; reports real progress, stays quiet otherwise.":`按计划推进目标;汇报实质进展,其余时间保持安静。`,"Checks in twice as often and always reports, even 'still on track'.":`检查频率加倍并总是汇报,即使只是“仍在正轨上”。`,"Background work":`后台工作`,"Check-in interval":`检查间隔`,"{n} min":`{n} 分钟`,"{n} h":`{n} 小时`,"{n} d":`{n} 天`,"Halved at this level":`此级别下减半`,"Doubled at this level":`此级别下加倍`,"Quiet hours":`免打扰时段`,"Quiet hours start":`免打扰时段开始`,"Quiet hours end":`免打扰时段结束`,From:`从`,to:`到`,Notifications:`通知`,"Approvals, questions, finished background work and check-ins; nothing while the app is on screen.":`审批、提问、后台完成的事和到点的跟进;应用在前台时不打扰。`,"Let {name} notify this device":`让 {name} 通知这台设备`,"Let {name} notify this phone":`让 {name} 通知这台手机`,"The app stays connected to your server in the background. Approvals, questions and finished background work arrive as notifications and open the right chat.":`应用在后台保持与服务器的连接。审批、提问和后台完成的工作会以通知送达,并打开对应的对话。`,"nanoMuse for Android {version}":`nanoMuse Android 版 {version}`,"Disconnect from this server":`断开此服务器`,"This device only":`仅这台设备`,"1 device subscribed":`1 台设备已订阅`,"{n} devices subscribed":`{n} 台设备已订阅`,"Send a test":`发送测试`,"Sent. It should arrive in a moment":`已发送,应该马上就到`,"Notifications need https:// (or localhost). Over plain http on your LAN the app works, this part stays off; see docs/deployment.md.":`通知需要 https://(或 localhost)。在局域网的普通 http 上应用可以使用,但这部分功能保持关闭,参见 docs/deployment.md。`,"This browser cannot receive push notifications.":`这个浏览器无法接收推送通知。`,"This browser has no push service (embedded browsers often don't). Use Chrome, Edge, Firefox or Safari 16.4+ on the phone.":`这个浏览器没有推送服务(内嵌浏览器通常没有)。请在手机上使用 Chrome、Edge、Firefox 或 Safari 16.4+。`,"Notifications are blocked for this site in the browser settings":`浏览器设置中已屏蔽此站点的通知`,"Blocked for this site. Allow notifications in the browser's site settings, then try again.":`通知在这个站点被关掉了。到浏览器的站点设置里允许通知,再试一次。`,"The server was installed without pywebpush.":`服务器安装时未包含 pywebpush。`,"On a phone, add the app to the home screen first; the icon then shows a badge and notifications open the right chat.":`手机上请先把应用添加到主屏幕;图标会显示角标,通知会打开对应的对话。`,Model:`模型`,"Provider / model":`服务商 / 模型`,"Reveal the model's reasoning under each reply when the provider exposes it.":`当服务商提供时,在每条回复下方显示模型的推理过程。`,"Reply language":`回复语言`,"What {name} writes in":`{name} 用什么语言回复`,Auto:`自动`,"Match mine":`跟随我的语言`,"App language":`应用语言`,Appearance:`外观`,Light:`浅色`,Dark:`深色`,"Follow the system":`跟随系统`,About:`关于`,"{version} is out":`{version} 已发布`,"nanoMuse {version}":`nanoMuse {version}`,"Tell {name} something to remember":`在对话里告诉 {name} 一件值得记住的事`,"Write one":`写一个`,"Latest {version}; you have it":`最新版 {version},你已经在用了`,Update:`更新`,"Check now":`现在检查`,"Checking…":`正在检查…`,"Could not check":`没能检查到最新版本`,"Checked {when}":`上次检查:{when}`,"The phone app checks for updates on its own.":`手机 App 会自己检查更新。`,"Update checks are off here.":`这里关闭了更新检查。`,"To update: pip install -U nanomuse, pull the new image, or use the desktop app's Update.":`更新方式:pip install -U nanomuse、拉取新镜像,或在桌面 App 里点“更新”。`,"Data:":`数据:`,"Workspace:":`工作区:`,"Forget this device's access token":`忘掉这台设备的访问令牌`,"does the work":`负责干活`,"Not scheduled":`未安排时间`,Calendar:`日历`,calendar:`日历`,Tomorrow:`明天`,"all day":`全天`,"{n} scheduled":`{n} 个安排`,"Nothing on the calendar today.":`今天日历上没有安排。`,"Ask about your week":`问问这周的安排`,"{name} could not be read":`{name} 读取失败`,"Your agenda, free time, and events it can draft":`你的日程、空闲时间,以及它起草的日程`,"{n} not reading":`{n} 个读取失败`,"1 event":`1 个事件`,"{n} calendars":`{n} 个日历`,"read {when}":`{when}读取`,"Calendar connected":`日历已连接`,"Reads your calendar from its private .ics link; the link stays in the vault. It never changes your calendar; an event it proposes comes as a file you add with a tap.":`通过私密 .ics 链接读取你的日历,链接存在保险库里。它不会改动你的日历;它建议的日程会做成文件给你,点一下就能加进去。`,"not read yet":`尚未读取`,"Where is the link?":`链接在哪里?`,"Settings → your calendar → Integrate calendar → Secret address in iCal format":`设置 → 你的日历 → 整合日历 → iCal 格式的私密地址`,"Settings → Calendar → Shared calendars → Publish a calendar → ICS link":`设置 → 日历 → 共享日历 → 发布日历 → ICS 链接`,"Share Calendar → Public Calendar → copy the webcal:// link":`共享日历 → 公共日历 → 复制 webcal:// 链接`,"Settings → Calendars → Export → Calendar URL":`设置 → 日历 → 导出 → 日历 URL`,"A path on the machine where nanoMuse runs, for example ~/calendar.ics":`nanoMuse 所在机器上的文件路径,例如 ~/calendar.ics`,".ics file":`.ics 文件`,Work:`工作`,"Private .ics link or file path":`私密 .ics 链接或文件路径`,"Stored encrypted in the vault as CALENDAR_{name}.":`加密保存在保险库中,名为 CALENDAR_{name}。`,"nanoMuse fetches whatever address you put here, from this machine; only paste links you trust.":`nanoMuse 会从这台机器上去取你填的任何地址,只粘贴你信任的链接。`,"Add a calendar":`添加日历`,"Added, but it could not be read: {error}":`已添加,但读取失败:{error}`,"Google Calendar":`Google 日历`,"Client set — sign in with Google":`客户端已配置,请用 Google 登录`,"Paste your Google OAuth client id and secret":`粘贴你的 Google OAuth 客户端 ID 和密钥`,"Client ID":`客户端 ID`,"From the OAuth client you downloaded in Google Cloud Console.":`来自你在 Google Cloud Console 下载的 OAuth 客户端。`,"Client secret":`客户端密钥`,"A secret is saved. Type a new one only to replace it.":`密钥已保存。只有在需要更换时才重新输入。`,"Stored encrypted in the vault as GOOGLE_CALENDAR_SECRET.":`加密保存在保险库中,名为 GOOGLE_CALENDAR_SECRET。`,"Callback URL":`回调 URL`,"Register this exact URL on the OAuth client as an authorized redirect URI.":`把这个 URL 原样注册为该 OAuth 客户端的已授权重定向 URI。`,"Let the agent create and change events":`允许它创建和修改日程`,"Off: read-only, the agent can look but not touch.":`关闭后为只读,它只能查看,不能改动。`,"Save client":`保存客户端`,"Sign in with Google":`用 Google 登录`,"Finish signing in with Google in the window that opened.":`在打开的窗口里完成 Google 登录。`,"Sign in needed":`需要登录`,"Read-only":`只读`,Disconnected:`已断开`,"Calendar to read and write":`读取和写入的日历`,"Events the agent reads and creates land here.":`它读取和创建的日程都会落在这个日历里。`,"{name} (primary)":`{name}(主日历)`,"read + write":`读写`,"read-only":`只读`,Contacts:`通讯录`,"1 person":`1 人`,"{n} people":`{n} 人`,"Address book connected":`通讯录已连接`,"Who is who, so it never guesses an address":`知道谁是谁,从不猜地址`,"told to it in chat":`在聊天中告诉它的`,"{n} address books":`{n} 个通讯录`,"Import a .vcf export from Google Contacts, iCloud, Outlook or your phone, or paste a link to one. People you mention in chat go into its own book. It looks people up before writing to them and warns when an address is unknown.":`导入 Google 通讯录、iCloud、Outlook 或手机导出的 .vcf 文件,或粘贴一个链接。你在聊天中提到的人会记进它自己的名册。写信前它会先查人,地址不认识时会提醒。`,"My contacts":`我的联系人`,"added in chat":`聊天中添加`,iPhone:`iPhone`,"A .vcf file from your phone or computer":`手机或电脑上的 .vcf 文件`,"Google Contacts: Export → vCard. iPhone: Contacts → select all → Share → Save to Files. Outlook: People → Manage → Export.":`Google 通讯录:导出 → vCard。iPhone:通讯录 → 全选 → 共享 → 存储到“文件”。Outlook:人员 → 管理 → 导出。`,"Choose a .vcf file":`选择 .vcf 文件`,"Or a link / path to one":`或一个链接 / 路径`,"A link is stored encrypted in the vault as CONTACTS_{name}.":`链接会加密保存在保险库中,名为 CONTACTS_{name}。`,"Add an address book":`添加通讯录`,"Find someone, as the agent would":`像 Agent 那样查一个人`,"No one matches.":`没有匹配的人。`,"Working hours":`工作时间`,"Working hours start":`工作时间开始`,"Working hours end":`工作时间结束`,"Free time is looked for inside these hours.":`空闲时间只在这个时段内查找。`,"Read again":`重新读取`,Event:`日程`,"No event in this file.":`这个文件里没有日程。`,"Untitled event":`未命名日程`,"Add to calendar":`加入日历`,"Opens in your calendar app, which asks before it saves anything.":`会在你的日历应用中打开,保存前会先询问你。`,"What {name} can reach; keys stay in the vault on this machine.":`{name} 能用到的东西;密钥留在这台机器的保险库里。`,"No key yet":`还没有密钥`,"Key missing from vault":`保险库中缺少密钥`,"Key in vault":`密钥已在保险库`,"Key from config":`密钥来自配置`,"No key needed":`无需密钥`,Provider:`服务商`,"Base URL":`Base URL`,"API key":`API 密钥`,"A key is in the vault. Leave blank to keep it.":`保险库中已有密钥。留空则保持不变。`,"Stored encrypted in the vault as LLM_API_KEY.":`以 LLM_API_KEY 加密存储在保险库中。`,"model name":`模型名称`,"Tool calling":`工具调用`,"Auto uses the API's function calling and falls back to describing tools in the prompt when the endpoint rejects them. Prompt: for endpoints that silently ignore tools.":`自动:使用 API 的函数调用,当端点拒绝时回退为在提示词中描述工具。提示词:用于会静默忽略工具的端点。`,Test:`测试`,"Model saved":`模型已保存`,'Replied "{reply}" in {ms} ms':`在 {ms} 毫秒内回复了“{reply}”`,"Email connected":`邮件已连接`,"Saved, but the test failed":`已保存,但测试失败`,"Email disconnected":`邮件已断开`,Incomplete:`未完成`,"Not connected":`未连接`,Email:`邮件`,"reads and sends":`读取和发送`,"Read your inbox, draft and send mail":`读取收件箱、起草和发送邮件`,"Reading is a moderate action; sending always asks you first. Use an app password where your provider offers one.":`读取是中等风险操作;发送总会先询问你。如果服务商提供应用专用密码,请使用它。`,Address:`邮箱地址`,Password:`密码`,"app password":`应用专用密码`,"A password is in the vault. Leave blank to keep it.":`保险库中已有密码。留空则保持不变。`,"Stored encrypted in the vault as EMAIL_PASSWORD.":`以 EMAIL_PASSWORD 加密存储在保险库中。`,"IMAP server":`IMAP 服务器`,Port:`端口`,"SMTP server":`SMTP 服务器`,"STARTTLS for SMTP (off for port 465)":`SMTP 使用 STARTTLS(465 端口请关闭)`,"Save & test":`保存并测试`,Disconnect:`断开`,"Signed in · {n} messages in the inbox":`已登录 · 收件箱有 {n} 封邮件`,Browser:`浏览器`,"Open pages, click, fill forms, screenshot":`打开页面、点击、填表、截图`,"Playwright is not installed on the server":`服务器上未安装 Playwright`,On:`开`,Unavailable:`不可用`,"Install it where the server runs:":`在服务器运行的机器上安装:`,"Server connected":`服务器已连接`,"MCP servers":`MCP 服务器`,"{n} of {total} connected · {tools} tools":`{total} 个中已连接 {n} 个 · {tools} 个工具`,"Add tools from any Model Context Protocol server":`从任意 Model Context Protocol 服务器添加工具`,"{n} on":`{n} 个已开启`,None:`无`,"{n} tools":`{n} 个工具`,"from config.toml":`来自 config.toml`,Remove:`移除`,Command:`命令`,"Run locally over stdio, for example: npx -y @modelcontextprotocol/server-filesystem ./workspace":`通过 stdio 在本地运行,例如:npx -y @modelcontextprotocol/server-filesystem ./workspace`,"or URL":`或 URL`,"A remote server over Streamable HTTP.":`通过 Streamable HTTP 连接的远程服务器。`,"Risk of its tools":`其工具的风险级别`,"Add a server":`添加服务器`,"Connected on {device}; sign in here to use it on this device":`已在 {device} 上连接,在这台设备上登录后即可使用`,"Sign in here":`在这里登录`,"Stored in the vault":`已存入保险库`,Vault:`保险库`,"{n} secrets · encrypted on your machine":`{n} 个密钥 · 在你的机器上加密`,"Encrypted secrets the model never sees":`模型永远看不到的加密密钥`,"Refer to a secret as":`在工具调用或配置中用`,"in a tool call or config: the value is filled in after the Sentinel approves and is redacted from everything the model reads.":`引用密钥:真实值会在 Sentinel 批准后填入,并从模型读到的所有内容中脱敏。`,"Delete {name}":`删除 {name}`,Value:`值`,Store:`存储`,"Skip setup":`跳过设置`,"Meet your nanoMuse":`认识你的 nanoMuse`,"Your name":`你的名字`,"The model behind it":`背后的模型`,"A model is already set up on the server. Keep it, or switch here.":`服务器上已经配置了模型。可以保留,也可以在这里切换。`,"Connect your mail, calendar and contacts":`连接你的邮箱、日历和通讯录`,"Optional. With a mailbox connected it can read what came in and draft replies; it will always ask before sending. With a calendar it knows your day and finds free time. With your contacts it knows who is who. The browser and MCP servers are under Connections later.":`可选。连上邮箱,它能读新邮件、起草回复,发之前一定先问你。连上日历,它知道你这一天的安排,也能找出空档。连上通讯录,它知道谁是谁。浏览器和 MCP 服务器之后在「连接」里设置。`,Back:`返回`,"Get started":`开始`,Skip:`跳过`,"Save a model to continue":`保存模型后继续`,"Skip for now":`暂时跳过`,"just now":`刚刚`,"any moment":`随时`,"in {span}":`{span}后`,"{span} ago":`{span}前`,"Checked on {label}: nothing new":`已检查 {label}:没有新进展`,"Notes from {name}":`来自 {name} 的笔记`,"Reminders from {name}":`来自 {name} 的提醒`,Once:`一次`,Plan:`计划`,Skills:`技能`,Yours:`你的`,"Built in":`内置`,Fetch:`获取`,"Use in chat":`在聊天中使用`,"Make your own copy":`复制一份改成你的`,"Edit skill":`编辑技能`,"New skill":`新建技能`,"From a link":`从链接导入`,"Files that come with it":`随附文件`,"Folders that could not be read":`无法读取的文件夹`,"Nothing of your own yet":`还没有你自己的技能`,"How {name} does a job, written down once. Start one in chat with /name, or just ask; it picks the skill that fits.":`把 {name} 做某件事的方法写下来,一次就够。在聊天里输入 /名称 直接开始,或者直接提要求,它会自己挑合适的技能。`,"After a job went well, tell {name} “save this as a skill”; it writes the steps down and asks you first. Or write one here, or paste a link to a SKILL.md.":`一件事做得顺利之后,对 {name} 说“把这个存成技能”,它会把步骤写下来,并先征求你的同意。也可以在这里手写一个,或粘贴一个 SKILL.md 的链接。`,"Switch one off to keep it out of {name}'s list. A skill of yours with the same name replaces it.":`关掉某一项,它就不会出现在 {name} 的清单里。你的同名技能会替代内置的那一个。`,"Yours live in {dir}, one folder each with a SKILL.md, the Agent Skills format, so recipes written for other agents work here too.":`你的技能保存在 {dir},每个一个文件夹,里面是一份 SKILL.md。这是 Agent Skills 通用格式,为其他智能体写的技能在这里同样可用。`,"Delete the skill “{name}”? Its folder goes with it.":`删除技能“{name}”?它的文件夹会一并删除。`,"Saving makes a copy of yours with the same name; it replaces the built-in one.":`保存后会生成一份你的同名技能,替代内置的那一个。`,"A SKILL.md: a name and a one-line description up top, then the steps in Markdown.":`一份 SKILL.md:开头是名称和一行说明,下面用 Markdown 写步骤。`,"A raw SKILL.md link, or a GitHub folder or file page.":`SKILL.md 的原始文件链接,或 GitHub 上的文件夹/文件页面。`,"Pick a name first; a template appears here.":`先起个名字,这里会出现一份模板。`,"Attach a file":`添加附件`,Attachments:`附件`,"Say what to do with it…":`说说要拿它做什么……`,"Upload failed":`上传失败`,"Web search":`网页搜索`,"Not set up":`未设置`,"{provider} at {host}":`{provider}({host})`,"{provider} needs {what}; searches use DuckDuckGo until then":`{provider}还需要{what},在此之前搜索走 DuckDuckGo`,"a key":`一个密钥`,"an instance URL":`实例地址`,"DuckDuckGo needs nothing, but it is scraped and rate-limits now and then. For searches that always work, use a provider with an API. Whichever you pick, a failed search falls back to DuckDuckGo with a note.":`DuckDuckGo 无需任何配置,但它是抓取来的结果,偶尔会被限流。想让搜索始终可用,选一个带 API 的服务。无论选哪个,搜索失败时都会退回 DuckDuckGo 并附上说明。`,"Stored encrypted in the vault as SEARCH_API_KEY.":`加密存入保险库,名为 SEARCH_API_KEY。`,"Get a key from {label}":`到 {label} 获取密钥`,"Instance URL":`实例地址`,"A SearXNG you run, with the JSON format enabled in its settings.":`你自己运行的 SearXNG,需在其设置中启用 JSON 格式。`,"{provider} · {n} results · {ms} ms":`{provider} · {n} 条结果 · {ms} 毫秒`,"Recall by meaning":`按含义召回`,"Keyword recall only":`仅按关键词召回`,"By keyword":`按关键词`,"Not reachable":`连不上`,"Not tried yet":`尚未尝试`,Mode:`模式`,Endpoint:`接口`,"Embedding model":`向量模型`,"Same as the model":`与模型相同`,"Another endpoint":`另一个接口`,"{model} at {host}":`{model}({host})`,"{model} · {n} of {total} memories indexed":`{model} · 已索引 {n}/{total} 条记忆`,"{model} · {dims} dims · {n} memories indexed · {ms} ms":`{model} · {dims} 维 · 已索引 {n} 条记忆 · {ms} 毫秒`,"Memories are embedded once and a message finds the ones that mean the same thing, in any language: “写邮件给房东” finds “the landlord is Bob Li”. Keyword recall stays; the two are fused.":`每条记忆只做一次向量化,一句话就能找到含义相同的记忆,不分语言:“写邮件给房东”能找到“the landlord is Bob Li”。关键词召回仍然保留,两者合并排序。`,"Auto uses the model's endpoint when it has embeddings and falls back to keywords when it does not. On insists and warns. Off: keywords only.":`自动:模型接口支持向量化就用,不支持就退回关键词。开:坚持使用,失败时给出警告。关:只用关键词。`,"Any OpenAI-compatible /embeddings: Ollama with an embedding model pulled, OpenAI, a gateway.":`任何 OpenAI 兼容的 /embeddings 接口:拉取了向量模型的 Ollama、OpenAI、网关。`,"The model's endpoint and key. DeepSeek has no embeddings; pick another endpoint.":`使用模型自己的接口和密钥。DeepSeek 没有向量化接口,请选另一个接口。`,"Stored encrypted in the vault as EMBEDDINGS_API_KEY. Ollama needs none.":`加密存在保险库里,名为 EMBEDDINGS_API_KEY。Ollama 不需要密钥。`,"Blank uses the endpoint's default: {model}. On Ollama: ollama pull qwen3-embedding:0.6b (reads Chinese and English).":`留空则用该接口的默认模型:{model}。Ollama 上:ollama pull qwen3-embedding:0.6b(中英文都能读)。`,Phone:`手机`,"{name} is connected":`{name} 已连接`,"A phone":`一台手机`,"No phone connected. Open the app on the phone":`没有连接的手机。在手机上打开 App`,"Tap, type and swipe in the apps on your phone":`在你手机上的 App 里点击、输入、滑动`,Waiting:`等待中`,"Operate the phone":`操作手机`,"When on, the agent can read the screen and act in the apps on the connected phone: 12306, WeChat, Alipay… It asks before paying, sending or deleting.":`打开后,智能体可以读取已连接手机的屏幕,并在上面的 App 里操作:12306、微信、支付宝……付款、发送、删除之前会先问你。`,"{name} ({platform}), {n} apps":`{name}({platform}),{n} 个 App`,Ready:`就绪`,"Not yet":`还没开`,"Not on this Android":`这个安卓版本不支持`,"Operating the screen needs Android 11 or newer; this phone can still be used for everything else.":`操作屏幕需要 Android 11 或更新;其他功能这台手机都能用。`,"Turn on the nanoMuse accessibility service; that is how it sees the screen and taps for you, only while a task runs, with a Stop button on screen.":`打开 nanoMuse 的无障碍服务,它靠这个看屏幕、替你点击,只在任务进行时工作,屏幕上始终有停止按钮。`,"Open Accessibility settings":`打开无障碍设置`,"App settings":`应用设置`,"Greyed out with “Restricted setting”? Android 13+ does that for apps installed from a download: in App settings tap ⋮ → Allow restricted settings, then come back.":`灰色且提示「受限设置」?Android 13+ 对下载安装的应用会这样:在应用设置里点 ⋮ → 允许受限设置,再回来。`,"Android may switch the service off after an update or a battery clean-up; if the phone stops answering, come back here.":`系统更新或电池清理后安卓可能会把服务关掉;手机不再响应时回到这里看看。`,"On the phone's screen: {gui} of {total} steps ({pct}%). The screen is the last resort; a skill, a fetch or the browser comes first.":`在手机屏幕上操作:{total} 步里有 {gui} 步({pct}%)。屏幕是最后一招,技能、抓取、浏览器优先。`,"last seen in {app}":`上次看到在 {app}`,"The operator's model looks at screens step by step: a small, fast model that takes pictures. The Hands model row under Chat model picks one on the same endpoint and key; the fields here are for a different endpoint. Empty = {model}.":`操作屏幕的模型一步步看截图:选一个小而快、能看图的模型。「对话模型」卡片里的「动手模型」一行在同一个接口和 key 上选;这里的字段用于另一个接口。留空 = {model}。`,"same as the chat model":`与对话模型相同`,"the chat model":`对话模型`,"Chat model":`对话模型`,"Hands model":`动手模型`,"Currently {value}":`当前为 {value}`,"The model that looks at screens when the hands run: the phone, this computer, a page the browser cannot read. Your account's hands model is {model}; the chat model above is a different pick.":`动手时看屏幕的模型:手机、这台电脑、浏览器读不了的页面。你账号的动手模型是 {model};上面的对话模型是另一项选择。`,"The model that looks at screens when the hands run: a small, fast one that takes pictures, on the same endpoint and key. Default: this provider's own hands model.":`动手时看屏幕的模型:小而快、能看图,用同一个接口和 key。默认:这个服务商自己的动手模型。`,"The model that looks at screens when the hands run. This provider has no model that sees, so the hands use your account's, {model}, unless you pick one here.":`动手时看屏幕的模型。这个服务商没有能看图的模型,所以不在这里选的话,双手用你账号里的 {model}。`,"{model} does not take pictures, so the hands would be blind with it. Pick a model that sees for them.":`{model} 不能看图,动手时会是盲的。给它选一个能看图的模型。`,"A key is in the vault; leave empty to keep it.":`保险库里已有密钥;留空则保留。`,"Set in config.toml.":`在 config.toml 里设置。`,"Leave empty to use the main model's key.":`留空则使用主模型的密钥。`,"Save and test":`保存并测试`,"The operator's model answers.":`操作手机的模型有回应。`,"A personal agent of your own. Three things to know:":`一个属于你自己的个人智能体。三件事:`,"It does things for you.":`它替你把事情做完。`,"Searches, browses, writes, books, reads mail, and hands you the result, not a list of links.":`搜索、浏览、写作、预订、读邮件,交给你的是结果,不是一堆链接。`,"It keeps working when you close the app.":`你关掉应用,它还在干活。`,"Goals move forward between your visits; it reports in the Feed and notifies you when something is worth it.":`目标在你不在的时候继续推进;它在动态里汇报,值得打扰你时才通知你。`,"It asks you first where it matters.":`要紧的事,它先问你。`,"A separate Sentinel reviews every action. Sending, paying, deleting: it stops and asks; your keys stay in a vault the model cannot read.":`独立的 Sentinel 审查每一个动作。发送、付款、删除:它会停下来问你;你的密钥放在模型读不到的保险库里。`,"Set it up":`设置一下`,"Add a model":`添加模型`,"Pick a provider and paste a key. Yours, stored in the vault.":`选一个服务商,粘贴密钥。密钥是你的,存在保险库里。`,"Connect mail, calendar, contacts":`连接邮箱、日历、通讯录`,"Connected. Tap to add more.":`已连接。点击添加更多。`,"Optional. It can read what came in, know your day, and who is who.":`可选。它就能读到来信、知道你的日程、认得谁是谁。`,Start:`开始`,"Needs a model first.":`先要有一个模型。`,"Add a model to start":`添加模型后开始`,optional:`可选`,"A line under the name, e.g. Your day, sorted.":`名字下面的一句话,例如:你的一天,安排好了。`,Tagline:`标语`,"More names":`换一批名字`,Tone:`语气`,Formal:`正式`,Casual:`随和`,Playful:`活泼`,Concise:`简洁`,"How much it says":`话说多少`,"Short replies":`回答简短`,Detailed:`详细`,"Bullet points":`要点列表`,"Anything else about how it should be":`还有什么想让它成为的样子`,"e.g. A little witty. Uses metric units. Never uses emoji.":`例如:有点风趣。用公制单位。从不用 emoji。`,"OpenAI-compatible · Chat Completions":`OpenAI 兼容 · Chat Completions`,"Responses API":`Responses API`,"Local or your own endpoint":`本地或你自己的端点`,"/v1 is added when the URL has no path.":`URL 没有路径时会自动补上 /v1。`,"The endpoint that serves /chat/completions, for example http://127.0.0.1:8000/v1.":`提供 /chat/completions 的端点,例如 http://127.0.0.1:8000/v1。`,"{n} models from the endpoint":`端点返回了 {n} 个模型`,"Asking the endpoint…":`正在询问端点…`,"Could not list the endpoint's models; these are the usual ones.":`无法列出端点的模型;这些是常见的几个。`,"Get a key from {vendor}":`去 {vendor} 获取密钥`,"No key":`无需密钥`,"No key will be sent.":`不会发送密钥。`,"Show key":`显示密钥`,"Hide key":`隐藏密钥`,"Actions {name} wants to take but cannot without you. Each one shows what will run and why; a permission you grant is bound to that exact tool and target.":`这些是 {name} 想做、但没有你点头就不能做的事。每一项都写明要运行什么、为什么;你给的许可只对那个具体的工具和对象有效。`,"Forget every permission you granted? {name} will ask again next time.":`忘掉你授予的所有权限?下次 {name} 会重新询问。`,"This phone":`这台手机`,"Keep it running":`保持运行`,"Android stops apps that seem idle. {name} runs as a foreground service and holds the phone awake only while a task runs; these switches let it keep that promise on this phone.":`安卓会停掉看起来闲着的应用。{name} 以前台服务运行,只在任务进行时让手机保持唤醒;下面这几个开关,是让它在这台手机上真能做到这一点。`,Battery:`电池`,Unrestricted:`无限制`,Optimised:`已优化`,"Optimised means Android may freeze the agent after a while with the screen off; routines and check-ins then wait until the phone wakes.":`「已优化」意味着熄屏一段时间后安卓可能冻结 Agent;例行任务和提醒要等手机醒来才跑。`,"Display over other apps":`显示在其他应用上层`,Allowed:`已允许`,"Not allowed":`未允许`,"Lets the agent bring an app to the front from the background and show its status capsule while it works in other apps.":`让 Agent 能从后台把应用调到前台,并在其他应用里工作时显示状态胶囊。`,"Alarms & reminders":`闹钟和提醒`,Exact:`精确`,Approximate:`大致`,"With exact alarms a reminder fires at the minute you named even when the phone is asleep; without them Android may deliver it up to a quarter of an hour late.":`有精确闹钟,提醒会在你说的那一分钟响起,哪怕手机在睡眠;没有的话安卓可能晚最多一刻钟送达。`,"Start after a reboot":`重启后自动启动`,"Bring the runtime back when the phone restarts, so routines and check-ins do not stop.":`手机重启后把运行时带回来,例行任务和提醒不中断。`,"Reconnect to your computer when the phone restarts, so approvals keep arriving.":`手机重启后重新连上你的电脑,审批照常送达。`,"On this phone's Android":`这台手机的安卓系统`,"Open the auto-start settings":`打开自启动设置`,"Xiaomi / Redmi / POCO: Settings → Apps → Manage apps → {name} → Autostart on; Battery saver → No restrictions; Other permissions → Display pop-up windows while running in the background on.":`小米 / Redmi / POCO:设置 → 应用设置 → 应用管理 → {name} → 自启动打开;省电策略 → 无限制;其他权限 → 后台弹出界面 允许。`,"Huawei: Settings → Battery → App launch → {name} → Manage manually, all three on (auto-launch, secondary launch, run in background); Settings → Apps → {name} → Battery → Launch: manage manually.":`华为:设置 → 电池 → 应用启动管理 → {name} → 手动管理,三项全开(自动启动、关联启动、后台活动);设置 → 应用 → {name} → 电池 → 启动管理:手动管理。`,"Honor: Settings → Battery → App launch → {name} → Manage manually, all three on; Battery → More battery settings → Stay connected while asleep on.":`荣耀:设置 → 电池 → 应用启动管理 → {name} → 手动管理,三项全开;电池 → 更多电池设置 → 休眠时始终保持网络连接 打开。`,"OPPO / realme / OnePlus: Settings → Battery → More settings → Optimise battery use → {name} → Don't optimise; Settings → Apps → {name} → Battery usage → Allow background activity, Allow auto launch.":`OPPO / realme / 一加:设置 → 电池 → 更多设置 → 应用耗电优化 → {name} → 不优化;设置 → 应用 → {name} → 耗电管理 → 允许后台活动、允许自动启动。`,"vivo / iQOO: i Manager → App manager → Autostart → {name} on; Settings → Battery → Background power consumption management → {name} → Allow high background power consumption.":`vivo / iQOO:i 管家 → 应用管理 → 自启动 → {name} 打开;设置 → 电池 → 后台耗电管理 → {name} → 允许后台高耗电。`,"Samsung: Settings → Battery → Background usage limits → {name} not in Sleeping or Deep sleeping apps (add it to Never sleeping apps); turn off Adaptive battery if it keeps stopping.":`三星:设置 → 电池 → 后台使用限制 → {name} 不在「休眠应用」或「深度休眠应用」里(加入「永不休眠的应用」);如果还是被停,关闭自适应电池。`,"Meizu: Settings → Apps → {name} → Background management → Keep running in the background; Battery → App power management → Allow.":`魅族:设置 → 应用管理 → {name} → 后台管理 → 允许后台运行;电池 → 应用耗电管理 → 允许。`,"Crashes are written to a file on this phone and nowhere else. Export bundles them with the runtime's log for someone you choose.":`崩溃只写到这台手机上的文件里,不上报任何地方。导出会把它们和运行时日志打成一个包,发给你选的人。`,"Export logs":`导出日志`,"clipboard, notifications, calendar, contacts, location, alarms, photos":`剪贴板、通知、日历、通讯录、位置、闹钟、照片`,Devices:`设备`,"Only this one":`只有这一台`,Idle:`空闲`,"A chat addressed to a device runs there; you see every step here and answer its approvals.":`对着某台设备的对话在那台设备上执行;每一步都在这里看得到,审批也在这里答。`,"nanoMuse Cloud":`nanoMuse Cloud`,"Free. One account for all your devices, and a model to start with.":`免费。一个账号连起你所有设备,还附带一个可以先用起来的模型。`,"Signed in":`已登录`,"Not signed in":`未登录`,"Not signed in.":`未登录。`,"Signed out":`已退出`,"{hint} · hub":`{hint} · 中继`,"{hint} · model and hub":`{hint} · 模型和中继`,"Signed in as {hint}. Your devices meet here; the Cloud model comes with a free allowance.":`已登录:{hint}。你的设备在这里互相看见;Cloud 模型自带一份免费额度。`,"Use the Cloud model":`使用 Cloud 模型`,"The Cloud model is in use.":`已切换到 Cloud 模型。`,"Sign out":`退出登录`,"Sign out of nanoMuse Cloud on this device? The hub and the Cloud model stop working here until you sign in again.":`在这台设备上退出 nanoMuse Cloud?重新登录之前,这里的中继和 Cloud 模型都会停用。`,"Mainland China phone number or e-mail":`中国大陆手机号或邮箱`,"138 0000 0000 or you@example.com":`138 0000 0000 或 you@example.com`,"One free account. It is what lets your phone and computers work as one and brings a model to start with.":`一个免费账号。有了它,手机和电脑就是同一个 nanoMuse,还自带一个可以先用起来的模型。`,"It uses your phone and computers for you":`替你操作手机和电脑`,"The relay keeps an account id, a masked identifier, usage counts and your agent's name and look; what else, and what is yours to switch off, is in the":`中继保存账号 id、打码后的手机号或邮箱、用量计数和你的智能体的名字与形象;其余保存什么、哪些由你决定,见`,"privacy policy":`隐私政策`,"Free, open source, non-profit":`免费、开源、非营利`,"nanoMuse is a non-profit open-source community project, free forever.":`nanoMuse 是非营利的开源社区项目,永久免费。`,"Chat apps":`聊天入口`,"nanoMuse is a non-profit open-source community project, free forever. Sign in with a phone number or an e-mail and the model comes with a free allowance, paid by the developer; when it is gone, use your own key (Alibaba Cloud Bailian in mainland China, OpenRouter elsewhere). Nothing is sold; what the relay keeps is in the privacy policy, and Settings → Data controls is yours. Delete the account whenever you like.":`nanoMuse 是非营利的开源社区项目,永久免费。用手机号或邮箱登录,模型自带一份免费额度,费用由开发者承担;用完可以换自己的 key(中国大陆用阿里云百炼,海外用 OpenRouter)。数据不会出售;服务器保存什么写在隐私政策里,「设置 → 数据控制」由你决定。账号随时可以删除。`,"The people building it use it every day. Report a bug, ask for a feature, send a pull request: that is what moves the project. A star on GitHub helps others find it.":`做它的人每天都在用。欢迎反馈问题、提需求、贡献代码,项目就是这样往前走的。在 GitHub 点个 Star,能让更多人找到它。`,"Star on GitHub":`去 GitHub 点个 Star`,"Report a bug or ask for a feature":`反馈问题 / 提需求`,"Data controls":`数据控制`,"Help improve nanoMuse's AI models":`帮助改进 nanoMuse 的 AI 模型`,"While this is on, the text of your chats with the nanoMuse Cloud models (what you wrote, what it answered and the tools it chose to call) is kept on the relay to train the community's own open model. Not your memory or SOUL (the system prompt), not what tools returned, not pictures, and never next to who you are. Your own API key never passes through the relay.":`开启后,你与 nanoMuse Cloud 模型对话的文字(你写的、它回答的,以及它选择调用的工具)会保存在中继上,用来训练社区自己的开源模型。不保存你的记忆和 SOUL(系统提示)、工具返回的内容和图片,也不和你的身份放在一起。用自己的 API key 时,对话不经过中继。`,"New accounts start with it on.":`新账号默认开启。`,"New accounts start with it off.":`新账号默认关闭。`,"Sign in to nanoMuse Cloud to use it.":`登录 nanoMuse Cloud 后可用。`,"{n} turns kept so far.":`目前已保存 {n} 轮对话。`,"{n} turns kept so far":`已保存 {n} 轮对话`,"{n} turns":`{n} 轮`,"On. Turn it off here at any time.":`已开启。随时可以在这里关闭。`,"Off. Nothing more is kept.":`已关闭。之后的对话不再保存。`,"Delete the kept conversations":`删除已保存的对话`,"Removes every turn kept from this account, whether the switch is on or off now. Turning the switch off keeps what was kept until you delete it here.":`删除这个账号已保存的全部对话,不管开关现在是开是关。只关掉开关不会删除已保存的内容,要在这里删。`,"The kept conversations are removed from the server. This cannot be undone.":`已保存的对话会从服务器上删除,不可恢复。`,"{n} turns deleted":`已删除 {n} 轮`,"Set a password":`设一个密码`,"Your account is in. With a password, your phone and your other computers sign in at once, without waiting for a code. Optional; you can set one later under Account.":`账号已登录。设了密码,手机和其他电脑就能直接登录,不用再等验证码。可选,以后也可以在「账号」里设置。`,"At least 8 characters":`至少 8 个字符`,"Set the password":`设置密码`,"Not now":`以后再说`,"I already starred":`已经点过了`,"Free allowance":`免费额度`,"left of ¥{grant}":`剩余 / 共 ¥{grant}`,"¥{spent} used{usd}; the allowance does not reset.":`已用 ¥{spent}{usd};额度不按天重置。`,"No limit on this account.":`这个账号不限额度。`,"¥{allowance} to start, +¥{invite} for each friend you invite, and +¥{invite} for them; after that, your own key keeps the model going.":`起始 ¥{allowance},每邀请一位朋友你 +¥{invite}、对方也 +¥{invite};用完后换自己的 key 继续。`,"The free allowance is used up.":`免费额度已用完。`,"The image provider is busy right now; try again in a minute.":`生图服务现在有点忙,请过一分钟再试。`,"Nearly used up: ¥{left} of ¥{grant} left.":`额度快用完了:还剩 ¥{left}(共 ¥{grant})。`,"Invite a friend (+¥{invite} for each of you) or bring your own key; your sign-in keeps working either way.":`邀请一位新用户(你和对方各 +¥{invite}),或者换成自己的 key;无论哪种,登录都不受影响。`,"See the ways":`看看怎么办`,Dismiss:`关闭`,"Three ways on; your sign-in and your devices keep working whichever you pick.":`三个办法继续用;无论选哪个,登录和多设备功能都不受影响。`,"Use your own model key":`换成自己的 key`,"Alibaba Cloud Bailian is a good start: a new account comes with a free quota, set-up takes about two minutes, and one key covers chat, the hands, pictures and clips.":`推荐阿里云百炼:新用户有免费额度,开通约 2 分钟,一个 key 就能对话、动手、画图、生成视频。`,"Alibaba Cloud Bailian only signs up accounts from mainland China. Outside, OpenRouter is the easy way: one account, one key, pay as you go, for chat, the hands and pictures; clips need Bailian.":`海外用户用不了百炼,推荐 OpenRouter:一个账号一把 key,按量付费,对话、动手、画图都行;生成视频需要百炼。`,"Other providers and what each key covers":`其他服务商,以及各自的 key 能做什么`,"Get a key":`去申请 key`,"covers {list}":`支持{list}`,", ":`、`," or ":`或`,"Sign in with a plan you already pay for":`用你已经在付费的套餐登录`,"{plans}: the plan's models answer here, no key to make. ChatGPT works on every device, the others on the phones. A ChatGPT sign-in covers chat and the hands; pictures and clips still want a key.":`{plans}:套餐里的模型直接在这里回答,不用申请 key。ChatGPT 在每台设备上都可以,其他的在手机上。ChatGPT 登录只覆盖对话和动手;画图和生成视频仍需要一把 key。`,"Sign in with ChatGPT":`用 ChatGPT 登录`,"Or sign in with a ChatGPT plan":`或者用 ChatGPT 套餐登录`,"Covers chat and the hands. Pictures and clips are not part of it; those need a provider with image or video models.":`覆盖对话和动手。画图和生成视频不在其中,那两项需要一个有图像或视频模型的服务商。`,"OpenAI's terms cover using a ChatGPT plan inside OpenAI's own Codex; other apps have had this access cut off before (OpenCode, January 2026). If it stops working, an API key does.":`OpenAI 的条款只允许在它自家的 Codex 里使用 ChatGPT 套餐;其他应用曾被切断过这条路(OpenCode,2026 年 1 月)。哪天它不能用了,API key 仍然可以。`,"This nanoMuse has no sign-in route yet. In a terminal on this computer, run":`这个 nanoMuse 还没有登录接口。在这台电脑的终端里运行`,"and reload this page.":`然后刷新本页。`,"Signed in with {label}.":`已用 {label} 登录。`,"Use it for the chat":`让它来回答对话`,"Sign out of ChatGPT":`退出 ChatGPT`,"A page from OpenAI opened in a new tab. Sign in there; this card follows on its own.":`已在新标签页打开 OpenAI 的页面。在那里登录,这张卡片会自己跟上。`,"Open the page again":`再次打开页面`,"The sign-in did not finish in ten minutes. Try again.":`登录十分钟内没有完成。再试一次。`,"A page from OpenAI opened in a new tab. Sign in there; when the browser ends on an address that will not load, paste that address below.":`已在新标签页打开 OpenAI 的页面。在那里登录;浏览器最后停在一个打不开的地址时,把那个地址粘贴到下面。`,"The address the browser ended on":`浏览器最后停在的地址`,"Use this address":`用这个地址`,"This nanoMuse runs where the browser cannot reach port 1455, so it cannot pick the sign-in up by itself.":`这个 nanoMuse 运行的机器上,浏览器连不到 1455 端口,所以它没法自己接住登录结果。`,"That address belongs to another sign-in attempt. Open the page again and paste the address it ends on.":`这个地址属于另一次登录尝试。再次打开页面,粘贴它最后停在的地址。`,"ChatGPT answers the chat now.":`现在由 ChatGPT 回答对话。`,"Pictures need a provider with image models: {providers}.":`画图需要一个有图像模型的服务商:{providers}。`,"Clips need a provider with video models: {providers}.":`生成视频需要一个有视频模型的服务商:{providers}。`,"The hands need a model that sees pictures: {providers}.":`动手需要一个能看图的模型:{providers}。`,"Chat needs a model: {providers}.":`对话需要一个模型:{providers}。`,How:`怎么做`,"Automatic · {model}":`自动 · {model}`,"E-mail (or a mainland China phone number)":`邮箱(或中国大陆手机号)`,"Text-message codes reach mainland-China numbers only. Use an e-mail address instead.":`短信验证码只能发到中国大陆手机号。其他地区请用邮箱登录。`,"Step-by-step guide":`图文教程`,"Invite a friend: +¥{bonus} for you and +¥{bonus} for them, for each new person who signs up with your link.":`邀请朋友:每有一位新用户通过你的链接注册,你 +¥{bonus},对方也 +¥{bonus}。`,"Your invite link is under Account":`邀请链接在「账号」页`,"Try nanoMuse with me, a fully open-source personal agent, free to use. Sign up with my link: {link}":`来和我一起用 nanoMuse,完全开源的个人智能体,免费使用。用我的链接注册:{link}`,"Invite code (optional)":`邀请码(选填)`,"A friend's code counts for a new account: you both get ¥{invite} more allowance.":`朋友的邀请码只对新账号有效:你和对方的额度各 +¥{invite}。`,"Have an invite code?":`有邀请码?`,"Invite a friend":`邀请朋友`,"Each new person who signs up with your code adds ¥{bonus} to your allowance, and ¥{bonus} to theirs. It never expires.":`每有一位新用户用你的邀请码注册,你的额度 +¥{bonus},对方也 +¥{bonus},不过期。`,"Your code":`邀请码`,Copied:`已复制`,"Share the link":`分享链接`,"Share the code":`分享邀请码`,"Try nanoMuse with me, a fully open-source personal agent, free to use. Sign up with my code {code}":`来和我一起用 nanoMuse,完全开源的个人智能体,免费使用。用我的邀请码 {code} 注册`,"relay privacy policy (ask your relay operator)":`中继的隐私政策(请询问你的中继运营者)`,"Copy the link":`复制链接`,"Try nanoMuse with me, a fully open-source personal agent, free to use. Sign up with my code {code}: {link}":`来和我一起用 nanoMuse,完全开源的个人智能体,免费使用。用我的邀请码 {code} 注册:{link}`,"{n} friends joined":`已邀请 {n} 位`,"¥{amount} added by invitations":`邀请带来 ¥{amount}`,"The code you received":`收到的验证码`,"Send again":`重新发送`,"Send me a code":`发送验证码`,"Sign in":`登录`,"Sign in and use its model":`登录并使用它的模型`,"Signed in to nanoMuse Cloud.":`已登录 nanoMuse Cloud。`,"Or bring your own key":`或者用你自己的密钥`,"This device":`这台设备`,"A name your other devices will see":`其他设备看到的名字`,"On the hub":`已连上中继`,"Reachable by your other devices while this runs.":`运行期间,你的其他设备可以找到它。`,"Sign in first.":`先登录。`,"My other devices may operate it":`允许我的其他设备操作它`,"They can run commands, read files and see its screen here; each step still goes through the Sentinel.":`其他设备可以在这里运行命令、读文件、看屏幕;每一步仍经 Sentinel 审核。`,Refused:`被拒绝`,"Connecting…":`连接中…`,"Connecting to the hub…":`正在连接中继…`,"The hub refused this device. Sign in again.":`中继拒绝了这台设备。请重新登录。`,"The hub is off on this device.":`这台设备没有开启中继。`,"Sign in above to see them.":`先在上面登录,就能看到。`,"{n} online":`{n} 台在线`,online:`在线`,Ask:`去问它`,"Ask one of your devices":`让某台设备去做`,"Every device signed in to your account is a Muse of its own, on the same conversations. Type @ and a device's name in the chat to hand it work; a computer lends its hands.":`登录你账号的每台设备都是一个自己的 Muse,看到的是同一批对话。在聊天里输入 @ 加设备名,就能把活交给它;电脑还能出借它的双手。`,"1 device":`1 台设备`,"{n} devices":`{n} 台设备`,"Other devices":`其他设备`,Online:`在线`,"Last seen {when}":`最后在线 {when}`,Tasks:`任务`,Commands:`命令`,Screenshot:`截屏`,"Open links":`打开链接`,Hands:`双手`,"More about {name}":`{name} 的更多操作`,"Forget this device":`移除这台设备`,"Type @{name} in the chat to hand it work.":`在聊天里输入 @{name},就能把活交给它。`,"Add a device":`添加一台设备`,"No other device yet":`还没有其他设备`,"Install nanoMuse on your phone, Mac or PC and sign in as {hint}; it appears here on its own.":`在手机、Mac 或 PC 上安装 nanoMuse,用 {hint} 登录,它就会自己出现在这里。`,"Install nanoMuse on your phone, Mac or PC and sign in with the same account; it appears here on its own.":`在手机、Mac 或 PC 上安装 nanoMuse,用同一个账号登录,它就会自己出现在这里。`,"Get the apps":`下载应用`,"Forget {name}? It can join again by signing in.":`忘掉 {name}?它重新登录后还可以加入。`,"on {device}":`在 {device} 上`,"from {device}":`来自 {device}`,"asked from {device}":`从 {device} 发来`,"{name} on {device} wants to":`{device} 上的 {name} 想要`,"Hands on this computer":`操作这台电脑`,"On the screen now":`正在操作屏幕`,"Nothing can drive this screen yet.":`目前没有能驱动这块屏幕的组件。`,'On a Mac, allow nanoMuse under System Settings → Privacy & Security → Accessibility and Screen Recording when macOS asks; without them clicks do nothing and the screenshot is black. The first action in each app asks you once ("Let {name} use Safari?") and the answer is kept under Permissions.':`Mac 上,macOS 弹窗询问时请在「系统设置 → 隐私与安全性」的「辅助功能」和「屏幕录制」里允许 nanoMuse;不允许的话点击没有反应,截图也是黑的。每个应用的第一步会先问你一次(「让 {name} 使用 Safari 吗?」),答复记在「权限」里。`,Where:`范围`,"One window":`单个窗口`,"Whole screen":`整个屏幕`,"Working in {app}'s window; the mouse stays yours.":`正在 {app} 的窗口里操作;鼠标仍归你用。`,"On the whole screen for now: {reason}":`暂时在整个屏幕上操作:{reason}`,"One window: the hands work inside the app they were given, send clicks and keys to it alone and leave your mouse alone. Whole screen: the system mouse, like other platforms. Auto picks one window as soon as an app is named.":`单个窗口:只在指定的应用里操作,点击和按键只发给它,不动你的鼠标。整个屏幕:用系统鼠标,和其他平台一样。自动:一旦指定了应用就用单个窗口。`,"It looks at a screenshot and clicks by position; paying, sending and deleting ask you first.":`它看截图、按位置点击;支付、发送、删除前都会先问你。`,Driver:`驱动`,Working:`工作中`,"Stop the hands":`停止操作`,"{name} is using this computer":`{name} 正在操作这台电脑`,"Hands done":`操作完成`,"Hands stopped":`操作已停止`,"{n} steps":`{n} 步`,Clicked:`点击`,"Clicked {label}":`点击了 {label}`,"Double-clicked":`双击`,"Double-clicked {label}":`双击了 {label}`,"Right-clicked":`右键点击`,"Right-clicked {label}":`右键点击了 {label}`,"Pointed at {label}":`指向了 {label}`,"Moved the mouse":`移动了鼠标`,"Typed {n} characters":`输入了 {n} 个字符`,"Pressed {keys}":`按下了 {keys}`,Scrolled:`滚动`,Dragged:`拖动`,"Opened {label}":`打开了 {label}`,"Opened an application":`打开了一个应用`,Waited:`等待`,"The dragon":`小龙`,"The face drawn for you":`为你画的形象`,"Draw four":`画四张`,send_email:`发邮件`,shell:`运行命令`,"E-mail, calendar, browser, MCP servers":`邮件、日历、浏览器、MCP 服务器`,"Rename this device":`给这台设备改名`,"Use my own API key or a plan I pay for":`用我自己的 API key,或我在付费的套餐`,"{first} first, then {others}":`首选 {first},其次 {others}`,"DeepSeek, Kimi, OpenAI, ChatGPT…":`DeepSeek、Kimi、OpenAI、ChatGPT…`,"OpenAI, ChatGPT, Gemini, DeepSeek…":`OpenAI、ChatGPT、Gemini、DeepSeek…`,"Which model answers?":`让哪个模型来回答?`,"Your account already brings one. You can add your own API key as well and switch at any time.":`你的账号已经自带了一个。也可以加上自己的 API key,随时切换。`,"DeepSeek for the chat and Qwen for the hands, with a free allowance per account paid by the developer. Nothing to configure.":`对话用 DeepSeek,动手用 Qwen;每个账号都有一份由开发者承担的免费额度,不用配置。`,"I have my own API key":`我有自己的 API key`,"Alibaba Cloud Bailian first (one key covers chat, the hands, pictures and clips), then DeepSeek, Kimi, Zhipu, OpenAI, OpenRouter and any OpenAI-compatible endpoint. The key stays on this device.":`首选阿里云百炼(一个 key 就能对话、动手、画图、生成视频),其次是 DeepSeek、Kimi、智谱、OpenAI、OpenRouter,以及任何兼容 OpenAI 接口的服务。key 只留在这台设备上。`,"OpenRouter first (one account, one key, pay as you go), then OpenAI, Anthropic, Gemini, DeepSeek and any OpenAI-compatible endpoint. The key stays on this device.":`首选 OpenRouter(一个账号一把 key,按量付费),其次是 OpenAI、Anthropic、Gemini、DeepSeek,以及任何兼容 OpenAI 接口的服务。key 只留在这台设备上。`,"A ChatGPT plan signs in from Connections and answers the chat and the hands. Pictures and clips still want a key.":`ChatGPT 套餐可在「连接」里登录,回答对话并驱动双手。画图和生成视频仍需要一把 key。`,"3D toy (Muse)":`3D 玩偶(Muse)`,Flat:`扁平`,"3D clay":`3D 黏土`,Watercolour:`水彩`,Pixel:`像素`,Line:`线条`,Sticker:`贴纸`,Draw:`画`,"Making pictures":`生成图片`,"Making clips":`生成视频`,"Portraits of your Muse.":`形象的肖像。`,"Short clips of your Muse.":`形象的短视频。`,"The chat model's provider":`对话模型的服务商`,"Your key":`你的 key`,"Add a provider":`添加服务商`,"Other OpenAI-compatible endpoint":`其他 OpenAI 兼容接口`,"The endpoint that serves /images/generations, for example https://host/v1.":`提供 /images/generations 的接口,例如 https://host/v1。`,"Stored encrypted in the vault as {name}.":`以 {name} 加密存储在保险库中。`,"Uses the chat model's key.":`用对话模型的 key。`,"Your phone can now operate this computer: run commands, fetch files, hand over whole tasks. Each risky step still asks here first.":`你的手机现在可以操作这台电脑了:跑命令、取文件、把整件事交给它。有风险的每一步仍会先在这里问你。`,"Picture model":`图片模型`,"Clip model":`短片模型`,"Other model…":`其他模型…`,"More models on your account":`账号可用的更多模型`,"Search models":`搜索模型`,"No model matches":`没有匹配的模型`,"reads pictures":`能看图`,"Type a model id…":`手动输入模型 id…`,"Pick from the list":`从列表里选`,"{n} models your account may use: the menu first, then everything else the provider lists under the Cloud key. Pick one; the ones beyond the menu are priced as the dearest menu model of their kind.":`账号可用的模型共 {n} 个:先是菜单,然后是服务商在 Cloud 这把 key 下列出的其他模型。直接选就行;菜单之外的按同类里最贵的菜单模型计费。`,"Your account may name any model the provider has, not only these: type its id (a chat model here, a picture or clip model below) and it goes through as typed.":`你的账号可以使用服务商的任意模型,不限于这几个:直接输入模型 id(对话模型填在这里,图片或短片模型填在下面),会原样转发。`,Automatic:`自动`,"{n} pictures":`{n} 张图`,"{n} pictures and {c} clips":`{n} 张图加 {c} 段短片`,"{what}, made with your own key at your provider's prices.":`{what},用你自己的 key 按服务商价格计费。`,"The cost could not be checked: {error}":`费用暂时查不到:{error}`,"Checking the cost…":`正在查费用…`,"About ¥{cny} for {what}; your account has no limit.":`{what}约 ¥{cny};你的账号没有额度限制。`,"About ¥{cny} for {what}, more than the ¥{left} left in your allowance.":`{what}约 ¥{cny},超过了额度里剩下的 ¥{left}。`,"About ¥{cny} for {what}; ¥{left} left in your allowance.":`{what}约 ¥{cny};额度还剩 ¥{left}。`,"A new look for {name}":`给{name}换个形象`,"Drawing four to choose from…":`正在画四个供你挑选…`,"Pick one: tap it, or say which":`选一个:点它,或者说第几个`,"Drawing the poses…":`正在画各种姿态…`,"The new look is on; making the clips…":`新形象已经换上,正在做短片…`,"The new look is on":`新形象已经换上`,"Not this time":`这次先不换`,"That did not work":`没成功`,"Candidate {n}":`第 {n} 个`,Redraw:`重画一组`,"Idle, working, waiting, happy, sorry: the face follows what {name} is doing.":`待机、工作、等待、开心、抱歉:形象会跟着 {name} 正在做的事变化。`,"Four more pictures from the one you picked; this takes a minute or two.":`根据你选的这张再画四张;需要一两分钟。`,"Some poses could not be drawn and show the idle picture instead.":`有几个姿态没画出来,先用待机图代替。`,"The face is already on; four short clips are being made from the poses, a few minutes.":`形象已经换上了;正在根据这几张姿态图做四段短片,需要几分钟。`,"Some clips could not be made; those moods stay still.":`有几段短片没做出来,这些状态就用静态图。`,"The new look is on; the clips are being made.":`新形象已经换上;短片正在做。`,"The new look is on.":`新形象已经换上。`,"Not this time.":`这次先不换。`,"New look: {description}. Say what to change any time, or pick another under Settings.":`新形象:{description}。想改随时说,也可以在「设置」里换别的。`,"Join the hub":`加入中继`,"This chat goes to {device}.":`这个对话发给 {device}。`,"Whatever you ask here, the {name} on {device} does where it is: its shell, its files, its screen. Every step shows up here, and anything that needs an approval asks you here.":`在这里说的每件事,都由 {device} 上的 {name} 在它那边完成:它的命令行、它的文件、它的屏幕。每一步都显示在这里,需要批准的事也在这里问你。`,"What is on your screen right now?":`你屏幕上现在是什么?`,"Which folder are you in, and what is in it?":`你在哪个目录,里面有什么?`,"Check for updates and tell me what needs a restart":`检查一下更新,告诉我哪些需要重启`,Account:`账号`,"Account deleted.":`账号已删除。`,"Account id":`账号 ID`,"Sign in to nanoMuse Cloud":`登录 nanoMuse Cloud`,"Sign in to {name}":`登录 {name}`,"nanoMuse Cloud · one account for all your devices":`nanoMuse Cloud · 一个账号,所有设备`,"Every device of yours, one nanoMuse":`你的每台设备,同一个 nanoMuse`,"A model with a free allowance, or your own key":`自带免费额度的模型,或用你自己的 key`,"Keys in your vault; nothing you say is kept on the relay":`key 留在你的保险库里;你说的内容不会留在中继上`,"Free. One account for all your devices, with a model and ¥{allowance} of use to start; a code the first time, a password afterwards if you like.":`免费。一个账号连起你所有设备,自带模型和 ¥{allowance} 的起始额度;第一次用验证码登录,之后可以设密码。`,"With a code":`验证码登录`,"With a password":`密码登录`,"No password yet? Use a code first; set one under Account.":`还没有密码?先用验证码登录,再到「账号」里设置。`,"E-mail":`邮箱`,"Mobile number":`手机号`,"since {date}":`{date} 起`,Unlimited:`不限量`,"All time":`累计`,Usage:`用量`,"Every kind of use is counted, not just the chat model.":`每一类用量都会统计,不只是对话模型。`,Pictures:`图片`,Clips:`视频`,Calls:`通话`,"Nothing yet":`还没有`,"{n} answers · {tokens} tokens":`{n} 次回答 · {tokens} tokens`,"{n} requests · {tokens} tokens":`{n} 次请求 · {tokens} tokens`,"{n} requests":`{n} 次请求`,"By model, all time":`按模型(累计)`,"A password is set":`已设置密码`,"No password yet":`还没有密码`,"Sign in with it on a new device, or with a code as before.":`新设备可以用密码登录,也可以像以前一样用验证码。`,"Optional. With one, a new device can sign in without waiting for a code.":`可选。设置后,新设备不用等验证码就能登录。`,Change:`修改`,Set:`设置`,"Current password":`当前密码`,"New password (8 characters or more)":`新密码(至少 8 位)`,"Once more":`再输一次`,"The two do not match.":`两次输入不一致。`,"Change password":`修改密码`,"Set password":`设置密码`,"Password set.":`密码已设置。`,"Password changed.":`密码已修改。`,"Password removed.":`密码已移除。`,"Signed in on":`已登录的设备`,"Unnamed device":`未命名设备`,"This one":`本机`,code:`验证码`,password:`密码`,"used {when}":`{when}用过`,"Sign out {device}? It will need to sign in again.":`让 {device} 退出登录?它需要重新登录。`,"Recent activity":`最近动态`,"Show all {n}":`全部 {n} 条`,"Show less":`收起`,"Account created":`账号已创建`,"Signed in with a code":`用验证码登录`,"Signed in with the password":`用密码登录`,"A sign-in attempt failed":`一次登录失败`,"Signed out everywhere":`已在所有设备退出`,"Password removed":`密码已移除`,"Password changed":`密码已修改`,"Password set":`密码已设置`,"A request was refused: the allowance is used up":`一次请求被拒绝:免费额度已用完`,"Call ended":`通话结束`,"The model provider returned an error":`模型服务返回了错误`,"Allowance added":`额度已增加`,"Allowance adjusted":`额度已调整`,"Signed up with a friend's code":`用朋友的邀请码注册`,"A friend signed up with your code":`一位朋友用你的邀请码注册`,"An invite code was not recognised":`邀请码无法识别`,"Data controls: on for new accounts":`数据控制:新账号默认开启`,"Data controls: help improve turned on":`数据控制:已开启「帮助改进」`,"Data controls: help improve turned off":`数据控制:已关闭「帮助改进」`,"Data controls: kept conversations deleted":`数据控制:已删除保存的对话`,"Agent's name and look saved":`已保存智能体的名字与形象`,"Agent's name and look cleared":`已清除智能体的名字与形象`,"Sign out everywhere":`在所有设备退出`,"Sign out on every device, including this one?":`在所有设备退出登录,包括这一台?`,"Delete the account? The relay forgets your identifier, your devices and your usage. This cannot be undone.":`删除账号?中继会忘掉你的标识、设备和用量记录,且无法恢复。`,"Really delete it?":`真的要删除吗?`,"Signed out.":`已退出登录。`,"Delete the account":`删除账号`,"The Cloud model is in use; after signing out, pick another under Connections.":`当前使用的是 Cloud 模型;退出后请到「连接」里换一个。`,"{n} min ago":`{n} 分钟前`,"{n} h ago":`{n} 小时前`,"{n} d ago":`{n} 天前`,"Use the nanoMuse Cloud model":`使用 nanoMuse Cloud 模型`,"Signed in as {hint}. A free allowance, nothing to paste. Recommended to start.":`已登录 {hint}。自带免费额度,无需粘贴任何 key,推荐先用它。`,"Your account brings a model with a free allowance, nothing to set up. Or paste a key of your own; it is stored encrypted in the vault on the server, never shown to the model, and nothing you say passes through the relay.":`你的账号自带一个有免费额度的模型,不用再设置什么。也可以粘贴自己的 key:它加密存在服务端的保险库里,不会给模型看到,你说的内容也不经过中继。`,"Voice input":`语音输入`,"Stop voice input":`停止语音输入`,"The microphone is not allowed. Allow it in the browser and try again.":`没有拿到麦克风权限。在浏览器里允许后再试一次。`,"Voice input stopped ({code}).":`语音输入中断了({code})。`,"said on a call":`通话中说的`,"Coding agents":`编程助手`,"Cursor, Codex and Claude Code: see what they are doing, and tell them things from anywhere.":`Cursor、Codex 和 Claude Code:随时看它们在做什么,在任何地方给它们发消息。`,Coding:`编程`,"This computer":`这台电脑`,"This one · {name}":`本机 · {name}`,installed:`已安装`,"chats only":`仅记录`,"not found":`未找到`,"{agent} chats":`{agent} 的对话`,"Recent chats":`最近的对话`,"New chat":`新对话`,"No coding agent found on this computer. Install Cursor, Codex or Claude Code and their chats appear here.":`这台电脑上没有找到编程助手。安装 Cursor、Codex 或 Claude Code 后,它们的对话会出现在这里。`,"No chats yet.":`还没有对话。`,"Untitled chat":`未命名对话`,"{n} messages":`{n} 条消息`,"Sent through nanoMuse":`经 nanoMuse 发送的`,stopped:`已停止`,"Sent to {agent}.":`已发给 {agent}。`,"{agent} is working…":`{agent} 正在处理…`,"Tell {agent}…":`对 {agent} 说…`,"Nothing readable in this chat yet.":`这个对话里还没有可读的内容。`,"via nanoMuse":`经 nanoMuse`,"Continued as a new chat: the agent could not reopen the old one.":`原来的对话打不开了,已经另起一个新对话接着聊。`,"Made in the IDE: your message starts a new chat in the same workspace, with the last exchange quoted.":`这是 IDE 里的对话:你的消息会在同一工作区开一个新对话,并带上上一轮的内容。`,"Continue in a new chat…":`在新对话里接着说…`,"starting…":`启动中…`,"Send to {agent}":`发给 {agent}`,"Project folder":`项目目录`,"What to do":`要做什么`,"Add tests for the parser and run them":`给解析器补上测试并跑一遍`,"The agent runs on that computer with its own permissions; nanoMuse only carries the message and brings the answer back.":`助手在那台电脑上以它自己的权限运行;nanoMuse 只负责传话和带回结果。`,"The file is larger than {n} MB.":`文件超过了 {n} MB。`,"empty file":`文件是空的`,"thread is busy":`这个对话正忙`,"the main chat cannot be deleted":`主对话不能删除`,"no pending approval with that id":`这张卡片已经不在等待中`,"the device did not take the answer":`那台设备没有接受这个回答`,"already finished":`已经结束了`,"already cancelled":`已经取消了`,"memory is disabled":`记忆已关闭`,"memory is off":`记忆已关闭`,"recall by meaning is off":`按含义回忆已关闭`,"nothing proposed":`没有待处理的提议`,"that frame is gone":`这一帧已经不在了`,"no such file":`没有这个文件`,"no such post":`没有这条动态`,"no such skill of yours (built-in skills are switched off, not removed)":`没有这个你自己的技能(内置技能只能关闭,不能删除)`,"the file is larger than 16 MB":`文件超过了 16 MB`,"body too large (64 KB max)":`内容太大(最多 64 KB)`,"fill in the servers, the address and the password first":`先填好服务器、地址和密码`,"add a calendar link first":`先添加一个日历链接`,"signed out":`未登录`,"Sign in to nanoMuse Cloud first.":`请先登录 nanoMuse Cloud。`,"Enter the password.":`请输入密码。`,"The relay returned no key.":`中继没有返回 key。`,Details:`详情`,"Hide details":`收起详情`,"Today's share of the free allowance is used up; it comes back tomorrow. Your own model key under Connections keeps you going now.":`今天的免费额度用完了,明天恢复。在「连接」里填上你自己的模型 key,现在就能继续。`,"The free allowance is used up. Invite a friend (the relay adds to both your allowances) or add your own model key under Connections; your sign-in and your devices keep working either way.":`免费额度已用完。邀请一位新用户(你和对方的额度都会增加),或者在「连接」里填上自己的模型 key;无论选哪个,登录和多设备功能都不受影响。`,"The account's free allowance is used up. Add your own model key under Connections to keep going.":`这个账号的免费额度已经用完。在「连接」里填上你自己的模型 key 就能继续。`,"Too many requests at once; wait a moment and try again.":`请求太密集了,稍等一下再试。`,"The model provider is busy; try again in a moment.":`模型服务商正忙,稍后再试。`,"The model provider's content check declined this request; try different words.":`模型服务商的内容审核没有放行这次请求,换个说法再试。`,"The relay's model provider refused its key; the operator has been told. Your own key under Connections works meanwhile.":`中继的模型服务商拒绝了它的 key,运营者已收到通知。这期间可以在「连接」里用你自己的 key。`,"The model provider does not know this model right now; pick another under Connections.":`模型服务商暂时不认识这个模型,在「连接」里换一个。`,"nanoMuse Cloud has no model key configured; the operator has been told.":`nanoMuse Cloud 还没有配置模型 key,运营者已收到通知。`,"This nanoMuse Cloud account is disabled.":`这个 nanoMuse Cloud 账号已被停用。`,"The nanoMuse Cloud sign-in is no longer valid; sign in again under Account.":`nanoMuse Cloud 的登录已失效,请在「账号」里重新登录。`,"That model is not offered by nanoMuse Cloud; pick another under Connections.":`nanoMuse Cloud 不提供这个模型,在「连接」里换一个。`,"That message is too large for the model's window. Shorten it, leave out some attachments, or start a new chat.":`这条消息超出了模型的上下文窗口。精简一下、去掉部分附件,或者开一个新对话。`,"This relay takes new accounts by invitation only; sign in with an invite code under Account.":`这个中继只接受邀请注册;在「账号」里用邀请码登录。`,"Too many turns are running on this account at once; wait for one to finish and try again.":`这个账号同时进行的对话太多了,等一轮结束后再试。`,"New sign-ups are paused on this relay for now; existing accounts keep working. Try again later.":`这个中继暂时停止了新注册,已有账号照常使用。稍后再试。`,"nanoMuse Cloud is paused by its operator for now; your sign-in and your data are kept. Try again later.":`nanoMuse Cloud 被运营者暂时停用了,你的登录和数据都保留着。稍后再试。`,"Conversation sync is paused on this relay for now; what is stored is kept and your devices keep working on their own.":`这个中继暂时停止了对话同步,已存的内容保留着,各设备各自继续使用。`,"The device hub is paused on this relay for now; each device keeps working on its own.":`这个中继暂时停止了设备互联,各设备各自继续使用。`,"The free allowance is paused on this relay for now, not used up. Your own model key under Connections keeps you going; your sign-in, your devices and what is left stay as they are.":`这个中继暂时停发了免费额度,不是用完了。在「连接」里填上你自己的模型 key 就能继续;你的登录、设备和剩余额度都保持原样。`,"This demo Muse has used its share of the model for this visit. Start over for a new one, or install nanoMuse and use your own key.":`这个演示 Muse 这一次的模型额度用完了。点「重新开始」再来一个,或者安装 nanoMuse,用你自己的 key。`,"The showcase has used today's share of the model; it comes back tomorrow. Install nanoMuse and use your own key to keep going.":`在线体验今天的模型额度用完了,明天会恢复。安装 nanoMuse,用你自己的 key 可以继续。`,"The model provider is having trouble; try again in a moment.":`模型服务商出了点问题,稍后再试。`,"The model provider refused the API key. Check it under Connections.":`模型服务商拒绝了这个 API key,去「连接」里检查一下。`,"The endpoint does not know this model. Pick another under Connections.":`这个接口不认识这个模型,在「连接」里换一个。`,"The model provider is rate-limiting this key; wait a moment and try again.":`模型服务商正在限制这个 key 的请求频率,稍等一下再试。`,"The model took too long to answer. Try again.":`模型回答超时了,再试一次。`,"Could not reach the model provider. Check the connection and try again.":`连不上模型服务商,检查一下网络再试。`,"This conversation is too long for the model. Start a new one, or pick a model with a larger context.":`这段对话对模型来说太长了。开一个新对话,或者换一个上下文更大的模型。`,"Enter a phone number or an e-mail address.":`请输入手机号或邮箱。`,"Enter a mainland phone number or an e-mail address":`请输入中国大陆手机号或邮箱`,"Enter a mainland phone number or an e-mail address.":`请输入中国大陆手机号或邮箱。`,"Codes reach mainland China numbers only for now; elsewhere, sign in with an e-mail address.":`短信验证码目前只支持中国大陆手机号,海外用户请用邮箱登录。`,"That code is not right.":`验证码不对。`,"That code has expired; ask for a new one.":`验证码已过期,重新获取一个。`,"Too many codes were sent; wait a few minutes.":`验证码发得太频繁了,几分钟后再试。`,"This relay is private; that address is not on its list.":`这个中继是私有的,这个邮箱不在它的名单上。`,"The code could not be sent; try again in a moment.":`验证码没能发出,稍后再试。`,"Sign in again.":`请重新登录。`,"This account has used its tokens.":`这个账号的额度已经用完。`,"This account is disabled.":`这个账号已被停用。`,"That model is not offered here.":`这里不提供这个模型。`,"Too many requests; slow down a little.":`请求太频繁了,稍微慢一点。`,"The free allowance is used up. Invite a friend (the relay adds to both your allowances) or add your own model key; your sign-in and your devices keep working either way.":`免费额度已用完。邀请一位新用户(你和对方的额度都会增加),或者换成自己的 key;无论选哪个,登录和多设备功能都不受影响。`,"Today's token quota is used up; it comes back tomorrow.":`今天的 token 配额用完了,明天恢复。`,"The model provider did not answer.":`模型服务商没有响应。`,"nanoMuse Cloud has no model key configured.":`nanoMuse Cloud 还没有配置模型 key。`,"nanoMuse Cloud cannot be reached.":`连不上 nanoMuse Cloud。`,"That address and password do not match.":`邮箱与密码不匹配。`,"This account has no password yet; sign in with a code and set one under Account.":`这个账号还没有设置密码:先用验证码登录,再在「账号」里设置。`,"Too many wrong passwords; wait a while or sign in with a code.":`密码错误次数太多,等一会儿再试,或者改用验证码登录。`,"Use at least 8 characters.":`至少 8 个字符。`,"Choose a stronger password.":`换一个更强的密码。`,"That is not the current password.":`当前密码不正确。`,"Enter the current password.":`请输入当前密码。`,"That sign-in is already gone.":`那个登录已经不存在了。`,"Cannot reach your nanoMuse right now.":`现在连不上你的 nanoMuse。`,"Your nanoMuse hit a problem; try again in a moment.":`你的 nanoMuse 出了点问题,稍后再试。`,"Your nanoMuse could not do that.":`你的 nanoMuse 没能完成这个操作。`,"Could not reach your nanoMuse.":`连不上你的 nanoMuse。`,"Connecting to your nanoMuse…":`正在连接你的 nanoMuse…`,"Try again":`再试一次`,"Could not load.":`没能加载出来。`,"Use /{name}":`使用 /{name}`,Retry:`重试`,"Could not load the conversation. Open the chat again to retry.":`对话没能加载出来,重新打开这个对话再试。`,"Could not load the connections.":`连接信息没能加载出来。`,"Your account":`你的账号`,"your account's model, with a free allowance":`账号自带的模型,带免费额度`,"on this machine, no key":`跑在本机,不用 key`,"vLLM, LM Studio, a gateway, anything with /v1":`vLLM、LM Studio、网关,任何带 /v1 的服务`,"Your account's model":`账号自带的模型`,"Your account's model, or a key of your own.":`用账号自带的模型,或者你自己的 key。`,"Your account's model, with its free allowance. Keep it, or switch to a key of your own here.":`账号自带的模型,带免费额度。可以保留,也可以在这里换成你自己的 key。`,"Avatar studio":`形象工坊`,"Avatar studio…":`形象工坊…`,"Draw a look with your image model; it moves with what it is doing.":`用你的图像模型画一个形象;它会随着工作状态动起来。`,More:`更多`,"Name & style":`名字与风格`,"Image model":`图像模型`,"Redraw the poses":`重画状态`,"Back to the built-in look":`换回内置形象`,"Back to the built-in look.":`已换回内置形象。`,"Something went wrong":`出了点问题`,"Drawing the poses… {done}/{total}":`正在画各个状态… {done}/{total}`,"The new look is on; making the clips… {done}/{total}":`新形象已经用上;正在生成动态片段… {done}/{total}`,"All five poses are in.":`五个状态都画好了。`,"{done} of {total} poses are in; the rest show the main picture.":`画好了 {total} 个状态里的 {done} 个,其余先用主图。`,"Describe a new look":`描述一个新形象`,"One sentence is enough: what it is, what it wears, its air. Pick a style and your image model draws four to choose from.":`一句话就够:它是什么、穿什么、什么气质。选一种风格,你的图像模型会画四张让你挑。`,"a round, custard-yellow baby dragon with small orange horns and folded little wings":`一只圆滚滚的奶黄色小龙,橙色小角,折着小翅膀`,"Drawing…":`正在画…`,"Draw four more":`再画四张`,"Drawn by {provider} · {model}":`由 {provider} · {model} 绘制`,"default model":`默认模型`,"your provider":`你的服务商`,"Pick one":`挑一张`,"Draw four more any time; the old ones stay until you do.":`随时可以再画四张;没重画之前旧的会留着。`,"Use this one":`就用这个`,"Next, its poses are drawn from it in the background: working, waiting for you, done, something wrong.":`接下来会在后台以它为底画出各个状态:干活、等你、搞定、出错。`,"Keep the current look":`先不换了`,"Nothing came back.":`什么也没生成出来。`,"The pictures stay in this computer's workspace under avatar/. Each new look asks your provider for eight pictures (four to choose from and four poses) and four short clips where there is a video model.":`图片存在这台电脑的工作区 avatar/ 下。每换一次形象会向你的服务商要八张图(四张供你挑选,四个状态),有视频模型时还会生成四段短动画。`,"Or just say it in the chat: “change your avatar to a corgi”.":`也可以直接在对话里说:“把虚拟形象改成一只柯基”。`,"Change your avatar to ":`把虚拟形象改成`,"Alibaba Cloud Bailian":`阿里云百炼`,Zhipu:`智谱`,"Volcano Ark":`火山方舟`,"this computer":`这台电脑`,"Change model":`更换`,Search:`搜索`,"Search chats":`搜索对话`,"Side chats":`旁聊`,"Start a side chat":`发起旁聊`,"Side chats are an optional way to keep conversations organised by topic.":`旁聊是按主题整理对话的可选方式。`,Keep:`保留`,"No chats match.":`没有匹配的对话。`,"A side chat keeps one topic apart from the rest.":`一个旁聊,把一个话题和其他的分开。`,"Report a bug":`报告问题`,"Developer tools":`开发者工具`,Developer:`开发者`,"The Coding screen (Cursor, Codex and the other coding agents on this computer) in the sidebar, and the runtime's address below. This device only.":`在侧栏显示「编程」(这台电脑上的 Cursor、Codex 等编程智能体),并在下面显示运行时的地址。仅此设备。`,"Runtime:":`运行时:`,"the token is in the server_token file in the data folder":`令牌在数据目录的 server_token 文件里`,"The command line and the API":`命令行与 API`,"nanoMuse on DeepSeek Harness":`nanoMuse 的 DeepSeek Harness 版`,"Desktop app":`桌面应用`,"Start with the computer":`开机自动启动`,"Opens in the tray at sign-in; the agent's goals and check-ins run from then on.":`登录系统后在托盘里启动;从那时起,它的目标和定时检查就开始跑了。`,"In the tray":`托盘图标`,"The icon by the clock shows what the hands are doing and has Stop; closing the window keeps the agent running.":`时钟旁的图标显示它正在操作什么,并带「停止」;关掉窗口后它仍在后台运行。`,Shortcuts:`快捷键`,"Quick chat":`快速对话`,"Show the window":`打开窗口`,"Feed settings":`动态设置`,"About the feed":`动态版块说明`,"Your feed is driven by the instruction below. Any edit you make here applies to every post from now on.":`动态由下面这句话来定。在这里改动它,今后的每一条帖子都会照着来。`,"Build me a feed about what I care about. Keep it short and direct, easy to skim, no clickbait.":`给我做一个关于我关心的事的动态。短一点、直接一点,扫一眼就能看完,别搞标题党。`,"Got it":`知道了`,"Write it now":`现在写一版`,"Nothing in the feed yet":`动态里还没有内容`,"As we get to know each other, new posts will show up here. Every day at {time} I read what I remember about you (your memory files, the last week of diary, your goals) and write a few short posts.":`随着我们相互了解,新的帖子会显示在这里。每天 {time},我会读一遍记得的关于你的东西(记忆文件、最近一周的日记、你的目标),然后写几条简短的帖子。`,"Steer it with one sentence":`一句话就能调整`,"Tap the sliders at the top right to tell me what you want more of, switch the daily routine off, or have me write the first day now.":`点右上角的滑杆,告诉我你想多看什么、关掉每天的例程,或者让我现在就写第一天。`,"Short posts your agent writes for you from what it remembers: your memory files, the last week of diary, your goals. The sentence below steers every post from now on; edit it any time.":`这里是你的智能体为你写的短帖子,取材于它记得的东西:记忆文件、最近一周的日记、你的目标。下面这句话决定今后每一条帖子的方向,随时可以改。`,"Write it every day":`每天自动写`,"Time of day":`时间`,"Add a model first; the feed is written by your agent.":`先添加一个模型,动态由你的智能体来写。`,Discuss:`讨论`,"About this post":`这条帖子的信息`,"Delete this post":`删除这条`,Written:`写于`,Note:`随记`,Files:`文件`,Fun:`休闲`,"About this post from my feed:":`聊聊我动态里的这一条:`,"Post type":`类型`,morning:`上午`,afternoon:`下午`,evening:`晚上`,"{weekday} {part}":`{weekday}{part}`,"Starts a conversation":`会开始一段对话`,"Send to chat":`发到聊天`,"Nothing tracked yet":`尚未追踪任何内容`,"Create a goal":`创建目标`,"Pick a category and tell me the goal you have in mind. I'll shape a plan with you and keep improving it as you go.":`选一个类别,告诉我你心里的目标。我会和你一起定出计划,并在推进过程中不断调整。`,"Create a {category} goal":`创建{category}目标`,"First, we'll shape the goal together in the chat. I'll ask a few questions so I understand exactly what you're after.":`首先,我们将在聊天中一起完善目标。我会问几个问题,准确了解你的目标。`,"Once it's set, I'll track your progress here.":`目标设置后,我会在这里追踪你的进度。`,"I'd like to create a {category} goal. Ask me a few short questions, one at a time (what exactly I want, why and by when, how often to check in), then create it with concrete steps using the goals tool.":`我想创建一个{category}目标。请一次问我一个简短的问题(我具体想达成什么、为什么以及什么时候、多久检查一次),然后用 goals 工具把它建成带具体步骤的目标。`,"Mark as done":`标记为已完成`,"Mark as not done":`标记为未完成`,"Plan my week":`规划我的一周`,"Tell me what's on your plate and I'll turn it into a realistic plan with the important things first.":`告诉我你手头有什么,我把它排成一份切实可行的计划,重要的事放前面。`,"Help me plan my week. Ask me what I need to get done, then propose a schedule.":`帮我规划这一周。先问我有哪些事要做,然后给出一份日程安排。`,"Research & compare options":`调研并比较选项`,"Laptops, flights, insurance, a new phone plan: I'll gather the facts and compare them for you.":`笔记本、机票、保险、新的手机套餐,我帮你收集事实并逐项比较。`,"I need to make a purchase decision. Ask me what I'm choosing between, then research and compare the options.":`我想买个东西,拿不定主意。先问我在哪几个里面挑,然后帮我查一查、比一比。`,"Set up a long-term goal":`建立一个长期目标`,"Share a goal (learn a language, run a 10k, save for a trip) and I'll break it into steps and keep track.":`说一个目标(学一门语言、跑完 10 公里、攒一次旅行的钱),我把它拆成步骤并持续跟进。`,"I want to set up a long-term goal. Ask me about it, then create a plan with concrete steps and track it.":`我想建立一个长期目标。先问问我,然后制定一份带具体步骤的计划并跟进。`,"Tell me about yourself":`介绍一下你自己`,"The more I know about your preferences, routines and constraints, the more useful I get. I'll remember what matters.":`我越了解你的偏好、作息和限制,就越能帮上忙。重要的事我会记住。`,"Ask me a few questions about myself so you can help me better, and remember the answers.":`问我几个关于我的问题,好更了解我,然后把答案记住。`,"Build a quick tracker":`做一个简单的追踪表`,"Spending, habits, workouts, reading: I can write a small script or document to track it for you.":`开支、习惯、锻炼、阅读,我可以写一个小脚本或文档帮你记录。`,"Build me a simple tracker. Ask me what I want to track and how, then create it in the workspace.":`帮我做一个简单的追踪表。先问我想记录什么、怎么记,然后在工作区里建好。`,Artifacts:`构件`,Media:`影音内容`,"Nothing created yet":`还没有创建任何内容`,"Documents, tables and pages I write for you will show up here.":`我为你写的文档、表格和页面会显示在这里。`,"No media yet":`还没有影音内容`,"Photos, screenshots and recordings I produce will show up here.":`我生成的图片、截图和录音会显示在这里。`,"No model yet":`还没有模型`,"Add a provider and pick its models":`添加一个服务商并选择模型`,"Image & video models":`图像与视频模型`,"Name & personality":`名字与人格`,"About nanoMuse":`关于 nanoMuse`,"Privacy policy":`隐私政策`,Feedback:`反馈问题`,none:`无`,"Change avatar":`更换虚拟形象`,"Edit name":`编辑名称`,Daily:`每日`,"Soul & memory":`SOUL 与记忆`,"Handle with care":`请谨慎访问`,"This device's name":`这台设备的名字`,"Sync conversations between my devices":`在我的设备之间同步对话`,"The text of your chats is kept on nanoMuse Cloud so every device shows the same conversations. Files and images stay on the device they were made on.":`对话文字会保存在 nanoMuse Cloud,让每台设备看到同样的对话。文件和图片只留在产生它们的设备上。`,"Paused: sign in again to continue.":`已暂停:重新登录后继续。`,"{c} chats, {m} messages kept so far.":`目前保存了 {c} 个对话、{m} 条消息。`,"Delete synced conversations":`删除已同步的对话`,"{n} chats":`{n} 个对话`,"Removes what nanoMuse Cloud stores for this account; the chats on each device stay, and the switch stays on. Deleting a chat on one device deletes it on all of them.":`删除 nanoMuse Cloud 为这个账号保存的内容;每台设备上的对话保留,开关也保持打开。在一台设备上删除某个对话,会在所有设备上一起删除。`,"Off deletes the synced conversations from nanoMuse Cloud. The chats on each device stay.":`关闭后会从 nanoMuse Cloud 删除已同步的对话。每台设备上的对话保留。`,"On. Your devices show the same conversations from now on.":`已打开。从现在起,你的设备会看到同样的对话。`,"Off. Nothing is kept on nanoMuse Cloud any more.":`已关闭。nanoMuse Cloud 不再保存任何对话。`,"The synced conversations are removed from nanoMuse Cloud. The chats on each device stay. This cannot be undone.":`已同步的对话将从 nanoMuse Cloud 删除。每台设备上的对话保留。此操作无法撤销。`,"Synced conversations deleted.":`已删除已同步的对话。`,"Also sync side chats":`同时同步旁聊`,"Off: side chats stay on this device. On: this device's side chats go to the account and the other devices' side chats come here.":`关:旁聊只留在本机。开:本机的旁聊上传到账号,其他设备的旁聊也会同步过来。`,"On. This device's side chats go to the account; the other devices' are on their way.":`已打开。本机的旁聊会上传到账号,其他设备的旁聊正在同步过来。`,"Off. Side chats stay on this device from now on.":`已关闭。从现在起,旁聊只留在本机。`,"{device} is working…":`{device} 正在处理…`,"From {device}":`来自 {device}`,"to {device}":`发给 {device}`,"This goes to {device}.":`这条会发给 {device}。`,"Runs this there and reports back":`在那台设备上执行并汇报结果`,Offline:`离线`,"There is no form to fill in: once it has a model, it introduces itself in the chat and asks what to call you.":`不用填表:有了模型之后,它会在聊天里介绍自己,并问你希望怎么称呼你。`,"A model, then the chat. A minute.":`先接一个模型,再去聊天。一分钟。`,"Open the chat. It introduces itself and asks your name.":`打开聊天。它会介绍自己,并问你的名字。`,"Pick a name for me, or type one":`给我挑一个名字,或者自己输入一个`,"Something else":`自己起一个`,"Proxy (optional)":`代理(可选)`,"Only this provider's requests go through it. nanoMuse Cloud never does.":`只有这个服务商的请求走代理;nanoMuse Cloud 的请求从不经过它。`,"Talk to your Muse from the chat apps you already use. Nothing needs a public address: each app keeps a long connection open.":`在你已经在用的聊天软件里和 Muse 对话。不需要公网地址:每个应用各自保持一条长连接。`,"Waiting for a yes":`等待通过`,"{name} wrote to the bot. Approve to let them talk to your Muse.":`{name} 给机器人发了消息。通过后对方就能和 Muse 对话。`,Approve:`通过`,"Code {code}":`配对码 {code}`,"Needs settings":`还缺设置`,"Not installed":`未安装`,Error:`出错`,Missing:`缺少`,"Switched on":`已开启`,"Install on the computer running nanoMuse, then switch it on again:":`在运行 nanoMuse 的电脑上安装,再重新开启:`,"Saved.":`已保存。`,Saving:`保存中`,"Set; leave blank to keep":`已设置,留空则保持不变`,"Clear the saved value":`清除已保存的值`,"In groups, reply":`在群里回复`,"only when @-mentioned":`只在被 @ 时`,"to every message":`每条消息`,"Always allowed (ids, one per line)":`免配对的 ID(每行一个)`,"People listed here never need a pairing code. A lone * lets anyone in; do that only on a bot nobody else can reach.":`列在这里的人不需要配对码。单独一个 * 表示放行所有人,只在别人找不到的机器人上这样做。`,"Paired chats":`已配对的聊天`,"Nobody yet. Write to the bot from the app; a pairing code comes back, approve it here.":`还没有人。在聊天软件里给机器人发条消息,会收到配对码,在这里通过即可。`,"Deliver here":`推送到这里`,"Chats with “deliver here” on also get what the Muse does on its own: check-ins, reminders, the results of background work, and the questions it needs answered.":`开了「推送到这里」的聊天还会收到 Muse 主动做的事:问候、提醒、后台任务的结果,以及需要你回答的问题。`,"Remove {name}? They will need a new pairing code.":`移除 {name}?对方需要重新配对。`,"Send a test message":`发送测试消息`,Sending:`发送中`,"Create the bot by QR code":`扫码创建机器人`,"Open in Feishu":`在飞书里打开`,"Scan with Feishu, confirm the new bot, and the App ID and Secret are saved for you.":`用飞书扫码,确认创建机器人,App ID 和 Secret 会自动保存。`,"Lark (international) instead of 飞书":`用 Lark(国际版)而不是飞书`,"Waiting for the scan…":`等待扫码…`,"The bot was created and is connecting.":`机器人已创建,正在连接。`,"The login did not finish ({error}).":`登录没有完成({error})。`,"Set up":`设置步骤`,"Open the console":`打开控制台`,"Then write to the bot from the app. The first message gets a pairing code; approve it here or run":`然后在聊天软件里给机器人发消息。第一条消息会收到配对码,在这里通过,或运行`,"Each chat is one conversation of your Muse; its replies stream back as they are written.":`每个聊天对应 Muse 的一个会话;回复会边写边发回来。`,"In the Feishu developer console create a custom app and add the Bot capability.":`在飞书开放平台创建企业自建应用,添加「机器人」能力。`,"Permissions: im:message, im:message.p2p_msg:readonly, im:message.group_at_msg:readonly, im:resource.":`权限:im:message、im:message.p2p_msg:readonly、im:message.group_at_msg:readonly、im:resource。`,"Events & callbacks: subscription mode Long connection; add im.message.receive_v1; callback mode Long connection; add card.action.trigger.":`事件与回调:订阅方式选「长连接」,添加 im.message.receive_v1;回调方式选「长连接」,添加 card.action.trigger。`,"Copy App ID and App Secret from Credentials & Basic Info, then publish a version.":`在「凭证与基础信息」复制 App ID 和 App Secret,然后发布版本。`,"In the DingTalk developer console create an internal app and add the Robot capability.":`在钉钉开放平台创建企业内部应用,添加「机器人」能力。`,"Set the message receive mode to Stream.":`消息接收模式选「Stream 模式」。`,"Copy Client ID (AppKey) and Client Secret (AppSecret) from Credentials & Basic Info.":`在「凭证与基础信息」复制 Client ID(AppKey)和 Client Secret(AppSecret)。`,"Add the robot send-message permission and publish the version.":`添加机器人发消息权限,发布版本。`,"In the WeCom admin console open Intelligent robot and create a robot in API mode with a long connection.":`在企业微信管理后台打开「智能机器人」,创建 API 模式、长连接的机器人。`,"Copy the Bot ID and Secret.":`复制 Bot ID 和 Secret。`,"Add the robot to the chats where it should listen.":`把机器人加到需要它在的聊天里。`,"In Telegram talk to @BotFather, send /newbot and copy the token.":`在 Telegram 里找 @BotFather,发送 /newbot,复制 token。`,"Direct messages work at once. For a group, add the bot to it; with Group Privacy on it only hears @-mentions and replies.":`私聊立即可用。群聊需要先把机器人拉进群;开着 Group Privacy 时它只听 @ 和回复。`,"If api.telegram.org is out of reach from this computer, set a proxy below.":`如果这台电脑连不上 api.telegram.org,在下面填一个代理。`,"Use nanoMuse Cloud models":`使用 nanoMuse Cloud 模型`,"nanoMuse Cloud is one of the sources for the chat, the hands, pictures and clips; what runs on it comes off your allowance.":`nanoMuse Cloud 是聊天、双手、图片和短片的来源之一;在它上面运行的内容会消耗你的额度。`,"Off: nothing runs on nanoMuse Cloud unless you choose it yourself. You stay signed in for sync and your devices.":`关闭后,除非你自己选择,否则不会有任何内容在 nanoMuse Cloud 上运行。账号保持登录,用于同步和你的设备。`,"Add a provider of your own first; with nanoMuse Cloud off, nothing else could answer.":`先添加一个自己的服务商;关掉 nanoMuse Cloud 后没有别的模型能回答。`,"Use your own API key instead":`改用自己的 API key`,"You can sign in later under Connections, for sync and your devices.":`之后可以在「连接」里登录,用于同步和你的设备。`,"Add an endpoint":`添加接口`,"Add endpoint":`添加接口`,"An endpoint joins your list with its own key and stays there; add as many as you use. Pick one as the chat model, or use its models for the hands, pictures and clips.":`接口带着自己的密钥加入列表并一直保留;用几个就加几个。可以选一个作为对话模型,也可以把它的模型用于双手、图片和短片。`,"Name (optional)":`名字(可选)`,"How the endpoint reads in the lists; its host when left empty.":`接口在列表里显示的名字;留空则显示主机名。`,"for example: my gateway":`例如:我的网关`,"Stored encrypted in the vault under this endpoint's own name.":`加密保存在保险库里,以这个接口自己的名字命名。`,"Models (optional)":`模型(可选)`,"Leave empty when the endpoint lists its models at /models. Otherwise type their ids, separated by commas.":`接口能在 /models 列出模型时留空;否则输入模型 id,用逗号分隔。`,"Endpoint added":`已添加接口`,"Endpoint renamed":`已给接口改名`,"Endpoint removed":`已移除接口`,"Key saved":`密钥已保存`,"Models saved":`模型已保存`,Models:`模型`,Rename:`改名`,"Change key":`换密钥`,"Edit models":`编辑模型`,"Ask for its models":`重新获取模型`,"{n} models":`{n} 个模型`,"{n} models saved with this endpoint":`这个接口保存了 {n} 个模型`,"Used by {slots}":`用于{slots}`,"the hands":`双手`,pictures:`图片`,clips:`短片`,"The ids of the models this endpoint serves, separated by commas; what it lists at /models is added after them.":`这个接口提供的模型 id,用逗号分隔;它在 /models 列出的模型会接在后面。`,"The endpoint did not list its models; the saved list stands.":`接口没有列出模型;沿用已保存的列表。`,"The chat model answers through this endpoint; pick another chat model first.":`对话模型正通过这个接口回答;请先换一个对话模型。`,"Its key goes with it, and the hands, pictures or clips set on it go back to automatic.":`它的密钥会一起删除;设在它上面的双手、图片或短片会回到自动。`,"Uses the key saved with this endpoint.":`使用这个接口保存的密钥。`,"Your endpoints":`你的接口`,"The model that looks at screens when the hands run: a small, fast one that takes pictures. Pick one of this provider's, or one from another endpoint of your list, which then lends its address and key.":`双手运行时看屏幕的模型:一个小而快、能看图的模型。可以选这个服务商的,也可以选你列表里另一个接口的,那个接口的地址和密钥会一并使用。`,"the endpoint did not list its models (GET /models); type the ids of the models it serves, separated by commas":`接口没有列出模型(GET /models);请输入它提供的模型 id,用逗号分隔`,"the chat model answers through this endpoint; pick another chat model first":`对话模型正通过这个接口回答;请先换一个对话模型`,"the address must start with http:// or https://":`地址必须以 http:// 或 https:// 开头`,"that is nanoMuse Cloud; it is the account, not an endpoint":`那是 nanoMuse Cloud;它是账号,不是接口`,"a key has no spaces in it":`密钥里不会有空格`},ne=[{value:`auto`,label:`Auto`},{value:`en`,label:`English`},{value:`zh-CN`,label:`简体中文`}],j=`nanomuse_locale`,M={en:{},"zh-CN":A};function re(){try{let e=localStorage.getItem(j);if(e===`en`||e===`zh-CN`||e===`auto`)return e}catch{}return`auto`}var N=re(),P=new Set;function ie(){return(typeof navigator>`u`?[]:[navigator.language,...navigator.languages??[]]).some(e=>/^zh\b/i.test(e??``))?`zh-CN`:`en`}function ae(){return N}function F(){return N===`auto`?ie():N}function oe(e){N=e;try{localStorage.setItem(j,e)}catch{}se(),P.forEach(e=>e())}function se(){typeof document<`u`&&(document.documentElement.lang=F())}function ce(e){return P.add(e),()=>P.delete(e)}function le(){return(0,f.useSyncExternalStore)(ce,F,F)}function ue(){return(0,f.useSyncExternalStore)(ce,ae,ae)}function de(e,t){return t?e.replace(/\{(\w+)\}/g,(e,n)=>n in t?String(t[n]):e):e}function I(e,t){let n=M[F()];return de(n[e]??e,t)}function fe(e){let t=t=>({title:e.slice(t.length)});return e.startsWith(`Working on your goal: `)?I(`Working on your goal: {title}`,t(`Working on your goal: `)):e.startsWith(`Check-in: `)?I(`Check-in: {title}`,t(`Check-in: `)):e.startsWith(`Reminder: `)?I(`Reminder: {title}`,t(`Reminder: `)):e.startsWith(`Routine: `)?I(`Routine: {title}`,t(`Routine: `)):e.startsWith(`New mail: `)?I(`New mail: {title}`,t(`New mail: `)):e.startsWith(`Coming up: `)?I(`Coming up: {title}`,t(`Coming up: `)):e.startsWith(`Webhook: `)?I(`Webhook: {title}`,t(`Webhook: `)):e===`Tidied memory`?I(`Tidied memory`):e}function pe(e){let t=/^'([^']+)' is in always_ask_tools$/.exec(e);return t?I(`{tool} is on your always-ask list`,{tool:t[1]}):(t=/^'([^']+)' is in always_allow_tools$/.exec(e),t?I(`{tool} is on your always-allow list`,{tool:t[1]}):(t=/^'([^']+)' is in sentinel\.deny_tools$/.exec(e),t?I(`{tool} is switched off in your settings`,{tool:t[1]}):(t=/^risk level is '(\w+)' \(mode=(\w+)\)$/.exec(e),t?I(`an action rated {risk}, in {mode} mode`,{risk:I(t[1]),mode:I(t[2])}):e===`auto mode: approval skipped`?I(`auto mode: not asked`):(t=/^covered by your '([^']+)' permission for (.+)$/.exec(e),t?I(`covered by your {scope} permission for {key}`,{scope:I(t[1]),key:t[2]}):(t=/^private data was read earlier in this conversation and '([^']+)' can send data to (.+), which is not on sentinel\.egress_allowlist$/.exec(e),t?I(`private data was read earlier in this conversation, and {tool} could send it to {target}, which is not on your allowed list`,{tool:t[1],target:t[2]}):I(e))))))}function me(e){let t=/^the file is larger than (\d+) MB$/.exec(e);return t?I(`The file is larger than {n} MB.`,{n:t[1]}):I(e)}function he(){return le(),I}function L(){return F()===`zh-CN`?`zh-CN`:`en-US`}function ge(e){if(!e)return``;let t=new Date(e);if(Number.isNaN(t.getTime()))return``;let n=new Date,r=t.toDateString()===n.toDateString(),i=t.toLocaleTimeString(L(),{hour:`2-digit`,minute:`2-digit`});return r?i:`${t.toLocaleDateString(L(),{month:`short`,day:`numeric`})} ${i}`}function _e(e){if(!e)return``;let t=new Date(e);if(Number.isNaN(t.getTime()))return``;let n=t.toLocaleTimeString(L(),{hour:`numeric`,minute:`2-digit`}),r=new Date,i=new Date(r);return i.setDate(r.getDate()-1),t.toDateString()===r.toDateString()?`${I(`Today`)} ${n}`:t.toDateString()===i.toDateString()?`${I(`Yesterday`)} ${n}`:`${ve(e)} ${n}`}function ve(e,t={}){if(!e)return``;let n=new Date(e);if(Number.isNaN(n.getTime()))return``;let r=n.getFullYear()===new Date().getFullYear();return n.toLocaleDateString(L(),{month:`short`,day:`numeric`,...r?{}:{year:`numeric`},...t})}function ye(e){if(!e)return``;let t=Date.now()-new Date(e).getTime();if(Number.isNaN(t))return``;let n=Math.round(Math.abs(t)/1e3);if(n<45)return I(t>=0?`just now`:`any moment`);let r=Math.round(n/60),i=Math.round(r/60),a=Math.round(i/24),o=r<60?I(`{n} min`,{n:r}):i<24?I(`{n} h`,{n:i}):I(`{n} d`,{n:a});return I(t>=0?`{span} ago`:`in {span}`,{span:o})}function be(e){let t=Math.max(0,Math.floor(Date.now()/1e3-e));return t<60?I(`just now`):t<3600?I(`{n} min ago`,{n:Math.floor(t/60)}):t<86400?I(`{n} h ago`,{n:Math.floor(t/3600)}):t<604800?I(`{n} d ago`,{n:Math.floor(t/86400)}):new Date(e*1e3).toLocaleDateString(L())}function R(e){try{return localStorage.getItem(e)}catch{return null}}function z(e,t){try{t===null?localStorage.removeItem(e):localStorage.setItem(e,t)}catch{}}function B(...e){return e.filter(Boolean).join(` `)}function xe(e){try{return decodeURIComponent(e)}catch{return e}}function Se(e){let t=e.toLowerCase().split(`.`).pop()??``;return t===`ics`?`event`:[`md`,`txt`,`log`,`rtf`].includes(t)?`text`:[`py`,`js`,`ts`,`tsx`,`jsx`,`sh`,`toml`,`yaml`,`yml`,`sql`,`rs`,`go`,`java`,`c`,`cpp`].includes(t)?`code`:[`html`,`htm`].includes(t)?`html`:[`png`,`jpg`,`jpeg`,`gif`,`webp`,`svg`].includes(t)?`image`:t===`pdf`?`pdf`:[`csv`,`json`,`xlsx`,`xls`,`parquet`].includes(t)?`data`:`other`}var V=`nanomuse_token`,H=class extends Error{constructor(){super(`unauthorized`)}};function Ce(e){let t=e.hash.replace(/^#/,``).split(`&`).filter(Boolean),n=t.findIndex(e=>e.startsWith(`token=`));if(n>=0){let r=decodeURIComponent(t[n].slice(6));return t.splice(n,1),e.hash=t.length?`#${t.join(`&`)}`:``,r||null}let r=e.searchParams.get(`token`);return r?(e.searchParams.delete(`token`),r):null}function U(){let e=new URL(window.location.href),t=Ce(e);return t&&(z(V,t),window.history.replaceState(null,``,e.pathname+e.search+e.hash)),R(V)??``}function we(e){z(V,e||null)}function W(e,t=!1){let n=U(),r=n?T(n,`/api/files/${e}`):new URLSearchParams;t&&r.set(`download`,`1`);let i=r.toString();return`/api/files/${e.split(`/`).map(encodeURIComponent).join(`/`)}${i?`?${i}`:``}`}function Te(e,t){let n=U(),r=n?`?${T(n,`/api/browser/${e}/frames/${t}.jpg`)}`:``;return`/api/browser/${encodeURIComponent(e)}/frames/${encodeURIComponent(t)}.jpg${r}`}async function G(e,t={}){let n={...t.headers},r=U();r&&(n.Authorization=`Bearer ${r}`),t.body&&!n[`Content-Type`]&&(n[`Content-Type`]=`application/json`);let i;try{i=await fetch(e,{...t,headers:n})}catch{throw Error(`Cannot reach your nanoMuse right now.`)}if(i.status===401)throw new H;if(!i.ok){let e;try{e=await i.json()}catch{}throw Error(Ee(i.status,e))}return await i.json()}function Ee(e,t){let n=t&&typeof t==`object`?t.detail:void 0;return typeof n==`string`&&n.trim()?n:e>=500?`Your nanoMuse hit a problem; try again in a moment.`:`Your nanoMuse could not do that.`}var K=e=>({method:`POST`,body:JSON.stringify(e)}),q={state:()=>G(`/api/state`),cloud:()=>G(`/api/cloud`),cloudCode:e=>G(`/api/cloud/code`,K({identifier:e})),cloudVerify:(e,t,n=``)=>G(`/api/cloud/verify`,K(n?{identifier:e,code:t,invite:n}:{identifier:e,code:t})),cloudSignOut:()=>G(`/api/cloud/sign-out`,K({})),cloudModels:e=>G(`/api/cloud/models`,K({on:e})),cloudLogin:(e,t)=>G(`/api/cloud/login`,K({identifier:e,password:t})),cloudPassword:(e,t)=>G(`/api/cloud/password`,K({password:e,current:t??null})),cloudSessions:()=>G(`/api/cloud/sessions`),cloudRevokeSession:e=>G(`/api/cloud/sessions/${encodeURIComponent(e)}`,{method:`DELETE`}),cloudSignOutAll:(e=!1)=>G(`/api/cloud/sign-out-all`,K({all:e})),cloudEvents:(e=50)=>G(`/api/cloud/events?limit=${e}`),cloudDelete:()=>G(`/api/cloud/delete`,K({})),cloudMe:()=>G(`/api/cloud/me`),cloudConfig:()=>G(`/api/cloud/config`),cloudContribute:e=>G(`/api/cloud/contribute`,K({on:e})),cloudDeleteSamples:()=>G(`/api/cloud/samples`,{method:`DELETE`}),cloudUseAsModel:(e=``)=>G(`/api/cloud/use-as-model`,K({model:e})),syncState:()=>G(`/api/sync/state`),syncSetState:e=>G(`/api/sync/state`,{method:`PUT`,body:JSON.stringify({enabled:e})}),syncSetSideChats:e=>G(`/api/sync/state`,{method:`PUT`,body:JSON.stringify({side_chats:e})}),syncDelete:()=>G(`/api/sync/delete`,K({})),syncPull:()=>G(`/api/sync/pull`,K({})),avatarView:()=>G(`/api/avatar`),avatarBegin:(e,t=`main`,n=`muse`)=>G(`/api/avatar/begin`,K({description:e,thread:t,style:n})),avatarStart:e=>G(`/api/avatar/start`,K({session:e})),avatarChoose:(e,t)=>G(`/api/avatar/choose`,K({session:e,index:t})),avatarCancel:e=>G(`/api/avatar/cancel`,K({session:e})),avatarMoods:()=>G(`/api/avatar/moods`,K({})),coding:(e=``)=>G(`/api/coding${e?`?device=${encodeURIComponent(e)}`:``}`),codingSessions:(e={})=>{let t=new URLSearchParams;e.agent&&t.set(`agent`,e.agent),e.limit&&t.set(`limit`,String(e.limit)),e.workspace&&t.set(`workspace`,e.workspace),e.device&&t.set(`device`,e.device);let n=t.toString();return G(`/api/coding/sessions${n?`?${n}`:``}`)},codingSession:(e,t,n=``)=>G(`/api/coding/sessions/${encodeURIComponent(e)}/${encodeURIComponent(t)}${n?`?device=${encodeURIComponent(n)}`:``}`),codingSend:e=>G(`/api/coding/send`,K(e)),codingStop:(e,t=``)=>G(`/api/coding/stop`,K({run:e,device:t})),hub:()=>G(`/api/hub`),updateHub:e=>G(`/api/hub`,{method:`PUT`,body:JSON.stringify(e)}),joinHub:()=>G(`/api/hub/join`,K({})),leaveHub:()=>G(`/api/hub/leave`,K({})),refreshHub:()=>G(`/api/hub/refresh`,K({})),forgetDevice:e=>G(`/api/hub/devices/${encodeURIComponent(e)}`,{method:`DELETE`}),askDevice:(e,t=``)=>G(`/api/hub/ask`,K({device:e,text:t})),hands:()=>G(`/api/hands`),setHands:e=>G(`/api/connections/hands`,{method:`PUT`,body:JSON.stringify(e)}),stopHands:()=>G(`/api/hands/stop`,K({})),holds:()=>G(`/api/holds`),openHold:(e,t,n=``)=>G(`/api/holds`,K({thread:e,tool:t,reason:n})),doneHold:e=>G(`/api/holds/${encodeURIComponent(e)}/done`,K({})),health:()=>G(`/api/health`),threads:()=>G(`/api/threads`),createThread:e=>G(`/api/threads`,K({title:e})),renameThread:(e,t)=>G(`/api/threads/${e}`,{method:`PATCH`,body:JSON.stringify({title:t})}),deleteThread:e=>G(`/api/threads/${e}`,{method:`DELETE`}),clearThread:e=>G(`/api/threads/${e}/clear`,{method:`POST`}),stopThread:e=>G(`/api/threads/${e}/stop`,{method:`POST`}),events:(e,t=200,n)=>G(`/api/threads/${e}/events?limit=${t}${n?`&before=${encodeURIComponent(n)}`:``}`),send:(e,t,n=[],r=``,i=``)=>G(`/api/threads/${e}/send`,K(i?{text:t,files:n,language:r,via:i}:{text:t,files:n,language:r})),upload:e=>G(`/api/files/upload?name=${encodeURIComponent(e.name||`photo.jpg`)}`,{method:`POST`,headers:{"Content-Type":e.type||`application/octet-stream`},body:e}),decide:(e,t,n=`once`,r=``)=>G(`/api/approvals/${e}`,K({approved:t,scope:n,reason:r})),resetApprovals:()=>G(`/api/approvals`,{method:`DELETE`}),revokeGrant:e=>G(`/api/approvals/grants/${encodeURIComponent(e)}`,{method:`DELETE`}),goals:()=>G(`/api/goals`),createGoal:e=>G(`/api/goals`,K(e)),patchGoal:(e,t)=>G(`/api/goals/${e}`,{method:`PATCH`,body:JSON.stringify(t)}),addStep:(e,t)=>G(`/api/goals/${e}/steps`,K({title:t})),advanceGoal:e=>G(`/api/goals/${e}/advance`,{method:`POST`}),checkInGoal:e=>G(`/api/goals/${e}/check-in`,{method:`POST`}),acceptProposal:e=>G(`/api/goals/${e}/proposal/accept`,{method:`POST`}),dismissProposal:e=>G(`/api/goals/${e}/proposal`,{method:`DELETE`}),deleteGoal:e=>G(`/api/goals/${e}`,{method:`DELETE`}),memory:()=>G(`/api/memory`),addMemory:(e,t)=>G(`/api/memory`,K({content:e,category:t})),forgetMemory:e=>G(`/api/memory/${e}`,{method:`DELETE`}),tidyMemory:()=>G(`/api/memory/tidy`,{method:`POST`}),memoryChanges:(e=30)=>G(`/api/memory/changes?limit=${e}`),restoreMemoryChange:e=>G(`/api/memory/changes/${e}/restore`,{method:`POST`}),ideas:(e=!1)=>G(`/api/ideas${e?`?refresh=1`:``}`),activity:(e=150)=>G(`/api/activity?n=${e}`),feed:(e=60)=>G(`/api/feed?limit=${e}`),feedPosts:()=>G(`/api/feed/posts`),setFeedInstructions:e=>G(`/api/feed/instructions`,{method:`PUT`,body:JSON.stringify(e)}),refreshFeedPosts:()=>G(`/api/feed/posts/refresh`,{method:`POST`}),deleteFeedPost:e=>G(`/api/feed/posts/${e}`,{method:`DELETE`}),upcoming:()=>G(`/api/upcoming`),reminders:(e=!1)=>G(`/api/reminders${e?`?all=1`:``}`),createReminder:e=>G(`/api/reminders`,{method:`POST`,body:JSON.stringify(e)}),fireReminder:e=>G(`/api/reminders/${e}/fire`,{method:`POST`}),cancelReminder:e=>G(`/api/reminders/${e}`,{method:`DELETE`}),triggers:()=>G(`/api/triggers`),createTrigger:e=>G(`/api/triggers`,{method:`POST`,body:JSON.stringify(e)}),fireTrigger:e=>G(`/api/triggers/${e}/fire`,{method:`POST`}),cancelTrigger:e=>G(`/api/triggers/${e}`,{method:`DELETE`}),files:(e=300)=>G(`/api/files?limit=${e}`),fileText:async e=>{let t={},n=U();n&&(t.Authorization=`Bearer ${n}`);let r=await fetch(`/api/files/${e.split(`/`).map(encodeURIComponent).join(`/`)}`,{headers:t});if(r.status===401)throw new H;if(!r.ok)throw Error(Ee(r.status,await r.json().catch(()=>void 0)));return r.text()},settings:()=>G(`/api/settings`),update:(e=!1)=>G(`/api/update${e?`?refresh=1`:``}`),nudges:()=>G(`/api/nudges`),updateSettings:e=>G(`/api/settings`,{method:`PUT`,body:JSON.stringify(e)}),connections:()=>G(`/api/connections`),providers:e=>G(`/api/providers${e?`?region=${encodeURIComponent(e)}`:``}`),chatgptLogin:()=>G(`/api/chatgpt/login`,K({})),chatgptStatus:()=>G(`/api/chatgpt/status`),chatgptCallback:e=>G(`/api/chatgpt/callback`,K({url:e})),chatgptLogout:()=>G(`/api/chatgpt/logout`,K({})),setLLM:e=>G(`/api/connections/llm`,{method:`PUT`,body:JSON.stringify(e)}),testLLM:()=>G(`/api/connections/llm/test`,{method:`POST`}),llmModels:e=>G(`/api/llm/models`,K(e)),addEndpoint:e=>G(`/api/connections/endpoints`,K(e)),updateEndpoint:(e,t)=>G(`/api/connections/endpoints/${encodeURIComponent(e)}`,{method:`PUT`,body:JSON.stringify(t)}),removeEndpoint:e=>G(`/api/connections/endpoints/${encodeURIComponent(e)}`,{method:`DELETE`}),refreshEndpointModels:e=>G(`/api/connections/endpoints/${encodeURIComponent(e)}/models`,K({})),setEmbeddings:e=>G(`/api/connections/embeddings`,{method:`PUT`,body:JSON.stringify(e)}),testEmbeddings:()=>G(`/api/connections/embeddings/test`,{method:`POST`}),setSearch:e=>G(`/api/connections/search`,{method:`PUT`,body:JSON.stringify(e)}),testSearch:()=>G(`/api/connections/search/test`,{method:`POST`}),setEmail:e=>G(`/api/connections/email`,{method:`PUT`,body:JSON.stringify(e)}),disconnectEmail:()=>G(`/api/connections/email`,{method:`DELETE`}),testEmail:()=>G(`/api/connections/email/test`,{method:`POST`}),calendar:()=>G(`/api/calendar`),setCalendar:e=>G(`/api/connections/calendar`,{method:`PUT`,body:JSON.stringify(e)}),addCalendarFeed:(e,t)=>G(`/api/connections/calendar/feeds`,K({name:e,url:t})),removeCalendarFeed:e=>G(`/api/connections/calendar/feeds/${encodeURIComponent(e)}`,{method:`DELETE`}),testCalendar:()=>G(`/api/connections/calendar/test`,{method:`POST`}),googleCalendar:()=>G(`/api/connections/calendar/google`),setGoogleCalendar:e=>G(`/api/connections/calendar/google`,{method:`PUT`,body:JSON.stringify(e)}),connectGoogleCalendar:e=>G(`/api/connections/calendar/google/connect`,K({write:e})),setGoogleCalendars:e=>G(`/api/connections/calendar/google/calendars`,K(e)),disconnectGoogleCalendar:()=>G(`/api/connections/calendar/google/disconnect`,{method:`POST`}),contacts:(e=``,t=8)=>G(`/api/contacts?q=${encodeURIComponent(e)}&limit=${t}`),setContacts:e=>G(`/api/connections/contacts`,{method:`PUT`,body:JSON.stringify(e)}),addContactsSource:(e,t)=>G(`/api/connections/contacts/sources`,K({name:e,url:t})),importContacts:(e,t)=>G(`/api/connections/contacts/import?name=${encodeURIComponent(e)}`,{method:`POST`,headers:{"Content-Type":`text/vcard; charset=utf-8`},body:t}),removeContactsSource:e=>G(`/api/connections/contacts/sources/${encodeURIComponent(e)}`,{method:`DELETE`}),testContacts:()=>G(`/api/connections/contacts/test`,{method:`POST`}),skills:()=>G(`/api/skills`),skill:e=>G(`/api/skills/${encodeURIComponent(e)}`),saveSkill:(e,t)=>G(`/api/skills/${encodeURIComponent(e)}`,{method:`PUT`,body:JSON.stringify({content:t})}),deleteSkill:e=>G(`/api/skills/${encodeURIComponent(e)}`,{method:`DELETE`}),setSkillEnabled:(e,t)=>G(`/api/skills/${encodeURIComponent(e)}/enabled`,K({enabled:t})),importSkill:e=>G(`/api/skills/import`,K({url:e})),setGui:e=>G(`/api/connections/gui`,{method:`PUT`,body:JSON.stringify(e)}),testGui:()=>G(`/api/connections/gui/test`,{method:`POST`}),media:e=>G(`/api/connections/${e}`),setMedia:(e,t)=>G(`/api/connections/${e}`,{method:`PUT`,body:JSON.stringify(t)}),setBrowser:e=>G(`/api/connections/browser`,{method:`PUT`,body:JSON.stringify({enabled:e})}),addMCP:e=>G(`/api/connections/mcp`,K(e)),removeMCP:e=>G(`/api/connections/mcp/${encodeURIComponent(e)}`,{method:`DELETE`}),vaultSet:(e,t)=>G(`/api/vault/${encodeURIComponent(e)}`,{method:`PUT`,body:JSON.stringify({value:t})}),vaultDelete:e=>G(`/api/vault/${encodeURIComponent(e)}`,{method:`DELETE`}),onboarded:(e=!0)=>G(`/api/onboarded`,K({done:e})),firstrun:e=>G(`/api/firstrun?lang=${encodeURIComponent(e)}`),firstrunStart:e=>G(`/api/firstrun/start`,K({lang:e})),firstrunPick:e=>G(`/api/firstrun/pick`,K({name:e})),firstrunDismiss:()=>G(`/api/firstrun/dismiss`,K({})),browserControl:(e,t)=>G(`/api/browser/${encodeURIComponent(e)}/control`,K(t)),push:()=>G(`/api/push`),pushSubscribe:e=>G(`/api/push/subscribe`,K({subscription:e})),pushUnsubscribe:e=>G(`/api/push/unsubscribe`,K({endpoint:e})),pushTest:()=>G(`/api/push/test`,{method:`POST`})};function De(e){return e===4401?`auth`:e===4404?`gone`:`retry`}function Oe(e){let t=null,n=!1,r=0,i,a=()=>{let o=window.location.protocol===`https:`?`wss`:`ws`;t=new WebSocket(`${o}://${window.location.host}/ws`),t.onopen=()=>{let n=U();n&&t?.send(JSON.stringify({kind:`auth`,token:n})),r=0,e.onOpen?.()},t.onmessage=t=>{try{e.onMessage(JSON.parse(t.data))}catch{}},t.onclose=t=>{e.onClose?.();let o=De(t.code);if(o===`auth`){e.onAuthError?.();return}if(o===`gone`){n=!0,e.onGone?.();return}if(n)return;let s=Math.min(15e3,500*2**r++);i=window.setTimeout(a,s)},t.onerror=()=>t?.close()};return a(),{send:e=>t&&t.readyState===WebSocket.OPEN?(t.send(JSON.stringify(e)),!0):!1,close:()=>{n=!0,i&&window.clearTimeout(i),t?.close()}}}var ke=o((e=>{var t=d(),n=Symbol.for(`react.element`),r=Symbol.for(`react.fragment`),i=Object.prototype.hasOwnProperty,a=t.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.ReactCurrentOwner,o={key:!0,ref:!0,__self:!0,__source:!0};function s(e,t,r){var s,c={},l=null,u=null;for(s in r!==void 0&&(l=``+r),t.key!==void 0&&(l=``+t.key),t.ref!==void 0&&(u=t.ref),t)i.call(t,s)&&!o.hasOwnProperty(s)&&(c[s]=t[s]);if(e&&e.defaultProps)for(s in t=e.defaultProps,t)c[s]===void 0&&(c[s]=t[s]);return{$$typeof:n,type:e,key:l,ref:u,props:c,_owner:a.current}}e.Fragment=r,e.jsx=s,e.jsxs=s})),Ae=o(((e,t)=>{t.exports=ke()})),je=6e5;function Me(e,t=Date.now()){let n={};for(let r of e??[])t-r.at*1e3<6e5&&(n[r.thread]=r);return n}function Ne(){return`serviceWorker`in navigator&&`PushManager`in window&&`Notification`in window}async function Pe(){if(!(`serviceWorker`in navigator)||!window.isSecureContext)return null;try{return await navigator.serviceWorker.register(`/sw.js`)}catch{return null}}async function Fe(){if(!Ne())return`unsupported`;if(!window.isSecureContext)return`insecure`;if(Notification.permission===`denied`)return`denied`;let e=await navigator.serviceWorker.getRegistration();return e&&await e.pushManager.getSubscription()?`on`:`off`}function Ie(e){let t=`=`.repeat((4-e.length%4)%4),n=atob((e+t).replace(/-/g,`+`).replace(/_/g,`/`)),r=new Uint8Array(new ArrayBuffer(n.length));for(let e=0;e0?t.setAppBadge?.(e):t.clearAppBadge?.()}catch{}}var Be=`nanomuse_theme`,Ve={light:`#ffffff`,dark:`#181819`};function He(){try{let e=localStorage.getItem(Be);if(e===`light`||e===`dark`||e===`system`)return e}catch{}return`light`}var J=He(),Y=new Set,Ue=typeof matchMedia==`function`?matchMedia(`(prefers-color-scheme: dark)`):null;function We(){return Ue?.matches?`dark`:`light`}function Ge(){return J}function X(){return J===`system`?We():J}function Ke(e){J=e;try{localStorage.setItem(Be,e)}catch{}Z(),Y.forEach(e=>e())}function Z(){if(typeof document>`u`)return;let e=X();document.documentElement.dataset.theme=e;let t=document.querySelector(`meta[name="theme-color"]`);t&&t.setAttribute(`content`,Ve[e])}Ue?.addEventListener?.(`change`,()=>{J===`system`&&(Z(),Y.forEach(e=>e()))});function qe(e){return Y.add(e),()=>Y.delete(e)}function Je(){return(0,f.useSyncExternalStore)(qe,Ge,Ge)}function Ye(){return(0,f.useSyncExternalStore)(qe,X,X)}var Q=Ae();function Xe(){if(window.parent===window)return null;let e=window.location.ancestorOrigins;if(e&&e.length>0&&e[0]!==`null`)return e[0];if(document.referrer)try{return new URL(document.referrer).origin}catch{return null}return null}function Ze(e){let t=Xe();t&&window.parent.postMessage(e,t)}var Qe=[`chat`,`feed`,`ideas`,`goals`,`library`,`memory`,`devices`,`connections`,`channels`,`skills`,`you`,`account`,`coding`,`avatar`],$e=`nanomuse_feed_seen`,et=`nanomuse_sign_in_skipped`,tt=`nanomuse.ui.lite`;function nt(){try{let e=new URL(window.location.href);return e.searchParams.get(`ui`)===`lite`?(sessionStorage.setItem(tt,`1`),!0):e.searchParams.get(`ui`)===`full`?(sessionStorage.removeItem(tt),!1):sessionStorage.getItem(tt)===`1`}catch{return!1}}var rt={connected:!1,loaded:!1,authError:!1,gone:!1,error:null,version:``,profile:null,status:{state:`idle`,detail:``,thread:`main`},threads:[],activeThread:`main`,events:{},hasMore:{},streams:{},goals:[],settings:null,goalsVersion:0,memoryVersion:0,remindersVersion:0,calendarVersion:0,pendingApprovals:[],feedVersion:0,feedSeenAt:R($e)??``,viewer:null,draft:null,draftFiles:null,connectionsVersion:0,skillsVersion:0,onboardingDismissed:!1,signInSkipped:R(et)===`1`,tab:`chat`,toast:null,drawer:!1,finishedAt:0,mishapAt:0,hub:null,codingLive:{},lite:nt(),hands:null,holds:[],handsLive:null,studio:null,working:{},firstrun:null};function it(e,t){if(t.type!==`approval`)return e;let n=e.filter(e=>e.id!==t.id);return t.status===`pending`?[...n,t]:n}function at(e){return e.type===`approval`||e.type===`question`||e.source===`background`||e.source===`goal`}function ot(e){let t=e.ts;return typeof t==`number`?{...e,ts:new Date(t*1e3).toISOString()}:e}function st(e,t){let n=e??[],r=n.findIndex(e=>e.id===t.id);if(r>=0){let e=n.slice();return e[r]=t,e}if(t.synced&&t.ts&&n.length>0&&(n[n.length-1]?.ts??``)>t.ts){let e=n.length;for(;e>0&&(n[e-1]?.ts??``)>t.ts;)--e;return[...n.slice(0,e),t,...n.slice(e)]}return[...n,t]}function ct(e,t){let n=e.filter(e=>e.id!==t.id);return t.status===`on`?[...n,t]:n}function lt(e,t){let n=e.findIndex(e=>e.id===t.id);if(n>=0){let r=e.slice();return r[n]=t,r}return[...e,t]}function ut(e,t){switch(t.type){case`hello`:{let n=t.state;for(let e of Object.keys($))delete $[e];return{...e,loaded:!0,authError:!1,version:n.version,profile:n.profile,status:n.status,streams:{},threads:n.threads,goals:n.goals,settings:n.settings,pendingApprovals:n.pending_approvals,feedVersion:e.feedVersion+1,activeThread:n.threads.some(t=>t.id===e.activeThread)?e.activeThread:`main`,hub:n.hub??e.hub,hands:n.hands??e.hands,holds:(n.holds??[]).map(ot),working:Me(n.working),firstrun:n.firstrun??e.firstrun}}case`connection`:return{...e,connected:t.connected};case`authError`:return{...e,authError:!0,connected:!1};case`gone`:return{...e,gone:!0,connected:!1};case`error`:return{...e,error:t.error};case`events`:{let n=e.events[t.thread]??[],r=t.events.map(ot),i=t.prepend?[...r,...n.filter(e=>!r.some(t=>t.id===e.id))]:r;return{...e,events:{...e.events,[t.thread]:i},hasMore:{...e.hasMore,[t.thread]:t.hasMore}}}case`eventsFailed`:return{...e,events:{...e.events,[t.thread]:e.events[t.thread]??[]},toast:I(`Could not load the conversation. Open the chat again to retry.`)};case`activeThread`:return{...e,activeThread:t.thread,tab:`chat`};case`goals`:return{...e,goals:t.goals};case`settings`:return{...e,settings:t.settings,profile:t.settings.profile};case`tab`:return{...e,tab:t.tab};case`drawer`:return{...e,drawer:t.open};case`feedSeen`:return z($e,t.at),{...e,feedSeenAt:t.at};case`viewer`:return{...e,viewer:t.path};case`draft`:return{...e,draft:t.text};case`draftFiles`:return{...e,draftFiles:t.files};case`onboardingDismissed`:return{...e,onboardingDismissed:!0};case`signInSkipped`:return{...e,signInSkipped:!0};case`toast`:return{...e,toast:t.toast};case`ws`:return dt(e,t.msg);default:return e}}function dt(e,t){switch(t.kind){case`hello`:return ut(e,{type:`hello`,state:t.state});case`event`:case`update`:{let n=ot(t.event),r={...e.streams},i=r[n.thread];n.type===`assistant`&&i&&i.id===n.id&&(r[n.thread]=void 0);let a=e.threads.map(e=>e.id===n.thread&&t.kind===`event`?{...e,updated_at:n.ts}:e),o=e.events[n.thread]!==void 0,s=n.type===`tool`&&(n.status===`error`||n.status===`blocked`)||n.type===`notice`&&n.level===`error`,c=e.working,l=c[n.thread];return l&&n.type===`assistant`&&n.synced&&n.via_device===l.device&&(c={...c,[n.thread]:void 0}),{...e,streams:r,threads:a,working:c,events:o?{...e.events,[n.thread]:st(e.events[n.thread],n)}:e.events,holds:n.type===`hold`?ct(e.holds,n):e.holds,pendingApprovals:it(e.pendingApprovals,n),feedVersion:at(n)?e.feedVersion+1:e.feedVersion,mishapAt:s?Date.now():e.mishapAt}}case`stream_start`:return{...e,streams:{...e.streams,[t.thread]:{id:t.id,text:``,ended:!1}}};case`delta`:{let n=e.streams[t.thread],r=n&&n.id===t.id?{...n,text:n.text+t.text}:{id:t.id,text:t.text,ended:!1};return{...e,streams:{...e.streams,[t.thread]:r}}}case`stream_end`:{let n=e.streams[t.thread];return!n||n.id!==t.id?e:t.discard||!n.text.trim()?{...e,streams:{...e.streams,[t.thread]:void 0}}:{...e,streams:{...e.streams,[t.thread]:{...n,ended:!0}}}}case`status`:{let n=t.status,r={...e.streams};r[n.thread]?.ended&&n.state!==`working`&&(r[n.thread]=void 0);let i=ft(e.status,n),a=e.status.state===`working`&&i.state===`idle`;return{...e,status:i,streams:r,finishedAt:a?Date.now():e.finishedAt}}case`thread`:return{...e,threads:lt(e.threads,t.thread)};case`thread_deleted`:{let n={...e.events};return delete n[t.thread],{...e,events:n,holds:e.holds.filter(e=>e.thread!==t.thread),threads:e.threads.filter(e=>e.id!==t.thread),pendingApprovals:e.pendingApprovals.filter(e=>e.thread!==t.thread),activeThread:e.activeThread===t.thread?`main`:e.activeThread}}case`thread_cleared`:return{...e,events:{...e.events,[t.thread]:[]},holds:e.holds.filter(e=>e.thread!==t.thread),pendingApprovals:e.pendingApprovals.filter(e=>e.thread!==t.thread)};case`event_removed`:{let n=e.events[t.thread];return n?{...e,events:{...e.events,[t.thread]:n.filter(e=>e.id!==t.id)}}:e}case`firstrun`:return{...e,firstrun:t.firstrun};case`working`:{let{kind:n,working:r,...i}=t,a=e.working[i.thread];return r?{...e,working:{...e.working,[i.thread]:i}}:!a||a.device!==i.device?e:{...e,working:{...e.working,[i.thread]:void 0}}}case`goals`:return{...e,goalsVersion:e.goalsVersion+1};case`memory`:return{...e,memoryVersion:e.memoryVersion+1};case`reminders`:case`triggers`:return{...e,remindersVersion:e.remindersVersion+1};case`calendar`:return{...e,calendarVersion:e.calendarVersion+1};case`feed_posts`:return{...e,feedVersion:e.feedVersion+1};case`profile`:return{...e,profile:t.profile,settings:e.settings?{...e.settings,profile:t.profile}:e.settings};case`settings`:return{...e,settings:t.settings,profile:t.settings.profile};case`connections`:return{...e,connectionsVersion:e.connectionsVersion+1};case`hub`:return{...e,hub:t.hub};case`coding`:{let n=t.run?.id??t.event.run;if(!n)return e;let r=e.codingLive[n],i=t.run??r?.run;if(!i)return e;let a=t.event.kind===`run`?r?.events??[]:[...r?.events??[],t.event].slice(-400),o=r?.current??``;t.event.kind===`text`&&(o=t.event.partial?o+(t.event.text??``):``),(t.event.kind===`done`||t.event.kind===`error`)&&(o=``);let s={...e.codingLive,[n]:{run:{...i,device:t.device??i.device},events:a,current:o}},c=Object.keys(s);if(c.length>20)for(let e of c.sort((e,t)=>s[e].run.started_at-s[t].run.started_at).slice(0,c.length-20))delete s[e];return{...e,codingLive:s}}case`hands_state`:return{...e,hands:t.hands};case`studio`:return{...e,studio:t.current};case`hands`:{let{kind:n,...r}=t,i=r.event===`end`||r.event===`stop`;return{...e,handsLive:i?null:r}}case`skills`:return{...e,skillsVersion:e.skillsVersion+1};case`error`:return{...e,toast:I(t.error)};case`pong`:return{...e,status:t.status};default:return e}}var $={};function ft(e,t){$[t.thread]=t;let n=Object.values($).filter(e=>e.state!==`idle`);return n.length?(n.sort((e,t)=>Number(e.thread!==`main`)-Number(t.thread!==`main`)),n[0]??e):{state:`idle`,detail:``,thread:`main`}}var pt=(0,f.createContext)(null);function mt({children:e}){let[t,n]=(0,f.useReducer)(ut,rt),r=(0,f.useRef)(null);(0,f.useEffect)(()=>{U();let e=[],t=0,i=()=>{t=0;let r=e.splice(0);for(let e of r)n({type:`ws`,msg:e})},a=Oe({onMessage:n=>{e.push(n),t||=window.setTimeout(i,0)},onOpen:()=>n({type:`connection`,connected:!0}),onClose:()=>n({type:`connection`,connected:!1}),onAuthError:()=>n({type:`authError`}),onGone:()=>n({type:`gone`})});return r.current=a,q.state().then(e=>n({type:`hello`,state:e})).catch(e=>{e instanceof H?n({type:`authError`}):n({type:`error`,error:String(e.message??e)})}),()=>{t&&window.clearTimeout(t),a.close()}},[]);let i=(0,f.useRef)({}),a=(0,f.useCallback)(async(e,t)=>{let r=t?void 0:i.current[e]=(i.current[e]??0)+1;try{let a=await q.events(e,150,t);if(r!==void 0&&i.current[e]!==r)return;n({type:`events`,thread:e,events:a.events,hasMore:a.has_more,prepend:!!t})}catch(t){t instanceof H?n({type:`authError`}):n({type:`eventsFailed`,thread:e})}},[]),o=(0,f.useCallback)(async()=>{try{n({type:`ws`,msg:{kind:`hub`,hub:await q.hub()}})}catch{}},[]);(0,f.useEffect)(()=>{t.loaded&&a(t.activeThread)},[t.loaded,t.activeThread,a]);let s=(0,f.useRef)(!1);(0,f.useEffect)(()=>{t.connected&&s.current&&t.loaded&&a(t.activeThread),s.current=t.connected},[t.connected,t.loaded,t.activeThread,a]);let c=(0,f.useCallback)(async()=>{try{n({type:`goals`,goals:await q.goals()})}catch{}},[]);(0,f.useEffect)(()=>{t.loaded&&c()},[t.goalsVersion,t.loaded,c]);let l=(0,f.useCallback)(async()=>{try{n({type:`settings`,settings:await q.settings()})}catch{}},[]);(0,f.useEffect)(()=>{if(!t.toast)return;let e=window.setTimeout(()=>n({type:`toast`,toast:null}),3500);return()=>window.clearTimeout(e)},[t.toast]),(0,f.useEffect)(()=>{Pe();let e=e=>{let t=new URL(e,window.location.origin),r=t.searchParams.get(`thread`),i=t.searchParams.get(`tab`);r&&n({type:`activeThread`,thread:r}),i&&Qe.includes(i)&&!r?n({type:`tab`,tab:i}):n({type:`tab`,tab:`chat`});let a=t.searchParams.get(`draft`);a&&n({type:`draft`,text:a});let o=t.searchParams.get(`attach`);if(o)try{let e=JSON.parse(o);Array.isArray(e)&&e.length&&n({type:`draftFiles`,files:e.filter(e=>e&&typeof e.path==`string`)})}catch{}},t=new URL(window.location.href);if([`thread`,`tab`,`draft`,`attach`,`ui`].some(e=>t.searchParams.has(e))){e(t.href);for(let e of[`thread`,`tab`,`draft`,`attach`,`ui`])t.searchParams.delete(e);window.history.replaceState({},``,t.toString())}let r=t=>{t.data&&t.data.type===`open`&&e(String(t.data.url||`/`))};navigator.serviceWorker?.addEventListener(`message`,r);let i=e=>{if(window.parent===window||e.source!==window.parent)return;let t=e.data;t&&t.type===`nanomuse:draft`&&typeof t.text==`string`&&(n({type:`tab`,tab:`chat`}),n({type:`draft`,text:t.text.slice(0,4e3)}))};return window.addEventListener(`message`,i),()=>{navigator.serviceWorker?.removeEventListener(`message`,r),window.removeEventListener(`message`,i)}},[]);let u=Ye();(0,f.useEffect)(()=>{t.loaded&&Ze({type:`nanomuse:ready`,name:t.profile?.name??``,theme:u})},[t.loaded,t.profile?.name]),(0,f.useEffect)(()=>{t.loaded&&Ze({type:`nanomuse:theme`,theme:u})},[t.loaded,u]),(0,f.useEffect)(()=>{t.loaded&&ze(t.pendingApprovals.length)},[t.loaded,t.pendingApprovals.length]);let d=(0,f.useMemo)(()=>({state:t,dispatch:n,send:async(e,t,i=[])=>{if(!t.trim()&&i.length===0)return;let a=F();try{(i.length>0||!r.current?.send({kind:`send`,thread:e,text:t,language:a}))&&await q.send(e,t,i,a)}catch(e){throw e instanceof H&&n({type:`authError`}),e}},sendViaCloud:async(e,t,r=[])=>{if(t.trim()||r.length!==0)try{await q.send(e,t,r,F(),`cloud`)}catch(e){throw e instanceof H&&n({type:`authError`}),e}},decide:async(e,t,i=`once`)=>{try{r.current?.send({kind:`approval`,id:e,approved:t,scope:i})||await q.decide(e,t,i)}catch(e){throw e instanceof H&&n({type:`authError`}),e}},loadEvents:a,refreshGoals:c,refreshSettings:l,refreshHub:o,setTab:e=>n({type:`tab`,tab:e}),setDrawer:e=>n({type:`drawer`,open:e}),openThread:e=>n({type:`activeThread`,thread:e}),markFeedSeen:e=>n({type:`feedSeen`,at:e}),openFile:e=>n({type:`viewer`,path:e}),draftFiles:e=>n({type:`draftFiles`,files:e}),draft:e=>{n({type:`draft`,text:e}),e!==null&&n({type:`tab`,tab:`chat`})},dismissOnboarding:()=>n({type:`onboardingDismissed`}),skipSignIn:()=>{z(et,`1`),n({type:`signInSkipped`})},toast:e=>n({type:`toast`,toast:I(e)})}),[t,a,c,l,o]);return(0,Q.jsx)(pt.Provider,{value:d,children:e})}function ht(){let e=(0,f.useContext)(pt);if(!e)throw Error(`useStore outside provider`);return e}var gt=`dragon`,_t=new Set([`panda`,`sunny`,`moss`,`sky`,`fox`,`bolt`,`plum`]);function vt(e){return!e||e===`dragon`||_t.has(e)}function yt(e,t){return W(`avatar/${e}/${t===`working`||t===`waiting`||t===`happy`||t===`error`?t:`idle`}.webp`)}function bt(e){return`/avatars/dragon-${e===`working`||e===`waiting`||e===`happy`||e===`error`?e:`idle`}.webp`}function xt(e){return e===`working`||e===`waiting`||e===`happy`?e:`idle`}function St(e){return e===`error`?null:`/avatars/dragon-${xt(e)}.mp4`}function Ct(e,t){return t===`error`?null:W(`avatar/${e}/${xt(t)}.mp4`)}var wt=3e3,Tt=4e3;function Et(e){let{state:t}=ht(),n=Dt(e?[t.mishapAt+Tt,t.finishedAt+wt]:[]);return e?t.loaded&&!t.connected?`sleepy`:e.state===`waiting`?`waiting`:e.state===`working`?`working`:t.mishapAt&&n-t.mishapAt<4e3?`error`:t.finishedAt&&n-t.finishedAt<3e3?`happy`:`idle`:`idle`}function Dt(e){let[t,n]=(0,f.useState)(()=>Date.now()),r=e.join(`,`);(0,f.useEffect)(()=>n(Date.now()),[r]);let i=Math.min(...e.filter(e=>e>t),1/0);return(0,f.useEffect)(()=>{if(!Number.isFinite(i))return;let e=window.setTimeout(()=>n(Date.now()),Math.max(0,i-Date.now())+20);return()=>window.clearTimeout(e)},[i]),t}var Ot=44,kt=new Set,At=typeof window<`u`&&typeof window.matchMedia==`function`&&window.matchMedia(`(prefers-reduced-motion: reduce)`).matches;function jt({profile:e,status:t,size:n=40,onClick:r,still:i=!1,className:a}){let[o,s]=(0,f.useState)(!1),[,c]=(0,f.useState)(0);(0,f.useEffect)(()=>{if(!o)return;let e=window.setTimeout(()=>s(!1),900);return()=>window.clearTimeout(e)},[o]);let l=Et(t),u=t?.state??`idle`,d=e?.color??`#0064d4`,p=!e||vt(e.avatar),m=!p&&e?.avatar?e.avatar:null,h=o?`happy`:i?`idle`:l,g=i||At||n{kt.add(_),c(e=>e+1)},className:`h-full w-full object-cover`},_):p||m?(0,Q.jsx)(`img`,{src:y,alt:``,draggable:!1,className:`h-full w-full object-cover`}):(0,Q.jsx)(`span`,{className:`flex h-full w-full items-center justify-center leading-none drop-shadow-sm`,style:{fontSize:n*.5},children:e?.emoji??`✨`})}),t&&u!==`idle`&&(0,Q.jsx)(`span`,{className:B(`absolute -bottom-0.5 -right-0.5 rounded-full border-2 border-bg`,u===`working`?`bg-amber-400`:`bg-rose-500`),style:{width:Math.max(10,n*.28),height:Math.max(10,n*.28)}})]});return r?(0,Q.jsx)(`button`,{type:`button`,onClick:()=>{s(!0),r()},"aria-label":b,className:B(x,`transition active:scale-95`),style:{width:n,height:n},children:S}):(0,Q.jsx)(`span`,{role:`img`,"aria-label":b,onClick:()=>s(!0),className:x,style:{width:n,height:n},children:S})}function Mt({profile:e,status:t,name:n,statusLine:r,statusTone:i=`muted`,spinning:a=!1,badge:o,onAvatar:s,onName:c,leading:l,trailing:u,under:d,size:f=72,className:p,scrim:m=!1}){return(0,Q.jsxs)(`header`,{className:B(`safe-top relative shrink-0 pt-1.5 pb-1`,m?`header-scrim`:`bg-bg`,p),children:[(0,Q.jsxs)(`div`,{className:`flex flex-col items-center px-16`,children:[(0,Q.jsxs)(`button`,{type:`button`,onClick:s,"aria-label":n,className:`relative rounded-full`,children:[(0,Q.jsx)(jt,{profile:e,status:t,size:f}),o!==void 0&&o>0&&(0,Q.jsx)(`span`,{className:`pointer-events-none absolute -right-0.5 top-0 flex h-[18px] min-w-[18px] items-center justify-center rounded-full border-2 border-bg bg-rose-500 px-1 text-[10.5px] font-bold text-white`,children:o})]}),(0,Q.jsxs)(`div`,{className:`relative z-10 -mt-2.5 flex min-h-[44px] flex-col items-center`,children:[(0,Q.jsx)(Nt,{name:n,statusLine:r,statusTone:i,spinning:a,onClick:c??s}),d&&(0,Q.jsx)(`div`,{className:`mt-1.5 flex max-w-full items-center`,children:d})]})]}),l&&(0,Q.jsx)(`div`,{className:`absolute left-4 top-1.5 safe-top`,children:l}),u&&(0,Q.jsx)(`div`,{className:`absolute right-4 top-1.5 safe-top flex items-center gap-2`,children:u})]})}function Nt({name:e,statusLine:t,statusTone:n=`muted`,spinning:r=!1,onClick:i}){let a=(0,Q.jsxs)(Q.Fragment,{children:[(0,Q.jsx)(`span`,{className:`max-w-[240px] truncate text-[14px] leading-[18px] text-fg`,children:e}),t&&(0,Q.jsxs)(`span`,{className:B(`mt-0.5 flex max-w-[240px] items-center gap-1 text-[11.5px] leading-[14px]`,n===`accent`?`text-accent`:`text-muted`),children:[r&&(0,Q.jsx)(`span`,{className:`h-2.5 w-2.5 shrink-0 animate-spin rounded-full border-[1.5px] border-current border-t-transparent`}),(0,Q.jsx)(`span`,{className:`truncate`,children:t})]})]}),o=`flex flex-col items-center rounded-[14px] bg-surface px-3 py-1 shadow-[0_1px_4px_rgba(0,0,0,0.16)] dark:border dark:border-border dark:shadow-none`;return i?(0,Q.jsx)(`button`,{type:`button`,onClick:i,className:o,children:a}):(0,Q.jsx)(`div`,{className:o,children:a})}function Pt({onClick:e,label:t,children:n,dot:r=!1,small:i=!1,className:a,disabled:o=!1,expanded:s}){return(0,Q.jsxs)(`button`,{type:`button`,onClick:e,"aria-label":t,"aria-expanded":s,disabled:o,className:B(`relative flex items-center justify-center rounded-full bg-surface text-fg shadow-[0_1px_4px_rgba(0,0,0,0.14)] hover:bg-surface-2 disabled:opacity-50 dark:border dark:border-border dark:shadow-none`,i?`h-10 w-10`:`h-11 w-11`,a),children:[n,r&&(0,Q.jsx)(`span`,{className:`absolute right-[3px] top-[3px] h-[9px] w-[9px] rounded-full border-[1.5px] border-surface bg-accent`})]})}function Ft({children:e,className:t}){return(0,Q.jsx)(`h1`,{className:B(`px-5 pt-1.5 pb-1.5 text-[26px] font-bold leading-8 tracking-tight`,t),children:e})}export{ye as A,fe as B,Te as C,Se as D,B as E,ne as F,ue as G,oe as H,se as I,b as J,he as K,F as L,_e as M,ge as N,R as O,z as P,l as Q,L as R,W as S,we as T,I as U,pe as V,le as W,o as X,d as Y,s as Z,Le as _,gt as a,Ae as b,vt as c,mt as d,ht as f,Re as g,Je as h,jt as i,xe as j,be as k,Ct as l,Ke as m,Ft as n,St as o,Z as p,x as q,Pt as r,bt as s,Mt as t,yt as u,Fe as v,G as w,q as x,je as y,me as z}; \ No newline at end of file diff --git a/nanomuse/server/static/assets/Onboarding-B0JPnst7.js b/nanomuse/server/static/assets/Onboarding-B0JPnst7.js deleted file mode 100644 index 5121d8024..000000000 --- a/nanomuse/server/static/assets/Onboarding-B0JPnst7.js +++ /dev/null @@ -1 +0,0 @@ -import{E as e,J as t,K as n,L as r,Q as i,Y as a,a as o,b as s,f as c,i as l,q as u,x as d}from"./MuseHeader-BvAlmxiL.js";import{A as f}from"./StarNudge-Cr_QPa4y.js";import{n as p}from"./external-link-V2ISE5bW.js";import"./Form-C77NCy9F.js";import{r as m}from"./IdentityForm-IeJQ0HCo.js";import{Et as h,bt as g,t as _,vt as v}from"./index-tZx-TDX4.js";import{t as y}from"./AvatarPicker-DUnXfRVQ.js";import{CalendarCard as b,ContactsCard as x,EmailCard as S,ModelCard as C}from"./ConnectionsScreen-DIFZneZ_.js";var w=t(`lock`,[[`rect`,{width:`18`,height:`11`,x:`3`,y:`11`,rx:`2`,ry:`2`,key:`1w4ew1`}],[`path`,{d:`M7 11V7a5 5 0 0 1 10 0v4`,key:`fwvmzm`}]]),T=i(a(),1),E=s();function D(){let{state:t,setTab:i,dismissOnboarding:a,refreshSettings:s,toast:p}=c(),[w,D]=(0,T.useState)(`welcome`),[M,N]=(0,T.useState)(null),[P,F]=(0,T.useState)(!1),[I,L]=(0,T.useState)(!1),R=n(),z=async()=>{L(!0);try{await d.cloudUseAsModel(),p(R(`The Cloud model is in use.`)),await H()}catch(e){p(e.message)}finally{L(!1)}},[B,V]=(0,T.useState)(null),H=async()=>{try{V(null),N(await d.connections())}catch(e){V(R(e.message)||R(`Could not load the connections.`))}};(0,T.useEffect)(()=>{H()},[t.connectionsVersion]);let U=async()=>{try{await d.onboarded(!0),await s()}catch{}a(),i(`chat`)},W=async()=>{F(!0);try{await d.firstrunStart(r()===`zh-CN`?`zh`:`en`)}catch{await d.onboarded(!0).catch(()=>void 0)}try{await s()}catch{}F(!1),a(),i(`chat`)},G={...m(t.profile,o,y[0]),proactivity:`default`,proactive:!0,goal_interval_minutes:60,quiet_hours:``},K=M?M.llm.key_source===`vault`||M.llm.key_source===`config`||!!M.providers[j(M)]?.no_key||!!M.llm.endpoint&&M.llm.key_source===`none`:!1,q=!!M&&(M.email.configured||M.calendar.feeds.length>0||M.contacts.sources.length>0),J=[`welcome`,`list`],Y=w===`welcome`?0:1;return(0,E.jsxs)(`div`,{className:`mx-auto flex h-[100dvh] max-w-[760px] flex-col bg-bg sm:border-x sm:border-border`,children:[(0,E.jsx)(`div`,{className:`titlebar-room`}),(0,E.jsxs)(`header`,{className:`safe-top shrink-0 px-5 pt-4 pb-2 flex items-center justify-between`,children:[(0,E.jsx)(`div`,{className:`flex gap-1`,children:J.map((t,n)=>(0,E.jsx)(`span`,{className:e(`h-1.5 rounded-full transition-all`,n<=Y?`w-5 bg-accent`:`w-1.5 bg-border`)},t))}),(0,E.jsx)(`button`,{type:`button`,onClick:()=>void U(),className:`text-[13px] text-muted`,children:R(`Skip setup`)})]}),(0,E.jsxs)(`div`,{className:`flex-1 overflow-y-auto px-5 pb-6`,children:[w===`welcome`&&(0,E.jsxs)(`div`,{className:`flex h-full flex-col items-center justify-center text-center`,children:[(0,E.jsx)(l,{profile:G,size:96}),(0,E.jsx)(`h1`,{className:`mt-6 text-[28px] font-bold tracking-tight`,children:R(`Meet your nanoMuse`)}),(0,E.jsx)(`p`,{className:`mt-2 text-[15px] text-muted`,children:R(`A personal agent of your own. Three things to know:`)}),(0,E.jsxs)(`ul`,{className:`mt-6 w-full max-w-sm space-y-2.5 text-left`,children:[(0,E.jsx)(O,{n:1,title:R(`It does things for you.`),body:R(`Searches, browses, writes, books, reads mail, and hands you the result, not a list of links.`)}),(0,E.jsx)(O,{n:2,title:R(`It keeps working when you close the app.`),body:R(`Goals move forward between your visits; it reports in the Feed and notifies you when something is worth it.`)}),(0,E.jsx)(O,{n:3,title:R(`It asks you first where it matters.`),body:R(`A separate Sentinel reviews every action. Sending, paying, deleting: it stops and asks; your keys stay in a vault the model cannot read.`)})]}),(0,E.jsx)(`p`,{className:`mt-5 max-w-sm text-[13px] text-muted`,children:R(`There is no form to fill in: once it has a model, it introduces itself in the chat and asks what to call you.`)}),(0,E.jsx)(`p`,{className:`mt-2 max-w-sm text-[13px] text-muted`,children:(0,E.jsx)(`a`,{href:`https://nanomuse.cn/#open-source`,target:`_blank`,rel:`noreferrer`,className:`underline decoration-dotted underline-offset-2 hover:text-accent`,children:R(`nanoMuse is a non-profit open-source community project, free forever.`)})})]}),w===`list`&&(0,E.jsxs)(`div`,{className:`pt-6`,children:[(0,E.jsxs)(`div`,{className:`flex items-center gap-3`,children:[(0,E.jsx)(l,{profile:G,size:56}),(0,E.jsxs)(`div`,{className:`min-w-0`,children:[(0,E.jsx)(`h1`,{className:`text-[24px] font-bold tracking-tight truncate`,children:R(`Set it up`)}),(0,E.jsx)(`p`,{className:`text-[13.5px] text-muted truncate`,children:R(`A model, then the chat. A minute.`)})]})]}),(0,E.jsxs)(`ol`,{className:`mt-6 space-y-2`,children:[(0,E.jsx)(k,{done:K,title:R(`Add a model`),body:K?M?.llm.cloud?`nanoMuse Cloud · ${M.llm.model}`:`${M?.llm.model} · ${A(M?.llm.base_url??``)}`:t.hub?.account.signed_in?R(`Your account's model, or a key of your own.`):R(`Pick a provider and paste a key. Yours, stored in the vault.`),onClick:()=>D(`model`)}),(0,E.jsx)(k,{done:q,optional:!0,title:R(`Connect mail, calendar, contacts`),body:R(q?`Connected. Tap to add more.`:`Optional. It can read what came in, know your day, and who is who.`),onClick:()=>D(`connect`)}),(0,E.jsx)(k,{locked:!K,done:!1,title:R(`Start`),body:R(K?`Open the chat. It introduces itself and asks your name.`:`Needs a model first.`),onClick:()=>K&&!P&&void W()})]})]}),w===`model`&&(0,E.jsxs)(`div`,{className:`pt-6 space-y-4`,children:[(0,E.jsxs)(`div`,{children:[(0,E.jsx)(`h1`,{className:`text-[26px] font-bold tracking-tight`,children:R(`The model behind it`)}),(0,E.jsx)(`p`,{className:`mt-1 text-[14px] text-muted`,children:K?M?.llm.cloud?R(`Your account's model, with its free allowance. Keep it, or switch to a key of your own here.`):R(`A model is already set up on the server. Keep it, or switch here.`):R(`Your account brings a model with a free allowance, nothing to set up. Or paste a key of your own; it is stored encrypted in the vault on the server, never shown to the model, and nothing you say passes through the relay.`)})]}),M?(0,E.jsxs)(E.Fragment,{children:[!K&&t.hub?.account.signed_in&&(0,E.jsxs)(`button`,{type:`button`,disabled:I,onClick:()=>void z(),className:`flex w-full items-center gap-3 rounded-3xl border border-accent/30 bg-accent/5 px-4 py-3.5 text-left`,children:[(0,E.jsx)(`span`,{className:`flex h-10 w-10 shrink-0 items-center justify-center rounded-2xl bg-accent text-white`,children:I?(0,E.jsx)(u,{size:18,className:`animate-spin`}):(0,E.jsx)(v,{size:18})}),(0,E.jsxs)(`span`,{className:`min-w-0 flex-1`,children:[(0,E.jsx)(`span`,{className:`block text-[15px] font-medium`,children:R(`Use the nanoMuse Cloud model`)}),(0,E.jsx)(`span`,{className:`block text-[12.5px] text-muted`,children:R(`Signed in as {hint}. A free allowance, nothing to paste. Recommended to start.`,{hint:t.hub.account.hint})})]}),(0,E.jsx)(g,{size:16,className:`shrink-0 text-muted`})]}),!K&&!t.hub?.account.signed_in&&(0,E.jsx)(`div`,{className:`rounded-3xl border border-border/70 bg-surface p-4`,children:(0,E.jsx)(_,{onSignedIn:()=>void H(),useAsModel:!0})}),!K&&(0,E.jsxs)(`p`,{className:`px-1 text-[12.5px] text-muted`,children:[(0,E.jsx)(`span`,{className:`font-medium`,children:R(`Or bring your own key`)}),` · `,f(R,t.hub?.account)]}),(0,E.jsx)(C,{data:M,onChange:()=>void H(),compact:!0})]}):B?(0,E.jsxs)(`div`,{className:`rounded-3xl border border-border/70 bg-surface p-4 text-center`,children:[(0,E.jsx)(`p`,{className:`text-[13.5px] text-muted`,children:B}),(0,E.jsx)(`button`,{type:`button`,onClick:()=>void H(),className:`mt-3 rounded-full bg-surface-2 px-4 py-1.5 text-[13px] font-medium`,children:R(`Retry`)})]}):(0,E.jsx)(`div`,{className:`flex justify-center py-8 text-muted`,children:(0,E.jsx)(u,{className:`animate-spin`,size:20})})]}),w===`connect`&&(0,E.jsxs)(`div`,{className:`pt-6 space-y-4`,children:[(0,E.jsxs)(`div`,{children:[(0,E.jsx)(`h1`,{className:`text-[26px] font-bold tracking-tight`,children:R(`Connect your mail, calendar and contacts`)}),(0,E.jsx)(`p`,{className:`mt-1 text-[14px] text-muted`,children:R(`Optional. With a mailbox connected it can read what came in and draft replies; it will always ask before sending. With a calendar it knows your day and finds free time. With your contacts it knows who is who. The browser and MCP servers are under Connections later.`)})]}),M?(0,E.jsxs)(E.Fragment,{children:[(0,E.jsx)(S,{data:M,onChange:()=>void H(),compact:!0}),(0,E.jsx)(b,{data:M,onChange:()=>void H(),compact:!0}),(0,E.jsx)(x,{data:M,onChange:()=>void H(),compact:!0})]}):B?(0,E.jsxs)(`div`,{className:`rounded-3xl border border-border/70 bg-surface p-4 text-center`,children:[(0,E.jsx)(`p`,{className:`text-[13.5px] text-muted`,children:B}),(0,E.jsx)(`button`,{type:`button`,onClick:()=>void H(),className:`mt-3 rounded-full bg-surface-2 px-4 py-1.5 text-[13px] font-medium`,children:R(`Retry`)})]}):(0,E.jsx)(`div`,{className:`flex justify-center py-8 text-muted`,children:(0,E.jsx)(u,{className:`animate-spin`,size:20})})]})]}),(0,E.jsxs)(`footer`,{className:`safe-bottom shrink-0 px-5 pb-5 pt-2 flex gap-2`,children:[(w===`model`||w===`connect`)&&(0,E.jsx)(`button`,{type:`button`,onClick:()=>D(`list`),className:`flex items-center justify-center gap-1.5 rounded-2xl border border-border px-4 py-2.5 text-[14px] font-medium text-muted disabled:opacity-40`,children:R(`Back`)}),w===`welcome`&&(0,E.jsxs)(`button`,{type:`button`,onClick:()=>D(`list`),className:e(`flex items-center justify-center gap-1.5 rounded-2xl bg-accent text-accent-fg px-4 py-2.5 text-[14px] font-medium disabled:opacity-40`,`flex-1 py-3`),children:[R(`Get started`),` `,(0,E.jsx)(h,{size:16})]}),w===`list`&&(0,E.jsxs)(`button`,{type:`button`,disabled:!K||P,onClick:()=>void W(),className:e(`flex items-center justify-center gap-1.5 rounded-2xl bg-accent text-accent-fg px-4 py-2.5 text-[14px] font-medium disabled:opacity-40`,`flex-1 py-3`),children:[P?(0,E.jsx)(u,{size:16,className:`animate-spin`}):null,` `,R(K?`Start`:`Add a model to start`),` `,(0,E.jsx)(h,{size:16})]}),w===`model`&&(0,E.jsxs)(`button`,{type:`button`,disabled:!K,onClick:()=>D(`list`),className:e(`flex items-center justify-center gap-1.5 rounded-2xl bg-accent text-accent-fg px-4 py-2.5 text-[14px] font-medium disabled:opacity-40`,`flex-1 py-3`),children:[R(K?`Done`:`Save a model to continue`),` `,(0,E.jsx)(h,{size:16})]}),w===`connect`&&(0,E.jsxs)(`button`,{type:`button`,onClick:()=>D(`list`),className:e(`flex items-center justify-center gap-1.5 rounded-2xl bg-accent text-accent-fg px-4 py-2.5 text-[14px] font-medium disabled:opacity-40`,`flex-1 py-3`),children:[R(q?`Done`:`Skip for now`),` `,(0,E.jsx)(h,{size:16})]})]})]})}function O({n:e,title:t,body:n}){return(0,E.jsxs)(`li`,{className:`flex gap-3 rounded-3xl bg-surface border border-border/70 p-4`,children:[(0,E.jsx)(`span`,{className:`flex h-7 w-7 shrink-0 items-center justify-center rounded-full bg-accent/12 text-[13px] font-semibold text-accent`,children:e}),(0,E.jsxs)(`div`,{className:`text-[13.5px] leading-relaxed`,children:[(0,E.jsx)(`div`,{className:`font-medium text-fg`,children:t}),(0,E.jsx)(`div`,{className:`text-muted`,children:n})]})]})}function k({done:t,locked:r,optional:i,title:a,body:o,onClick:s}){let c=n();return(0,E.jsx)(`li`,{children:(0,E.jsxs)(`button`,{type:`button`,onClick:s,disabled:r,"aria-disabled":r,className:e(`w-full flex items-center gap-3 rounded-3xl border px-4 py-3.5 text-left transition-colors`,t?`border-accent/30 bg-accent/5`:`border-border/70 bg-surface`,r&&`opacity-50`),children:[(0,E.jsx)(`span`,{className:e(`flex h-7 w-7 shrink-0 items-center justify-center rounded-full`,t?`bg-accent text-white`:r?`bg-surface-2 text-muted`:`border border-border text-muted`),children:t?(0,E.jsx)(p,{size:15,strokeWidth:3}):r?(0,E.jsx)(w,{size:13}):null}),(0,E.jsxs)(`span`,{className:`min-w-0 flex-1`,children:[(0,E.jsxs)(`span`,{className:`flex items-center gap-2 text-[15px] font-medium`,children:[(0,E.jsx)(`span`,{className:`truncate`,children:a}),i&&(0,E.jsx)(`span`,{className:`rounded-full bg-surface-2 px-2 py-0.5 text-[10.5px] font-medium text-muted`,children:c(`optional`)})]}),(0,E.jsx)(`span`,{className:`block truncate text-[12.5px] text-muted`,children:o})]}),!r&&(0,E.jsx)(g,{size:16,className:`shrink-0 text-muted`})]})})}function A(e){try{return new URL(e).host}catch{return e}}function j(e){return Object.entries(e.providers).find(([t,n])=>t!==`custom`&&n.base_url&&e.llm.base_url.startsWith(n.base_url))?.[0]??`custom`}export{D as Onboarding}; \ No newline at end of file diff --git a/nanomuse/server/static/assets/Onboarding-DBBDNzyW.js b/nanomuse/server/static/assets/Onboarding-DBBDNzyW.js new file mode 100644 index 000000000..348140cf6 --- /dev/null +++ b/nanomuse/server/static/assets/Onboarding-DBBDNzyW.js @@ -0,0 +1 @@ +import{E as e,J as t,K as n,L as r,Q as i,Y as a,a as o,b as s,f as c,i as l,q as u,x as d}from"./MuseHeader-RC--uR8o.js";import{k as f}from"./StarNudge-Df6LQyo9.js";import{n as p}from"./external-link-TvxP_dKX.js";import"./Form-H3s9oTHq.js";import{r as m}from"./IdentityForm-g-zvQ2IC.js";import{Tt as h,_t as g,t as _,yt as v}from"./index-tYqPtwPX.js";import{t as y}from"./AvatarPicker-BCihUURa.js";import{CalendarCard as b,ContactsCard as x,EmailCard as S,ModelCard as C}from"./ConnectionsScreen-CuIVN07d.js";var w=t(`lock`,[[`rect`,{width:`18`,height:`11`,x:`3`,y:`11`,rx:`2`,ry:`2`,key:`1w4ew1`}],[`path`,{d:`M7 11V7a5 5 0 0 1 10 0v4`,key:`fwvmzm`}]]),T=i(a(),1),E=s();function D(){let{state:t,setTab:i,dismissOnboarding:a,refreshSettings:s,toast:p}=c(),[w,D]=(0,T.useState)(`welcome`),[M,N]=(0,T.useState)(null),[P,F]=(0,T.useState)(!1),[I,L]=(0,T.useState)(!1),R=n(),z=async()=>{L(!0);try{await d.cloudUseAsModel(),p(R(`The Cloud model is in use.`)),await H()}catch(e){p(e.message)}finally{L(!1)}},[B,V]=(0,T.useState)(null),H=async()=>{try{V(null),N(await d.connections())}catch(e){V(R(e.message)||R(`Could not load the connections.`))}};(0,T.useEffect)(()=>{H()},[t.connectionsVersion]);let U=async()=>{try{await d.onboarded(!0),await s()}catch{}a(),i(`chat`)},W=async()=>{F(!0);try{await d.firstrunStart(r()===`zh-CN`?`zh`:`en`)}catch{await d.onboarded(!0).catch(()=>void 0)}try{await s()}catch{}F(!1),a(),i(`chat`)},G={...m(t.profile,o,y[0]),proactivity:`default`,proactive:!0,goal_interval_minutes:60,quiet_hours:``},K=M?M.llm.key_source===`vault`||M.llm.key_source===`config`||!!M.providers[j(M)]?.no_key||!!M.llm.endpoint&&M.llm.key_source===`none`:!1,q=!!M&&(M.email.configured||M.calendar.feeds.length>0||M.contacts.sources.length>0),J=[`welcome`,`list`],Y=w===`welcome`?0:1;return(0,E.jsxs)(`div`,{className:`mx-auto flex h-[100dvh] max-w-[760px] flex-col bg-bg sm:border-x sm:border-border`,children:[(0,E.jsx)(`div`,{className:`titlebar-room`}),(0,E.jsxs)(`header`,{className:`safe-top shrink-0 px-5 pt-4 pb-2 flex items-center justify-between`,children:[(0,E.jsx)(`div`,{className:`flex gap-1`,children:J.map((t,n)=>(0,E.jsx)(`span`,{className:e(`h-1.5 rounded-full transition-all`,n<=Y?`w-5 bg-accent`:`w-1.5 bg-border`)},t))}),(0,E.jsx)(`button`,{type:`button`,onClick:()=>void U(),className:`text-[13px] text-muted`,children:R(`Skip setup`)})]}),(0,E.jsxs)(`div`,{className:`flex-1 overflow-y-auto px-5 pb-6`,children:[w===`welcome`&&(0,E.jsxs)(`div`,{className:`flex h-full flex-col items-center justify-center text-center`,children:[(0,E.jsx)(l,{profile:G,size:96}),(0,E.jsx)(`h1`,{className:`mt-6 text-[28px] font-bold tracking-tight`,children:R(`Meet your nanoMuse`)}),(0,E.jsx)(`p`,{className:`mt-2 text-[15px] text-muted`,children:R(`A personal agent of your own. Three things to know:`)}),(0,E.jsxs)(`ul`,{className:`mt-6 w-full max-w-sm space-y-2.5 text-left`,children:[(0,E.jsx)(O,{n:1,title:R(`It does things for you.`),body:R(`Searches, browses, writes, books, reads mail, and hands you the result, not a list of links.`)}),(0,E.jsx)(O,{n:2,title:R(`It keeps working when you close the app.`),body:R(`Goals move forward between your visits; it reports in the Feed and notifies you when something is worth it.`)}),(0,E.jsx)(O,{n:3,title:R(`It asks you first where it matters.`),body:R(`A separate Sentinel reviews every action. Sending, paying, deleting: it stops and asks; your keys stay in a vault the model cannot read.`)})]}),(0,E.jsx)(`p`,{className:`mt-5 max-w-sm text-[13px] text-muted`,children:R(`There is no form to fill in: once it has a model, it introduces itself in the chat and asks what to call you.`)}),(0,E.jsx)(`p`,{className:`mt-2 max-w-sm text-[13px] text-muted`,children:(0,E.jsx)(`a`,{href:`https://github.com/zeeshanhaque21/nanoMuse`,target:`_blank`,rel:`noreferrer`,className:`underline decoration-dotted underline-offset-2 hover:text-accent`,children:R(`nanoMuse is a non-profit open-source community project, free forever.`)})})]}),w===`list`&&(0,E.jsxs)(`div`,{className:`pt-6`,children:[(0,E.jsxs)(`div`,{className:`flex items-center gap-3`,children:[(0,E.jsx)(l,{profile:G,size:56}),(0,E.jsxs)(`div`,{className:`min-w-0`,children:[(0,E.jsx)(`h1`,{className:`text-[24px] font-bold tracking-tight truncate`,children:R(`Set it up`)}),(0,E.jsx)(`p`,{className:`text-[13.5px] text-muted truncate`,children:R(`A model, then the chat. A minute.`)})]})]}),(0,E.jsxs)(`ol`,{className:`mt-6 space-y-2`,children:[(0,E.jsx)(k,{done:K,title:R(`Add a model`),body:K?M?.llm.cloud?`nanoMuse Cloud · ${M.llm.model}`:`${M?.llm.model} · ${A(M?.llm.base_url??``)}`:t.hub?.account.signed_in?R(`Your account's model, or a key of your own.`):R(`Pick a provider and paste a key. Yours, stored in the vault.`),onClick:()=>D(`model`)}),(0,E.jsx)(k,{done:q,optional:!0,title:R(`Connect mail, calendar, contacts`),body:R(q?`Connected. Tap to add more.`:`Optional. It can read what came in, know your day, and who is who.`),onClick:()=>D(`connect`)}),(0,E.jsx)(k,{locked:!K,done:!1,title:R(`Start`),body:R(K?`Open the chat. It introduces itself and asks your name.`:`Needs a model first.`),onClick:()=>K&&!P&&void W()})]})]}),w===`model`&&(0,E.jsxs)(`div`,{className:`pt-6 space-y-4`,children:[(0,E.jsxs)(`div`,{children:[(0,E.jsx)(`h1`,{className:`text-[26px] font-bold tracking-tight`,children:R(`The model behind it`)}),(0,E.jsx)(`p`,{className:`mt-1 text-[14px] text-muted`,children:K?M?.llm.cloud?R(`Your account's model, with its free allowance. Keep it, or switch to a key of your own here.`):R(`A model is already set up on the server. Keep it, or switch here.`):R(`Your account brings a model with a free allowance, nothing to set up. Or paste a key of your own; it is stored encrypted in the vault on the server, never shown to the model, and nothing you say passes through the relay.`)})]}),M?(0,E.jsxs)(E.Fragment,{children:[!K&&t.hub?.account.signed_in&&(0,E.jsxs)(`button`,{type:`button`,disabled:I,onClick:()=>void z(),className:`flex w-full items-center gap-3 rounded-3xl border border-accent/30 bg-accent/5 px-4 py-3.5 text-left`,children:[(0,E.jsx)(`span`,{className:`flex h-10 w-10 shrink-0 items-center justify-center rounded-2xl bg-accent text-white`,children:I?(0,E.jsx)(u,{size:18,className:`animate-spin`}):(0,E.jsx)(g,{size:18})}),(0,E.jsxs)(`span`,{className:`min-w-0 flex-1`,children:[(0,E.jsx)(`span`,{className:`block text-[15px] font-medium`,children:R(`Use the nanoMuse Cloud model`)}),(0,E.jsx)(`span`,{className:`block text-[12.5px] text-muted`,children:R(`Signed in as {hint}. A free allowance, nothing to paste. Recommended to start.`,{hint:t.hub.account.hint})})]}),(0,E.jsx)(v,{size:16,className:`shrink-0 text-muted`})]}),!K&&!t.hub?.account.signed_in&&(0,E.jsx)(`div`,{className:`rounded-3xl border border-border/70 bg-surface p-4`,children:(0,E.jsx)(_,{onSignedIn:()=>void H(),useAsModel:!0})}),!K&&(0,E.jsxs)(`p`,{className:`px-1 text-[12.5px] text-muted`,children:[(0,E.jsx)(`span`,{className:`font-medium`,children:R(`Or bring your own key`)}),` · `,f(R,t.hub?.account)]}),(0,E.jsx)(C,{data:M,onChange:()=>void H(),compact:!0})]}):B?(0,E.jsxs)(`div`,{className:`rounded-3xl border border-border/70 bg-surface p-4 text-center`,children:[(0,E.jsx)(`p`,{className:`text-[13.5px] text-muted`,children:B}),(0,E.jsx)(`button`,{type:`button`,onClick:()=>void H(),className:`mt-3 rounded-full bg-surface-2 px-4 py-1.5 text-[13px] font-medium`,children:R(`Retry`)})]}):(0,E.jsx)(`div`,{className:`flex justify-center py-8 text-muted`,children:(0,E.jsx)(u,{className:`animate-spin`,size:20})})]}),w===`connect`&&(0,E.jsxs)(`div`,{className:`pt-6 space-y-4`,children:[(0,E.jsxs)(`div`,{children:[(0,E.jsx)(`h1`,{className:`text-[26px] font-bold tracking-tight`,children:R(`Connect your mail, calendar and contacts`)}),(0,E.jsx)(`p`,{className:`mt-1 text-[14px] text-muted`,children:R(`Optional. With a mailbox connected it can read what came in and draft replies; it will always ask before sending. With a calendar it knows your day and finds free time. With your contacts it knows who is who. The browser and MCP servers are under Connections later.`)})]}),M?(0,E.jsxs)(E.Fragment,{children:[(0,E.jsx)(S,{data:M,onChange:()=>void H(),compact:!0}),(0,E.jsx)(b,{data:M,onChange:()=>void H(),compact:!0}),(0,E.jsx)(x,{data:M,onChange:()=>void H(),compact:!0})]}):B?(0,E.jsxs)(`div`,{className:`rounded-3xl border border-border/70 bg-surface p-4 text-center`,children:[(0,E.jsx)(`p`,{className:`text-[13.5px] text-muted`,children:B}),(0,E.jsx)(`button`,{type:`button`,onClick:()=>void H(),className:`mt-3 rounded-full bg-surface-2 px-4 py-1.5 text-[13px] font-medium`,children:R(`Retry`)})]}):(0,E.jsx)(`div`,{className:`flex justify-center py-8 text-muted`,children:(0,E.jsx)(u,{className:`animate-spin`,size:20})})]})]}),(0,E.jsxs)(`footer`,{className:`safe-bottom shrink-0 px-5 pb-5 pt-2 flex gap-2`,children:[(w===`model`||w===`connect`)&&(0,E.jsx)(`button`,{type:`button`,onClick:()=>D(`list`),className:`flex items-center justify-center gap-1.5 rounded-2xl border border-border px-4 py-2.5 text-[14px] font-medium text-muted disabled:opacity-40`,children:R(`Back`)}),w===`welcome`&&(0,E.jsxs)(`button`,{type:`button`,onClick:()=>D(`list`),className:e(`flex items-center justify-center gap-1.5 rounded-2xl bg-accent text-accent-fg px-4 py-2.5 text-[14px] font-medium disabled:opacity-40`,`flex-1 py-3`),children:[R(`Get started`),` `,(0,E.jsx)(h,{size:16})]}),w===`list`&&(0,E.jsxs)(`button`,{type:`button`,disabled:!K||P,onClick:()=>void W(),className:e(`flex items-center justify-center gap-1.5 rounded-2xl bg-accent text-accent-fg px-4 py-2.5 text-[14px] font-medium disabled:opacity-40`,`flex-1 py-3`),children:[P?(0,E.jsx)(u,{size:16,className:`animate-spin`}):null,` `,R(K?`Start`:`Add a model to start`),` `,(0,E.jsx)(h,{size:16})]}),w===`model`&&(0,E.jsxs)(`button`,{type:`button`,disabled:!K,onClick:()=>D(`list`),className:e(`flex items-center justify-center gap-1.5 rounded-2xl bg-accent text-accent-fg px-4 py-2.5 text-[14px] font-medium disabled:opacity-40`,`flex-1 py-3`),children:[R(K?`Done`:`Save a model to continue`),` `,(0,E.jsx)(h,{size:16})]}),w===`connect`&&(0,E.jsxs)(`button`,{type:`button`,onClick:()=>D(`list`),className:e(`flex items-center justify-center gap-1.5 rounded-2xl bg-accent text-accent-fg px-4 py-2.5 text-[14px] font-medium disabled:opacity-40`,`flex-1 py-3`),children:[R(q?`Done`:`Skip for now`),` `,(0,E.jsx)(h,{size:16})]})]})]})}function O({n:e,title:t,body:n}){return(0,E.jsxs)(`li`,{className:`flex gap-3 rounded-3xl bg-surface border border-border/70 p-4`,children:[(0,E.jsx)(`span`,{className:`flex h-7 w-7 shrink-0 items-center justify-center rounded-full bg-accent/12 text-[13px] font-semibold text-accent`,children:e}),(0,E.jsxs)(`div`,{className:`text-[13.5px] leading-relaxed`,children:[(0,E.jsx)(`div`,{className:`font-medium text-fg`,children:t}),(0,E.jsx)(`div`,{className:`text-muted`,children:n})]})]})}function k({done:t,locked:r,optional:i,title:a,body:o,onClick:s}){let c=n();return(0,E.jsx)(`li`,{children:(0,E.jsxs)(`button`,{type:`button`,onClick:s,disabled:r,"aria-disabled":r,className:e(`w-full flex items-center gap-3 rounded-3xl border px-4 py-3.5 text-left transition-colors`,t?`border-accent/30 bg-accent/5`:`border-border/70 bg-surface`,r&&`opacity-50`),children:[(0,E.jsx)(`span`,{className:e(`flex h-7 w-7 shrink-0 items-center justify-center rounded-full`,t?`bg-accent text-white`:r?`bg-surface-2 text-muted`:`border border-border text-muted`),children:t?(0,E.jsx)(p,{size:15,strokeWidth:3}):r?(0,E.jsx)(w,{size:13}):null}),(0,E.jsxs)(`span`,{className:`min-w-0 flex-1`,children:[(0,E.jsxs)(`span`,{className:`flex items-center gap-2 text-[15px] font-medium`,children:[(0,E.jsx)(`span`,{className:`truncate`,children:a}),i&&(0,E.jsx)(`span`,{className:`rounded-full bg-surface-2 px-2 py-0.5 text-[10.5px] font-medium text-muted`,children:c(`optional`)})]}),(0,E.jsx)(`span`,{className:`block truncate text-[12.5px] text-muted`,children:o})]}),!r&&(0,E.jsx)(v,{size:16,className:`shrink-0 text-muted`})]})})}function A(e){try{return new URL(e).host}catch{return e}}function j(e){return Object.entries(e.providers).find(([t,n])=>t!==`custom`&&n.base_url&&e.llm.base_url.startsWith(n.base_url))?.[0]??`custom`}export{D as Onboarding}; \ No newline at end of file diff --git a/nanomuse/server/static/assets/SettingsScreen-B84xmoRg.js b/nanomuse/server/static/assets/SettingsScreen-B84xmoRg.js new file mode 100644 index 000000000..c4d68328d --- /dev/null +++ b/nanomuse/server/static/assets/SettingsScreen-B84xmoRg.js @@ -0,0 +1 @@ +import{A as e,E as t,F as n,G as r,H as i,J as a,K as o,L as s,Q as c,T as l,Y as u,_ as d,a as f,b as p,f as m,g as h,h as g,m as _,v,x as y}from"./MuseHeader-RC--uR8o.js";import{A as b,C as x,S,T as ee,g as C,u as w,w as T}from"./StarNudge-Df6LQyo9.js";import{n as te}from"./external-link-TvxP_dKX.js";import{n as E}from"./Form-H3s9oTHq.js";import{t as ne}from"./clapperboard-CuoVHGrc.js";import{t as re}from"./database-zap-Bce5E3JJ.js";import{t as D}from"./plug-DV_c5_Ny.js";import{n as ie,r as O,t as ae}from"./IdentityForm-g-zvQ2IC.js";import{Ct as k,D as oe,E as A,G as j,H as M,I as N,K as P,L as F,O as se,T as I,U as L,_t as R,a as z,et as ce,gt as B,i as V,it as le,j as ue,l as de,n as fe,nt as H,o as U,r as W,st as pe,tt as G,u as me,ut as K,xt as q,yt as J}from"./index-tYqPtwPX.js";import{t as Y}from"./BackBar-JEuC8Q_e.js";import{t as X}from"./AvatarPicker-BCihUURa.js";var he=a(`battery-full`,[[`path`,{d:`M10 10v4`,key:`1mb2ec`}],[`path`,{d:`M14 10v4`,key:`1nt88p`}],[`path`,{d:`M22 14v-4`,key:`14q9d5`}],[`path`,{d:`M6 10v4`,key:`1n77qd`}],[`rect`,{x:`2`,y:`6`,width:`16`,height:`12`,rx:`2`,key:`13zb55`}]]),ge=a(`box`,[[`path`,{d:`M21 8a2 2 0 0 0-1-1.73l-7-4a2 2 0 0 0-2 0l-7 4A2 2 0 0 0 3 8v8a2 2 0 0 0 1 1.73l7 4a2 2 0 0 0 2 0l7-4A2 2 0 0 0 21 16Z`,key:`hh9hay`}],[`path`,{d:`m3.3 7 8.7 5 8.7-5`,key:`g66t2b`}],[`path`,{d:`M12 22V12`,key:`d0xqtd`}]]),_e=a(`chart-column`,[[`path`,{d:`M3 3v16a2 2 0 0 0 2 2h16`,key:`c24i48`}],[`path`,{d:`M18 17V9`,key:`2bz60n`}],[`path`,{d:`M13 17V5`,key:`1frdt8`}],[`path`,{d:`M8 17v-3`,key:`17ska0`}]]),ve=a(`message-square-warning`,[[`path`,{d:`M22 17a2 2 0 0 1-2 2H6.828a2 2 0 0 0-1.414.586l-2.202 2.202A.71.71 0 0 1 2 21.286V5a2 2 0 0 1 2-2h16a2 2 0 0 1 2 2z`,key:`18887p`}],[`path`,{d:`M12 15h.01`,key:`q59x07`}],[`path`,{d:`M12 7v4`,key:`xawao1`}]]),ye=a(`puzzle`,[[`path`,{d:`M15.39 4.39a1 1 0 0 0 1.68-.474 2.5 2.5 0 1 1 3.014 3.015 1 1 0 0 0-.474 1.68l1.683 1.682a2.414 2.414 0 0 1 0 3.414L19.61 15.39a1 1 0 0 1-1.68-.474 2.5 2.5 0 1 0-3.014 3.015 1 1 0 0 1 .474 1.68l-1.683 1.682a2.414 2.414 0 0 1-3.414 0L8.61 19.61a1 1 0 0 0-1.68.474 2.5 2.5 0 1 1-3.014-3.015 1 1 0 0 0 .474-1.68l-1.683-1.682a2.414 2.414 0 0 1 0-3.414L4.39 8.61a1 1 0 0 1 1.68.474 2.5 2.5 0 1 0 3.014-3.015 1 1 0 0 1-.474-1.68l1.683-1.682a2.414 2.414 0 0 1 3.414 0z`,key:`w46dr5`}]]),be=a(`shield`,[[`path`,{d:`M20 13c0 5-3.5 7.5-7.66 8.95a1 1 0 0 1-.67-.01C7.5 20.5 4 18 4 13V6a1 1 0 0 1 1-1c2 0 4.5-1.2 6.24-2.72a1.17 1.17 0 0 1 1.52 0C14.51 3.81 17 5 19 5a1 1 0 0 1 1 1z`,key:`oel41y`}]]),xe=a(`smile`,[[`circle`,{cx:`12`,cy:`12`,r:`10`,key:`1mglay`}],[`path`,{d:`M8 14s1.5 2 4 2 4-2 4-2`,key:`1y1vjs`}],[`line`,{x1:`9`,x2:`9.01`,y1:`9`,y2:`9`,key:`yxxnd0`}],[`line`,{x1:`15`,x2:`15.01`,y1:`9`,y2:`9`,key:`1p4y9e`}]]),Se=a(`zap`,[[`path`,{d:`M4 14a1 1 0 0 1-.78-1.63l9.9-10.2a.5.5 0 0 1 .86.46l-1.92 6.02A1 1 0 0 0 13 10h7a1 1 0 0 1 .78 1.63l-9.9 10.2a.5.5 0 0 1-.86-.46l1.92-6.02A1 1 0 0 0 11 14z`,key:`1xq2db`}]]),Z=c(u(),1),Ce=`(min-width: 64rem)`;function we(){return typeof window>`u`?!1:document.documentElement.classList.contains(`desktop`)?!0:typeof window.matchMedia==`function`&&window.matchMedia(Ce).matches}function Te(){let[e,t]=(0,Z.useState)(we);return(0,Z.useEffect)(()=>{if(typeof window.matchMedia!=`function`)return;let e=window.matchMedia(Ce),n=()=>t(we());return e.addEventListener(`change`,n),()=>e.removeEventListener(`change`,n)},[]),e}var Q=p(),Ee=`w-full rounded-2xl bg-surface-2 px-3.5 py-2.5 outline-none focus:ring-2 focus:ring-accent/40`,De=[{id:`ask`,title:`Balanced`,text:`Browse, read and write files freely; stop for anything hard to undo: email, purchases, shell commands.`,icon:(0,Q.jsx)(j,{size:18})},{id:`strict`,title:`Cautious`,text:`Also ask before moderate actions like fetching web pages or writing files.`,icon:(0,Q.jsx)(be,{size:18})},{id:`auto`,title:`Hands-off`,text:`Approve everything automatically except explicit deny rules. For trusted, unattended runs only.`,icon:(0,Q.jsx)(P,{size:18})}];function Oe(){let{state:e,refreshSettings:a,setTab:s,toast:c}=m(),u=e.settings,[d,p]=(0,Z.useState)(()=>O(e.profile,f,X[0])),[h,v]=(0,Z.useState)(!1),x=o(),S=r(),C=g(),[T,ne]=(0,Z.useState)(null),[re,D]=(0,Z.useState)(!1),k=(0,Z.useId)(),j=`${k}-interval`,M=`${k}-theme`,N=`${k}-app-language`,P=`${k}-reply-language`;(0,Z.useEffect)(()=>{u||a()},[u,a]);let L=(0,Z.useCallback)(async(e=!1)=>{D(!0);try{ne(await y.update(e))}catch{ne(null)}finally{D(!1)}},[]);(0,Z.useEffect)(()=>{L()},[L]),(0,Z.useEffect)(()=>{e.profile&&p(O(e.profile,``,X[0]))},[e.profile]);let R=async(e,t)=>{v(!0);try{await y.updateSettings(e),await a(),t&&c(t)}catch(e){c(e.message)}finally{v(!1)}},z=O(e.profile,``,X[0]),ce=!!e.profile&&Object.keys(d).some(e=>d[e]!==z[e]),B=e.profile?.name??`nanoMuse`,V=se(),le=me(),H=Te()&&!e.lite,[U,W]=(0,Z.useState)(null),G=[{id:`who`,title:B},{id:`sentinel`,title:x(`Safety · Sentinel`)},{id:`proactivity`,title:x(`Proactivity`)},{id:`notifications`,title:x(`Notifications`)},...A()?[{id:`keep-running`,title:x(`Keep it running`)}]:[],{id:`model`,title:x(`Model`)},{id:`appearance`,title:x(`Appearance`)},...F()?[{id:`desktop`,title:x(`Desktop app`)}]:[],{id:`data`,title:x(`Data controls`)},{id:`developer`,title:x(`Developer`)},{id:`about`,title:x(`About`)}],K=e=>H||U===e,[q,he]=(0,Z.useState)(()=>{let e=window.location.hash.slice(1);return ke.includes(e)?e:null});if((0,Z.useEffect)(()=>{if(q&&u){if(he(null),history.replaceState(null,``,window.location.pathname+window.location.search),!H){W(q);return}requestAnimationFrame(()=>document.getElementById(q)?.scrollIntoView({behavior:`smooth`,block:`start`}))}},[q,u,H]),!H&&U===null)return(0,Q.jsx)(je,{release:T,onOpen:W});let _e=G.find(e=>e.id===U);return(0,Q.jsxs)(`div`,{className:`flex h-full flex-col`,children:[H?(0,Q.jsx)(Y,{title:x(`Settings`),description:x(`Its name and look, how careful it is, how often it speaks up.`)}):(0,Q.jsx)(Y,{title:_e?.title??x(`Settings`),onBack:()=>W(null),backLabel:x(`Settings`)}),(0,Q.jsxs)(`div`,{className:`flex min-h-0 flex-1`,children:[H&&(0,Q.jsx)(`nav`,{className:`flex w-[188px] shrink-0 flex-col gap-0.5 self-start pl-4 pr-2 pt-1`,"aria-label":x(`Settings`),children:G.map(e=>(0,Q.jsx)(`button`,{type:`button`,onClick:()=>document.getElementById(e.id)?.scrollIntoView({behavior:`smooth`,block:`start`}),className:`truncate rounded-xl px-3 py-1.5 text-left text-[13px] font-medium text-fg/75 hover:bg-surface-2 hover:text-fg`,children:e.title},e.id))}),(0,Q.jsxs)(`div`,{className:`flex-1 overflow-y-auto px-4 pb-8 space-y-5`,children:[K(`who`)&&(0,Q.jsxs)($,{title:B,id:`who`,plain:!H,children:[(0,Q.jsx)(ae,{value:d,onChange:p,suggestions:!1,inputCls:Ee,onStudio:()=>s(`avatar`)}),(0,Q.jsx)(`button`,{type:`button`,disabled:!ce||h,onClick:()=>void R({profile:ie(d)},x(`Saved`)),className:`w-full rounded-2xl bg-accent text-accent-fg py-2.5 font-medium disabled:opacity-40`,children:x(`Save`)})]}),K(`sentinel`)&&(0,Q.jsxs)($,{title:x(`Safety · Sentinel`),id:`sentinel`,plain:!H,children:[(0,Q.jsx)(`p`,{className:`text-[13px] text-muted -mt-1`,children:x(`A separate gatekeeper reviews every action. Pick how often it should check in with you.`)}),(0,Q.jsx)(`div`,{className:`space-y-2`,children:De.map(e=>(0,Q.jsxs)(`button`,{type:`button`,onClick:()=>void R({sentinel_mode:e.id}),"aria-pressed":u?.sentinel.mode===e.id,className:t(`w-full text-left rounded-2xl border px-3.5 py-3 flex items-start gap-3 transition`,u?.sentinel.mode===e.id?`border-accent bg-accent/8`:`border-border`),children:[(0,Q.jsx)(`div`,{className:t(`mt-0.5`,e.id===`auto`?`text-rose-500`:`text-accent`),children:e.icon}),(0,Q.jsxs)(`div`,{className:`flex-1`,children:[(0,Q.jsx)(`div`,{className:`font-medium text-[14.5px]`,children:x(e.title)}),(0,Q.jsx)(`div`,{className:`text-[12.5px] text-muted leading-snug mt-0.5`,children:x(e.text)})]}),u?.sentinel.mode===e.id&&(0,Q.jsx)(te,{size:18,className:`text-accent mt-0.5`})]},e.id))}),u&&(0,Q.jsxs)(`div`,{className:`text-[12.5px] text-muted leading-relaxed`,children:[x(`Always asks before: {tools}.`,{tools:u.sentinel.always_ask_tools.map(e=>x(e)).join(`, `)||x(`none`)}),` `,u.sentinel.taint_tracking&&x(`After reading private data, new network destinations need approval.`)]}),u?.sandbox&&(0,Q.jsxs)(`div`,{className:`flex items-start gap-2.5 rounded-2xl bg-surface-2/60 px-3.5 py-2.5 text-[12.5px] leading-snug`,children:[(0,Q.jsx)(ge,{size:15,className:t(`shrink-0 mt-[2px]`,u.sandbox.active?`text-emerald-500`:`text-muted`)}),(0,Q.jsxs)(`div`,{children:[(0,Q.jsxs)(`div`,{className:`font-medium text-fg`,children:[u.sandbox.active?x(`Commands run in a sandbox`):x(`Commands run without a sandbox`),(0,Q.jsxs)(`span`,{className:`text-muted font-normal`,children:[` · `,u.sandbox.status]})]}),(0,Q.jsx)(`div`,{className:`text-muted mt-0.5`,children:u.sandbox.active?x(`Each shell or Python call gets its own namespace: only the workspace is writable, your home directory is not there, and there is no network unless the command needs it.`):u.sandbox.status.includes(`container`)?x(`Each shell or Python call runs in the workspace with a scrubbed environment; the container is the boundary.`):x(`Each shell or Python call runs in the workspace with a scrubbed environment. On Linux, installing bubblewrap gives each one its own namespace.`)})]})]})]}),K(`proactivity`)&&(0,Q.jsxs)($,{title:x(`Proactivity`),id:`proactivity`,plain:!H,children:[(0,Q.jsx)(Le,{value:e.profile?.proactivity??`default`,onChange:e=>void R({profile:{proactivity:e}})}),(0,Q.jsxs)(`div`,{className:`flex items-center gap-3`,children:[(0,Q.jsxs)(`label`,{htmlFor:j,className:`text-[13.5px] flex-1`,children:[x(`Check-in interval`),e.profile&&e.profile.proactivity!=="default"&&e.profile.proactivity!==`off`&&(0,Q.jsx)(`span`,{className:`block text-[12px] text-muted`,children:e.profile.proactivity===`low`?x(`Doubled at this level`):x(`Halved at this level`)})]}),(0,Q.jsx)(`select`,{id:j,value:e.profile?.goal_interval_minutes??60,onChange:e=>void R({profile:{goal_interval_minutes:Number(e.target.value)}}),className:`rounded-2xl bg-surface-2 px-3 py-2 text-[13.5px] outline-none`,children:[...new Set([15,30,60,120,240,480,1440,e.profile?.goal_interval_minutes??60])].sort((e,t)=>e-t).map(e=>(0,Q.jsx)(`option`,{value:e,children:e<60?x(`{n} min`,{n:e}):e%60?`${x(`{n} h`,{n:Math.floor(e/60)})} ${x(`{n} min`,{n:e%60})}`:x(`{n} h`,{n:e/60})},e))})]}),(0,Q.jsx)(Re,{value:e.profile?.quiet_hours??``,onChange:e=>void R({profile:{quiet_hours:e}})})]}),K(`notifications`)&&(0,Q.jsx)($,{title:x(`Notifications`),id:`notifications`,plain:!H,children:I()?(0,Q.jsx)(Me,{name:e.profile?.name??`nanoMuse`}):(0,Q.jsx)(Fe,{name:e.profile?.name??`nanoMuse`})}),A()&&K(`keep-running`)&&(0,Q.jsx)($,{title:x(`Keep it running`),id:`keep-running`,plain:!H,children:(0,Q.jsx)(Ne,{name:e.profile?.name??`nanoMuse`})}),K(`model`)&&(0,Q.jsxs)($,{title:x(`Model`),id:`model`,plain:!H,children:[u&&(0,Q.jsxs)(`button`,{type:`button`,onClick:()=>s(`connections`),className:`w-full text-[13.5px] flex items-center justify-between`,children:[(0,Q.jsx)(`span`,{className:`text-muted`,children:x(`Provider / model`)}),(0,Q.jsxs)(`span`,{className:`font-mono text-[12.5px] flex items-center gap-1`,children:[u.llm.model,` `,(0,Q.jsx)(J,{size:14,className:`text-muted`})]})]}),u?.llm.cloud&&(0,Q.jsxs)(`button`,{type:`button`,onClick:()=>ue(s,b(e.hub?.account).preset),className:`w-full text-[13.5px] flex items-center justify-between`,children:[(0,Q.jsx)(`span`,{className:`text-muted`,children:x(`Use my own API key or a plan I pay for`)}),(0,Q.jsxs)(`span`,{className:`text-[12.5px] text-muted flex items-center gap-1`,children:[x(`{first} first, then {others}`,{first:b(e.hub?.account).label,others:ee(e.hub?.account)?x(`DeepSeek, Kimi, OpenAI, ChatGPT…`):x(`OpenAI, ChatGPT, Gemini, DeepSeek…`)}),` `,(0,Q.jsx)(J,{size:14})]})]}),(0,Q.jsxs)(`button`,{type:`button`,onClick:()=>s(`connections`),className:`w-full text-[13.5px] flex items-center justify-between`,children:[(0,Q.jsx)(`span`,{className:`text-muted`,children:x(`Connections`)}),(0,Q.jsxs)(`span`,{className:`text-[12.5px] text-muted flex items-center gap-1`,children:[x(`E-mail, calendar, browser, MCP servers`),` `,(0,Q.jsx)(J,{size:14})]})]})]}),K(`appearance`)&&(0,Q.jsxs)($,{title:x(`Appearance`),id:`appearance`,plain:!H,children:[(0,Q.jsx)(E,{label:x(`Show the agent's steps`),hint:x(`Every tool it uses becomes a chip in the chat. Off, the chat keeps to the conversation and the line under the name says what it is on. This device only.`),checked:le,onChange:de}),(0,Q.jsx)(E,{label:x(`Show thinking`),hint:x(`Reveal the model's reasoning under each reply when the provider exposes it.`),checked:!!u?.agent.show_thinking,onChange:e=>void R({show_thinking:e})}),(0,Q.jsxs)(`div`,{className:`flex items-center gap-3`,children:[(0,Q.jsxs)(`label`,{htmlFor:M,className:`text-[13.5px] flex-1`,children:[x(`Appearance`),(0,Q.jsx)(`span`,{className:`block text-[12px] text-muted`,children:x(`This device only`)})]}),(0,Q.jsxs)(`select`,{id:M,value:C,onChange:e=>_(e.target.value),className:`rounded-2xl bg-surface-2 px-3 py-2 text-[13.5px] outline-none`,children:[(0,Q.jsx)(`option`,{value:`light`,children:x(`Light`)}),(0,Q.jsx)(`option`,{value:`dark`,children:x(`Dark`)}),(0,Q.jsx)(`option`,{value:`system`,children:x(`Follow the system`)})]})]}),(0,Q.jsxs)(`div`,{className:`flex items-center gap-3`,children:[(0,Q.jsxs)(`label`,{htmlFor:N,className:`text-[13.5px] flex-1`,children:[x(`App language`),(0,Q.jsx)(`span`,{className:`block text-[12px] text-muted`,children:x(`This device only`)})]}),(0,Q.jsx)(`select`,{id:N,value:S,onChange:e=>i(e.target.value),className:`rounded-2xl bg-surface-2 px-3 py-2 text-[13.5px] outline-none`,children:n.map(e=>(0,Q.jsx)(`option`,{value:e.value,children:e.value===`auto`?x(`Auto`):e.label},e.value))})]}),(0,Q.jsxs)(`div`,{className:`flex items-center gap-3`,children:[(0,Q.jsxs)(`label`,{htmlFor:P,className:`text-[13.5px] flex-1`,children:[x(`Reply language`),(0,Q.jsx)(`span`,{className:`block text-[12px] text-muted`,children:x(`What {name} writes in`,{name:e.profile?.name??`nanoMuse`})})]}),(0,Q.jsxs)(`select`,{id:P,value:u?.agent.language??`auto`,onChange:e=>void R({language:e.target.value}),className:`rounded-2xl bg-surface-2 px-3 py-2 text-[13.5px] outline-none`,children:[(0,Q.jsx)(`option`,{value:`auto`,children:x(`Match mine`)}),(0,Q.jsx)(`option`,{value:`English`,children:`English`}),(0,Q.jsx)(`option`,{value:`中文`,children:`中文`}),(0,Q.jsx)(`option`,{value:`日本語`,children:`日本語`}),(0,Q.jsx)(`option`,{value:`Español`,children:`Español`}),(0,Q.jsx)(`option`,{value:`Deutsch`,children:`Deutsch`}),(0,Q.jsx)(`option`,{value:`Français`,children:`Français`})]})]})]}),F()&&K(`desktop`)&&(0,Q.jsx)($,{title:x(`Desktop app`),id:`desktop`,plain:!H,children:(0,Q.jsx)(ze,{})}),K(`data`)&&(0,Q.jsx)($,{title:x(`Data controls`),id:`data`,plain:!H,children:(0,Q.jsx)(fe,{flush:!0})}),K(`developer`)&&(0,Q.jsxs)($,{title:x(`Developer`),id:`developer`,plain:!H,children:[(0,Q.jsx)(E,{label:x(`Developer tools`),hint:x(`The Coding screen (Cursor, Codex and the other coding agents on this computer) in the sidebar, and the runtime's address below. This device only.`),checked:V,onChange:oe}),V&&(0,Q.jsxs)(`div`,{className:`text-[13px] text-muted space-y-1`,children:[(0,Q.jsxs)(`div`,{className:`break-all`,children:[x(`Runtime:`),` `,window.location.origin,` · `,(0,Q.jsx)(`span`,{className:`text-fg/70`,children:x(`the token is in the server_token file in the data folder`)})]}),(0,Q.jsxs)(`div`,{children:[(0,Q.jsx)(`a`,{href:`https://github.com/zeeshanhaque21/nanoMuse/blob/main/docs/cli.md`,target:`_blank`,rel:`noreferrer`,className:`text-accent underline-offset-2 hover:underline`,children:x(`The command line and the API`)}),` · `,(0,Q.jsx)(`a`,{href:`https://github.com/zeeshanhaque21/nanoMuse/blob/main/docs/harness.md`,target:`_blank`,rel:`noreferrer`,className:`text-accent underline-offset-2 hover:underline`,children:x(`nanoMuse on DeepSeek Harness`)})]})]})]}),K(`about`)&&(0,Q.jsxs)($,{title:x(`About`),id:`about`,plain:!H,children:[(0,Q.jsx)(w,{}),(0,Q.jsx)(Ae,{installed:e.version,release:T,checking:re,onCheck:()=>void L(!0)}),(0,Q.jsxs)(`div`,{className:`text-[13px] text-muted space-y-1`,children:[u&&(0,Q.jsxs)(`div`,{className:`break-all`,children:[x(`Data:`),` `,u.data_dir]}),u&&(0,Q.jsxs)(`div`,{className:`break-all`,children:[x(`Workspace:`),` `,u.agent.workspace]}),(0,Q.jsx)(`div`,{children:e.connected?x(`Connected`):x(`Reconnecting…`)})]}),(0,Q.jsxs)(`button`,{type:`button`,onClick:()=>{let e=I();if(e){e.disconnect();return}l(``),window.location.reload()},className:`w-full rounded-2xl border border-border py-2.5 text-[14px] font-medium flex items-center justify-center gap-2 text-muted`,children:[(0,Q.jsx)(pe,{size:16}),` `,I()?x(`Disconnect from this server`):x(`Forget this device's access token`)]})]})]})]})]})}var ke=[`who`,`sentinel`,`proactivity`,`notifications`,`keep-running`,`model`,`appearance`,`desktop`,`data`,`developer`,`about`];function Ae({installed:t,release:n,checking:r,onCheck:i}){let a=o(),s=!!I(),c=(0,Q.jsx)(`button`,{type:`button`,onClick:i,disabled:r,className:`text-accent underline-offset-2 hover:underline disabled:opacity-60`,children:a(r?`Checking…`:`Check now`)}),l;return l=s?a(`The phone app checks for updates on its own.`):n&&!n.enabled?a(`Update checks are off here.`):r&&!n?a(`Checking…`):n?.latest&&n.newer?(0,Q.jsxs)(Q.Fragment,{children:[a(`{version} is out`,{version:n.latest}),` · `,(0,Q.jsx)(`a`,{href:n.download_url||n.url,target:`_blank`,rel:`noreferrer`,className:`font-medium text-accent underline-offset-2 hover:underline`,children:a(`Update`)})]}):n?.latest?(0,Q.jsxs)(Q.Fragment,{children:[a(`Latest {version}; you have it`,{version:n.latest}),` · `,c]}):(0,Q.jsxs)(Q.Fragment,{children:[a(`Could not check`),` · `,c]}),(0,Q.jsxs)(`div`,{className:`rounded-2xl bg-surface-2/60 px-3.5 py-2.5 text-[13px]`,children:[(0,Q.jsx)(`div`,{className:`font-medium`,children:a(`nanoMuse {version}`,{version:t})}),(0,Q.jsx)(`div`,{className:`mt-0.5 text-muted`,children:l}),!s&&n?.latest&&n.newer&&(0,Q.jsx)(`div`,{className:`mt-1 text-[12px] text-muted`,children:a(`To update: pip install -U nanomuse, pull the new image, or use the desktop app's Update.`)}),!s&&n?.checked_at&&(0,Q.jsx)(`div`,{className:`mt-1 text-[12px] text-muted`,children:a(`Checked {when}`,{when:e(n.checked_at)})})]})}function je({release:e,onOpen:t}){let{state:n,setTab:r}=m(),i=o(),a=n.settings,c=n.hub,l=T(),u=n.profile?.name??`nanoMuse`,d=g(),f=c?.devices.filter(e=>!e.this&&e.kind!==`web`)??[],p=f.filter(e=>e.kind===`computer`),h=f.filter(e=>e.online&&e.actions?.includes(`coding.sessions`)),_=a?.sentinel.mode,v=_===`ask`?i(`Balanced`):_===`strict`?i(`Cautious`):_===`auto`?i(`Hands-off`):``,y=n.profile?.proactivity??`default`,b=i(y===`off`?`Off`:y===`low`?`Low`:y===`high`?`High`:`Default`),ee=i(d===`dark`?`Dark`:d===`light`?`Light`:`Follow the system`),w=i(`none`);return(0,Q.jsxs)(`div`,{className:`flex h-full flex-col`,children:[(0,Q.jsx)(Y,{title:i(`Settings`)}),(0,Q.jsxs)(`div`,{className:`flex-1 overflow-y-auto pb-8 pt-2`,children:[(0,Q.jsxs)(V,{className:`mb-3`,children:[(0,Q.jsxs)(`button`,{type:`button`,onClick:()=>r(`connections`),className:`flex w-full items-center gap-3 px-4 py-3.5 text-left hover:bg-surface-2/60`,children:[(0,Q.jsxs)(`span`,{className:`min-w-0 flex-1`,children:[(0,Q.jsx)(`span`,{className:`block truncate text-[16px] font-medium leading-[21px]`,children:a?.llm.model||i(`No model yet`)}),(0,Q.jsx)(`span`,{className:`mt-0.5 block truncate text-[12.5px] leading-4 text-muted`,children:a?a.llm.cloud?`nanoMuse Cloud`:a.llm.provider:i(`Add a provider and pick its models`)})]}),(0,Q.jsx)(`span`,{className:`text-[14px] font-medium text-accent`,children:i(`Change`)})]}),(0,Q.jsx)(z,{}),(0,Q.jsx)(U,{icon:(0,Q.jsx)(R,{size:22}),label:`nanoMuse Cloud`,value:c?.account.signed_in?c.account.hint:i(`Sign in`),onClick:()=>r(`account`)}),(0,Q.jsx)(z,{}),(0,Q.jsx)(U,{icon:(0,Q.jsx)(ne,{size:22}),label:i(`Image & video models`),value:C(l,`image`)===!1?x(i,`image`,S(c?.account),s()):C(l,`video`)===!1?x(i,`video`,S(c?.account),s()):void 0,onClick:()=>r(`connections`)}),(0,Q.jsx)(z,{}),(0,Q.jsx)(U,{icon:(0,Q.jsx)(_e,{size:22}),label:i(`Usage`),onClick:()=>r(`account`)})]}),(0,Q.jsxs)(V,{className:`mb-3`,children:[(0,Q.jsx)(U,{icon:(0,Q.jsx)(L,{size:22}),label:i(`Name & personality`),value:u,onClick:()=>t(`who`)}),(0,Q.jsx)(z,{}),(0,Q.jsx)(U,{icon:(0,Q.jsx)(xe,{size:22}),label:i(`Avatar`),onClick:()=>r(`avatar`)}),(0,Q.jsx)(z,{}),(0,Q.jsx)(U,{icon:(0,Q.jsx)(q,{size:22}),label:i(`Memory`),onClick:()=>r(`memory`)}),a?.skills?.enabled!==!1&&(0,Q.jsxs)(Q.Fragment,{children:[(0,Q.jsx)(z,{}),(0,Q.jsx)(U,{icon:(0,Q.jsx)(ye,{size:22}),label:i(`Skills`),value:a?String(a.skills.count):void 0,onClick:()=>r(`skills`)})]}),(0,Q.jsx)(z,{}),(0,Q.jsx)(U,{icon:(0,Q.jsx)(D,{size:22}),label:i(`Connections`),value:a?.connectors.mcp.length?`${a.connectors.mcp.length} MCP`:void 0,onClick:()=>r(`connections`)}),(0,Q.jsx)(z,{}),(0,Q.jsx)(U,{icon:(0,Q.jsx)(le,{size:22}),label:i(`Chat apps`),onClick:()=>r(`channels`)}),(0,Q.jsx)(z,{}),(0,Q.jsx)(U,{icon:(0,Q.jsx)(H,{size:22}),label:i(`Devices`),value:p.length?String(p.length):w,onClick:()=>r(`devices`)}),(0,Q.jsx)(z,{}),(0,Q.jsx)(U,{icon:(0,Q.jsx)(M,{size:22}),label:i(`Coding agents`),value:h.length?String(h.length):w,onClick:()=>r(`coding`)})]}),(0,Q.jsxs)(V,{className:`mb-3`,children:[(0,Q.jsx)(U,{icon:(0,Q.jsx)(j,{size:22}),label:i(`Safety · Sentinel`),value:v,onClick:()=>t(`sentinel`)}),(0,Q.jsx)(z,{}),(0,Q.jsx)(U,{icon:(0,Q.jsx)(Se,{size:22}),label:i(`Proactivity`),value:b,onClick:()=>t(`proactivity`)}),(0,Q.jsx)(z,{}),(0,Q.jsx)(U,{icon:(0,Q.jsx)(k,{size:22}),label:i(`Notifications`),onClick:()=>t(`notifications`)}),A()&&(0,Q.jsxs)(Q.Fragment,{children:[(0,Q.jsx)(z,{}),(0,Q.jsx)(U,{icon:(0,Q.jsx)(he,{size:22}),label:i(`Keep it running`),onClick:()=>t(`keep-running`)})]})]}),(0,Q.jsxs)(V,{className:`mb-3`,children:[(0,Q.jsx)(U,{icon:(0,Q.jsx)(ce,{size:22}),label:i(`Appearance`),value:ee,onClick:()=>t(`appearance`)}),F()&&(0,Q.jsxs)(Q.Fragment,{children:[(0,Q.jsx)(z,{}),(0,Q.jsx)(U,{icon:(0,Q.jsx)(H,{size:22}),label:i(`Desktop app`),onClick:()=>t(`desktop`)})]}),(0,Q.jsx)(z,{}),(0,Q.jsx)(U,{icon:(0,Q.jsx)(re,{size:22}),label:i(`Data controls`),onClick:()=>t(`data`)}),(0,Q.jsx)(z,{}),(0,Q.jsx)(U,{icon:(0,Q.jsx)(B,{size:22}),label:i(`Developer`),onClick:()=>t(`developer`)})]}),(0,Q.jsxs)(V,{className:`mb-3`,children:[(0,Q.jsx)(U,{icon:(0,Q.jsx)(K,{size:22}),label:i(`About nanoMuse`),value:e?.newer&&e.latest?i(`{version} is out`,{version:e.latest}):void 0,onClick:()=>t(`about`)}),null,(0,Q.jsx)(z,{}),(0,Q.jsx)(U,{icon:(0,Q.jsx)(ve,{size:22}),label:i(`Feedback`),onClick:()=>window.open(`https://github.com/zeeshanhaque21/nanoMuse/issues`,`_blank`,`noopener`),external:!0})]}),(0,Q.jsxs)(W,{children:[`nanoMuse `,n.version]})]})]})}function Me({name:e}){let t=o(),n=I(),[r,i]=(0,Z.useState)(()=>n?.notificationsEnabled()??!1);return n?(0,Q.jsxs)(Q.Fragment,{children:[(0,Q.jsx)(E,{label:t(`Let {name} notify this phone`,{name:e}),hint:t(`The app stays connected to your server in the background. Approvals, questions and finished background work arrive as notifications and open the right chat.`),checked:r,onChange:e=>{n.setNotificationsEnabled(e),i(e)}}),(0,Q.jsx)(`div`,{className:`text-[12.5px] text-muted`,children:t(`nanoMuse for Android {version}`,{version:n.version()})})]}):null}function Ne({name:e}){let t=o(),n=I(),[r,i]=(0,Z.useState)(A);if((0,Z.useEffect)(()=>{let e=()=>i(A());return document.addEventListener(`visibilitychange`,e),window.addEventListener(`focus`,e),()=>{document.removeEventListener(`visibilitychange`,e),window.removeEventListener(`focus`,e)}},[]),!n||!r)return null;let a=e=>n.openKeepRunning?.(e),s={xiaomi:t(`Xiaomi / Redmi / POCO: Settings → Apps → Manage apps → {name} → Autostart on; Battery saver → No restrictions; Other permissions → Display pop-up windows while running in the background on.`),huawei:t(`Huawei: Settings → Battery → App launch → {name} → Manage manually, all three on (auto-launch, secondary launch, run in background); Settings → Apps → {name} → Battery → Launch: manage manually.`),honor:t(`Honor: Settings → Battery → App launch → {name} → Manage manually, all three on; Battery → More battery settings → Stay connected while asleep on.`),oppo:t(`OPPO / realme / OnePlus: Settings → Battery → More settings → Optimise battery use → {name} → Don't optimise; Settings → Apps → {name} → Battery usage → Allow background activity, Allow auto launch.`),vivo:t(`vivo / iQOO: i Manager → App manager → Autostart → {name} on; Settings → Battery → Background power consumption management → {name} → Allow high background power consumption.`),samsung:t(`Samsung: Settings → Battery → Background usage limits → {name} not in Sleeping or Deep sleeping apps (add it to Never sleeping apps); turn off Adaptive battery if it keeps stopping.`),meizu:t(`Meizu: Settings → Apps → {name} → Background management → Keep running in the background; Battery → App power management → Allow.`)}[r.vendor];return(0,Q.jsxs)(Q.Fragment,{children:[(0,Q.jsx)(`p`,{className:`text-[12.5px] text-muted leading-snug`,children:t(`Android stops apps that seem idle. {name} runs as a foreground service and holds the phone awake only while a task runs; these switches let it keep that promise on this phone.`,{name:e})}),(0,Q.jsx)(Pe,{label:t(`Battery`),value:r.battery_unrestricted?t(`Unrestricted`):t(`Optimised`),ok:r.battery_unrestricted,hint:t(`Optimised means Android may freeze the agent after a while with the screen off; routines and check-ins then wait until the phone wakes.`),action:r.battery_unrestricted?void 0:{label:t(`Allow`),onClick:()=>a(`battery`)}}),(0,Q.jsx)(Pe,{label:t(`Display over other apps`),value:r.overlay?t(`Allowed`):t(`Not allowed`),ok:r.overlay,hint:t(`Lets the agent bring an app to the front from the background and show its status capsule while it works in other apps.`),action:r.overlay?void 0:{label:t(`Allow`),onClick:()=>a(`overlay`)}}),r.exact_alarms!==`n/a`&&r.local&&(0,Q.jsx)(Pe,{label:t(`Alarms & reminders`),value:r.exact_alarms===`granted`?t(`Exact`):t(`Approximate`),ok:r.exact_alarms===`granted`,hint:t(`With exact alarms a reminder fires at the minute you named even when the phone is asleep; without them Android may deliver it up to a quarter of an hour late.`),action:r.exact_alarms===`granted`?void 0:{label:t(`Allow`),onClick:()=>a(`alarms`)}}),(0,Q.jsx)(E,{label:t(`Start after a reboot`),hint:r.local?t(`Bring the runtime back when the phone restarts, so routines and check-ins do not stop.`):t(`Reconnect to your computer when the phone restarts, so approvals keep arriving.`),checked:r.boot_start,onChange:e=>{n.setStartOnBoot?.(e),i({...r,boot_start:e})}}),s&&(0,Q.jsxs)(`div`,{className:`rounded-2xl bg-surface-2 px-3 py-2.5 text-[12.5px] leading-snug space-y-2`,children:[(0,Q.jsx)(`div`,{className:`font-medium`,children:t(`On this phone's Android`)}),(0,Q.jsx)(`div`,{className:`text-muted`,children:s}),r.autostart_settings&&(0,Q.jsx)(`button`,{type:`button`,onClick:()=>a(`autostart`),className:`rounded-full border border-border px-3 py-1.5 text-[12.5px]`,children:t(`Open the auto-start settings`)})]}),(0,Q.jsxs)(`div`,{className:`flex items-center justify-between gap-3 pt-1`,children:[(0,Q.jsx)(`div`,{className:`text-[12.5px] text-muted leading-snug`,children:t(`Crashes are written to a file on this phone and nowhere else. Export bundles them with the runtime's log for someone you choose.`)}),(0,Q.jsx)(`button`,{type:`button`,onClick:()=>n.exportLogs?.(),className:`shrink-0 rounded-full border border-border px-3 py-1.5 text-[12.5px]`,children:t(`Export logs`)})]})]})}function Pe({label:e,value:n,ok:r,hint:i,action:a}){return(0,Q.jsxs)(`div`,{className:`flex items-start gap-3`,children:[(0,Q.jsxs)(`div`,{className:`flex-1`,children:[(0,Q.jsxs)(`div`,{className:`flex items-center gap-2 text-[14px]`,children:[(0,Q.jsx)(`span`,{children:e}),(0,Q.jsx)(`span`,{className:t(`rounded-full px-2 py-0.5 text-[11px] font-medium`,r?`bg-emerald-500/12 text-emerald-700 dark:text-emerald-300`:`bg-amber-500/15 text-amber-700 dark:text-amber-300`),children:n})]}),i&&(0,Q.jsx)(`div`,{className:`text-[12.5px] text-muted leading-snug`,children:i})]}),a&&(0,Q.jsx)(`button`,{type:`button`,onClick:a.onClick,className:`shrink-0 rounded-full bg-accent px-3 py-1.5 text-[12.5px] font-medium text-white`,children:a.label})]})}function Fe({name:e}){let{toast:t}=m(),[n,r]=(0,Z.useState)(null),[i,a]=(0,Z.useState)(`off`),[s,c]=(0,Z.useState)(!1),l=o(),u=async()=>{a(await v());try{r(await y.push())}catch{}};(0,Z.useEffect)(()=>{u()},[]);let f=async()=>{if(n){c(!0);try{let e=i===`on`?await h():await d(n.public_key);a(e),e===`denied`&&t(l(`Notifications are blocked for this site in the browser settings`)),await u()}catch(e){let n=e;t(n.name===`AbortError`?l(`This browser has no push service (embedded browsers often don't). Use Chrome, Edge, Firefox or Safari 16.4+ on the phone.`):n.message)}finally{c(!1)}}},p=async()=>{try{let e=await y.pushTest();t(e.ok?l(`Sent. It should arrive in a moment`):e.error??l(`Could not send`))}catch(e){t(e.message)}},g=i===`unsupported`?l(`This browser cannot receive push notifications.`):i===`insecure`?l(`Notifications need https:// (or localhost). Over plain http on your LAN the app works, this part stays off; see docs/deployment.md.`):i===`denied`?l(`Blocked for this site. Allow notifications in the browser's site settings, then try again.`):n&&!n.available?l(`The server was installed without pywebpush.`):``;return(0,Q.jsxs)(Q.Fragment,{children:[(0,Q.jsx)(E,{label:l(`Let {name} notify this device`,{name:e}),hint:l(`Approvals, questions, finished background work and check-ins; nothing while the app is on screen.`),checked:i===`on`,onChange:()=>void f(),disabled:s||!!g}),g&&(0,Q.jsx)(`div`,{className:`text-[12.5px] text-muted`,children:g}),n&&n.subscriptions>0&&(0,Q.jsxs)(`div`,{className:`flex items-center justify-between text-[12.5px] text-muted`,children:[(0,Q.jsx)(`span`,{children:n.subscriptions===1?l(`1 device subscribed`):l(`{n} devices subscribed`,{n:n.subscriptions})}),(0,Q.jsx)(`button`,{type:`button`,onClick:()=>void p(),className:`text-accent font-medium`,children:l(`Send a test`)})]}),!F()&&(0,Q.jsx)(`div`,{className:`text-[12.5px] text-muted`,children:l(`On a phone, add the app to the home screen first; the icon then shows a badge and notifications open the right chat.`)})]})}var Ie=[{id:`off`,title:`Off`,text:`Only works when you ask.`},{id:`low`,title:`Low`,text:`Checks in half as often; speaks up only when a step is done or it needs you.`},{id:`default`,title:`Default`,text:`Works on goals on schedule; reports real progress, stays quiet otherwise.`},{id:`high`,title:`High`,text:`Checks in twice as often and always reports, even 'still on track'.`}];function Le({value:e,onChange:n}){let r=o(),i=Ie.find(t=>t.id===e)??Ie[2];return(0,Q.jsxs)(`div`,{children:[(0,Q.jsx)(`div`,{className:`flex items-center gap-3`,children:(0,Q.jsx)(`div`,{className:`flex-1 text-[13px] text-muted leading-snug`,children:r(i.text)})}),(0,Q.jsx)(`div`,{className:`mt-2 grid grid-cols-4 gap-1 rounded-2xl bg-surface-2 p-1`,children:Ie.map(i=>(0,Q.jsx)(`button`,{type:`button`,onClick:()=>n(i.id),"aria-pressed":e===i.id,className:t(`rounded-xl py-1.5 text-[13px] font-medium transition`,e===i.id?`bg-surface shadow-sm text-accent`:`text-muted`),children:r(i.title)},i.id))})]})}function Re({value:e,onChange:n}){let[r,i]=e?e.split(`-`):[``,``],a=!!e,s=o(),c=(e,t)=>n(e&&t?`${e}-${t}`:``);return(0,Q.jsxs)(`div`,{children:[(0,Q.jsxs)(`label`,{className:`flex items-start gap-3 cursor-pointer`,children:[(0,Q.jsxs)(`div`,{className:`flex-1`,children:[(0,Q.jsxs)(`div`,{className:`text-[14px] flex items-center gap-1.5`,children:[(0,Q.jsx)(G,{size:15,className:`text-muted`}),` `,s(`Quiet hours`)]}),(0,Q.jsx)(`div`,{className:`text-[12.5px] text-muted leading-snug`,children:s(`No background work in this window; anything due waits until it ends.`)})]}),(0,Q.jsx)(`button`,{type:`button`,role:`switch`,"aria-checked":a,onClick:()=>c(a?``:`22:00`,a?``:`08:00`),className:t(`relative mt-0.5 h-7 w-12 shrink-0 rounded-full transition`,a?`bg-accent`:`bg-surface-2 border border-border`),children:(0,Q.jsx)(`span`,{className:t(`absolute top-0.5 h-6 w-6 rounded-full bg-white shadow transition`,a?`left-[22px]`:`left-0.5`)})})]}),a&&(0,Q.jsxs)(`div`,{className:`mt-2 flex items-center gap-2 text-[13.5px]`,children:[(0,Q.jsx)(`span`,{className:`text-muted`,children:s(`From`)}),(0,Q.jsx)(`input`,{type:`time`,value:r,onChange:e=>c(e.target.value,i),"aria-label":s(`Quiet hours start`),className:`rounded-xl bg-surface-2 px-2.5 py-1.5 outline-none`}),(0,Q.jsx)(`span`,{className:`text-muted`,children:s(`to`)}),(0,Q.jsx)(`input`,{type:`time`,value:i,onChange:e=>c(r,e.target.value),"aria-label":s(`Quiet hours end`),className:`rounded-xl bg-surface-2 px-2.5 py-1.5 outline-none`})]})]})}function ze(){let e=o(),t=N(),[n,r]=(0,Z.useState)(null);(0,Z.useEffect)(()=>{let e=!0;return t?.loginItem?.().then(t=>{e&&r(t)}),()=>{e=!1}},[t]);let i=t?.platform===`darwin`,a=[[e(`Quick chat`),i?`⌥ Space`:`Ctrl+Shift+Space`],[e(`Show the window`),i?`⌘⇧M`:`Ctrl+Shift+M`],[e(`Stop the hands`),i?`⌘⇧Esc`:`Ctrl+Shift+Esc`]];return(0,Q.jsxs)(Q.Fragment,{children:[t?.setLoginItem&&n!==null&&t.platform!==`linux`&&(0,Q.jsx)(E,{label:e(`Start with the computer`),hint:e(`Opens in the tray at sign-in; the agent's goals and check-ins run from then on.`),checked:n,onChange:e=>{r(e),t.setLoginItem?.(e)}}),(0,Q.jsxs)(`div`,{className:`text-[13.5px]`,children:[e(`In the tray`),(0,Q.jsx)(`span`,{className:`block text-[12px] text-muted`,children:e(`The icon by the clock shows what the hands are doing and has Stop; closing the window keeps the agent running.`)})]}),(0,Q.jsxs)(`div`,{className:`space-y-1`,children:[(0,Q.jsx)(`div`,{className:`text-[13.5px]`,children:e(`Shortcuts`)}),a.map(([e,t])=>(0,Q.jsxs)(`div`,{className:`flex items-center justify-between text-[13px]`,children:[(0,Q.jsx)(`span`,{className:`text-muted`,children:e}),(0,Q.jsx)(`kbd`,{className:`rounded-md border border-border bg-surface-2 px-1.5 py-0.5 font-sans text-[12px] text-fg/80`,children:t})]},e))]})]})}function $({title:e,children:n,id:r,plain:i=!1}){return(0,Q.jsxs)(`section`,{id:r,className:t(`space-y-3 scroll-mt-4`,i?`pt-1`:`rounded-3xl bg-surface border border-border/70 shadow-sm p-4`),children:[!i&&(0,Q.jsx)(`h2`,{className:`text-[12px] font-semibold uppercase tracking-wide text-muted`,children:e}),n]})}export{Oe as SettingsScreen}; \ No newline at end of file diff --git a/nanomuse/server/static/assets/SettingsScreen-CJQ-5PSy.js b/nanomuse/server/static/assets/SettingsScreen-CJQ-5PSy.js deleted file mode 100644 index f01a1d2d7..000000000 --- a/nanomuse/server/static/assets/SettingsScreen-CJQ-5PSy.js +++ /dev/null @@ -1 +0,0 @@ -import{A as e,E as t,F as n,G as r,H as i,J as a,K as o,L as s,Q as c,T as l,Y as u,_ as d,a as f,b as p,f as m,g as h,h as g,m as _,v,x as y}from"./MuseHeader-BvAlmxiL.js";import{C as b,E as ee,T as te,_ as x,j as S,u as C,w}from"./StarNudge-Cr_QPa4y.js";import{n as ne}from"./external-link-V2ISE5bW.js";import{n as T}from"./Form-C77NCy9F.js";import{t as E}from"./clapperboard-90G9CI1B.js";import{t as re}from"./database-zap-Bv9NPF9E.js";import{t as D}from"./plug-u8jLJjTk.js";import{n as ie,r as O,t as ae}from"./IdentityForm-IeJQ0HCo.js";import{D as k,E as A,K as j,L as oe,M as se,O as ce,R as M,St as N,U as P,W as F,_t as I,a as L,at as le,bt as R,ct as ue,d as de,dt as fe,ft as z,i as B,k as pe,n as me,nt as he,o as V,q as H,r as U,rt as W,s as G,tt as K,u as ge,vt as _e,wt as ve}from"./index-tZx-TDX4.js";import{t as q}from"./BackBar-DmScFXW_.js";import{t as J}from"./AvatarPicker-DUnXfRVQ.js";var ye=a(`battery-full`,[[`path`,{d:`M10 10v4`,key:`1mb2ec`}],[`path`,{d:`M14 10v4`,key:`1nt88p`}],[`path`,{d:`M22 14v-4`,key:`14q9d5`}],[`path`,{d:`M6 10v4`,key:`1n77qd`}],[`rect`,{x:`2`,y:`6`,width:`16`,height:`12`,rx:`2`,key:`13zb55`}]]),be=a(`box`,[[`path`,{d:`M21 8a2 2 0 0 0-1-1.73l-7-4a2 2 0 0 0-2 0l-7 4A2 2 0 0 0 3 8v8a2 2 0 0 0 1 1.73l7 4a2 2 0 0 0 2 0l7-4A2 2 0 0 0 21 16Z`,key:`hh9hay`}],[`path`,{d:`m3.3 7 8.7 5 8.7-5`,key:`g66t2b`}],[`path`,{d:`M12 22V12`,key:`d0xqtd`}]]),xe=a(`chart-column`,[[`path`,{d:`M3 3v16a2 2 0 0 0 2 2h16`,key:`c24i48`}],[`path`,{d:`M18 17V9`,key:`2bz60n`}],[`path`,{d:`M13 17V5`,key:`1frdt8`}],[`path`,{d:`M8 17v-3`,key:`17ska0`}]]),Se=a(`message-square-warning`,[[`path`,{d:`M22 17a2 2 0 0 1-2 2H6.828a2 2 0 0 0-1.414.586l-2.202 2.202A.71.71 0 0 1 2 21.286V5a2 2 0 0 1 2-2h16a2 2 0 0 1 2 2z`,key:`18887p`}],[`path`,{d:`M12 15h.01`,key:`q59x07`}],[`path`,{d:`M12 7v4`,key:`xawao1`}]]),Ce=a(`puzzle`,[[`path`,{d:`M15.39 4.39a1 1 0 0 0 1.68-.474 2.5 2.5 0 1 1 3.014 3.015 1 1 0 0 0-.474 1.68l1.683 1.682a2.414 2.414 0 0 1 0 3.414L19.61 15.39a1 1 0 0 1-1.68-.474 2.5 2.5 0 1 0-3.014 3.015 1 1 0 0 1 .474 1.68l-1.683 1.682a2.414 2.414 0 0 1-3.414 0L8.61 19.61a1 1 0 0 0-1.68.474 2.5 2.5 0 1 1-3.014-3.015 1 1 0 0 0 .474-1.68l-1.683-1.682a2.414 2.414 0 0 1 0-3.414L4.39 8.61a1 1 0 0 1 1.68.474 2.5 2.5 0 1 0 3.014-3.015 1 1 0 0 1-.474-1.68l1.683-1.682a2.414 2.414 0 0 1 3.414 0z`,key:`w46dr5`}]]),we=a(`shield`,[[`path`,{d:`M20 13c0 5-3.5 7.5-7.66 8.95a1 1 0 0 1-.67-.01C7.5 20.5 4 18 4 13V6a1 1 0 0 1 1-1c2 0 4.5-1.2 6.24-2.72a1.17 1.17 0 0 1 1.52 0C14.51 3.81 17 5 19 5a1 1 0 0 1 1 1z`,key:`oel41y`}]]),Te=a(`smile`,[[`circle`,{cx:`12`,cy:`12`,r:`10`,key:`1mglay`}],[`path`,{d:`M8 14s1.5 2 4 2 4-2 4-2`,key:`1y1vjs`}],[`line`,{x1:`9`,x2:`9.01`,y1:`9`,y2:`9`,key:`yxxnd0`}],[`line`,{x1:`15`,x2:`15.01`,y1:`9`,y2:`9`,key:`1p4y9e`}]]),Ee=a(`zap`,[[`path`,{d:`M4 14a1 1 0 0 1-.78-1.63l9.9-10.2a.5.5 0 0 1 .86.46l-1.92 6.02A1 1 0 0 0 13 10h7a1 1 0 0 1 .78 1.63l-9.9 10.2a.5.5 0 0 1-.86-.46l1.92-6.02A1 1 0 0 0 11 14z`,key:`1xq2db`}]]),Y=c(u(),1),De=`(min-width: 64rem)`;function Oe(){return typeof window>`u`?!1:document.documentElement.classList.contains(`desktop`)?!0:typeof window.matchMedia==`function`&&window.matchMedia(De).matches}function ke(){let[e,t]=(0,Y.useState)(Oe);return(0,Y.useEffect)(()=>{if(typeof window.matchMedia!=`function`)return;let e=window.matchMedia(De),n=()=>t(Oe());return e.addEventListener(`change`,n),()=>e.removeEventListener(`change`,n)},[]),e}var X=p(),Ae=`w-full rounded-2xl bg-surface-2 px-3.5 py-2.5 outline-none focus:ring-2 focus:ring-accent/40`,je=[{id:`ask`,title:`Balanced`,text:`Browse, read and write files freely; stop for anything hard to undo: email, purchases, shell commands.`,icon:(0,X.jsx)(j,{size:18})},{id:`strict`,title:`Cautious`,text:`Also ask before moderate actions like fetching web pages or writing files.`,icon:(0,X.jsx)(we,{size:18})},{id:`auto`,title:`Hands-off`,text:`Approve everything automatically except explicit deny rules. For trusted, unattended runs only.`,icon:(0,X.jsx)(H,{size:18})}];function Me(){let{state:e,refreshSettings:a,setTab:s,toast:c}=m(),u=e.settings,[d,p]=(0,Y.useState)(()=>O(e.profile,f,J[0])),[h,v]=(0,Y.useState)(!1),b=o(),te=r(),x=g(),[w,E]=(0,Y.useState)(null),[re,D]=(0,Y.useState)(!1),j=(0,Y.useId)(),oe=`${j}-interval`,N=`${j}-theme`,P=`${j}-app-language`,F=`${j}-reply-language`;(0,Y.useEffect)(()=>{u||a()},[u,a]);let I=(0,Y.useCallback)(async(e=!1)=>{D(!0);try{E(await y.update(e))}catch{E(null)}finally{D(!1)}},[]);(0,Y.useEffect)(()=>{I()},[I]),(0,Y.useEffect)(()=>{e.profile&&p(O(e.profile,``,J[0]))},[e.profile]);let L=async(e,t)=>{v(!0);try{await y.updateSettings(e),await a(),t&&c(t)}catch(e){c(e.message)}finally{v(!1)}},le=O(e.profile,``,J[0]),fe=!!e.profile&&Object.keys(d).some(e=>d[e]!==le[e]),z=e.profile?.name??`nanoMuse`,B=pe(),he=de(),V=ke()&&!e.lite,[H,U]=(0,Y.useState)(null),W=[{id:`who`,title:z},{id:`sentinel`,title:b(`Safety · Sentinel`)},{id:`proactivity`,title:b(`Proactivity`)},{id:`notifications`,title:b(`Notifications`)},...k()?[{id:`keep-running`,title:b(`Keep it running`)}]:[],{id:`model`,title:b(`Model`)},{id:`appearance`,title:b(`Appearance`)},...M()?[{id:`desktop`,title:b(`Desktop app`)}]:[],{id:`data`,title:b(`Data controls`)},{id:`developer`,title:b(`Developer`)},{id:`about`,title:b(`About`)}],G=e=>V||H===e,[K,_e]=(0,Y.useState)(()=>{let e=window.location.hash.slice(1);return Ne.includes(e)?e:null});if((0,Y.useEffect)(()=>{if(K&&u){if(_e(null),history.replaceState(null,``,window.location.pathname+window.location.search),!V){U(K);return}requestAnimationFrame(()=>document.getElementById(K)?.scrollIntoView({behavior:`smooth`,block:`start`}))}},[K,u,V]),!V&&H===null)return(0,X.jsx)(Fe,{release:w,onOpen:U});let ve=W.find(e=>e.id===H);return(0,X.jsxs)(`div`,{className:`flex h-full flex-col`,children:[V?(0,X.jsx)(q,{title:b(`Settings`),description:b(`Its name and look, how careful it is, how often it speaks up.`)}):(0,X.jsx)(q,{title:ve?.title??b(`Settings`),onBack:()=>U(null),backLabel:b(`Settings`)}),(0,X.jsxs)(`div`,{className:`flex min-h-0 flex-1`,children:[V&&(0,X.jsx)(`nav`,{className:`flex w-[188px] shrink-0 flex-col gap-0.5 self-start pl-4 pr-2 pt-1`,"aria-label":b(`Settings`),children:W.map(e=>(0,X.jsx)(`button`,{type:`button`,onClick:()=>document.getElementById(e.id)?.scrollIntoView({behavior:`smooth`,block:`start`}),className:`truncate rounded-xl px-3 py-1.5 text-left text-[13px] font-medium text-fg/75 hover:bg-surface-2 hover:text-fg`,children:e.title},e.id))}),(0,X.jsxs)(`div`,{className:`flex-1 overflow-y-auto px-4 pb-8 space-y-5`,children:[G(`who`)&&(0,X.jsxs)($,{title:z,id:`who`,plain:!V,children:[(0,X.jsx)(ae,{value:d,onChange:p,suggestions:!1,inputCls:Ae,onStudio:()=>s(`avatar`)}),(0,X.jsx)(`button`,{type:`button`,disabled:!fe||h,onClick:()=>void L({profile:ie(d)},b(`Saved`)),className:`w-full rounded-2xl bg-accent text-accent-fg py-2.5 font-medium disabled:opacity-40`,children:b(`Save`)})]}),G(`sentinel`)&&(0,X.jsxs)($,{title:b(`Safety · Sentinel`),id:`sentinel`,plain:!V,children:[(0,X.jsx)(`p`,{className:`text-[13px] text-muted -mt-1`,children:b(`A separate gatekeeper reviews every action. Pick how often it should check in with you.`)}),(0,X.jsx)(`div`,{className:`space-y-2`,children:je.map(e=>(0,X.jsxs)(`button`,{type:`button`,onClick:()=>void L({sentinel_mode:e.id}),"aria-pressed":u?.sentinel.mode===e.id,className:t(`w-full text-left rounded-2xl border px-3.5 py-3 flex items-start gap-3 transition`,u?.sentinel.mode===e.id?`border-accent bg-accent/8`:`border-border`),children:[(0,X.jsx)(`div`,{className:t(`mt-0.5`,e.id===`auto`?`text-rose-500`:`text-accent`),children:e.icon}),(0,X.jsxs)(`div`,{className:`flex-1`,children:[(0,X.jsx)(`div`,{className:`font-medium text-[14.5px]`,children:b(e.title)}),(0,X.jsx)(`div`,{className:`text-[12.5px] text-muted leading-snug mt-0.5`,children:b(e.text)})]}),u?.sentinel.mode===e.id&&(0,X.jsx)(ne,{size:18,className:`text-accent mt-0.5`})]},e.id))}),u&&(0,X.jsxs)(`div`,{className:`text-[12.5px] text-muted leading-relaxed`,children:[b(`Always asks before: {tools}.`,{tools:u.sentinel.always_ask_tools.map(e=>b(e)).join(`, `)||b(`none`)}),` `,u.sentinel.taint_tracking&&b(`After reading private data, new network destinations need approval.`)]}),u?.sandbox&&(0,X.jsxs)(`div`,{className:`flex items-start gap-2.5 rounded-2xl bg-surface-2/60 px-3.5 py-2.5 text-[12.5px] leading-snug`,children:[(0,X.jsx)(be,{size:15,className:t(`shrink-0 mt-[2px]`,u.sandbox.active?`text-emerald-500`:`text-muted`)}),(0,X.jsxs)(`div`,{children:[(0,X.jsxs)(`div`,{className:`font-medium text-fg`,children:[u.sandbox.active?b(`Commands run in a sandbox`):b(`Commands run without a sandbox`),(0,X.jsxs)(`span`,{className:`text-muted font-normal`,children:[` · `,u.sandbox.status]})]}),(0,X.jsx)(`div`,{className:`text-muted mt-0.5`,children:u.sandbox.active?b(`Each shell or Python call gets its own namespace: only the workspace is writable, your home directory is not there, and there is no network unless the command needs it.`):u.sandbox.status.includes(`container`)?b(`Each shell or Python call runs in the workspace with a scrubbed environment; the container is the boundary.`):b(`Each shell or Python call runs in the workspace with a scrubbed environment. On Linux, installing bubblewrap gives each one its own namespace.`)})]})]})]}),G(`proactivity`)&&(0,X.jsxs)($,{title:b(`Proactivity`),id:`proactivity`,plain:!V,children:[(0,X.jsx)(ze,{value:e.profile?.proactivity??`default`,onChange:e=>void L({profile:{proactivity:e}})}),(0,X.jsxs)(`div`,{className:`flex items-center gap-3`,children:[(0,X.jsxs)(`label`,{htmlFor:oe,className:`text-[13.5px] flex-1`,children:[b(`Check-in interval`),e.profile&&e.profile.proactivity!=="default"&&e.profile.proactivity!==`off`&&(0,X.jsx)(`span`,{className:`block text-[12px] text-muted`,children:e.profile.proactivity===`low`?b(`Doubled at this level`):b(`Halved at this level`)})]}),(0,X.jsx)(`select`,{id:oe,value:e.profile?.goal_interval_minutes??60,onChange:e=>void L({profile:{goal_interval_minutes:Number(e.target.value)}}),className:`rounded-2xl bg-surface-2 px-3 py-2 text-[13.5px] outline-none`,children:[...new Set([15,30,60,120,240,480,1440,e.profile?.goal_interval_minutes??60])].sort((e,t)=>e-t).map(e=>(0,X.jsx)(`option`,{value:e,children:e<60?b(`{n} min`,{n:e}):e%60?`${b(`{n} h`,{n:Math.floor(e/60)})} ${b(`{n} min`,{n:e%60})}`:b(`{n} h`,{n:e/60})},e))})]}),(0,X.jsx)(Be,{value:e.profile?.quiet_hours??``,onChange:e=>void L({profile:{quiet_hours:e}})})]}),G(`notifications`)&&(0,X.jsx)($,{title:b(`Notifications`),id:`notifications`,plain:!V,children:A()?(0,X.jsx)(Ie,{name:e.profile?.name??`nanoMuse`}):(0,X.jsx)(Re,{name:e.profile?.name??`nanoMuse`})}),k()&&G(`keep-running`)&&(0,X.jsx)($,{title:b(`Keep it running`),id:`keep-running`,plain:!V,children:(0,X.jsx)(Le,{name:e.profile?.name??`nanoMuse`})}),G(`model`)&&(0,X.jsxs)($,{title:b(`Model`),id:`model`,plain:!V,children:[u&&(0,X.jsxs)(`button`,{type:`button`,onClick:()=>s(`connections`),className:`w-full text-[13.5px] flex items-center justify-between`,children:[(0,X.jsx)(`span`,{className:`text-muted`,children:b(`Provider / model`)}),(0,X.jsxs)(`span`,{className:`font-mono text-[12.5px] flex items-center gap-1`,children:[u.llm.model,` `,(0,X.jsx)(R,{size:14,className:`text-muted`})]})]}),u?.llm.cloud&&(0,X.jsxs)(`button`,{type:`button`,onClick:()=>se(s,S(e.hub?.account).preset),className:`w-full text-[13.5px] flex items-center justify-between`,children:[(0,X.jsx)(`span`,{className:`text-muted`,children:b(`Use my own API key or a plan I pay for`)}),(0,X.jsxs)(`span`,{className:`text-[12.5px] text-muted flex items-center gap-1`,children:[b(`{first} first, then {others}`,{first:S(e.hub?.account).label,others:ee(e.hub?.account)?b(`DeepSeek, Kimi, OpenAI, ChatGPT…`):b(`OpenAI, ChatGPT, Gemini, DeepSeek…`)}),` `,(0,X.jsx)(R,{size:14})]})]}),(0,X.jsxs)(`button`,{type:`button`,onClick:()=>s(`connections`),className:`w-full text-[13.5px] flex items-center justify-between`,children:[(0,X.jsx)(`span`,{className:`text-muted`,children:b(`Connections`)}),(0,X.jsxs)(`span`,{className:`text-[12.5px] text-muted flex items-center gap-1`,children:[b(`E-mail, calendar, browser, MCP servers`),` `,(0,X.jsx)(R,{size:14})]})]})]}),G(`appearance`)&&(0,X.jsxs)($,{title:b(`Appearance`),id:`appearance`,plain:!V,children:[(0,X.jsx)(T,{label:b(`Show the agent's steps`),hint:b(`Every tool it uses becomes a chip in the chat. Off, the chat keeps to the conversation and the line under the name says what it is on. This device only.`),checked:he,onChange:ge}),(0,X.jsx)(T,{label:b(`Show thinking`),hint:b(`Reveal the model's reasoning under each reply when the provider exposes it.`),checked:!!u?.agent.show_thinking,onChange:e=>void L({show_thinking:e})}),(0,X.jsxs)(`div`,{className:`flex items-center gap-3`,children:[(0,X.jsxs)(`label`,{htmlFor:N,className:`text-[13.5px] flex-1`,children:[b(`Appearance`),(0,X.jsx)(`span`,{className:`block text-[12px] text-muted`,children:b(`This device only`)})]}),(0,X.jsxs)(`select`,{id:N,value:x,onChange:e=>_(e.target.value),className:`rounded-2xl bg-surface-2 px-3 py-2 text-[13.5px] outline-none`,children:[(0,X.jsx)(`option`,{value:`light`,children:b(`Light`)}),(0,X.jsx)(`option`,{value:`dark`,children:b(`Dark`)}),(0,X.jsx)(`option`,{value:`system`,children:b(`Follow the system`)})]})]}),(0,X.jsxs)(`div`,{className:`flex items-center gap-3`,children:[(0,X.jsxs)(`label`,{htmlFor:P,className:`text-[13.5px] flex-1`,children:[b(`App language`),(0,X.jsx)(`span`,{className:`block text-[12px] text-muted`,children:b(`This device only`)})]}),(0,X.jsx)(`select`,{id:P,value:te,onChange:e=>i(e.target.value),className:`rounded-2xl bg-surface-2 px-3 py-2 text-[13.5px] outline-none`,children:n.map(e=>(0,X.jsx)(`option`,{value:e.value,children:e.value===`auto`?b(`Auto`):e.label},e.value))})]}),(0,X.jsxs)(`div`,{className:`flex items-center gap-3`,children:[(0,X.jsxs)(`label`,{htmlFor:F,className:`text-[13.5px] flex-1`,children:[b(`Reply language`),(0,X.jsx)(`span`,{className:`block text-[12px] text-muted`,children:b(`What {name} writes in`,{name:e.profile?.name??`nanoMuse`})})]}),(0,X.jsxs)(`select`,{id:F,value:u?.agent.language??`auto`,onChange:e=>void L({language:e.target.value}),className:`rounded-2xl bg-surface-2 px-3 py-2 text-[13.5px] outline-none`,children:[(0,X.jsx)(`option`,{value:`auto`,children:b(`Match mine`)}),(0,X.jsx)(`option`,{value:`English`,children:`English`}),(0,X.jsx)(`option`,{value:`中文`,children:`中文`}),(0,X.jsx)(`option`,{value:`日本語`,children:`日本語`}),(0,X.jsx)(`option`,{value:`Español`,children:`Español`}),(0,X.jsx)(`option`,{value:`Deutsch`,children:`Deutsch`}),(0,X.jsx)(`option`,{value:`Français`,children:`Français`})]})]})]}),M()&&G(`desktop`)&&(0,X.jsx)($,{title:b(`Desktop app`),id:`desktop`,plain:!V,children:(0,X.jsx)(Ve,{})}),G(`data`)&&(0,X.jsx)($,{title:b(`Data controls`),id:`data`,plain:!V,children:(0,X.jsx)(me,{flush:!0})}),G(`developer`)&&(0,X.jsxs)($,{title:b(`Developer`),id:`developer`,plain:!V,children:[(0,X.jsx)(T,{label:b(`Developer tools`),hint:b(`The Coding screen (Cursor, Codex and the other coding agents on this computer) in the sidebar, and the runtime's address below. This device only.`),checked:B,onChange:ce}),B&&(0,X.jsxs)(`div`,{className:`text-[13px] text-muted space-y-1`,children:[(0,X.jsxs)(`div`,{className:`break-all`,children:[b(`Runtime:`),` `,window.location.origin,` · `,(0,X.jsx)(`span`,{className:`text-fg/70`,children:b(`the token is in the server_token file in the data folder`)})]}),(0,X.jsxs)(`div`,{children:[(0,X.jsx)(`a`,{href:`https://github.com/nano-muse/nanoMuse/blob/main/docs/cli.md`,target:`_blank`,rel:`noreferrer`,className:`text-accent underline-offset-2 hover:underline`,children:b(`The command line and the API`)}),` · `,(0,X.jsx)(`a`,{href:`https://github.com/nano-muse/nanoMuse/blob/main/docs/harness.md`,target:`_blank`,rel:`noreferrer`,className:`text-accent underline-offset-2 hover:underline`,children:b(`nanoMuse on DeepSeek Harness`)})]})]})]}),G(`about`)&&(0,X.jsxs)($,{title:b(`About`),id:`about`,plain:!V,children:[(0,X.jsx)(C,{}),(0,X.jsx)(Pe,{installed:e.version,release:w,checking:re,onCheck:()=>void I(!0)}),(0,X.jsxs)(`div`,{className:`text-[13px] text-muted space-y-1`,children:[u&&(0,X.jsxs)(`div`,{className:`break-all`,children:[b(`Data:`),` `,u.data_dir]}),u&&(0,X.jsxs)(`div`,{className:`break-all`,children:[b(`Workspace:`),` `,u.agent.workspace]}),(0,X.jsx)(`div`,{children:e.connected?b(`Connected`):b(`Reconnecting…`)})]}),(0,X.jsxs)(`button`,{type:`button`,onClick:()=>{let e=A();if(e){e.disconnect();return}l(``),window.location.reload()},className:`w-full rounded-2xl border border-border py-2.5 text-[14px] font-medium flex items-center justify-center gap-2 text-muted`,children:[(0,X.jsx)(ue,{size:16}),` `,A()?b(`Disconnect from this server`):b(`Forget this device's access token`)]})]})]})]})]})}var Ne=[`who`,`sentinel`,`proactivity`,`notifications`,`keep-running`,`model`,`appearance`,`desktop`,`data`,`developer`,`about`];function Pe({installed:t,release:n,checking:r,onCheck:i}){let a=o(),s=!!A(),c=(0,X.jsx)(`button`,{type:`button`,onClick:i,disabled:r,className:`text-accent underline-offset-2 hover:underline disabled:opacity-60`,children:a(r?`Checking…`:`Check now`)}),l;return l=s?a(`The phone app checks for updates on its own.`):n&&!n.enabled?a(`Update checks are off here.`):r&&!n?a(`Checking…`):n?.latest&&n.newer?(0,X.jsxs)(X.Fragment,{children:[a(`{version} is out`,{version:n.latest}),` · `,(0,X.jsx)(`a`,{href:n.download_url||n.url,target:`_blank`,rel:`noreferrer`,className:`font-medium text-accent underline-offset-2 hover:underline`,children:a(`Update`)})]}):n?.latest?(0,X.jsxs)(X.Fragment,{children:[a(`Latest {version}; you have it`,{version:n.latest}),` · `,c]}):(0,X.jsxs)(X.Fragment,{children:[a(`Could not check`),` · `,c]}),(0,X.jsxs)(`div`,{className:`rounded-2xl bg-surface-2/60 px-3.5 py-2.5 text-[13px]`,children:[(0,X.jsx)(`div`,{className:`font-medium`,children:a(`nanoMuse {version}`,{version:t})}),(0,X.jsx)(`div`,{className:`mt-0.5 text-muted`,children:l}),!s&&n?.latest&&n.newer&&(0,X.jsx)(`div`,{className:`mt-1 text-[12px] text-muted`,children:a(`To update: pip install -U nanomuse, pull the new image, or use the desktop app's Update.`)}),!s&&n?.checked_at&&(0,X.jsx)(`div`,{className:`mt-1 text-[12px] text-muted`,children:a(`Checked {when}`,{when:e(n.checked_at)})})]})}function Fe({release:e,onOpen:t}){let{state:n,setTab:r}=m(),i=o(),a=n.settings,c=n.hub,l=te(),u=n.profile?.name??`nanoMuse`,d=g(),f=c?.devices.filter(e=>!e.this&&e.kind!==`web`)??[],p=f.filter(e=>e.kind===`computer`),h=f.filter(e=>e.online&&e.actions?.includes(`coding.sessions`)),_=a?.sentinel.mode,v=_===`ask`?i(`Balanced`):_===`strict`?i(`Cautious`):_===`auto`?i(`Hands-off`):``,y=n.profile?.proactivity??`default`,ee=i(y===`off`?`Off`:y===`low`?`Low`:y===`high`?`High`:`Default`),S=i(d===`dark`?`Dark`:d===`light`?`Light`:`Follow the system`),C=i(`none`);return(0,X.jsxs)(`div`,{className:`flex h-full flex-col`,children:[(0,X.jsx)(q,{title:i(`Settings`)}),(0,X.jsxs)(`div`,{className:`flex-1 overflow-y-auto pb-8 pt-2`,children:[(0,X.jsxs)(L,{className:`mb-3`,children:[(0,X.jsxs)(`button`,{type:`button`,onClick:()=>r(`connections`),className:`flex w-full items-center gap-3 px-4 py-3.5 text-left hover:bg-surface-2/60`,children:[(0,X.jsxs)(`span`,{className:`min-w-0 flex-1`,children:[(0,X.jsx)(`span`,{className:`block truncate text-[16px] font-medium leading-[21px]`,children:a?.llm.model||i(`No model yet`)}),(0,X.jsx)(`span`,{className:`mt-0.5 block truncate text-[12.5px] leading-4 text-muted`,children:a?a.llm.cloud?`nanoMuse Cloud`:a.llm.provider:i(`Add a provider and pick its models`)})]}),(0,X.jsx)(`span`,{className:`text-[14px] font-medium text-accent`,children:i(`Change`)})]}),(0,X.jsx)(V,{}),(0,X.jsx)(G,{icon:(0,X.jsx)(_e,{size:22}),label:`nanoMuse Cloud`,value:c?.account.signed_in?c.account.hint:i(`Sign in`),onClick:()=>r(`account`)}),(0,X.jsx)(V,{}),(0,X.jsx)(G,{icon:(0,X.jsx)(E,{size:22}),label:i(`Image & video models`),value:x(l,`image`)===!1?w(i,`image`,b(c?.account),s()):x(l,`video`)===!1?w(i,`video`,b(c?.account),s()):void 0,onClick:()=>r(`connections`)}),(0,X.jsx)(V,{}),(0,X.jsx)(G,{icon:(0,X.jsx)(xe,{size:22}),label:i(`Usage`),onClick:()=>r(`account`)})]}),(0,X.jsxs)(L,{className:`mb-3`,children:[(0,X.jsx)(G,{icon:(0,X.jsx)(F,{size:22}),label:i(`Name & personality`),value:u,onClick:()=>t(`who`)}),(0,X.jsx)(V,{}),(0,X.jsx)(G,{icon:(0,X.jsx)(Te,{size:22}),label:i(`Avatar`),onClick:()=>r(`avatar`)}),(0,X.jsx)(V,{}),(0,X.jsx)(G,{icon:(0,X.jsx)(N,{size:22}),label:i(`Memory`),onClick:()=>r(`memory`)}),a?.skills?.enabled!==!1&&(0,X.jsxs)(X.Fragment,{children:[(0,X.jsx)(V,{}),(0,X.jsx)(G,{icon:(0,X.jsx)(Ce,{size:22}),label:i(`Skills`),value:a?String(a.skills.count):void 0,onClick:()=>r(`skills`)})]}),(0,X.jsx)(V,{}),(0,X.jsx)(G,{icon:(0,X.jsx)(D,{size:22}),label:i(`Connections`),value:a?.connectors.mcp.length?`${a.connectors.mcp.length} MCP`:void 0,onClick:()=>r(`connections`)}),(0,X.jsx)(V,{}),(0,X.jsx)(G,{icon:(0,X.jsx)(le,{size:22}),label:i(`Chat apps`),onClick:()=>r(`channels`)}),(0,X.jsx)(V,{}),(0,X.jsx)(G,{icon:(0,X.jsx)(W,{size:22}),label:i(`Devices`),value:p.length?String(p.length):C,onClick:()=>r(`devices`)}),(0,X.jsx)(V,{}),(0,X.jsx)(G,{icon:(0,X.jsx)(P,{size:22}),label:i(`Coding agents`),value:h.length?String(h.length):C,onClick:()=>r(`coding`)})]}),(0,X.jsxs)(L,{className:`mb-3`,children:[(0,X.jsx)(G,{icon:(0,X.jsx)(j,{size:22}),label:i(`Safety · Sentinel`),value:v,onClick:()=>t(`sentinel`)}),(0,X.jsx)(V,{}),(0,X.jsx)(G,{icon:(0,X.jsx)(Ee,{size:22}),label:i(`Proactivity`),value:ee,onClick:()=>t(`proactivity`)}),(0,X.jsx)(V,{}),(0,X.jsx)(G,{icon:(0,X.jsx)(ve,{size:22}),label:i(`Notifications`),onClick:()=>t(`notifications`)}),k()&&(0,X.jsxs)(X.Fragment,{children:[(0,X.jsx)(V,{}),(0,X.jsx)(G,{icon:(0,X.jsx)(ye,{size:22}),label:i(`Keep it running`),onClick:()=>t(`keep-running`)})]})]}),(0,X.jsxs)(L,{className:`mb-3`,children:[(0,X.jsx)(G,{icon:(0,X.jsx)(K,{size:22}),label:i(`Appearance`),value:S,onClick:()=>t(`appearance`)}),M()&&(0,X.jsxs)(X.Fragment,{children:[(0,X.jsx)(V,{}),(0,X.jsx)(G,{icon:(0,X.jsx)(W,{size:22}),label:i(`Desktop app`),onClick:()=>t(`desktop`)})]}),(0,X.jsx)(V,{}),(0,X.jsx)(G,{icon:(0,X.jsx)(re,{size:22}),label:i(`Data controls`),onClick:()=>t(`data`)}),(0,X.jsx)(V,{}),(0,X.jsx)(G,{icon:(0,X.jsx)(I,{size:22}),label:i(`Developer`),onClick:()=>t(`developer`)})]}),(0,X.jsxs)(L,{className:`mb-3`,children:[(0,X.jsx)(G,{icon:(0,X.jsx)(fe,{size:22}),label:i(`About nanoMuse`),value:e?.newer&&e.latest?i(`{version} is out`,{version:e.latest}):void 0,onClick:()=>t(`about`)}),(0,X.jsx)(V,{}),(0,X.jsx)(G,{icon:(0,X.jsx)(z,{size:22}),label:i(`Privacy policy`),onClick:()=>window.open(U,`_blank`,`noopener`),external:!0}),(0,X.jsx)(V,{}),(0,X.jsx)(G,{icon:(0,X.jsx)(Se,{size:22}),label:i(`Feedback`),onClick:()=>window.open(`https://github.com/nano-muse/nanoMuse/issues/new/choose`,`_blank`,`noopener`),external:!0})]}),(0,X.jsxs)(B,{children:[`nanoMuse `,n.version]})]})]})}function Ie({name:e}){let t=o(),n=A(),[r,i]=(0,Y.useState)(()=>n?.notificationsEnabled()??!1);return n?(0,X.jsxs)(X.Fragment,{children:[(0,X.jsx)(T,{label:t(`Let {name} notify this phone`,{name:e}),hint:t(`The app stays connected to your server in the background. Approvals, questions and finished background work arrive as notifications and open the right chat.`),checked:r,onChange:e=>{n.setNotificationsEnabled(e),i(e)}}),(0,X.jsx)(`div`,{className:`text-[12.5px] text-muted`,children:t(`nanoMuse for Android {version}`,{version:n.version()})})]}):null}function Le({name:e}){let t=o(),n=A(),[r,i]=(0,Y.useState)(k);if((0,Y.useEffect)(()=>{let e=()=>i(k());return document.addEventListener(`visibilitychange`,e),window.addEventListener(`focus`,e),()=>{document.removeEventListener(`visibilitychange`,e),window.removeEventListener(`focus`,e)}},[]),!n||!r)return null;let a=e=>n.openKeepRunning?.(e),s={xiaomi:t(`Xiaomi / Redmi / POCO: Settings → Apps → Manage apps → {name} → Autostart on; Battery saver → No restrictions; Other permissions → Display pop-up windows while running in the background on.`),huawei:t(`Huawei: Settings → Battery → App launch → {name} → Manage manually, all three on (auto-launch, secondary launch, run in background); Settings → Apps → {name} → Battery → Launch: manage manually.`),honor:t(`Honor: Settings → Battery → App launch → {name} → Manage manually, all three on; Battery → More battery settings → Stay connected while asleep on.`),oppo:t(`OPPO / realme / OnePlus: Settings → Battery → More settings → Optimise battery use → {name} → Don't optimise; Settings → Apps → {name} → Battery usage → Allow background activity, Allow auto launch.`),vivo:t(`vivo / iQOO: i Manager → App manager → Autostart → {name} on; Settings → Battery → Background power consumption management → {name} → Allow high background power consumption.`),samsung:t(`Samsung: Settings → Battery → Background usage limits → {name} not in Sleeping or Deep sleeping apps (add it to Never sleeping apps); turn off Adaptive battery if it keeps stopping.`),meizu:t(`Meizu: Settings → Apps → {name} → Background management → Keep running in the background; Battery → App power management → Allow.`)}[r.vendor];return(0,X.jsxs)(X.Fragment,{children:[(0,X.jsx)(`p`,{className:`text-[12.5px] text-muted leading-snug`,children:t(`Android stops apps that seem idle. {name} runs as a foreground service and holds the phone awake only while a task runs; these switches let it keep that promise on this phone.`,{name:e})}),(0,X.jsx)(Z,{label:t(`Battery`),value:r.battery_unrestricted?t(`Unrestricted`):t(`Optimised`),ok:r.battery_unrestricted,hint:t(`Optimised means Android may freeze the agent after a while with the screen off; routines and check-ins then wait until the phone wakes.`),action:r.battery_unrestricted?void 0:{label:t(`Allow`),onClick:()=>a(`battery`)}}),(0,X.jsx)(Z,{label:t(`Display over other apps`),value:r.overlay?t(`Allowed`):t(`Not allowed`),ok:r.overlay,hint:t(`Lets the agent bring an app to the front from the background and show its status capsule while it works in other apps.`),action:r.overlay?void 0:{label:t(`Allow`),onClick:()=>a(`overlay`)}}),r.exact_alarms!==`n/a`&&r.local&&(0,X.jsx)(Z,{label:t(`Alarms & reminders`),value:r.exact_alarms===`granted`?t(`Exact`):t(`Approximate`),ok:r.exact_alarms===`granted`,hint:t(`With exact alarms a reminder fires at the minute you named even when the phone is asleep; without them Android may deliver it up to a quarter of an hour late.`),action:r.exact_alarms===`granted`?void 0:{label:t(`Allow`),onClick:()=>a(`alarms`)}}),(0,X.jsx)(T,{label:t(`Start after a reboot`),hint:r.local?t(`Bring the runtime back when the phone restarts, so routines and check-ins do not stop.`):t(`Reconnect to your computer when the phone restarts, so approvals keep arriving.`),checked:r.boot_start,onChange:e=>{n.setStartOnBoot?.(e),i({...r,boot_start:e})}}),s&&(0,X.jsxs)(`div`,{className:`rounded-2xl bg-surface-2 px-3 py-2.5 text-[12.5px] leading-snug space-y-2`,children:[(0,X.jsx)(`div`,{className:`font-medium`,children:t(`On this phone's Android`)}),(0,X.jsx)(`div`,{className:`text-muted`,children:s}),r.autostart_settings&&(0,X.jsx)(`button`,{type:`button`,onClick:()=>a(`autostart`),className:`rounded-full border border-border px-3 py-1.5 text-[12.5px]`,children:t(`Open the auto-start settings`)})]}),(0,X.jsxs)(`div`,{className:`flex items-center justify-between gap-3 pt-1`,children:[(0,X.jsx)(`div`,{className:`text-[12.5px] text-muted leading-snug`,children:t(`Crashes are written to a file on this phone and nowhere else. Export bundles them with the runtime's log for someone you choose.`)}),(0,X.jsx)(`button`,{type:`button`,onClick:()=>n.exportLogs?.(),className:`shrink-0 rounded-full border border-border px-3 py-1.5 text-[12.5px]`,children:t(`Export logs`)})]})]})}function Z({label:e,value:n,ok:r,hint:i,action:a}){return(0,X.jsxs)(`div`,{className:`flex items-start gap-3`,children:[(0,X.jsxs)(`div`,{className:`flex-1`,children:[(0,X.jsxs)(`div`,{className:`flex items-center gap-2 text-[14px]`,children:[(0,X.jsx)(`span`,{children:e}),(0,X.jsx)(`span`,{className:t(`rounded-full px-2 py-0.5 text-[11px] font-medium`,r?`bg-emerald-500/12 text-emerald-700 dark:text-emerald-300`:`bg-amber-500/15 text-amber-700 dark:text-amber-300`),children:n})]}),i&&(0,X.jsx)(`div`,{className:`text-[12.5px] text-muted leading-snug`,children:i})]}),a&&(0,X.jsx)(`button`,{type:`button`,onClick:a.onClick,className:`shrink-0 rounded-full bg-accent px-3 py-1.5 text-[12.5px] font-medium text-white`,children:a.label})]})}function Re({name:e}){let{toast:t}=m(),[n,r]=(0,Y.useState)(null),[i,a]=(0,Y.useState)(`off`),[s,c]=(0,Y.useState)(!1),l=o(),u=async()=>{a(await v());try{r(await y.push())}catch{}};(0,Y.useEffect)(()=>{u()},[]);let f=async()=>{if(n){c(!0);try{let e=i===`on`?await h():await d(n.public_key);a(e),e===`denied`&&t(l(`Notifications are blocked for this site in the browser settings`)),await u()}catch(e){let n=e;t(n.name===`AbortError`?l(`This browser has no push service (embedded browsers often don't). Use Chrome, Edge, Firefox or Safari 16.4+ on the phone.`):n.message)}finally{c(!1)}}},p=async()=>{try{let e=await y.pushTest();t(e.ok?l(`Sent. It should arrive in a moment`):e.error??l(`Could not send`))}catch(e){t(e.message)}},g=i===`unsupported`?l(`This browser cannot receive push notifications.`):i===`insecure`?l(`Notifications need https:// (or localhost). Over plain http on your LAN the app works, this part stays off; see docs/deployment.md.`):i===`denied`?l(`Blocked for this site. Allow notifications in the browser's site settings, then try again.`):n&&!n.available?l(`The server was installed without pywebpush.`):``;return(0,X.jsxs)(X.Fragment,{children:[(0,X.jsx)(T,{label:l(`Let {name} notify this device`,{name:e}),hint:l(`Approvals, questions, finished background work and check-ins; nothing while the app is on screen.`),checked:i===`on`,onChange:()=>void f(),disabled:s||!!g}),g&&(0,X.jsx)(`div`,{className:`text-[12.5px] text-muted`,children:g}),n&&n.subscriptions>0&&(0,X.jsxs)(`div`,{className:`flex items-center justify-between text-[12.5px] text-muted`,children:[(0,X.jsx)(`span`,{children:n.subscriptions===1?l(`1 device subscribed`):l(`{n} devices subscribed`,{n:n.subscriptions})}),(0,X.jsx)(`button`,{type:`button`,onClick:()=>void p(),className:`text-accent font-medium`,children:l(`Send a test`)})]}),!M()&&(0,X.jsx)(`div`,{className:`text-[12.5px] text-muted`,children:l(`On a phone, add the app to the home screen first; the icon then shows a badge and notifications open the right chat.`)})]})}var Q=[{id:`off`,title:`Off`,text:`Only works when you ask.`},{id:`low`,title:`Low`,text:`Checks in half as often; speaks up only when a step is done or it needs you.`},{id:`default`,title:`Default`,text:`Works on goals on schedule; reports real progress, stays quiet otherwise.`},{id:`high`,title:`High`,text:`Checks in twice as often and always reports, even 'still on track'.`}];function ze({value:e,onChange:n}){let r=o(),i=Q.find(t=>t.id===e)??Q[2];return(0,X.jsxs)(`div`,{children:[(0,X.jsx)(`div`,{className:`flex items-center gap-3`,children:(0,X.jsx)(`div`,{className:`flex-1 text-[13px] text-muted leading-snug`,children:r(i.text)})}),(0,X.jsx)(`div`,{className:`mt-2 grid grid-cols-4 gap-1 rounded-2xl bg-surface-2 p-1`,children:Q.map(i=>(0,X.jsx)(`button`,{type:`button`,onClick:()=>n(i.id),"aria-pressed":e===i.id,className:t(`rounded-xl py-1.5 text-[13px] font-medium transition`,e===i.id?`bg-surface shadow-sm text-accent`:`text-muted`),children:r(i.title)},i.id))})]})}function Be({value:e,onChange:n}){let[r,i]=e?e.split(`-`):[``,``],a=!!e,s=o(),c=(e,t)=>n(e&&t?`${e}-${t}`:``);return(0,X.jsxs)(`div`,{children:[(0,X.jsxs)(`label`,{className:`flex items-start gap-3 cursor-pointer`,children:[(0,X.jsxs)(`div`,{className:`flex-1`,children:[(0,X.jsxs)(`div`,{className:`text-[14px] flex items-center gap-1.5`,children:[(0,X.jsx)(he,{size:15,className:`text-muted`}),` `,s(`Quiet hours`)]}),(0,X.jsx)(`div`,{className:`text-[12.5px] text-muted leading-snug`,children:s(`No background work in this window; anything due waits until it ends.`)})]}),(0,X.jsx)(`button`,{type:`button`,role:`switch`,"aria-checked":a,onClick:()=>c(a?``:`22:00`,a?``:`08:00`),className:t(`relative mt-0.5 h-7 w-12 shrink-0 rounded-full transition`,a?`bg-accent`:`bg-surface-2 border border-border`),children:(0,X.jsx)(`span`,{className:t(`absolute top-0.5 h-6 w-6 rounded-full bg-white shadow transition`,a?`left-[22px]`:`left-0.5`)})})]}),a&&(0,X.jsxs)(`div`,{className:`mt-2 flex items-center gap-2 text-[13.5px]`,children:[(0,X.jsx)(`span`,{className:`text-muted`,children:s(`From`)}),(0,X.jsx)(`input`,{type:`time`,value:r,onChange:e=>c(e.target.value,i),"aria-label":s(`Quiet hours start`),className:`rounded-xl bg-surface-2 px-2.5 py-1.5 outline-none`}),(0,X.jsx)(`span`,{className:`text-muted`,children:s(`to`)}),(0,X.jsx)(`input`,{type:`time`,value:i,onChange:e=>c(r,e.target.value),"aria-label":s(`Quiet hours end`),className:`rounded-xl bg-surface-2 px-2.5 py-1.5 outline-none`})]})]})}function Ve(){let e=o(),t=oe(),[n,r]=(0,Y.useState)(null);(0,Y.useEffect)(()=>{let e=!0;return t?.loginItem?.().then(t=>{e&&r(t)}),()=>{e=!1}},[t]);let i=t?.platform===`darwin`,a=[[e(`Quick chat`),i?`⌥ Space`:`Ctrl+Shift+Space`],[e(`Show the window`),i?`⌘⇧M`:`Ctrl+Shift+M`],[e(`Stop the hands`),i?`⌘⇧Esc`:`Ctrl+Shift+Esc`]];return(0,X.jsxs)(X.Fragment,{children:[t?.setLoginItem&&n!==null&&t.platform!==`linux`&&(0,X.jsx)(T,{label:e(`Start with the computer`),hint:e(`Opens in the tray at sign-in; the agent's goals and check-ins run from then on.`),checked:n,onChange:e=>{r(e),t.setLoginItem?.(e)}}),(0,X.jsxs)(`div`,{className:`text-[13.5px]`,children:[e(`In the tray`),(0,X.jsx)(`span`,{className:`block text-[12px] text-muted`,children:e(`The icon by the clock shows what the hands are doing and has Stop; closing the window keeps the agent running.`)})]}),(0,X.jsxs)(`div`,{className:`space-y-1`,children:[(0,X.jsx)(`div`,{className:`text-[13.5px]`,children:e(`Shortcuts`)}),a.map(([e,t])=>(0,X.jsxs)(`div`,{className:`flex items-center justify-between text-[13px]`,children:[(0,X.jsx)(`span`,{className:`text-muted`,children:e}),(0,X.jsx)(`kbd`,{className:`rounded-md border border-border bg-surface-2 px-1.5 py-0.5 font-sans text-[12px] text-fg/80`,children:t})]},e))]})]})}function $({title:e,children:n,id:r,plain:i=!1}){return(0,X.jsxs)(`section`,{id:r,className:t(`space-y-3 scroll-mt-4`,i?`pt-1`:`rounded-3xl bg-surface border border-border/70 shadow-sm p-4`),children:[!i&&(0,X.jsx)(`h2`,{className:`text-[12px] font-semibold uppercase tracking-wide text-muted`,children:e}),n]})}export{Me as SettingsScreen}; \ No newline at end of file diff --git a/nanomuse/server/static/assets/SkillsScreen-ZetN1PPI.js b/nanomuse/server/static/assets/SkillsScreen-DsMpJe1f.js similarity index 74% rename from nanomuse/server/static/assets/SkillsScreen-ZetN1PPI.js rename to nanomuse/server/static/assets/SkillsScreen-DsMpJe1f.js index 60fadc2c7..bb6a09946 100644 --- a/nanomuse/server/static/assets/SkillsScreen-ZetN1PPI.js +++ b/nanomuse/server/static/assets/SkillsScreen-DsMpJe1f.js @@ -1,4 +1,4 @@ -import{A as e,E as t,J as n,K as r,Q as i,Y as a,b as o,f as s,q as c,r as l,x as u}from"./MuseHeader-BvAlmxiL.js";import{B as d,C as f,F as p,Q as m,V as h,Z as g,bt as _,et as v}from"./index-tZx-TDX4.js";import{t as y}from"./BackBar-DmScFXW_.js";var b=n(`file-code-corner`,[[`path`,{d:`M4 12.15V4a2 2 0 0 1 2-2h8a2.4 2.4 0 0 1 1.706.706l3.588 3.588A2.4 2.4 0 0 1 20 8v12a2 2 0 0 1-2 2h-3.35`,key:`1wthlu`}],[`path`,{d:`M14 2v5a1 1 0 0 0 1 1h5`,key:`wfsgrz`}],[`path`,{d:`m5 16-3 3 3 3`,key:`331omg`}],[`path`,{d:`m9 22 3-3-3-3`,key:`lsp7cz`}]]),x=n(`link-2`,[[`path`,{d:`M9 17H7A5 5 0 0 1 7 7h2`,key:`8i5ue5`}],[`path`,{d:`M15 7h2a5 5 0 1 1 0 10h-2`,key:`1b9ql8`}],[`line`,{x1:`8`,x2:`16`,y1:`12`,y2:`12`,key:`1jonct`}]]),S=i(a(),1),C=o(),w=e=>`--- +import{A as e,E as t,J as n,K as r,Q as i,Y as a,b as o,f as s,q as c,r as l,x as u}from"./MuseHeader-RC--uR8o.js";import{$ as d,B as f,P as p,S as m,X as h,Z as g,yt as _,z as v}from"./index-tYqPtwPX.js";import{t as y}from"./BackBar-JEuC8Q_e.js";var b=n(`file-code-corner`,[[`path`,{d:`M4 12.15V4a2 2 0 0 1 2-2h8a2.4 2.4 0 0 1 1.706.706l3.588 3.588A2.4 2.4 0 0 1 20 8v12a2 2 0 0 1-2 2h-3.35`,key:`1wthlu`}],[`path`,{d:`M14 2v5a1 1 0 0 0 1 1h5`,key:`wfsgrz`}],[`path`,{d:`m5 16-3 3 3 3`,key:`331omg`}],[`path`,{d:`m9 22 3-3-3-3`,key:`lsp7cz`}]]),x=n(`link-2`,[[`path`,{d:`M9 17H7A5 5 0 0 1 7 7h2`,key:`8i5ue5`}],[`path`,{d:`M15 7h2a5 5 0 1 1 0 10h-2`,key:`1b9ql8`}],[`line`,{x1:`8`,x2:`16`,y1:`12`,y2:`12`,key:`1jonct`}]]),S=i(a(),1),C=o(),w=e=>`--- name: ${e} description: What this does, and when to use it; the model picks the skill from this line. --- @@ -17,4 +17,4 @@ description: What this does, and when to use it; the model picks the skill from ## Finish - What to say in chat; what to ask; what never to do. -`;function T(){let{state:e,toast:t,draft:n}=s(),i=r(),a=e.profile?.name??`nanoMuse`,[o,p]=(0,S.useState)(null),[m,h]=(0,S.useState)(null),[_,v]=(0,S.useState)(null),[b,x]=(0,S.useState)(!1),w=()=>u.skills().then(e=>{p(e),h(null)}).catch(e=>o===null?h(e.message):t(e.message));if((0,S.useEffect)(()=>{w()},[e.skillsVersion]),_)return(0,C.jsx)(D,{name:_,onBack:()=>v(null),onUse:e=>n(`/${e} `),onGone:()=>{v(null),w()}});if(b)return(0,C.jsx)(O,{onCancel:()=>x(!1),onSaved:e=>{x(!1),v(e.name)}});let T=o?.skills.filter(e=>e.source===`yours`)??[],k=o?.skills.filter(e=>e.source===`built-in`)??[];return(0,C.jsxs)(`div`,{className:`flex h-full flex-col`,children:[(0,C.jsx)(y,{title:i(`Skills`),description:i(`How {name} does a job, written down once. Start one in chat with /name, or just ask; it picks the skill that fits.`,{name:a}),actions:(0,C.jsx)(l,{small:!0,onClick:()=>x(!0),label:i(`New`),children:(0,C.jsx)(g,{size:20})})}),(0,C.jsxs)(`div`,{className:`flex-1 overflow-y-auto px-4 pb-6 space-y-5`,children:[o===null&&m&&(0,C.jsx)(f,{message:m,onRetry:()=>void w()}),o===null&&!m&&(0,C.jsx)(`div`,{className:`py-10 flex justify-center text-muted`,children:(0,C.jsx)(c,{className:`animate-spin`,size:20})}),o&&(0,C.jsxs)(C.Fragment,{children:[(0,C.jsxs)(`section`,{children:[(0,C.jsxs)(`div`,{className:`px-1 mb-2 text-[12px] font-semibold uppercase tracking-wide text-muted`,children:[i(`Yours`),` · `,T.length]}),T.length===0?(0,C.jsxs)(`div`,{className:`rounded-3xl border border-dashed border-border p-5 text-center`,children:[(0,C.jsx)(d,{className:`mx-auto text-accent`}),(0,C.jsx)(`div`,{className:`mt-2 font-semibold`,children:i(`Nothing of your own yet`)}),(0,C.jsx)(`p`,{className:`mt-1 text-[13.5px] text-muted`,children:i(`After a job went well, tell {name} “save this as a skill”; it writes the steps down and asks you first. Or write one here, or paste a link to a SKILL.md.`,{name:a})}),(0,C.jsxs)(`button`,{type:`button`,onClick:()=>x(!0),className:`mt-3 inline-flex items-center gap-1.5 rounded-full bg-accent px-4 py-2 text-[13.5px] font-semibold text-accent-fg`,children:[(0,C.jsx)(g,{size:15}),` `,i(`Write one`)]})]}):(0,C.jsx)(E,{items:T,onOpen:v,onChange:w})]}),(0,C.jsxs)(`section`,{children:[(0,C.jsxs)(`div`,{className:`px-1 mb-2 text-[12px] font-semibold uppercase tracking-wide text-muted`,children:[i(`Built in`),` · `,k.length]}),(0,C.jsx)(E,{items:k,onOpen:v,onChange:w}),(0,C.jsx)(`p`,{className:`mt-2 px-1 text-[12px] text-muted`,children:i(`Switch one off to keep it out of {name}'s list. A skill of yours with the same name replaces it.`,{name:a})})]}),Object.keys(o.errors).length>0&&(0,C.jsxs)(`section`,{className:`rounded-3xl bg-amber-500/10 text-amber-800 dark:text-amber-200 p-3.5 text-[13px]`,children:[(0,C.jsx)(`div`,{className:`font-semibold`,children:i(`Folders that could not be read`)}),Object.entries(o.errors).map(([e,t])=>(0,C.jsxs)(`div`,{className:`mt-1 break-words`,children:[(0,C.jsx)(`span`,{className:`font-mono`,children:e}),`: `,t]},e))]}),(0,C.jsx)(`p`,{className:`px-1 text-[12px] text-muted`,children:i(`Yours live in {dir}, one folder each with a SKILL.md, the Agent Skills format, so recipes written for other agents work here too.`,{dir:o.dir})})]})]})]})}function E({items:e,onOpen:n,onChange:i}){let{toast:a}=s(),o=r(),c=async(e,t)=>{try{await u.setSkillEnabled(e.name,t),i()}catch(e){a(e.message)}};return(0,C.jsx)(`ul`,{className:`rounded-3xl bg-surface border border-border/70 shadow-sm divide-y divide-border/70 overflow-hidden`,children:e.map(e=>(0,C.jsxs)(`li`,{className:t(`flex items-center gap-3 px-4 py-3`,!e.enabled&&`opacity-60`),children:[(0,C.jsxs)(`button`,{type:`button`,onClick:()=>n(e.name),className:`flex min-w-0 flex-1 items-center gap-3 text-left`,children:[(0,C.jsx)(`span`,{className:`rounded-2xl bg-accent/12 text-accent p-2`,children:(0,C.jsx)(d,{size:17})}),(0,C.jsxs)(`span`,{className:`min-w-0 flex-1`,children:[(0,C.jsxs)(`span`,{className:`block text-[14.5px] font-medium`,children:[`/`,e.name]}),(0,C.jsx)(`span`,{className:`text-[12.5px] text-muted line-clamp-2`,children:e.description})]}),(0,C.jsx)(_,{size:17,className:`shrink-0 text-muted`})]}),(0,C.jsx)(`button`,{type:`button`,role:`switch`,"aria-checked":e.enabled,"aria-label":o(`Use /{name}`,{name:e.name}),onClick:()=>void c(e,!e.enabled),className:t(`relative h-6 w-10 shrink-0 rounded-full transition`,e.enabled?`bg-accent`:`bg-border`),children:(0,C.jsx)(`span`,{className:t(`absolute top-0.5 h-5 w-5 rounded-full bg-white shadow transition`,e.enabled?`left-[18px]`:`left-0.5`)})})]},e.name))})}function D({name:t,onBack:n,onUse:i,onGone:a}){let{toast:o}=s(),l=r(),[d,f]=(0,S.useState)(null),[g,_]=(0,S.useState)(!1),x=()=>u.skill(t).then(f).catch(e=>o(e.message));(0,S.useEffect)(()=>{x()},[t]);let w=async()=>{if(d&&window.confirm(l(`Delete the skill “{name}”? Its folder goes with it.`,{name:d.name})))try{await u.deleteSkill(d.name),a()}catch(e){o(e.message)}};return g&&d?(0,C.jsx)(O,{initial:d,onCancel:()=>_(!1),onSaved:()=>{_(!1),x()}}):(0,C.jsxs)(`div`,{className:`flex h-full flex-col`,children:[(0,C.jsx)(y,{onBack:n,backLabel:l(`Skills`),title:d?(0,C.jsxs)(`span`,{className:`font-mono`,children:[`/`,d.name]}):l(`Skills`),description:d&&(0,C.jsxs)(C.Fragment,{children:[d.source===`built-in`?l(`Built in`):l(`Yours`),d.updated_at?` · ${l(`updated {when}`,{when:e(d.updated_at)})}`:``,d.metadata.author?` · ${d.metadata.author}`:``]})}),(0,C.jsxs)(`div`,{className:`flex-1 overflow-y-auto px-4 pb-6 space-y-4`,children:[!d&&(0,C.jsx)(`div`,{className:`py-10 flex justify-center text-muted`,children:(0,C.jsx)(c,{className:`animate-spin`,size:20})}),d&&(0,C.jsxs)(C.Fragment,{children:[(0,C.jsxs)(`div`,{className:`flex gap-2`,children:[(0,C.jsxs)(`button`,{type:`button`,onClick:()=>i(d.name),className:`flex-1 rounded-2xl bg-accent text-accent-fg px-3.5 py-2.5 text-[14px] font-medium flex items-center justify-center gap-1.5`,children:[(0,C.jsx)(m,{size:15}),` `,l(`Use in chat`)]}),(0,C.jsxs)(`button`,{type:`button`,onClick:()=>_(!0),className:`rounded-2xl bg-surface border border-border/70 px-3.5 py-2.5 text-[14px] font-medium flex items-center gap-1.5`,children:[(0,C.jsx)(v,{size:15}),` `,d.source===`built-in`?l(`Make your own copy`):l(`Edit`)]}),d.source===`yours`&&(0,C.jsx)(`button`,{type:`button`,"aria-label":l(`Delete`),onClick:()=>void w(),className:`rounded-2xl bg-surface border border-border/70 px-3 py-2.5 text-muted hover:text-rose-500`,children:(0,C.jsx)(h,{size:17})})]}),(0,C.jsx)(`div`,{className:`rounded-3xl bg-surface border border-border/70 shadow-sm p-4`,children:(0,C.jsx)(`p`,{className:`text-[14px] leading-snug`,children:d.description})}),(0,C.jsx)(`div`,{className:`rounded-3xl bg-surface border border-border/70 shadow-sm p-4 text-[14px]`,children:(0,C.jsx)(p,{text:d.body})}),d.files.length>0&&(0,C.jsxs)(`div`,{className:`rounded-3xl bg-surface border border-border/70 shadow-sm p-4`,children:[(0,C.jsx)(`div`,{className:`text-[12px] font-semibold uppercase tracking-wide text-muted mb-2`,children:l(`Files that come with it`)}),(0,C.jsx)(`ul`,{className:`space-y-1`,children:d.files.map(e=>(0,C.jsxs)(`li`,{className:`flex items-center gap-2 text-[13.5px] font-mono`,children:[(0,C.jsx)(b,{size:15,className:`text-muted`}),` `,e]},e))})]}),(0,C.jsx)(`p`,{className:`px-1 text-[12px] text-muted break-all`,children:d.path})]})]})]})}function O({initial:e,onCancel:t,onSaved:n}){let{toast:i}=s(),a=r(),[o,c]=(0,S.useState)(e?.name??``),[l,d]=(0,S.useState)(e?.content??``),[f,p]=(0,S.useState)(``),[m,h]=(0,S.useState)(!1),[g,_]=(0,S.useState)(``),v=/^[a-z0-9](?:[a-z0-9-]{0,62}[a-z0-9])?$/.test(o),b=async()=>{h(!0),_(``);try{let e=l.trim()?l:w(o);n(await u.saveSkill(o,e.replace(/^---\nname: .*\n/,`---\nname: ${o}\n`)))}catch(e){_(e.message)}finally{h(!1)}},T=async()=>{h(!0),_(``);try{n(await u.importSkill(f.trim()))}catch(e){_(e.message),i(e.message)}finally{h(!1)}};return(0,C.jsxs)(`div`,{className:`flex h-full flex-col`,children:[(0,C.jsx)(y,{onBack:t,title:a(e?`Edit skill`:`New skill`),description:e?.source===`built-in`?a(`Saving makes a copy of yours with the same name; it replaces the built-in one.`):a(`A SKILL.md: a name and a one-line description up top, then the steps in Markdown.`)}),(0,C.jsxs)(`div`,{className:`flex-1 overflow-y-auto px-4 pb-6 space-y-4`,children:[!e&&(0,C.jsxs)(`div`,{className:`rounded-3xl bg-surface border border-border/70 shadow-sm p-3.5 space-y-2`,children:[(0,C.jsxs)(`div`,{className:`text-[12px] font-semibold uppercase tracking-wide text-muted flex items-center gap-1.5`,children:[(0,C.jsx)(x,{size:13}),` `,a(`From a link`)]}),(0,C.jsxs)(`div`,{className:`flex gap-2`,children:[(0,C.jsx)(`input`,{value:f,onChange:e=>p(e.target.value),placeholder:`https://github.com/…/skills/pdf`,inputMode:`url`,autoComplete:`off`,className:`flex-1 min-w-0 rounded-2xl bg-surface-2 px-3.5 py-2.5 text-[14px] outline-none focus:ring-2 focus:ring-accent/40`}),(0,C.jsx)(`button`,{type:`button`,disabled:!f.trim().startsWith(`https://`)||m,onClick:()=>void T(),className:`rounded-2xl bg-surface-2 px-3.5 py-2.5 text-[14px] font-medium disabled:opacity-50`,children:a(`Fetch`)})]}),(0,C.jsx)(`p`,{className:`text-[12px] text-muted`,children:a(`A raw SKILL.md link, or a GitHub folder or file page.`)})]}),(0,C.jsxs)(`div`,{className:`rounded-3xl bg-surface border border-border/70 shadow-sm p-3.5 space-y-2.5`,children:[(0,C.jsxs)(`label`,{className:`block`,children:[(0,C.jsx)(`span`,{className:`text-[12px] font-semibold uppercase tracking-wide text-muted`,children:a(`Name`)}),(0,C.jsx)(`input`,{value:o,onChange:e=>c(e.target.value.toLowerCase().replace(/[^a-z0-9-]/g,`-`)),placeholder:`weekly-review`,disabled:!!e,autoComplete:`off`,className:`mt-1 w-full rounded-2xl bg-surface-2 px-3.5 py-2.5 text-[14px] font-mono outline-none focus:ring-2 focus:ring-accent/40 disabled:opacity-70`})]}),(0,C.jsxs)(`label`,{className:`block`,children:[(0,C.jsx)(`span`,{className:`text-[12px] font-semibold uppercase tracking-wide text-muted`,children:`SKILL.md`}),(0,C.jsx)(`textarea`,{value:l,onChange:e=>d(e.target.value),onFocus:()=>{!l&&v&&d(w(o))},rows:16,spellCheck:!1,placeholder:v?w(o):a(`Pick a name first; a template appears here.`),className:`mt-1 w-full resize-y rounded-2xl bg-surface-2 px-3.5 py-2.5 text-[13px] font-mono leading-relaxed outline-none focus:ring-2 focus:ring-accent/40`})]}),g&&(0,C.jsx)(`div`,{className:`text-[13px] text-rose-600 dark:text-rose-400 break-words`,children:g}),(0,C.jsxs)(`div`,{className:`flex gap-2`,children:[(0,C.jsx)(`button`,{type:`button`,onClick:t,className:`rounded-2xl bg-surface-2 px-3.5 py-2.5 text-[14px] font-medium`,children:a(`Cancel`)}),(0,C.jsx)(`button`,{type:`button`,disabled:!v||m,onClick:()=>void b(),className:`flex-1 rounded-2xl bg-accent text-accent-fg px-3.5 py-2.5 text-[14px] font-medium disabled:opacity-50`,children:a(m?`Saving…`:`Save`)})]})]})]})]})}export{T as SkillsScreen}; \ No newline at end of file +`;function T(){let{state:e,toast:t,draft:n}=s(),i=r(),a=e.profile?.name??`nanoMuse`,[o,d]=(0,S.useState)(null),[f,p]=(0,S.useState)(null),[g,_]=(0,S.useState)(null),[b,x]=(0,S.useState)(!1),w=()=>u.skills().then(e=>{d(e),p(null)}).catch(e=>o===null?p(e.message):t(e.message));if((0,S.useEffect)(()=>{w()},[e.skillsVersion]),g)return(0,C.jsx)(D,{name:g,onBack:()=>_(null),onUse:e=>n(`/${e} `),onGone:()=>{_(null),w()}});if(b)return(0,C.jsx)(O,{onCancel:()=>x(!1),onSaved:e=>{x(!1),_(e.name)}});let T=o?.skills.filter(e=>e.source===`yours`)??[],k=o?.skills.filter(e=>e.source===`built-in`)??[];return(0,C.jsxs)(`div`,{className:`flex h-full flex-col`,children:[(0,C.jsx)(y,{title:i(`Skills`),description:i(`How {name} does a job, written down once. Start one in chat with /name, or just ask; it picks the skill that fits.`,{name:a}),actions:(0,C.jsx)(l,{small:!0,onClick:()=>x(!0),label:i(`New`),children:(0,C.jsx)(h,{size:20})})}),(0,C.jsxs)(`div`,{className:`flex-1 overflow-y-auto px-4 pb-6 space-y-5`,children:[o===null&&f&&(0,C.jsx)(m,{message:f,onRetry:()=>void w()}),o===null&&!f&&(0,C.jsx)(`div`,{className:`py-10 flex justify-center text-muted`,children:(0,C.jsx)(c,{className:`animate-spin`,size:20})}),o&&(0,C.jsxs)(C.Fragment,{children:[(0,C.jsxs)(`section`,{children:[(0,C.jsxs)(`div`,{className:`px-1 mb-2 text-[12px] font-semibold uppercase tracking-wide text-muted`,children:[i(`Yours`),` · `,T.length]}),T.length===0?(0,C.jsxs)(`div`,{className:`rounded-3xl border border-dashed border-border p-5 text-center`,children:[(0,C.jsx)(v,{className:`mx-auto text-accent`}),(0,C.jsx)(`div`,{className:`mt-2 font-semibold`,children:i(`Nothing of your own yet`)}),(0,C.jsx)(`p`,{className:`mt-1 text-[13.5px] text-muted`,children:i(`After a job went well, tell {name} “save this as a skill”; it writes the steps down and asks you first. Or write one here, or paste a link to a SKILL.md.`,{name:a})}),(0,C.jsxs)(`button`,{type:`button`,onClick:()=>x(!0),className:`mt-3 inline-flex items-center gap-1.5 rounded-full bg-accent px-4 py-2 text-[13.5px] font-semibold text-accent-fg`,children:[(0,C.jsx)(h,{size:15}),` `,i(`Write one`)]})]}):(0,C.jsx)(E,{items:T,onOpen:_,onChange:w})]}),(0,C.jsxs)(`section`,{children:[(0,C.jsxs)(`div`,{className:`px-1 mb-2 text-[12px] font-semibold uppercase tracking-wide text-muted`,children:[i(`Built in`),` · `,k.length]}),(0,C.jsx)(E,{items:k,onOpen:_,onChange:w}),(0,C.jsx)(`p`,{className:`mt-2 px-1 text-[12px] text-muted`,children:i(`Switch one off to keep it out of {name}'s list. A skill of yours with the same name replaces it.`,{name:a})})]}),Object.keys(o.errors).length>0&&(0,C.jsxs)(`section`,{className:`rounded-3xl bg-amber-500/10 text-amber-800 dark:text-amber-200 p-3.5 text-[13px]`,children:[(0,C.jsx)(`div`,{className:`font-semibold`,children:i(`Folders that could not be read`)}),Object.entries(o.errors).map(([e,t])=>(0,C.jsxs)(`div`,{className:`mt-1 break-words`,children:[(0,C.jsx)(`span`,{className:`font-mono`,children:e}),`: `,t]},e))]}),(0,C.jsx)(`p`,{className:`px-1 text-[12px] text-muted`,children:i(`Yours live in {dir}, one folder each with a SKILL.md, the Agent Skills format, so recipes written for other agents work here too.`,{dir:o.dir})})]})]})]})}function E({items:e,onOpen:n,onChange:i}){let{toast:a}=s(),o=r(),c=async(e,t)=>{try{await u.setSkillEnabled(e.name,t),i()}catch(e){a(e.message)}};return(0,C.jsx)(`ul`,{className:`rounded-3xl bg-surface border border-border/70 shadow-sm divide-y divide-border/70 overflow-hidden`,children:e.map(e=>(0,C.jsxs)(`li`,{className:t(`flex items-center gap-3 px-4 py-3`,!e.enabled&&`opacity-60`),children:[(0,C.jsxs)(`button`,{type:`button`,onClick:()=>n(e.name),className:`flex min-w-0 flex-1 items-center gap-3 text-left`,children:[(0,C.jsx)(`span`,{className:`rounded-2xl bg-accent/12 text-accent p-2`,children:(0,C.jsx)(v,{size:17})}),(0,C.jsxs)(`span`,{className:`min-w-0 flex-1`,children:[(0,C.jsxs)(`span`,{className:`block text-[14.5px] font-medium`,children:[`/`,e.name]}),(0,C.jsx)(`span`,{className:`text-[12.5px] text-muted line-clamp-2`,children:e.description})]}),(0,C.jsx)(_,{size:17,className:`shrink-0 text-muted`})]}),(0,C.jsx)(`button`,{type:`button`,role:`switch`,"aria-checked":e.enabled,"aria-label":o(`Use /{name}`,{name:e.name}),onClick:()=>void c(e,!e.enabled),className:t(`relative h-6 w-10 shrink-0 rounded-full transition`,e.enabled?`bg-accent`:`bg-border`),children:(0,C.jsx)(`span`,{className:t(`absolute top-0.5 h-5 w-5 rounded-full bg-white shadow transition`,e.enabled?`left-[18px]`:`left-0.5`)})})]},e.name))})}function D({name:t,onBack:n,onUse:i,onGone:a}){let{toast:o}=s(),l=r(),[m,h]=(0,S.useState)(null),[_,v]=(0,S.useState)(!1),x=()=>u.skill(t).then(h).catch(e=>o(e.message));(0,S.useEffect)(()=>{x()},[t]);let w=async()=>{if(m&&window.confirm(l(`Delete the skill “{name}”? Its folder goes with it.`,{name:m.name})))try{await u.deleteSkill(m.name),a()}catch(e){o(e.message)}};return _&&m?(0,C.jsx)(O,{initial:m,onCancel:()=>v(!1),onSaved:()=>{v(!1),x()}}):(0,C.jsxs)(`div`,{className:`flex h-full flex-col`,children:[(0,C.jsx)(y,{onBack:n,backLabel:l(`Skills`),title:m?(0,C.jsxs)(`span`,{className:`font-mono`,children:[`/`,m.name]}):l(`Skills`),description:m&&(0,C.jsxs)(C.Fragment,{children:[m.source===`built-in`?l(`Built in`):l(`Yours`),m.updated_at?` · ${l(`updated {when}`,{when:e(m.updated_at)})}`:``,m.metadata.author?` · ${m.metadata.author}`:``]})}),(0,C.jsxs)(`div`,{className:`flex-1 overflow-y-auto px-4 pb-6 space-y-4`,children:[!m&&(0,C.jsx)(`div`,{className:`py-10 flex justify-center text-muted`,children:(0,C.jsx)(c,{className:`animate-spin`,size:20})}),m&&(0,C.jsxs)(C.Fragment,{children:[(0,C.jsxs)(`div`,{className:`flex gap-2`,children:[(0,C.jsxs)(`button`,{type:`button`,onClick:()=>i(m.name),className:`flex-1 rounded-2xl bg-accent text-accent-fg px-3.5 py-2.5 text-[14px] font-medium flex items-center justify-center gap-1.5`,children:[(0,C.jsx)(g,{size:15}),` `,l(`Use in chat`)]}),(0,C.jsxs)(`button`,{type:`button`,onClick:()=>v(!0),className:`rounded-2xl bg-surface border border-border/70 px-3.5 py-2.5 text-[14px] font-medium flex items-center gap-1.5`,children:[(0,C.jsx)(d,{size:15}),` `,m.source===`built-in`?l(`Make your own copy`):l(`Edit`)]}),m.source===`yours`&&(0,C.jsx)(`button`,{type:`button`,"aria-label":l(`Delete`),onClick:()=>void w(),className:`rounded-2xl bg-surface border border-border/70 px-3 py-2.5 text-muted hover:text-rose-500`,children:(0,C.jsx)(f,{size:17})})]}),(0,C.jsx)(`div`,{className:`rounded-3xl bg-surface border border-border/70 shadow-sm p-4`,children:(0,C.jsx)(`p`,{className:`text-[14px] leading-snug`,children:m.description})}),(0,C.jsx)(`div`,{className:`rounded-3xl bg-surface border border-border/70 shadow-sm p-4 text-[14px]`,children:(0,C.jsx)(p,{text:m.body})}),m.files.length>0&&(0,C.jsxs)(`div`,{className:`rounded-3xl bg-surface border border-border/70 shadow-sm p-4`,children:[(0,C.jsx)(`div`,{className:`text-[12px] font-semibold uppercase tracking-wide text-muted mb-2`,children:l(`Files that come with it`)}),(0,C.jsx)(`ul`,{className:`space-y-1`,children:m.files.map(e=>(0,C.jsxs)(`li`,{className:`flex items-center gap-2 text-[13.5px] font-mono`,children:[(0,C.jsx)(b,{size:15,className:`text-muted`}),` `,e]},e))})]}),(0,C.jsx)(`p`,{className:`px-1 text-[12px] text-muted break-all`,children:m.path})]})]})]})}function O({initial:e,onCancel:t,onSaved:n}){let{toast:i}=s(),a=r(),[o,c]=(0,S.useState)(e?.name??``),[l,d]=(0,S.useState)(e?.content??``),[f,p]=(0,S.useState)(``),[m,h]=(0,S.useState)(!1),[g,_]=(0,S.useState)(``),v=/^[a-z0-9](?:[a-z0-9-]{0,62}[a-z0-9])?$/.test(o),b=async()=>{h(!0),_(``);try{let e=l.trim()?l:w(o);n(await u.saveSkill(o,e.replace(/^---\nname: .*\n/,`---\nname: ${o}\n`)))}catch(e){_(e.message)}finally{h(!1)}},T=async()=>{h(!0),_(``);try{n(await u.importSkill(f.trim()))}catch(e){_(e.message),i(e.message)}finally{h(!1)}};return(0,C.jsxs)(`div`,{className:`flex h-full flex-col`,children:[(0,C.jsx)(y,{onBack:t,title:a(e?`Edit skill`:`New skill`),description:e?.source===`built-in`?a(`Saving makes a copy of yours with the same name; it replaces the built-in one.`):a(`A SKILL.md: a name and a one-line description up top, then the steps in Markdown.`)}),(0,C.jsxs)(`div`,{className:`flex-1 overflow-y-auto px-4 pb-6 space-y-4`,children:[!e&&(0,C.jsxs)(`div`,{className:`rounded-3xl bg-surface border border-border/70 shadow-sm p-3.5 space-y-2`,children:[(0,C.jsxs)(`div`,{className:`text-[12px] font-semibold uppercase tracking-wide text-muted flex items-center gap-1.5`,children:[(0,C.jsx)(x,{size:13}),` `,a(`From a link`)]}),(0,C.jsxs)(`div`,{className:`flex gap-2`,children:[(0,C.jsx)(`input`,{value:f,onChange:e=>p(e.target.value),placeholder:`https://github.com/…/skills/pdf`,inputMode:`url`,autoComplete:`off`,className:`flex-1 min-w-0 rounded-2xl bg-surface-2 px-3.5 py-2.5 text-[14px] outline-none focus:ring-2 focus:ring-accent/40`}),(0,C.jsx)(`button`,{type:`button`,disabled:!f.trim().startsWith(`https://`)||m,onClick:()=>void T(),className:`rounded-2xl bg-surface-2 px-3.5 py-2.5 text-[14px] font-medium disabled:opacity-50`,children:a(`Fetch`)})]}),(0,C.jsx)(`p`,{className:`text-[12px] text-muted`,children:a(`A raw SKILL.md link, or a GitHub folder or file page.`)})]}),(0,C.jsxs)(`div`,{className:`rounded-3xl bg-surface border border-border/70 shadow-sm p-3.5 space-y-2.5`,children:[(0,C.jsxs)(`label`,{className:`block`,children:[(0,C.jsx)(`span`,{className:`text-[12px] font-semibold uppercase tracking-wide text-muted`,children:a(`Name`)}),(0,C.jsx)(`input`,{value:o,onChange:e=>c(e.target.value.toLowerCase().replace(/[^a-z0-9-]/g,`-`)),placeholder:`weekly-review`,disabled:!!e,autoComplete:`off`,className:`mt-1 w-full rounded-2xl bg-surface-2 px-3.5 py-2.5 text-[14px] font-mono outline-none focus:ring-2 focus:ring-accent/40 disabled:opacity-70`})]}),(0,C.jsxs)(`label`,{className:`block`,children:[(0,C.jsx)(`span`,{className:`text-[12px] font-semibold uppercase tracking-wide text-muted`,children:`SKILL.md`}),(0,C.jsx)(`textarea`,{value:l,onChange:e=>d(e.target.value),onFocus:()=>{!l&&v&&d(w(o))},rows:16,spellCheck:!1,placeholder:v?w(o):a(`Pick a name first; a template appears here.`),className:`mt-1 w-full resize-y rounded-2xl bg-surface-2 px-3.5 py-2.5 text-[13px] font-mono leading-relaxed outline-none focus:ring-2 focus:ring-accent/40`})]}),g&&(0,C.jsx)(`div`,{className:`text-[13px] text-rose-600 dark:text-rose-400 break-words`,children:g}),(0,C.jsxs)(`div`,{className:`flex gap-2`,children:[(0,C.jsx)(`button`,{type:`button`,onClick:t,className:`rounded-2xl bg-surface-2 px-3.5 py-2.5 text-[14px] font-medium`,children:a(`Cancel`)}),(0,C.jsx)(`button`,{type:`button`,disabled:!v||m,onClick:()=>void b(),className:`flex-1 rounded-2xl bg-accent text-accent-fg px-3.5 py-2.5 text-[14px] font-medium disabled:opacity-50`,children:a(m?`Saving…`:`Save`)})]})]})]})]})}export{T as SkillsScreen}; \ No newline at end of file diff --git a/nanomuse/server/static/assets/StarNudge-Cr_QPa4y.js b/nanomuse/server/static/assets/StarNudge-Df6LQyo9.js similarity index 71% rename from nanomuse/server/static/assets/StarNudge-Cr_QPa4y.js rename to nanomuse/server/static/assets/StarNudge-Df6LQyo9.js index 64bbd8482..05cb4e9fc 100644 --- a/nanomuse/server/static/assets/StarNudge-Cr_QPa4y.js +++ b/nanomuse/server/static/assets/StarNudge-Df6LQyo9.js @@ -1 +1 @@ -import{E as e,J as t,K as n,L as r,Q as i,W as a,Y as o,b as s,x as c}from"./MuseHeader-BvAlmxiL.js";import{t as ee}from"./external-link-V2ISE5bW.js";import{a as l,i as te}from"./Form-C77NCy9F.js";var u=t(`bug`,[[`path`,{d:`M12 20v-9`,key:`1qisl0`}],[`path`,{d:`M14 7a4 4 0 0 1 4 4v3a6 6 0 0 1-12 0v-3a4 4 0 0 1 4-4z`,key:`uouzyp`}],[`path`,{d:`M14.12 3.88 16 2`,key:`qol33r`}],[`path`,{d:`M21 21a4 4 0 0 0-3.81-4`,key:`1b0z45`}],[`path`,{d:`M21 5a4 4 0 0 1-3.55 3.97`,key:`5cxbf6`}],[`path`,{d:`M22 13h-4`,key:`1jl80f`}],[`path`,{d:`M3 21a4 4 0 0 1 3.81-4`,key:`1fjd4g`}],[`path`,{d:`M3 5a4 4 0 0 0 3.55 3.97`,key:`1d7oge`}],[`path`,{d:`M6 13H2`,key:`82j7cp`}],[`path`,{d:`m8 2 1.88 1.88`,key:`fmnt4t`}],[`path`,{d:`M9 7.13V6a3 3 0 1 1 6 0v1.13`,key:`1vgav8`}]]),ne=t(`github`,[[`path`,{d:`M15 22v-4a4.8 4.8 0 0 0-1-3.5c3 0 6-2 6-5.5.08-1.25-.27-2.48-1-3.5.28-1.15.28-2.35 0-3.5 0 0-1 0-3 1.5-2.64-.5-5.36-.5-8 0C6 2 5 2 5 2c-.3 1.15-.3 2.35 0 3.5A5.403 5.403 0 0 0 4 9c0 3.5 3 5.5 6 5.5-.39.49-.68 1.05-.85 1.65-.17.6-.22 1.23-.15 1.85v4`,key:`tonef`}],[`path`,{d:`M9 18c-4.51 2-5-2-7-2`,key:`9comsn`}]]),d=t(`heart-handshake`,[[`path`,{d:`M19.414 14.414C21 12.828 22 11.5 22 9.5a5.5 5.5 0 0 0-9.591-3.676.6.6 0 0 1-.818.001A5.5 5.5 0 0 0 2 9.5c0 2.3 1.5 4 3 5.5l5.535 5.362a2 2 0 0 0 2.879.052 2.12 2.12 0 0 0-.004-3 2.124 2.124 0 1 0 3-3 2.124 2.124 0 0 0 3.004 0 2 2 0 0 0 0-2.828l-1.881-1.882a2.41 2.41 0 0 0-3.409 0l-1.71 1.71a2 2 0 0 1-2.828 0 2 2 0 0 1 0-2.828l2.823-2.762`,key:`17lmqv`}]]),f=t(`star`,[[`path`,{d:`M11.525 2.295a.53.53 0 0 1 .95 0l2.31 4.679a2.123 2.123 0 0 0 1.595 1.16l5.166.756a.53.53 0 0 1 .294.904l-3.736 3.638a2.123 2.123 0 0 0-.611 1.878l.882 5.14a.53.53 0 0 1-.771.56l-4.618-2.428a2.122 2.122 0 0 0-1.973 0L6.396 21.01a.53.53 0 0 1-.77-.56l.881-5.139a2.122 2.122 0 0 0-.611-1.879L2.16 9.795a.53.53 0 0 1 .294-.906l5.165-.755a2.122 2.122 0 0 0 1.597-1.16z`,key:`r04s7s`}]]),p=i(o(),1),m={version:1,updated:`2026-10`,capabilities:[`chat`,`vision`,`image`,`video`],auth_kinds:[`key`,`none`,`oauth-chatgpt`,`oauth-claude`,`oauth-openrouter`,`device-kimi`],providers:[{id:`bailian`,name:`Alibaba Cloud Bailian`,name_zh:`阿里云百炼`,protocol:`openai`,base_url:`https://dashscope.aliyuncs.com/compatible-mode/v1`,key_url:`https://bailian.console.aliyun.com/?apiKey=1`,key_hint:`sk-…`,auth:[`key`],regions:[`cn`],capabilities:[`chat`,`vision`,`image`,`video`],defaults:{chat:`deepseek-v4.1-flash`,hands:`qwen3.8-27b`,image:`qwen-image-3.0`,video:`wan2.2-i2v-flash`},note:`One key for chat, hands, pictures and clips. Signs up accounts with a mainland China identity only; the international edition (dashscope-intl) does not carry these models. Pictures and clips go through Model Studio's own API, which nanoMuse speaks.`,note_zh:`一把 key 覆盖对话、手、画图和视频。只给中国大陆身份注册;国际版(dashscope-intl)没有这几个模型。画图和视频走百炼自己的接口,nanoMuse 已支持。`,verified:`2026-10`},{id:`deepseek`,name:`DeepSeek`,name_zh:`DeepSeek(深度求索)`,protocol:`openai`,base_url:`https://api.deepseek.com/v1`,key_url:`https://platform.deepseek.com/api_keys`,key_hint:`sk-…`,auth:[`key`],regions:[`cn`,`global`],capabilities:[`chat`,`vision`],defaults:{chat:`deepseek-flash`,hands:`deepseek-flash`},note:`deepseek-flash (DeepSeek-V4.1-Flash) reads pictures; deepseek-v4-pro is text only. No image or video models.`,note_zh:`deepseek-flash(DeepSeek-V4.1-Flash)能看图;deepseek-v4-pro 只处理文字。没有图像和视频模型。`,verified:`2026-10`,reasoning:{doc:`https://api-docs.deepseek.com/guides/thinking_mode`,wire:`thinking+reasoning_effort`,rules:[{models:`^deepseek-`,levels:[`low`,`high`,`max`],default:`high`}]}},{id:`moonshot`,name:`Kimi (Moonshot AI)`,name_zh:`Kimi(月之暗面)`,protocol:`openai`,base_url:`https://api.moonshot.cn/v1`,base_url_global:`https://api.moonshot.ai/v1`,key_url:`https://platform.moonshot.cn/console/api-keys`,key_url_global:`https://platform.kimi.ai/console`,key_hint:`sk-…`,auth:[`key`,`device-kimi`],regions:[`cn`,`global`],capabilities:[`chat`,`vision`],defaults:{chat:`kimi-k2.6`,hands:`kimi-k2.6`},note:`Two editions: api.moonshot.cn for mainland China, api.moonshot.ai elsewhere, each with its own console and keys. kimi-k2.6 and kimi-k3 read pictures. The phone apps can sign in with a Kimi account (device code) instead of a key.`,note_zh:`两个版本:中国大陆用 api.moonshot.cn,海外用 api.moonshot.ai,各自有控制台和 key。kimi-k2.6、kimi-k3 能看图。手机 App 可以用 Kimi 账号登录(设备码),不用贴 key。`,verified:`2026-10`,reasoning:{doc:`https://platform.moonshot.ai/docs/api/chat`,wire:`reasoning_effort`,rules:[{models:`^kimi-k3`,levels:[`low`,`high`,`max`],default:`max`}]}},{id:`zhipu`,name:`Zhipu GLM`,name_zh:`智谱 GLM`,protocol:`openai`,base_url:`https://open.bigmodel.cn/api/paas/v4`,key_url:`https://open.bigmodel.cn/usercenter/apikeys`,key_hint:`xxxxxxxx.xxxxxxxx`,auth:[`key`],regions:[`cn`],capabilities:[`chat`,`vision`,`image`],defaults:{chat:`glm-5.3`,hands:`glm-4.6v`,image:`glm-image`},note:`glm-4.6v reads pictures; pictures are drawn by glm-image or cogview-4 through /images/generations.`,note_zh:`glm-4.6v 能看图;画图用 glm-image 或 cogview-4,走 /images/generations。`,verified:`2026-10`,reasoning:{doc:`https://docs.bigmodel.cn/api-reference/%E6%A8%A1%E5%9E%8B-api/%E5%AF%B9%E8%AF%9D%E8%A1%A5%E5%85%A8`,wire:`thinking+reasoning_effort`,rules:[{models:`^glm-5\\.3`,levels:[`low`,`high`,`max`],default:`max`},{models:`^glm-5\\.2`,levels:[`high`,`max`],default:`max`}]}},{id:`siliconflow`,name:`SiliconFlow`,name_zh:`硅基流动`,protocol:`openai`,base_url:`https://api.siliconflow.cn/v1`,key_url:`https://cloud.siliconflow.cn/account/ak`,key_hint:`sk-…`,auth:[`key`],regions:[`cn`],capabilities:[`chat`,`vision`,`image`],defaults:{chat:`deepseek-ai/DeepSeek-V4-Flash`,hands:`Qwen/Qwen3-VL-32B-Instruct`,image:`Qwen/Qwen-Image`},note:`Many open models behind one key; model ids carry the maker's prefix. Pictures through /images/generations (Qwen-Image, Kolors, FLUX).`,note_zh:`一把 key 后面是许多开源模型,模型 id 带厂商前缀。画图走 /images/generations(Qwen-Image、Kolors、FLUX)。`,verified:`2026-10`,reasoning:{doc:`https://docs.siliconflow.cn/cn/api-reference/chat-completions/chat-completions`,wire:`reasoning_effort`,rules:[{models:`^(Pro/)?deepseek-ai/DeepSeek-V4(-|$)`,levels:[`high`,`max`],default:`high`},{models:`^Pro/zai-org/GLM-5\\.2`,levels:[`high`,`max`],default:`high`}]}},{id:`volcengine`,name:`Volcengine Ark (Doubao)`,name_zh:`火山方舟(豆包)`,protocol:`openai`,base_url:`https://ark.cn-beijing.volces.com/api/v3`,key_url:`https://console.volcengine.com/ark/region:ark+cn-beijing/apiKey`,key_hint:`xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx`,auth:[`key`],regions:[`cn`],capabilities:[`chat`,`vision`,`image`],defaults:{chat:`doubao-seed-2-0-pro-260215`,hands:`doubao-seed-2-0-pro-260215`,image:`doubao-seedream-5-0-lite-260128`},note:`Model ids are dated deployments; the live list has the exact ones. Doubao Seed 2.0 reads pictures; Seedream draws them through /images/generations. Seedance video uses Ark's own task API, which nanoMuse does not speak, so clips are left out.`,note_zh:`模型 id 带日期后缀,以实时列表为准。豆包 Seed 2.0 能看图;Seedream 画图走 /images/generations。Seedance 视频走方舟自己的任务接口,nanoMuse 还不支持,所以不列视频。`,verified:`2026-10`,reasoning:{doc:`https://docs.volcengine.com/docs/ark/model-parameter-support?lang=zh`,wire:`reasoning_effort`,rules:[{models:`^doubao-seed-2-`,levels:[`minimal`,`low`,`medium`,`high`],default:`high`},{models:`^deepseek-v4-`,levels:[`low`,`high`,`max`],default:`high`},{models:`^glm-5-2`,levels:[`high`,`max`],default:`max`}]}},{id:`minimax`,name:`MiniMax`,name_zh:`MiniMax(稀宇科技)`,protocol:`openai`,base_url:`https://api.minimaxi.com/v1`,base_url_global:`https://api.minimax.io/v1`,key_url:`https://platform.minimaxi.com/user-center/basic-information/interface-key`,key_hint:`eyJ…`,auth:[`key`],regions:[`cn`,`global`],capabilities:[`chat`,`vision`],defaults:{chat:`MiniMax-M3`,hands:`MiniMax-M3`},note:`Two editions: api.minimaxi.com for mainland China, api.minimax.io elsewhere. MiniMax-M3 reads pictures; the M2 series is text only.`,note_zh:`两个版本:中国大陆用 api.minimaxi.com,海外用 api.minimax.io。MiniMax-M3 能看图;M2 系列只处理文字。`,verified:`2026-10`,reasoning:{doc:`https://platform.minimax.io/docs/api-reference/text-chat`,wire:`reasoning_effort`,rules:[{models:`^MiniMax-M3\\.1`,levels:[`low`,`medium`,`high`,`xhigh`,`max`],default:`max`}]}},{id:`openrouter`,name:`OpenRouter`,name_zh:`OpenRouter`,protocol:`openai`,base_url:`https://openrouter.ai/api/v1`,key_url:`https://openrouter.ai/keys`,key_hint:`sk-or-v1-…`,auth:[`key`,`oauth-openrouter`],regions:[`global`],capabilities:[`chat`,`vision`,`image`],defaults:{chat:`deepseek/deepseek-v4.1-flash`,hands:`qwen/qwen3.8-27b`,image:`openai/gpt-image-2`},note:`One account, one key, pay as you go, international cards; models carry the maker's prefix. Pictures only through image-output models (openai/gpt-image-2, google/gemini-2.5-flash-image, bytedance-seed/seedream-4.5) on OpenRouter's Image API (/api/v1/images). The phone apps can sign in to OpenRouter instead of pasting a key.`,note_zh:`一个账号一把 key,按量付费,国际信用卡;模型带厂商前缀。画图只能用出图模型(openai/gpt-image-2、google/gemini-2.5-flash-image、bytedance-seed/seedream-4.5),走 OpenRouter 的图像接口(/api/v1/images)。手机 App 可以直接登录 OpenRouter,不用贴 key。`,verified:`2026-10`,reasoning:{doc:`https://openrouter.ai/docs/use-cases/reasoning-tokens`,wire:`reasoning.effort`,listed:!0,rules:[]}},{id:`openai`,name:`OpenAI`,name_zh:`OpenAI`,protocol:`openai`,base_url:`https://api.openai.com/v1`,key_url:`https://platform.openai.com/api-keys`,key_hint:`sk-proj-…`,auth:[`key`,`oauth-chatgpt`],auth_capabilities:{"oauth-chatgpt":[`chat`,`vision`]},regions:[`global`],capabilities:[`chat`,`vision`,`image`],defaults:{chat:`gpt-5.4-mini`,hands:`gpt-5.4`,image:`gpt-image-2.5-flare`},note:`With an API key: chat, hands and pictures (gpt-image-2.5-flare / gpt-image-2 through /images/generations). Signed in with a ChatGPT plan (the Codex OAuth): chat and hands only; the Codex backend has no image or video endpoints. OpenAI's terms cover using a ChatGPT plan inside OpenAI's own Codex; other apps have had this access cut off before (OpenCode, January 2026). If it stops working, an API key does.`,note_zh:`用 API key:对话、手、画图(gpt-image-2.5-flare / gpt-image-2,走 /images/generations)。用 ChatGPT 订阅登录(Codex 的 OAuth):只有对话和手,Codex 后端没有图像和视频接口。OpenAI 的条款只允许在它自己的 Codex 里使用 ChatGPT 订阅;其他应用的这条路曾被切断过(OpenCode,2026 年 1 月)。如果哪天不能用了,API key 还能用。`,verified:`2026-10`,reasoning:{doc:`https://developers.openai.com/api/docs/guides/reasoning`,wire:`reasoning_effort`,rules:[{models:`^o[1-9]`,levels:[`low`,`medium`,`high`],default:`medium`},{models:`^gpt-5(-|$)`,levels:[`minimal`,`low`,`medium`,`high`],default:`medium`},{models:`^gpt-5\\.1(-|$)`,levels:[`low`,`medium`,`high`],default:`none`},{models:`^gpt-5\\.4`,levels:[`low`,`medium`,`high`,`xhigh`],default:`none`},{models:`^gpt-5\\.[235-9]`,levels:[`low`,`medium`,`high`,`xhigh`]},{models:`^gpt-6`,levels:[`low`,`medium`,`high`,`xhigh`]}]}},{id:`anthropic`,name:`Anthropic Claude`,name_zh:`Anthropic Claude`,protocol:`anthropic`,base_url:`https://api.anthropic.com`,key_url:`https://platform.claude.com/settings/keys`,key_hint:`sk-ant-…`,auth:[`key`,`oauth-claude`],regions:[`global`],capabilities:[`chat`,`vision`],defaults:{chat:`claude-sonnet-5-5`,hands:`claude-sonnet-5-5`},note:`The Messages API, not OpenAI's shape; every current Claude model reads pictures. No image or video models. The phone apps can sign in with a Claude account instead of a key.`,note_zh:`用的是 Messages 接口,不是 OpenAI 格式;现行 Claude 模型都能看图。没有图像和视频模型。手机 App 可以用 Claude 账号登录,不用贴 key。`,verified:`2026-10`,reasoning:{doc:`https://docs.claude.com/en/docs/build-with-claude/effort`,wire:`output_config.effort`,rules:[{models:`^claude-(opus|haiku)-5-5`,levels:[`low`,`medium`,`high`,`xhigh`,`max`],default:`medium`},{models:`^claude-(opus|sonnet)-4-6`,levels:[`low`,`medium`,`high`,`max`],default:`high`},{models:`^claude-(opus-4-[78]|opus-5|sonnet-5|haiku-5|fable-5|mythos-5)`,levels:[`low`,`medium`,`high`,`xhigh`,`max`],default:`high`}]}},{id:`gemini`,name:`Google Gemini`,name_zh:`Google Gemini`,protocol:`gemini`,base_url:`https://generativelanguage.googleapis.com/v1beta/openai`,key_url:`https://aistudio.google.com/apikey`,key_hint:`AIza…`,auth:[`key`],regions:[`global`],capabilities:[`chat`,`vision`,`image`],defaults:{chat:`gemini-3.8-flash`,hands:`gemini-3.8-flash`,image:`gemini-2.5-flash-image`},note:`Google's OpenAI-compatible layer. Gemini models read pictures. Pictures through /images/generations work with gemini-2.5-flash-image and gemini-3-pro-image-preview only; the newer 3.1 image models are not served there. Veo video is not on the compatible layer, so clips are left out.`,note_zh:`Google 的 OpenAI 兼容层。Gemini 模型能看图。走 /images/generations 画图只支持 gemini-2.5-flash-image 和 gemini-3-pro-image-preview,更新的 3.1 出图模型不在兼容层上。Veo 视频不走兼容层,所以不列视频。`,verified:`2026-10`,reasoning:{doc:`https://ai.google.dev/gemini-api/docs/openai`,wire:`reasoning_effort`,rules:[{models:`^gemini-(2\\.5|3)`,levels:[`low`,`medium`,`high`]}]}},{id:`xai`,name:`xAI Grok`,name_zh:`xAI Grok`,protocol:`openai`,base_url:`https://api.x.ai/v1`,key_url:`https://console.x.ai`,key_hint:`xai-…`,auth:[`key`],regions:[`global`],capabilities:[`chat`,`vision`,`image`],defaults:{chat:`grok-4.7`,hands:`grok-4.7`,image:`grok-imagine-image-2.0`},note:`grok-4.7 reads pictures (JPEG and PNG). Pictures through /images/generations with grok-imagine-image-2.0. Grok Imagine video uses xAI's own endpoints, so clips are left out.`,note_zh:`grok-4.7 能看图(JPEG、PNG)。画图走 /images/generations,模型 grok-imagine-image-2.0。Grok Imagine 视频走 xAI 自己的接口,所以不列视频。`,verified:`2026-10`,reasoning:{doc:`https://docs.x.ai/docs/guides/reasoning`,wire:`reasoning_effort`,rules:[{models:`^grok-4\\.5`,levels:[`low`,`medium`,`high`],default:`high`},{models:`^grok-4\\.[6-9]`,levels:[`low`,`medium`,`high`,`xhigh`],default:`high`}]}},{id:`groq`,name:`Groq`,name_zh:`Groq`,protocol:`openai`,base_url:`https://api.groq.com/openai/v1`,key_url:`https://console.groq.com/keys`,key_hint:`gsk_…`,auth:[`key`],regions:[`global`],capabilities:[`chat`,`vision`],defaults:{chat:`openai/gpt-oss-120b`,hands:`qwen/qwen3.8-27b`},note:`Fast hosting of open models. qwen/qwen3.8-27b reads pictures; gpt-oss and Llama do not. No image or video models.`,note_zh:`开源模型的高速托管。qwen/qwen3.8-27b 能看图;gpt-oss 和 Llama 不能。没有图像和视频模型。`,verified:`2026-10`,reasoning:{doc:`https://console.groq.com/docs/reasoning`,wire:`reasoning_effort`,rules:[{models:`^openai/gpt-oss-`,levels:[`low`,`medium`,`high`]},{models:`^qwen/qwen3\\.8`,levels:[`low`,`medium`,`high`],default:`none`}]}},{id:`mistral`,name:`Mistral AI`,name_zh:`Mistral AI`,protocol:`openai`,base_url:`https://api.mistral.ai/v1`,key_url:`https://console.mistral.ai/api-keys`,key_hint:`…`,auth:[`key`],regions:[`global`],capabilities:[`chat`,`vision`],defaults:{chat:`mistral-medium-2508`,hands:`mistral-medium-2508`},note:`mistral-large-2512, mistral-medium-2508, mistral-small-2506 and the Ministral 3 models read pictures. No image or video models.`,note_zh:`mistral-large-2512、mistral-medium-2508、mistral-small-2506 和 Ministral 3 系列能看图。没有图像和视频模型。`,verified:`2026-10`,reasoning:{doc:`https://docs.mistral.ai/capabilities/reasoning/`,wire:`reasoning_effort`,rules:[{models:`^mistral-(small-latest|medium-3-5|large-4-0)`,levels:[`high`],default:`none`},{models:`^zai-glm-5-3`,levels:[`low`,`high`,`max`]}]}},{id:`opencode-zen`,name:`OpenCode Zen`,name_zh:`OpenCode Zen`,protocol:`openai`,base_url:`https://opencode.ai/zen/v1`,key_url:`https://opencode.ai/auth`,auth:[`key`],regions:[`global`],capabilities:[`chat`],defaults:{chat:`deepseek-v4.1-flash`},note:`OpenCode's own gateway: pay per request from a balance, a key made in the OpenCode console, and a few free models beside the paid ones. Chat answers on the OpenAI shape; the GPT, Claude and Gemini ids on the same host speak the Responses, Messages and Google shapes, which this entry does not reach, and the vision model OpenCode lists is deepseek-v4-flash-vision-exp, the id DeepSeek has retired on its own platform, so the hands are not claimed here. OpenCode publishes no plan sign-in, only a key.`,note_zh:`OpenCode 自己的网关:按请求从余额里扣费,key 在 OpenCode 控制台申请,付费模型之外还有几个免费的。对话走 OpenAI 格式;同一域名上的 GPT、Claude、Gemini 走 Responses、Messages 和 Google 格式,本条目到不了;它列的视觉模型是 deepseek-v4-flash-vision-exp,这个 id 在 DeepSeek 自家平台上已经退役,所以「动手」不列入。OpenCode 没有套餐登录,只有 key。`,verified:`2026-10`},{id:`opencode-go`,name:`OpenCode Go`,name_zh:`OpenCode Go`,protocol:`openai`,base_url:`https://opencode.ai/zen/go/v1`,key_url:`https://opencode.ai/auth`,auth:[`key`],regions:[`global`],capabilities:[`chat`],defaults:{chat:`deepseek-v4.1-flash`},session_header:`x-opencode-session`,note:`A subscription for coding agents: Go ($10 a month) or Go Plus ($40) in the OpenCode console, then a key made there; usage is counted per model against monthly, weekly and five hour limits. OpenCode asks every client to name itself and to send one stable id per conversation in x-opencode-session: the runtime sends both, the desktop reaches Go through its model adapter's own OpenCode Go route, which sends the id and speaks each model's shape, and the phone apps send an id per chat (a hash of its first message, the same on every turn). Outside the desktop only the OpenAI shape is reached, which is where the open coding models answer; the GPT, Grok, Claude, MiniMax and Qwen ids speak the Responses and Messages shapes. The one vision model OpenCode lists (deepseek-v4-flash-vision-exp) is an id DeepSeek has retired on its own platform, so the hands are not claimed here. OpenCode publishes no plan sign-in, only a key.`,note_zh:`面向编程智能体的订阅:在 OpenCode 控制台订阅 Go(每月 10 美元)或 Go Plus(每月 40 美元),再在那里申请 key;用量按模型计,分每月、每周和每 5 小时三档上限。OpenCode 要求每个客户端说明自己是谁,并在 x-opencode-session 里为每个对话带上一个固定的 id:运行时两样都发;桌面版通过模型适配器自带的 OpenCode Go 路由访问,这条路由会带上 id,也按每个模型自己的格式说话;手机端为每个聊天带一个 id(由第一条消息算出,每一轮都一样)。桌面版以外只走 OpenAI 格式,开源编程模型都在这个格式上;GPT、Grok、Claude、MiniMax 和 Qwen 走 Responses 和 Messages 格式。它列的那个视觉模型(deepseek-v4-flash-vision-exp)在 DeepSeek 自家平台上已经退役,所以「动手」不列入。OpenCode 没有套餐登录,只有 key。`,verified:`2026-10`},{id:`ollama`,name:`Ollama`,name_zh:`Ollama(本机)`,protocol:`openai`,base_url:`http://127.0.0.1:11434/v1`,key_url:`https://ollama.com/download`,auth:[`none`],regions:[`cn`,`global`],capabilities:[`chat`],defaults:{chat:`qwen3:8b`},note:`Runs on this machine, no key, nothing leaves it. Hands need a model that reads pictures (a vision model such as a Qwen VL build); the model list says which.`,note_zh:`跑在本机,不要 key,什么都不出去。手需要能看图的模型(例如 Qwen 的 VL 版本),模型列表里能看出来。`,verified:`2026-10`,reasoning:{doc:`https://docs.ollama.com/api/openai-compatibility`,wire:`reasoning_effort`,rules:[{models:`gpt-oss`,levels:[`low`,`medium`,`high`]}]}},{id:`lm-studio`,name:`LM Studio`,name_zh:`LM Studio(本机)`,protocol:`openai`,base_url:`http://127.0.0.1:1234/v1`,key_url:`https://lmstudio.ai`,auth:[`none`],regions:[`cn`,`global`],capabilities:[`chat`],defaults:{},note:`LM Studio's local server, OpenAI-compatible, no key. Vision only if the loaded model has it.`,note_zh:`LM Studio 的本地服务,OpenAI 兼容,不要 key。装了能看图的模型才能用手。`,verified:`2026-10`},{id:`vllm`,name:`vLLM`,name_zh:`vLLM(自建)`,protocol:`openai`,base_url:`http://127.0.0.1:8000/v1`,key_url:`https://docs.vllm.ai`,auth:[`none`,`key`],regions:[`cn`,`global`],capabilities:[`chat`],defaults:{},note:`A vLLM server you run yourself; a key only if you started it with one. Vision only if the served model has it.`,note_zh:`自己跑的 vLLM 服务;启动时设了 key 才需要填。服务的模型能看图才能用手。`,verified:`2026-10`,reasoning:{doc:`https://docs.vllm.ai/en/latest/features/reasoning_outputs/`,wire:`reasoning_effort`,rules:[{models:`gpt-oss`,levels:[`low`,`medium`,`high`]}]}},{id:`custom`,name:`Any OpenAI-compatible endpoint`,name_zh:`任何 OpenAI 兼容接口`,protocol:`openai`,base_url:``,key_url:``,auth:[`key`,`none`],regions:[`cn`,`global`],capabilities:[`chat`],user_capabilities:!0,defaults:{},note:`A gateway, a relay, a server of your own: paste the address (usually ending in /v1) and say what it can do; the person sets the capabilities.`,note_zh:`网关、中转、自己的服务:贴地址(一般以 /v1 结尾),再说明它能做什么,能力由你勾选。`,verified:`2026-10`}]};function h(e){return e?.region?e.region===`cn`:e?.signed_in&&e.channel===`sms`?!0:r()===`zh-CN`}function re(e){return/^\s*(\+|00)(?!86\b)\d/.test(e)}var ie=new Map(m.providers.map(e=>[e.id,e]));function g(e,t){let n=ie.get(e);if(!n)throw Error(`providers.json has no ${e}`);return{id:e,preset:t,label:n.name,keyUrl:n.key_url,baseUrl:n.base_url,chatModel:n.defaults.chat??``,guiModel:n.defaults.hands??n.defaults.chat??``,covers:n.capabilities}}var ae=g(`bailian`,`qwen`),oe=g(`openrouter`,`openrouter`);function _(e){return h(e)?ae:oe}function se(e,t){return h(t)?e(`Alibaba Cloud Bailian is a good start: a new account comes with a free quota, set-up takes about two minutes, and one key covers chat, the hands, pictures and clips.`):e(`Alibaba Cloud Bailian only signs up accounts from mainland China. Outside, OpenRouter is the easy way: one account, one key, pay as you go, for chat, the hands and pictures; clips need Bailian.`)}function ce(e){let t=(e||``).toLowerCase().split(`/`).pop()??``;return t?t.startsWith(`deepseek`)?/v4\.1|vision|ocr/.test(t):t.startsWith(`qwen`)&&(t.includes(`-vl`)||t.startsWith(`qwen3.8`))?!0:null:null}function le(e,t,n){let r=_(n).preset;if(!e.includes(r))return e;let i=h(n),a=e.filter(e=>e!==r);if(i)return[r,...a];let o=a.filter(e=>t[e]?.region===`cn`);return[r,...a.filter(e=>!o.includes(e)),...o]}var ue=[`chat`,`vision`,`image`,`video`],v=m.providers,de=[`ollama`,`lm-studio`,`vllm`],fe={cn:[`bailian`],global:[`openrouter`,`openai`]},y={bailian:`qwen`,moonshot:`kimi`,zhipu:`glm`,volcengine:`doubao`};function pe(e){return y[e]??e}function me(e){return Object.entries(y).find(([,t])=>t===e)?.[0]??(e===`openai_responses`?`openai`:e)}function he(e){return h(e)?`cn`:`global`}function b(e,t){return t===`zh-CN`&&e.name_zh||e.name}function ge(e,t){return t===`global`&&e.regions.includes(`global`)&&e.base_url_global?{base_url:e.base_url_global,key_url:e.key_url_global||e.key_url}:{base_url:e.base_url,key_url:e.key_url}}function x(e,t){return e.regions.includes(t)}function S(e,t,n=v){let r=new Map(n.map(e=>[e.id,e])),i=fe[e].map(e=>r.get(e)).filter(t=>!!t&&x(t,e)),a=n.filter(t=>!i.includes(t)&&!de.includes(t.id)&&t.id!==`custom`&&x(t,e)).sort((e,t)=>t.capabilities.length-e.capabilities.length),o=[...i,...a];return t?o.filter(e=>e.capabilities.includes(t)):o}function _e(e=v){let t=[{id:`chatgpt`,provider:`openai`,name:`ChatGPT`,auth:`oauth-chatgpt`,here:!0},{id:`claude`,provider:`anthropic`,name:`Claude`,auth:`oauth-claude`,here:!1},{id:`kimi`,provider:`moonshot`,name:`Kimi`,auth:`device-kimi`,here:!1},{id:`openrouter`,provider:`openrouter`,name:`OpenRouter`,auth:`oauth-openrouter`,here:!1}],n=[];for(let r of t){let t=e.find(e=>e.id===r.provider);t&&t.auth.includes(r.auth)&&n.push({...r,covers:t.auth_capabilities?.[r.auth]??t.capabilities})}return n}function ve(e,t){switch(t){case`chat`:return e(`Chat`);case`vision`:return e(`Hands`);case`image`:return e(`Pictures`);case`video`:return e(`Clips`)}}function ye(e,t){return e(`covers {list}`,{list:ue.filter(e=>t.includes(e)).map(t=>ve(e,t).toLowerCase()).join(e(`, `))})}function be(e,t,n,r,i=v){let a=S(n,t,i).slice(0,4).map(e=>b(e,r)),o=a.pop()??``,s=a.length?`${a.join(e(`, `))}${e(` or `)}${o}`:o;switch(t){case`image`:return e(`Pictures need a provider with image models: {providers}.`,{providers:s});case`video`:return e(`Clips need a provider with video models: {providers}.`,{providers:s});case`vision`:return e(`The hands need a model that sees pictures: {providers}.`,{providers:s});case`chat`:return e(`Chat needs a model: {providers}.`,{providers:s})}}var xe=`https://nanomuse.cn/own-key`,C=null,w=null;async function Se(e=!1){return C&&!e?C:(w&&!e||(w=c.providers().then(e=>({...e,capabilities:e.capabilities??null,source:`runtime`})).catch(()=>({providers:v,region:``,configured:{},capabilities:null,unavailable:{},source:`bundled`})).then(e=>(C=e,w=null,e))),w)}function Ce(){C=null}function we(e=0){let[t,n]=(0,p.useState)(C);return(0,p.useEffect)(()=>{let t=!0;return Se(e>0).then(e=>t&&n(e)),()=>{t=!1}},[e]),t}function Te(e,t){return!e||e.capabilities===null?null:e.capabilities.includes(t)}var T={version:1,star:{enabled:!0,url:`https://github.com/nano-muse/nanoMuse`,moments:{signed_in:!0,tasks:[3,10,30],new_look:!0,exhausted:!0,days_used:[7,30],goal_done:!0},cooldown_days:7,max_asks:4,text:``,text_zh:``}},Ee=864e5;function E(e){if(typeof e!=`string`)return``;let t=e.trim();return t.length<=200?t:``}function De(e,t,n){let{text:r,text_zh:i}=e.star;return t&&i?i:r||n}var D=e=>typeof e==`object`&&!!e&&!Array.isArray(e),O=(e,t)=>typeof e==`boolean`?e:t,k=(e,t,n,r)=>typeof e==`number`&&Number.isFinite(e)&&Math.trunc(e)>=t&&Math.trunc(e)<=n?Math.trunc(e):r;function A(e,t){if(!Array.isArray(e))return t;let n=new Set;for(let r of e){if(typeof r!=`number`||!Number.isFinite(r)||Math.trunc(r)<1)return t;n.add(Math.trunc(r))}return[...n].sort((e,t)=>e-t)}function Oe(e){let t=T.star;if(!D(e))return structuredClone(T);let n=k(e.version,1,1e9,1),r=D(e.star)?e.star:{},i=D(r.moments)?r.moments:{},a=typeof r.url==`string`&&/^https?:\/\//.test(r.url)&&r.url.length<=200?r.url:t.url;return{version:n,star:{enabled:O(r.enabled,t.enabled),url:a,moments:{signed_in:O(i.signed_in,t.moments.signed_in),tasks:A(i.tasks,t.moments.tasks),new_look:O(i.new_look,t.moments.new_look),exhausted:O(i.exhausted,t.moments.exhausted),days_used:A(i.days_used,t.moments.days_used),goal_done:O(i.goal_done,t.moments.goal_done)},cooldown_days:k(r.cooldown_days,0,365,t.cooldown_days),max_asks:k(r.max_asks,0,50,t.max_asks),text:E(r.text),text_zh:E(r.text_zh)}}}var j={starred:`nm.star.starred`,tasks:`nm.star.tasks`,asks:`nm.star.asks`,lastAsk:`nm.star.last_ask`,shown:`nm.star.shown`,days:`nm.star.days`,lastDay:`nm.star.last_day`,migrated:`nm.star.v2`},ke=[`signed_in`,`first_task`,`tenth_task`,`new_look`],M=e=>{let t=Number(e);return Number.isFinite(t)&&t>=0?Math.trunc(t):0};function N(e){let t=[];try{let n=JSON.parse(e.getItem(j.shown)??`[]`);Array.isArray(n)&&(t=n.filter(e=>typeof e==`string`))}catch{t=[]}let n=e.getItem(j.lastAsk);return{starred:e.getItem(j.starred)===`1`,tasks:M(e.getItem(j.tasks)),asks:M(e.getItem(j.asks)),lastAsk:n&&M(n)||null,shown:t,days:M(e.getItem(j.days)),lastDay:e.getItem(j.lastDay)??``}}function P(e,t){e.setItem(j.starred,t.starred?`1`:`0`),e.setItem(j.tasks,String(t.tasks)),e.setItem(j.asks,String(t.asks)),t.lastAsk?e.setItem(j.lastAsk,String(t.lastAsk)):e.removeItem(j.lastAsk),e.setItem(j.shown,JSON.stringify(t.shown)),e.setItem(j.days,String(t.days)),e.setItem(j.lastDay,t.lastDay)}function Ae(e){let t=N(e);if(e.getItem(j.migrated)===`1`)return t;for(let n of ke){let r=`nm.star.${n}`;e.getItem(r)===`1`&&!t.shown.includes(n)&&(t.shown.push(n),t.asks+=1),e.removeItem(r)}return P(e,t),e.setItem(j.migrated,`1`),t}var F=(e,t)=>e===`tasks`||e===`days_used`?`${e}:${t??0}`:e;function je(e,t,n){let r=e.star;return!r.enabled||t.starred||t.asks>=r.max_asks?!1:t.lastAsk===null||n-t.lastAsk>=r.cooldown_days*Ee}function Me(e,t,n,r,i){if(!je(t,n,r))return!1;let a=t.star.moments;return(e===`tasks`||e===`days_used`?i!==void 0&&a[e].includes(i):a[e])&&!n.shown.includes(F(e,i))}function Ne(e,t,n){let r=N(e);return r.shown.includes(t)||(r.shown.push(t),r.asks+=1,r.lastAsk=n,P(e,r)),r}function Pe(e){let t=N(e);t.starred=!0,P(e,t)}function Fe(e){let t=N(e);return t.tasks+=1,P(e,t),t.tasks}var Ie=e=>`${e.getFullYear()}-${String(e.getMonth()+1).padStart(2,`0`)}-${String(e.getDate()).padStart(2,`0`)}`;function Le(e,t){let n=N(e),r=Ie(t);return n.lastDay===r?{days:n.days,fresh:!1}:(n.days+=1,n.lastDay=r,P(e,n),{days:n.days,fresh:!0})}var I=s(),Re=`https://github.com/nano-muse/nanoMuse`,ze=`https://github.com/nano-muse/nanoMuse/issues/new/choose`,L=`https://nanomuse.cn/#open-source`;function Be({compact:t=!1,className:r}){let i=n();return(0,I.jsxs)(`section`,{className:e(`rounded-[22px] border border-accent/25 bg-accent/[0.06] p-4 dark:bg-accent/[0.10]`,r),children:[(0,I.jsxs)(`a`,{href:L,target:`_blank`,rel:`noreferrer`,className:`flex items-start gap-2 text-[13.5px] font-semibold hover:text-accent`,children:[(0,I.jsx)(d,{size:16,className:`mt-0.5 shrink-0 text-accent`}),(0,I.jsx)(`span`,{className:`min-w-0 flex-1 leading-snug`,children:i(`Free, open source, non-profit`)}),(0,I.jsx)(ee,{size:12,className:`mt-1 shrink-0 text-muted`})]}),(0,I.jsx)(`p`,{className:e(`mt-1.5 leading-relaxed text-fg/85`,t?`text-[12.5px]`:`text-[13px]`),children:i(`nanoMuse is a non-profit open-source community project, free forever. Sign in with a phone number or an e-mail and the model comes with a free allowance, paid by the developer; when it is gone, use your own key (Alibaba Cloud Bailian in mainland China, OpenRouter elsewhere). Nothing is sold; what the relay keeps is in the privacy policy, and Settings → Data controls is yours. Delete the account whenever you like.`)}),(0,I.jsx)(`p`,{className:e(`mt-1.5 leading-relaxed text-fg/85`,t?`text-[12.5px]`:`text-[13px]`),children:i(`The people building it use it every day. Report a bug, ask for a feature, send a pull request: that is what moves the project. A star on GitHub helps others find it.`)}),(0,I.jsxs)(`div`,{className:`mt-3 flex flex-wrap gap-2 text-[12.5px] font-medium`,children:[(0,I.jsxs)(`a`,{href:Re,target:`_blank`,rel:`noreferrer`,onClick:K,className:`inline-flex items-center gap-1.5 rounded-full bg-fg px-3 py-1.5 text-bg hover:opacity-90`,children:[(0,I.jsx)(ne,{size:13}),` `,i(`Star on GitHub`)]}),(0,I.jsxs)(`a`,{href:ze,target:`_blank`,rel:`noreferrer`,className:`inline-flex items-center gap-1.5 rounded-full border border-border bg-surface px-3 py-1.5 text-fg hover:bg-surface-2`,children:[(0,I.jsx)(u,{size:13}),` `,i(`Report a bug or ask for a feature`)]})]})]})}var R=new Map,z={getItem:e=>{try{return localStorage.getItem(e)}catch{return R.get(e)??null}},setItem:(e,t)=>{try{localStorage.setItem(e,t)}catch{R.set(e,t)}},removeItem:e=>{try{localStorage.removeItem(e)}catch{R.delete(e)}}},B=!1;function Ve(){return B?N(z):(B=!0,Ae(z))}var V=T,H=!1,U=null,W=new Set;function He(){return U??=c.nudges().then(e=>{V=Oe(e?.policy)}).catch(()=>{V=T}).finally(()=>{H=!0,W.forEach(e=>e())}),U}function G(){let[,e]=(0,p.useState)(0);return(0,p.useEffect)(()=>{let t=()=>e(e=>e+1);return W.add(t),He(),()=>{W.delete(t)}},[]),{policy:V,ready:H}}var Ue=()=>Fe(z),We=()=>Le(z,new Date),Ge=(e,t)=>H&&Me(e,V,Ve(),Date.now(),t),Ke=(e,t)=>{Ne(z,F(e,t),Date.now())},K=()=>Pe(z);function q(e){K(),window.open(e||V.star.url||`https://github.com/nano-muse/nanoMuse`,`_blank`,`noopener,noreferrer`)}function J(e,t,n){switch(t){case`signed_in`:return e(`Welcome. nanoMuse is free, open source and non-profit, a personal agent for anyone who runs it. If that is worth something to you, a star on GitHub is how the next person finds it.`);case`tasks`:return n===3?e(`Three tasks done. If nanoMuse is useful, a star on GitHub helps the next person find it.`):n===10?e(`Ten tasks together. If nanoMuse has become part of your day, a star on GitHub tells others it is worth a try.`):e(`{n} tasks done. If nanoMuse is useful, a star on GitHub helps the next person find it.`,{n:n??0});case`new_look`:return e(`A new face, drawn for you. If you like where nanoMuse is going, a star on GitHub helps more people find it.`);case`exhausted`:return e(`The free allowance is used up. Thank you for coming this far. If nanoMuse has earned it, a star on GitHub keeps the project in view for the next person.`);case`days_used`:return n===7?e(`A week with nanoMuse. If it has earned a place in your day, a star on GitHub helps the next person find it.`):n===30?e(`A month with nanoMuse. If it has become part of your routine, a star on GitHub tells others it is worth a try.`):e(`{n} days with nanoMuse. If it has earned a place in your day, a star on GitHub helps the next person find it.`,{n:n??0});case`goal_done`:return e(`Goal reached. If nanoMuse helped you get there, a star on GitHub tells the people building it that it did.`)}}var Y=null,X=null;function Z(){let[e,t]=(0,p.useState)(Y??{});return(0,p.useEffect)(()=>{if(Y)return;X??=c.cloudConfig().then(e=>Y=e&&typeof e==`object`?e:{}).catch(()=>Y={});let e=!0;return X.then(n=>e&&t(n)),()=>{e=!1}},[]),e}function Q(e){let{policy:t}=G();return De(t,a()===`zh-CN`,e)}function qe({text:t,onDone:r,className:i}){let a=n(),o=Z(),s=Q(t);return(0,I.jsxs)(`section`,{className:e(`rounded-[22px] border border-amber-400/40 bg-amber-50/70 p-4 dark:bg-amber-400/[0.08]`,i),children:[(0,I.jsxs)(`div`,{className:`flex items-start gap-2.5`,children:[(0,I.jsx)(f,{size:18,className:`mt-0.5 shrink-0 text-amber-500`}),(0,I.jsxs)(`div`,{className:`min-w-0 flex-1`,children:[(0,I.jsx)(`div`,{className:`text-[14px] font-semibold leading-snug`,children:a(`A star on GitHub helps`)}),(0,I.jsx)(`p`,{className:`mt-1 text-[13px] leading-relaxed text-fg/85`,children:s})]})]}),(0,I.jsxs)(`div`,{className:`mt-3 flex flex-wrap gap-2 pl-7`,children:[(0,I.jsx)(`button`,{type:`button`,className:e(te,`!w-auto !py-1.5 !px-3.5 text-[13px]`),onClick:()=>{q(o.repo_url),r()},children:a(`Star on GitHub`)}),(0,I.jsx)(`button`,{type:`button`,className:e(l,`!w-auto !py-1.5 !px-3.5 text-[13px]`),onClick:r,children:a(`Not now`)}),(0,I.jsx)(`button`,{type:`button`,className:e(l,`!w-auto !py-1.5 !px-3.5 text-[13px]`),onClick:()=>{K(),r()},children:a(`I already starred`)})]})]})}function Je({moment:e,n:t,text:r,className:i,due:a=!0}){let o=n(),[s,c]=$(e,a,t);return s?(0,I.jsx)(qe,{text:r??J(o,e,t),onDone:()=>c(!1),className:i}):null}function $(e,t=!0,n){let{ready:r}=G(),[i,a]=(0,p.useState)(!1);return(0,p.useEffect)(()=>{t&&r&&!i&&Ge(e,n)&&(Ke(e,n),a(!0))},[t,r,e,n,i]),[i,a]}export{se as A,he as C,re as D,h as E,f as M,d as N,ce as O,u as P,S,we as T,Te as _,q as a,pe as b,$ as c,L as d,v as f,ge as g,ye as h,K as i,_ as j,le as k,Q as l,me as m,We as n,J as o,xe as p,Ue as r,Z as s,Je as t,Be as u,Ce as v,be as w,b as x,_e as y}; \ No newline at end of file +import{E as e,J as t,K as n,L as r,Q as i,W as a,Y as o,b as s,x as c}from"./MuseHeader-RC--uR8o.js";import{t as ee}from"./external-link-TvxP_dKX.js";import{a as l,i as te}from"./Form-H3s9oTHq.js";var u=t(`bug`,[[`path`,{d:`M12 20v-9`,key:`1qisl0`}],[`path`,{d:`M14 7a4 4 0 0 1 4 4v3a6 6 0 0 1-12 0v-3a4 4 0 0 1 4-4z`,key:`uouzyp`}],[`path`,{d:`M14.12 3.88 16 2`,key:`qol33r`}],[`path`,{d:`M21 21a4 4 0 0 0-3.81-4`,key:`1b0z45`}],[`path`,{d:`M21 5a4 4 0 0 1-3.55 3.97`,key:`5cxbf6`}],[`path`,{d:`M22 13h-4`,key:`1jl80f`}],[`path`,{d:`M3 21a4 4 0 0 1 3.81-4`,key:`1fjd4g`}],[`path`,{d:`M3 5a4 4 0 0 0 3.55 3.97`,key:`1d7oge`}],[`path`,{d:`M6 13H2`,key:`82j7cp`}],[`path`,{d:`m8 2 1.88 1.88`,key:`fmnt4t`}],[`path`,{d:`M9 7.13V6a3 3 0 1 1 6 0v1.13`,key:`1vgav8`}]]),ne=t(`github`,[[`path`,{d:`M15 22v-4a4.8 4.8 0 0 0-1-3.5c3 0 6-2 6-5.5.08-1.25-.27-2.48-1-3.5.28-1.15.28-2.35 0-3.5 0 0-1 0-3 1.5-2.64-.5-5.36-.5-8 0C6 2 5 2 5 2c-.3 1.15-.3 2.35 0 3.5A5.403 5.403 0 0 0 4 9c0 3.5 3 5.5 6 5.5-.39.49-.68 1.05-.85 1.65-.17.6-.22 1.23-.15 1.85v4`,key:`tonef`}],[`path`,{d:`M9 18c-4.51 2-5-2-7-2`,key:`9comsn`}]]),d=t(`heart-handshake`,[[`path`,{d:`M19.414 14.414C21 12.828 22 11.5 22 9.5a5.5 5.5 0 0 0-9.591-3.676.6.6 0 0 1-.818.001A5.5 5.5 0 0 0 2 9.5c0 2.3 1.5 4 3 5.5l5.535 5.362a2 2 0 0 0 2.879.052 2.12 2.12 0 0 0-.004-3 2.124 2.124 0 1 0 3-3 2.124 2.124 0 0 0 3.004 0 2 2 0 0 0 0-2.828l-1.881-1.882a2.41 2.41 0 0 0-3.409 0l-1.71 1.71a2 2 0 0 1-2.828 0 2 2 0 0 1 0-2.828l2.823-2.762`,key:`17lmqv`}]]),f=t(`star`,[[`path`,{d:`M11.525 2.295a.53.53 0 0 1 .95 0l2.31 4.679a2.123 2.123 0 0 0 1.595 1.16l5.166.756a.53.53 0 0 1 .294.904l-3.736 3.638a2.123 2.123 0 0 0-.611 1.878l.882 5.14a.53.53 0 0 1-.771.56l-4.618-2.428a2.122 2.122 0 0 0-1.973 0L6.396 21.01a.53.53 0 0 1-.77-.56l.881-5.139a2.122 2.122 0 0 0-.611-1.879L2.16 9.795a.53.53 0 0 1 .294-.906l5.165-.755a2.122 2.122 0 0 0 1.597-1.16z`,key:`r04s7s`}]]),p=i(o(),1),m={version:1,updated:`2026-10`,capabilities:[`chat`,`vision`,`image`,`video`],auth_kinds:[`key`,`none`,`oauth-chatgpt`,`oauth-claude`,`oauth-openrouter`,`device-kimi`],providers:[{id:`bailian`,name:`Alibaba Cloud Bailian`,name_zh:`阿里云百炼`,protocol:`openai`,base_url:`https://dashscope.aliyuncs.com/compatible-mode/v1`,key_url:`https://bailian.console.aliyun.com/?apiKey=1`,key_hint:`sk-…`,auth:[`key`],regions:[`cn`],capabilities:[`chat`,`vision`,`image`,`video`],defaults:{chat:`deepseek-v4.1-flash`,hands:`qwen3.8-27b`,image:`qwen-image-3.0`,video:`wan2.2-i2v-flash`},note:`One key for chat, hands, pictures and clips. Signs up accounts with a mainland China identity only; the international edition (dashscope-intl) does not carry these models. Pictures and clips go through Model Studio's own API, which nanoMuse speaks.`,note_zh:`一把 key 覆盖对话、手、画图和视频。只给中国大陆身份注册;国际版(dashscope-intl)没有这几个模型。画图和视频走百炼自己的接口,nanoMuse 已支持。`,verified:`2026-10`},{id:`deepseek`,name:`DeepSeek`,name_zh:`DeepSeek(深度求索)`,protocol:`openai`,base_url:`https://api.deepseek.com/v1`,key_url:`https://platform.deepseek.com/api_keys`,key_hint:`sk-…`,auth:[`key`],regions:[`cn`,`global`],capabilities:[`chat`,`vision`],defaults:{chat:`deepseek-flash`,hands:`deepseek-flash`},note:`deepseek-flash (DeepSeek-V4.1-Flash) reads pictures; deepseek-v4-pro is text only. No image or video models.`,note_zh:`deepseek-flash(DeepSeek-V4.1-Flash)能看图;deepseek-v4-pro 只处理文字。没有图像和视频模型。`,verified:`2026-10`,reasoning:{doc:`https://api-docs.deepseek.com/guides/thinking_mode`,wire:`thinking+reasoning_effort`,rules:[{models:`^deepseek-`,levels:[`low`,`high`,`max`],default:`high`}]}},{id:`moonshot`,name:`Kimi (Moonshot AI)`,name_zh:`Kimi(月之暗面)`,protocol:`openai`,base_url:`https://api.moonshot.cn/v1`,base_url_global:`https://api.moonshot.ai/v1`,key_url:`https://platform.moonshot.cn/console/api-keys`,key_url_global:`https://platform.kimi.ai/console`,key_hint:`sk-…`,auth:[`key`,`device-kimi`],regions:[`cn`,`global`],capabilities:[`chat`,`vision`],defaults:{chat:`kimi-k2.6`,hands:`kimi-k2.6`},note:`Two editions: api.moonshot.cn for mainland China, api.moonshot.ai elsewhere, each with its own console and keys. kimi-k2.6 and kimi-k3 read pictures. The phone apps can sign in with a Kimi account (device code) instead of a key.`,note_zh:`两个版本:中国大陆用 api.moonshot.cn,海外用 api.moonshot.ai,各自有控制台和 key。kimi-k2.6、kimi-k3 能看图。手机 App 可以用 Kimi 账号登录(设备码),不用贴 key。`,verified:`2026-10`,reasoning:{doc:`https://platform.moonshot.ai/docs/api/chat`,wire:`reasoning_effort`,rules:[{models:`^kimi-k3`,levels:[`low`,`high`,`max`],default:`max`}]}},{id:`zhipu`,name:`Zhipu GLM`,name_zh:`智谱 GLM`,protocol:`openai`,base_url:`https://open.bigmodel.cn/api/paas/v4`,key_url:`https://open.bigmodel.cn/usercenter/apikeys`,key_hint:`xxxxxxxx.xxxxxxxx`,auth:[`key`],regions:[`cn`],capabilities:[`chat`,`vision`,`image`],defaults:{chat:`glm-5.3`,hands:`glm-4.6v`,image:`glm-image`},note:`glm-4.6v reads pictures; pictures are drawn by glm-image or cogview-4 through /images/generations.`,note_zh:`glm-4.6v 能看图;画图用 glm-image 或 cogview-4,走 /images/generations。`,verified:`2026-10`,reasoning:{doc:`https://docs.bigmodel.cn/api-reference/%E6%A8%A1%E5%9E%8B-api/%E5%AF%B9%E8%AF%9D%E8%A1%A5%E5%85%A8`,wire:`thinking+reasoning_effort`,rules:[{models:`^glm-5\\.3`,levels:[`low`,`high`,`max`],default:`max`},{models:`^glm-5\\.2`,levels:[`high`,`max`],default:`max`}]}},{id:`siliconflow`,name:`SiliconFlow`,name_zh:`硅基流动`,protocol:`openai`,base_url:`https://api.siliconflow.cn/v1`,key_url:`https://cloud.siliconflow.cn/account/ak`,key_hint:`sk-…`,auth:[`key`],regions:[`cn`],capabilities:[`chat`,`vision`,`image`],defaults:{chat:`deepseek-ai/DeepSeek-V4-Flash`,hands:`Qwen/Qwen3-VL-32B-Instruct`,image:`Qwen/Qwen-Image`},note:`Many open models behind one key; model ids carry the maker's prefix. Pictures through /images/generations (Qwen-Image, Kolors, FLUX).`,note_zh:`一把 key 后面是许多开源模型,模型 id 带厂商前缀。画图走 /images/generations(Qwen-Image、Kolors、FLUX)。`,verified:`2026-10`,reasoning:{doc:`https://docs.siliconflow.cn/cn/api-reference/chat-completions/chat-completions`,wire:`reasoning_effort`,rules:[{models:`^(Pro/)?deepseek-ai/DeepSeek-V4(-|$)`,levels:[`high`,`max`],default:`high`},{models:`^Pro/zai-org/GLM-5\\.2`,levels:[`high`,`max`],default:`high`}]}},{id:`volcengine`,name:`Volcengine Ark (Doubao)`,name_zh:`火山方舟(豆包)`,protocol:`openai`,base_url:`https://ark.cn-beijing.volces.com/api/v3`,key_url:`https://console.volcengine.com/ark/region:ark+cn-beijing/apiKey`,key_hint:`xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx`,auth:[`key`],regions:[`cn`],capabilities:[`chat`,`vision`,`image`],defaults:{chat:`doubao-seed-2-0-pro-260215`,hands:`doubao-seed-2-0-pro-260215`,image:`doubao-seedream-5-0-lite-260128`},note:`Model ids are dated deployments; the live list has the exact ones. Doubao Seed 2.0 reads pictures; Seedream draws them through /images/generations. Seedance video uses Ark's own task API, which nanoMuse does not speak, so clips are left out.`,note_zh:`模型 id 带日期后缀,以实时列表为准。豆包 Seed 2.0 能看图;Seedream 画图走 /images/generations。Seedance 视频走方舟自己的任务接口,nanoMuse 还不支持,所以不列视频。`,verified:`2026-10`,reasoning:{doc:`https://docs.volcengine.com/docs/ark/model-parameter-support?lang=zh`,wire:`reasoning_effort`,rules:[{models:`^doubao-seed-2-`,levels:[`minimal`,`low`,`medium`,`high`],default:`high`},{models:`^deepseek-v4-`,levels:[`low`,`high`,`max`],default:`high`},{models:`^glm-5-2`,levels:[`high`,`max`],default:`max`}]}},{id:`minimax`,name:`MiniMax`,name_zh:`MiniMax(稀宇科技)`,protocol:`openai`,base_url:`https://api.minimaxi.com/v1`,base_url_global:`https://api.minimax.io/v1`,key_url:`https://platform.minimaxi.com/user-center/basic-information/interface-key`,key_hint:`eyJ…`,auth:[`key`],regions:[`cn`,`global`],capabilities:[`chat`,`vision`],defaults:{chat:`MiniMax-M3`,hands:`MiniMax-M3`},note:`Two editions: api.minimaxi.com for mainland China, api.minimax.io elsewhere. MiniMax-M3 reads pictures; the M2 series is text only.`,note_zh:`两个版本:中国大陆用 api.minimaxi.com,海外用 api.minimax.io。MiniMax-M3 能看图;M2 系列只处理文字。`,verified:`2026-10`,reasoning:{doc:`https://platform.minimax.io/docs/api-reference/text-chat`,wire:`reasoning_effort`,rules:[{models:`^MiniMax-M3\\.1`,levels:[`low`,`medium`,`high`,`xhigh`,`max`],default:`max`}]}},{id:`openrouter`,name:`OpenRouter`,name_zh:`OpenRouter`,protocol:`openai`,base_url:`https://openrouter.ai/api/v1`,key_url:`https://openrouter.ai/keys`,key_hint:`sk-or-v1-…`,auth:[`key`,`oauth-openrouter`],regions:[`global`],capabilities:[`chat`,`vision`,`image`],defaults:{chat:`deepseek/deepseek-v4.1-flash`,hands:`qwen/qwen3.8-27b`,image:`openai/gpt-image-2`},note:`One account, one key, pay as you go, international cards; models carry the maker's prefix. Pictures only through image-output models (openai/gpt-image-2, google/gemini-2.5-flash-image, bytedance-seed/seedream-4.5) on OpenRouter's Image API (/api/v1/images). The phone apps can sign in to OpenRouter instead of pasting a key.`,note_zh:`一个账号一把 key,按量付费,国际信用卡;模型带厂商前缀。画图只能用出图模型(openai/gpt-image-2、google/gemini-2.5-flash-image、bytedance-seed/seedream-4.5),走 OpenRouter 的图像接口(/api/v1/images)。手机 App 可以直接登录 OpenRouter,不用贴 key。`,verified:`2026-10`,reasoning:{doc:`https://openrouter.ai/docs/use-cases/reasoning-tokens`,wire:`reasoning.effort`,listed:!0,rules:[]}},{id:`openai`,name:`OpenAI`,name_zh:`OpenAI`,protocol:`openai`,base_url:`https://api.openai.com/v1`,key_url:`https://platform.openai.com/api-keys`,key_hint:`sk-proj-…`,auth:[`key`,`oauth-chatgpt`],auth_capabilities:{"oauth-chatgpt":[`chat`,`vision`]},regions:[`global`],capabilities:[`chat`,`vision`,`image`],defaults:{chat:`gpt-5.4-mini`,hands:`gpt-5.4`,image:`gpt-image-2.5-flare`},note:`With an API key: chat, hands and pictures (gpt-image-2.5-flare / gpt-image-2 through /images/generations). Signed in with a ChatGPT plan (the Codex OAuth): chat and hands only; the Codex backend has no image or video endpoints. OpenAI's terms cover using a ChatGPT plan inside OpenAI's own Codex; other apps have had this access cut off before (OpenCode, January 2026). If it stops working, an API key does.`,note_zh:`用 API key:对话、手、画图(gpt-image-2.5-flare / gpt-image-2,走 /images/generations)。用 ChatGPT 订阅登录(Codex 的 OAuth):只有对话和手,Codex 后端没有图像和视频接口。OpenAI 的条款只允许在它自己的 Codex 里使用 ChatGPT 订阅;其他应用的这条路曾被切断过(OpenCode,2026 年 1 月)。如果哪天不能用了,API key 还能用。`,verified:`2026-10`,reasoning:{doc:`https://developers.openai.com/api/docs/guides/reasoning`,wire:`reasoning_effort`,rules:[{models:`^o[1-9]`,levels:[`low`,`medium`,`high`],default:`medium`},{models:`^gpt-5(-|$)`,levels:[`minimal`,`low`,`medium`,`high`],default:`medium`},{models:`^gpt-5\\.1(-|$)`,levels:[`low`,`medium`,`high`],default:`none`},{models:`^gpt-5\\.4`,levels:[`low`,`medium`,`high`,`xhigh`],default:`none`},{models:`^gpt-5\\.[235-9]`,levels:[`low`,`medium`,`high`,`xhigh`]},{models:`^gpt-6`,levels:[`low`,`medium`,`high`,`xhigh`]}]}},{id:`anthropic`,name:`Anthropic Claude`,name_zh:`Anthropic Claude`,protocol:`anthropic`,base_url:`https://api.anthropic.com`,key_url:`https://platform.claude.com/settings/keys`,key_hint:`sk-ant-…`,auth:[`key`,`oauth-claude`],regions:[`global`],capabilities:[`chat`,`vision`],defaults:{chat:`claude-sonnet-5-5`,hands:`claude-sonnet-5-5`},note:`The Messages API, not OpenAI's shape; every current Claude model reads pictures. No image or video models. The phone apps can sign in with a Claude account instead of a key.`,note_zh:`用的是 Messages 接口,不是 OpenAI 格式;现行 Claude 模型都能看图。没有图像和视频模型。手机 App 可以用 Claude 账号登录,不用贴 key。`,verified:`2026-10`,reasoning:{doc:`https://docs.claude.com/en/docs/build-with-claude/effort`,wire:`output_config.effort`,rules:[{models:`^claude-(opus|haiku)-5-5`,levels:[`low`,`medium`,`high`,`xhigh`,`max`],default:`medium`},{models:`^claude-(opus|sonnet)-4-6`,levels:[`low`,`medium`,`high`,`max`],default:`high`},{models:`^claude-(opus-4-[78]|opus-5|sonnet-5|haiku-5|fable-5|mythos-5)`,levels:[`low`,`medium`,`high`,`xhigh`,`max`],default:`high`}]}},{id:`gemini`,name:`Google Gemini`,name_zh:`Google Gemini`,protocol:`gemini`,base_url:`https://generativelanguage.googleapis.com/v1beta/openai`,key_url:`https://aistudio.google.com/apikey`,key_hint:`AIza…`,auth:[`key`],regions:[`global`],capabilities:[`chat`,`vision`,`image`],defaults:{chat:`gemini-3.8-flash`,hands:`gemini-3.8-flash`,image:`gemini-2.5-flash-image`},note:`Google's OpenAI-compatible layer. Gemini models read pictures. Pictures through /images/generations work with gemini-2.5-flash-image and gemini-3-pro-image-preview only; the newer 3.1 image models are not served there. Veo video is not on the compatible layer, so clips are left out.`,note_zh:`Google 的 OpenAI 兼容层。Gemini 模型能看图。走 /images/generations 画图只支持 gemini-2.5-flash-image 和 gemini-3-pro-image-preview,更新的 3.1 出图模型不在兼容层上。Veo 视频不走兼容层,所以不列视频。`,verified:`2026-10`,reasoning:{doc:`https://ai.google.dev/gemini-api/docs/openai`,wire:`reasoning_effort`,rules:[{models:`^gemini-(2\\.5|3)`,levels:[`low`,`medium`,`high`]}]}},{id:`xai`,name:`xAI Grok`,name_zh:`xAI Grok`,protocol:`openai`,base_url:`https://api.x.ai/v1`,key_url:`https://console.x.ai`,key_hint:`xai-…`,auth:[`key`],regions:[`global`],capabilities:[`chat`,`vision`,`image`],defaults:{chat:`grok-4.7`,hands:`grok-4.7`,image:`grok-imagine-image-2.0`},note:`grok-4.7 reads pictures (JPEG and PNG). Pictures through /images/generations with grok-imagine-image-2.0. Grok Imagine video uses xAI's own endpoints, so clips are left out.`,note_zh:`grok-4.7 能看图(JPEG、PNG)。画图走 /images/generations,模型 grok-imagine-image-2.0。Grok Imagine 视频走 xAI 自己的接口,所以不列视频。`,verified:`2026-10`,reasoning:{doc:`https://docs.x.ai/docs/guides/reasoning`,wire:`reasoning_effort`,rules:[{models:`^grok-4\\.5`,levels:[`low`,`medium`,`high`],default:`high`},{models:`^grok-4\\.[6-9]`,levels:[`low`,`medium`,`high`,`xhigh`],default:`high`}]}},{id:`groq`,name:`Groq`,name_zh:`Groq`,protocol:`openai`,base_url:`https://api.groq.com/openai/v1`,key_url:`https://console.groq.com/keys`,key_hint:`gsk_…`,auth:[`key`],regions:[`global`],capabilities:[`chat`,`vision`],defaults:{chat:`openai/gpt-oss-120b`,hands:`qwen/qwen3.8-27b`},note:`Fast hosting of open models. qwen/qwen3.8-27b reads pictures; gpt-oss and Llama do not. No image or video models.`,note_zh:`开源模型的高速托管。qwen/qwen3.8-27b 能看图;gpt-oss 和 Llama 不能。没有图像和视频模型。`,verified:`2026-10`,reasoning:{doc:`https://console.groq.com/docs/reasoning`,wire:`reasoning_effort`,rules:[{models:`^openai/gpt-oss-`,levels:[`low`,`medium`,`high`]},{models:`^qwen/qwen3\\.8`,levels:[`low`,`medium`,`high`],default:`none`}]}},{id:`mistral`,name:`Mistral AI`,name_zh:`Mistral AI`,protocol:`openai`,base_url:`https://api.mistral.ai/v1`,key_url:`https://console.mistral.ai/api-keys`,key_hint:`…`,auth:[`key`],regions:[`global`],capabilities:[`chat`,`vision`],defaults:{chat:`mistral-medium-2508`,hands:`mistral-medium-2508`},note:`mistral-large-2512, mistral-medium-2508, mistral-small-2506 and the Ministral 3 models read pictures. No image or video models.`,note_zh:`mistral-large-2512、mistral-medium-2508、mistral-small-2506 和 Ministral 3 系列能看图。没有图像和视频模型。`,verified:`2026-10`,reasoning:{doc:`https://docs.mistral.ai/capabilities/reasoning/`,wire:`reasoning_effort`,rules:[{models:`^mistral-(small-latest|medium-3-5|large-4-0)`,levels:[`high`],default:`none`},{models:`^zai-glm-5-3`,levels:[`low`,`high`,`max`]}]}},{id:`opencode-zen`,name:`OpenCode Zen`,name_zh:`OpenCode Zen`,protocol:`openai`,base_url:`https://opencode.ai/zen/v1`,key_url:`https://opencode.ai/auth`,auth:[`key`],regions:[`global`],capabilities:[`chat`],defaults:{chat:`deepseek-v4.1-flash`},note:`OpenCode's own gateway: pay per request from a balance, a key made in the OpenCode console, and a few free models beside the paid ones. Chat answers on the OpenAI shape; the GPT, Claude and Gemini ids on the same host speak the Responses, Messages and Google shapes, which this entry does not reach, and the vision model OpenCode lists is deepseek-v4-flash-vision-exp, the id DeepSeek has retired on its own platform, so the hands are not claimed here. OpenCode publishes no plan sign-in, only a key.`,note_zh:`OpenCode 自己的网关:按请求从余额里扣费,key 在 OpenCode 控制台申请,付费模型之外还有几个免费的。对话走 OpenAI 格式;同一域名上的 GPT、Claude、Gemini 走 Responses、Messages 和 Google 格式,本条目到不了;它列的视觉模型是 deepseek-v4-flash-vision-exp,这个 id 在 DeepSeek 自家平台上已经退役,所以「动手」不列入。OpenCode 没有套餐登录,只有 key。`,verified:`2026-10`},{id:`opencode-go`,name:`OpenCode Go`,name_zh:`OpenCode Go`,protocol:`openai`,base_url:`https://opencode.ai/zen/go/v1`,key_url:`https://opencode.ai/auth`,auth:[`key`],regions:[`global`],capabilities:[`chat`],defaults:{chat:`deepseek-v4.1-flash`},session_header:`x-opencode-session`,note:`A subscription for coding agents: Go ($10 a month) or Go Plus ($40) in the OpenCode console, then a key made there; usage is counted per model against monthly, weekly and five hour limits. OpenCode asks every client to name itself and to send one stable id per conversation in x-opencode-session: the runtime sends both, the desktop reaches Go through its model adapter's own OpenCode Go route, which sends the id and speaks each model's shape, and the phone apps send an id per chat (a hash of its first message, the same on every turn). Outside the desktop only the OpenAI shape is reached, which is where the open coding models answer; the GPT, Grok, Claude, MiniMax and Qwen ids speak the Responses and Messages shapes. The one vision model OpenCode lists (deepseek-v4-flash-vision-exp) is an id DeepSeek has retired on its own platform, so the hands are not claimed here. OpenCode publishes no plan sign-in, only a key.`,note_zh:`面向编程智能体的订阅:在 OpenCode 控制台订阅 Go(每月 10 美元)或 Go Plus(每月 40 美元),再在那里申请 key;用量按模型计,分每月、每周和每 5 小时三档上限。OpenCode 要求每个客户端说明自己是谁,并在 x-opencode-session 里为每个对话带上一个固定的 id:运行时两样都发;桌面版通过模型适配器自带的 OpenCode Go 路由访问,这条路由会带上 id,也按每个模型自己的格式说话;手机端为每个聊天带一个 id(由第一条消息算出,每一轮都一样)。桌面版以外只走 OpenAI 格式,开源编程模型都在这个格式上;GPT、Grok、Claude、MiniMax 和 Qwen 走 Responses 和 Messages 格式。它列的那个视觉模型(deepseek-v4-flash-vision-exp)在 DeepSeek 自家平台上已经退役,所以「动手」不列入。OpenCode 没有套餐登录,只有 key。`,verified:`2026-10`},{id:`ollama`,name:`Ollama`,name_zh:`Ollama(本机)`,protocol:`openai`,base_url:`http://127.0.0.1:11434/v1`,key_url:`https://ollama.com/download`,auth:[`none`],regions:[`cn`,`global`],capabilities:[`chat`],defaults:{chat:`qwen3:8b`},note:`Runs on this machine, no key, nothing leaves it. Hands need a model that reads pictures (a vision model such as a Qwen VL build); the model list says which.`,note_zh:`跑在本机,不要 key,什么都不出去。手需要能看图的模型(例如 Qwen 的 VL 版本),模型列表里能看出来。`,verified:`2026-10`,reasoning:{doc:`https://docs.ollama.com/api/openai-compatibility`,wire:`reasoning_effort`,rules:[{models:`gpt-oss`,levels:[`low`,`medium`,`high`]}]}},{id:`lm-studio`,name:`LM Studio`,name_zh:`LM Studio(本机)`,protocol:`openai`,base_url:`http://127.0.0.1:1234/v1`,key_url:`https://lmstudio.ai`,auth:[`none`],regions:[`cn`,`global`],capabilities:[`chat`],defaults:{},note:`LM Studio's local server, OpenAI-compatible, no key. Vision only if the loaded model has it.`,note_zh:`LM Studio 的本地服务,OpenAI 兼容,不要 key。装了能看图的模型才能用手。`,verified:`2026-10`},{id:`vllm`,name:`vLLM`,name_zh:`vLLM(自建)`,protocol:`openai`,base_url:`http://127.0.0.1:8000/v1`,key_url:`https://docs.vllm.ai`,auth:[`none`,`key`],regions:[`cn`,`global`],capabilities:[`chat`],defaults:{},note:`A vLLM server you run yourself; a key only if you started it with one. Vision only if the served model has it.`,note_zh:`自己跑的 vLLM 服务;启动时设了 key 才需要填。服务的模型能看图才能用手。`,verified:`2026-10`,reasoning:{doc:`https://docs.vllm.ai/en/latest/features/reasoning_outputs/`,wire:`reasoning_effort`,rules:[{models:`gpt-oss`,levels:[`low`,`medium`,`high`]}]}},{id:`custom`,name:`Any OpenAI-compatible endpoint`,name_zh:`任何 OpenAI 兼容接口`,protocol:`openai`,base_url:``,key_url:``,auth:[`key`,`none`],regions:[`cn`,`global`],capabilities:[`chat`],user_capabilities:!0,defaults:{},note:`A gateway, a relay, a server of your own: paste the address (usually ending in /v1) and say what it can do; the person sets the capabilities.`,note_zh:`网关、中转、自己的服务:贴地址(一般以 /v1 结尾),再说明它能做什么,能力由你勾选。`,verified:`2026-10`}]};function h(e){return e?.region?e.region===`cn`:e?.signed_in&&e.channel===`sms`?!0:r()===`zh-CN`}function re(e){return/^\s*(\+|00)(?!86\b)\d/.test(e)}var ie=new Map(m.providers.map(e=>[e.id,e]));function g(e,t){let n=ie.get(e);if(!n)throw Error(`providers.json has no ${e}`);return{id:e,preset:t,label:n.name,keyUrl:n.key_url,baseUrl:n.base_url,chatModel:n.defaults.chat??``,guiModel:n.defaults.hands??n.defaults.chat??``,covers:n.capabilities}}var ae=g(`bailian`,`qwen`),oe=g(`openrouter`,`openrouter`);function _(e){return h(e)?ae:oe}function se(e,t){return h(t)?e(`Alibaba Cloud Bailian is a good start: a new account comes with a free quota, set-up takes about two minutes, and one key covers chat, the hands, pictures and clips.`):e(`Alibaba Cloud Bailian only signs up accounts from mainland China. Outside, OpenRouter is the easy way: one account, one key, pay as you go, for chat, the hands and pictures; clips need Bailian.`)}function ce(e){let t=(e||``).toLowerCase().split(`/`).pop()??``;return t?t.startsWith(`deepseek`)?/v4\.1|vision|ocr/.test(t):t.startsWith(`qwen`)&&(t.includes(`-vl`)||t.startsWith(`qwen3.8`))?!0:null:null}function le(e,t,n){let r=_(n).preset;if(!e.includes(r))return e;let i=h(n),a=e.filter(e=>e!==r);if(i)return[r,...a];let o=a.filter(e=>t[e]?.region===`cn`);return[r,...a.filter(e=>!o.includes(e)),...o]}var ue=[`chat`,`vision`,`image`,`video`],v=m.providers,de=[`ollama`,`lm-studio`,`vllm`],fe={cn:[`bailian`],global:[`openrouter`,`openai`]},y={bailian:`qwen`,moonshot:`kimi`,zhipu:`glm`,volcengine:`doubao`};function pe(e){return y[e]??e}function me(e){return Object.entries(y).find(([,t])=>t===e)?.[0]??(e===`openai_responses`?`openai`:e)}function he(e){return h(e)?`cn`:`global`}function b(e,t){return t===`zh-CN`&&e.name_zh||e.name}function ge(e,t){return t===`global`&&e.regions.includes(`global`)&&e.base_url_global?{base_url:e.base_url_global,key_url:e.key_url_global||e.key_url}:{base_url:e.base_url,key_url:e.key_url}}function x(e,t){return e.regions.includes(t)}function S(e,t,n=v){let r=new Map(n.map(e=>[e.id,e])),i=fe[e].map(e=>r.get(e)).filter(t=>!!t&&x(t,e)),a=n.filter(t=>!i.includes(t)&&!de.includes(t.id)&&t.id!==`custom`&&x(t,e)).sort((e,t)=>t.capabilities.length-e.capabilities.length),o=[...i,...a];return t?o.filter(e=>e.capabilities.includes(t)):o}function _e(e=v){let t=[{id:`chatgpt`,provider:`openai`,name:`ChatGPT`,auth:`oauth-chatgpt`,here:!0},{id:`claude`,provider:`anthropic`,name:`Claude`,auth:`oauth-claude`,here:!1},{id:`kimi`,provider:`moonshot`,name:`Kimi`,auth:`device-kimi`,here:!1},{id:`openrouter`,provider:`openrouter`,name:`OpenRouter`,auth:`oauth-openrouter`,here:!1}],n=[];for(let r of t){let t=e.find(e=>e.id===r.provider);t&&t.auth.includes(r.auth)&&n.push({...r,covers:t.auth_capabilities?.[r.auth]??t.capabilities})}return n}function ve(e,t){switch(t){case`chat`:return e(`Chat`);case`vision`:return e(`Hands`);case`image`:return e(`Pictures`);case`video`:return e(`Clips`)}}function ye(e,t){return e(`covers {list}`,{list:ue.filter(e=>t.includes(e)).map(t=>ve(e,t).toLowerCase()).join(e(`, `))})}function be(e,t,n,r,i=v){let a=S(n,t,i).slice(0,4).map(e=>b(e,r)),o=a.pop()??``,s=a.length?`${a.join(e(`, `))}${e(` or `)}${o}`:o;switch(t){case`image`:return e(`Pictures need a provider with image models: {providers}.`,{providers:s});case`video`:return e(`Clips need a provider with video models: {providers}.`,{providers:s});case`vision`:return e(`The hands need a model that sees pictures: {providers}.`,{providers:s});case`chat`:return e(`Chat needs a model: {providers}.`,{providers:s})}}var C=null,w=null;async function xe(e=!1){return C&&!e?C:(w&&!e||(w=c.providers().then(e=>({...e,capabilities:e.capabilities??null,source:`runtime`})).catch(()=>({providers:v,region:``,configured:{},capabilities:null,unavailable:{},source:`bundled`})).then(e=>(C=e,w=null,e))),w)}function Se(){C=null}function Ce(e=0){let[t,n]=(0,p.useState)(C);return(0,p.useEffect)(()=>{let t=!0;return xe(e>0).then(e=>t&&n(e)),()=>{t=!1}},[e]),t}function we(e,t){return!e||e.capabilities===null?null:e.capabilities.includes(t)}var T={version:1,star:{enabled:!0,url:`https://github.com/zeeshanhaque21/nanoMuse`,moments:{signed_in:!0,tasks:[3,10,30],new_look:!0,exhausted:!0,days_used:[7,30],goal_done:!0},cooldown_days:7,max_asks:4,text:``,text_zh:``}},Te=864e5;function E(e){if(typeof e!=`string`)return``;let t=e.trim();return t.length<=200?t:``}function Ee(e,t,n){let{text:r,text_zh:i}=e.star;return t&&i?i:r||n}var D=e=>typeof e==`object`&&!!e&&!Array.isArray(e),O=(e,t)=>typeof e==`boolean`?e:t,k=(e,t,n,r)=>typeof e==`number`&&Number.isFinite(e)&&Math.trunc(e)>=t&&Math.trunc(e)<=n?Math.trunc(e):r;function A(e,t){if(!Array.isArray(e))return t;let n=new Set;for(let r of e){if(typeof r!=`number`||!Number.isFinite(r)||Math.trunc(r)<1)return t;n.add(Math.trunc(r))}return[...n].sort((e,t)=>e-t)}function De(e){let t=T.star;if(!D(e))return structuredClone(T);let n=k(e.version,1,1e9,1),r=D(e.star)?e.star:{},i=D(r.moments)?r.moments:{},a=typeof r.url==`string`&&/^https?:\/\//.test(r.url)&&r.url.length<=200?r.url:t.url;return{version:n,star:{enabled:O(r.enabled,t.enabled),url:a,moments:{signed_in:O(i.signed_in,t.moments.signed_in),tasks:A(i.tasks,t.moments.tasks),new_look:O(i.new_look,t.moments.new_look),exhausted:O(i.exhausted,t.moments.exhausted),days_used:A(i.days_used,t.moments.days_used),goal_done:O(i.goal_done,t.moments.goal_done)},cooldown_days:k(r.cooldown_days,0,365,t.cooldown_days),max_asks:k(r.max_asks,0,50,t.max_asks),text:E(r.text),text_zh:E(r.text_zh)}}}var j={starred:`nm.star.starred`,tasks:`nm.star.tasks`,asks:`nm.star.asks`,lastAsk:`nm.star.last_ask`,shown:`nm.star.shown`,days:`nm.star.days`,lastDay:`nm.star.last_day`,migrated:`nm.star.v2`},Oe=[`signed_in`,`first_task`,`tenth_task`,`new_look`],M=e=>{let t=Number(e);return Number.isFinite(t)&&t>=0?Math.trunc(t):0};function N(e){let t=[];try{let n=JSON.parse(e.getItem(j.shown)??`[]`);Array.isArray(n)&&(t=n.filter(e=>typeof e==`string`))}catch{t=[]}let n=e.getItem(j.lastAsk);return{starred:e.getItem(j.starred)===`1`,tasks:M(e.getItem(j.tasks)),asks:M(e.getItem(j.asks)),lastAsk:n&&M(n)||null,shown:t,days:M(e.getItem(j.days)),lastDay:e.getItem(j.lastDay)??``}}function P(e,t){e.setItem(j.starred,t.starred?`1`:`0`),e.setItem(j.tasks,String(t.tasks)),e.setItem(j.asks,String(t.asks)),t.lastAsk?e.setItem(j.lastAsk,String(t.lastAsk)):e.removeItem(j.lastAsk),e.setItem(j.shown,JSON.stringify(t.shown)),e.setItem(j.days,String(t.days)),e.setItem(j.lastDay,t.lastDay)}function ke(e){let t=N(e);if(e.getItem(j.migrated)===`1`)return t;for(let n of Oe){let r=`nm.star.${n}`;e.getItem(r)===`1`&&!t.shown.includes(n)&&(t.shown.push(n),t.asks+=1),e.removeItem(r)}return P(e,t),e.setItem(j.migrated,`1`),t}var F=(e,t)=>e===`tasks`||e===`days_used`?`${e}:${t??0}`:e;function Ae(e,t,n){let r=e.star;return!r.enabled||t.starred||t.asks>=r.max_asks?!1:t.lastAsk===null||n-t.lastAsk>=r.cooldown_days*Te}function je(e,t,n,r,i){if(!Ae(t,n,r))return!1;let a=t.star.moments;return(e===`tasks`||e===`days_used`?i!==void 0&&a[e].includes(i):a[e])&&!n.shown.includes(F(e,i))}function Me(e,t,n){let r=N(e);return r.shown.includes(t)||(r.shown.push(t),r.asks+=1,r.lastAsk=n,P(e,r)),r}function Ne(e){let t=N(e);t.starred=!0,P(e,t)}function Pe(e){let t=N(e);return t.tasks+=1,P(e,t),t.tasks}var Fe=e=>`${e.getFullYear()}-${String(e.getMonth()+1).padStart(2,`0`)}-${String(e.getDate()).padStart(2,`0`)}`;function Ie(e,t){let n=N(e),r=Fe(t);return n.lastDay===r?{days:n.days,fresh:!1}:(n.days+=1,n.lastDay=r,P(e,n),{days:n.days,fresh:!0})}var I=s(),Le=`https://github.com/zeeshanhaque21/nanoMuse`,Re=`https://github.com/zeeshanhaque21/nanoMuse/issues/new/choose`,L=`https://github.com/zeeshanhaque21/nanoMuse`;function ze({compact:t=!1,className:r}){let i=n();return(0,I.jsxs)(`section`,{className:e(`rounded-[22px] border border-accent/25 bg-accent/[0.06] p-4 dark:bg-accent/[0.10]`,r),children:[(0,I.jsxs)(`a`,{href:L,target:`_blank`,rel:`noreferrer`,className:`flex items-start gap-2 text-[13.5px] font-semibold hover:text-accent`,children:[(0,I.jsx)(d,{size:16,className:`mt-0.5 shrink-0 text-accent`}),(0,I.jsx)(`span`,{className:`min-w-0 flex-1 leading-snug`,children:i(`Free, open source, non-profit`)}),(0,I.jsx)(ee,{size:12,className:`mt-1 shrink-0 text-muted`})]}),(0,I.jsx)(`p`,{className:e(`mt-1.5 leading-relaxed text-fg/85`,t?`text-[12.5px]`:`text-[13px]`),children:i(`nanoMuse is a non-profit open-source community project, free forever. Sign in with a phone number or an e-mail and the model comes with a free allowance, paid by the developer; when it is gone, use your own key (Alibaba Cloud Bailian in mainland China, OpenRouter elsewhere). Nothing is sold; what the relay keeps is in the privacy policy, and Settings → Data controls is yours. Delete the account whenever you like.`)}),(0,I.jsx)(`p`,{className:e(`mt-1.5 leading-relaxed text-fg/85`,t?`text-[12.5px]`:`text-[13px]`),children:i(`The people building it use it every day. Report a bug, ask for a feature, send a pull request: that is what moves the project. A star on GitHub helps others find it.`)}),(0,I.jsxs)(`div`,{className:`mt-3 flex flex-wrap gap-2 text-[12.5px] font-medium`,children:[(0,I.jsxs)(`a`,{href:Le,target:`_blank`,rel:`noreferrer`,onClick:K,className:`inline-flex items-center gap-1.5 rounded-full bg-fg px-3 py-1.5 text-bg hover:opacity-90`,children:[(0,I.jsx)(ne,{size:13}),` `,i(`Star on GitHub`)]}),(0,I.jsxs)(`a`,{href:Re,target:`_blank`,rel:`noreferrer`,className:`inline-flex items-center gap-1.5 rounded-full border border-border bg-surface px-3 py-1.5 text-fg hover:bg-surface-2`,children:[(0,I.jsx)(u,{size:13}),` `,i(`Report a bug or ask for a feature`)]})]})]})}var R=new Map,z={getItem:e=>{try{return localStorage.getItem(e)}catch{return R.get(e)??null}},setItem:(e,t)=>{try{localStorage.setItem(e,t)}catch{R.set(e,t)}},removeItem:e=>{try{localStorage.removeItem(e)}catch{R.delete(e)}}},B=!1;function Be(){return B?N(z):(B=!0,ke(z))}var V=T,H=!1,U=null,W=new Set;function Ve(){return U??=c.nudges().then(e=>{V=De(e?.policy)}).catch(()=>{V=T}).finally(()=>{H=!0,W.forEach(e=>e())}),U}function G(){let[,e]=(0,p.useState)(0);return(0,p.useEffect)(()=>{let t=()=>e(e=>e+1);return W.add(t),Ve(),()=>{W.delete(t)}},[]),{policy:V,ready:H}}var He=()=>Pe(z),Ue=()=>Ie(z,new Date),We=(e,t)=>H&&je(e,V,Be(),Date.now(),t),Ge=(e,t)=>{Me(z,F(e,t),Date.now())},K=()=>Ne(z);function q(e){K(),window.open(e||V.star.url||`https://github.com/zeeshanhaque21/nanoMuse`,`_blank`,`noopener,noreferrer`)}function J(e,t,n){switch(t){case`signed_in`:return e(`Welcome. nanoMuse is free, open source and non-profit, a personal agent for anyone who runs it. If that is worth something to you, a star on GitHub is how the next person finds it.`);case`tasks`:return n===3?e(`Three tasks done. If nanoMuse is useful, a star on GitHub helps the next person find it.`):n===10?e(`Ten tasks together. If nanoMuse has become part of your day, a star on GitHub tells others it is worth a try.`):e(`{n} tasks done. If nanoMuse is useful, a star on GitHub helps the next person find it.`,{n:n??0});case`new_look`:return e(`A new face, drawn for you. If you like where nanoMuse is going, a star on GitHub helps more people find it.`);case`exhausted`:return e(`The free allowance is used up. Thank you for coming this far. If nanoMuse has earned it, a star on GitHub keeps the project in view for the next person.`);case`days_used`:return n===7?e(`A week with nanoMuse. If it has earned a place in your day, a star on GitHub helps the next person find it.`):n===30?e(`A month with nanoMuse. If it has become part of your routine, a star on GitHub tells others it is worth a try.`):e(`{n} days with nanoMuse. If it has earned a place in your day, a star on GitHub helps the next person find it.`,{n:n??0});case`goal_done`:return e(`Goal reached. If nanoMuse helped you get there, a star on GitHub tells the people building it that it did.`)}}var Y=null,X=null;function Z(){let[e,t]=(0,p.useState)(Y??{});return(0,p.useEffect)(()=>{if(Y)return;X??=c.cloudConfig().then(e=>Y=e&&typeof e==`object`?e:{}).catch(()=>Y={});let e=!0;return X.then(n=>e&&t(n)),()=>{e=!1}},[]),e}function Q(e){let{policy:t}=G();return Ee(t,a()===`zh-CN`,e)}function Ke({text:t,onDone:r,className:i}){let a=n(),o=Z(),s=Q(t);return(0,I.jsxs)(`section`,{className:e(`rounded-[22px] border border-amber-400/40 bg-amber-50/70 p-4 dark:bg-amber-400/[0.08]`,i),children:[(0,I.jsxs)(`div`,{className:`flex items-start gap-2.5`,children:[(0,I.jsx)(f,{size:18,className:`mt-0.5 shrink-0 text-amber-500`}),(0,I.jsxs)(`div`,{className:`min-w-0 flex-1`,children:[(0,I.jsx)(`div`,{className:`text-[14px] font-semibold leading-snug`,children:a(`A star on GitHub helps`)}),(0,I.jsx)(`p`,{className:`mt-1 text-[13px] leading-relaxed text-fg/85`,children:s})]})]}),(0,I.jsxs)(`div`,{className:`mt-3 flex flex-wrap gap-2 pl-7`,children:[(0,I.jsx)(`button`,{type:`button`,className:e(te,`!w-auto !py-1.5 !px-3.5 text-[13px]`),onClick:()=>{q(o.repo_url),r()},children:a(`Star on GitHub`)}),(0,I.jsx)(`button`,{type:`button`,className:e(l,`!w-auto !py-1.5 !px-3.5 text-[13px]`),onClick:r,children:a(`Not now`)}),(0,I.jsx)(`button`,{type:`button`,className:e(l,`!w-auto !py-1.5 !px-3.5 text-[13px]`),onClick:()=>{K(),r()},children:a(`I already starred`)})]})]})}function qe({moment:e,n:t,text:r,className:i,due:a=!0}){let o=n(),[s,c]=$(e,a,t);return s?(0,I.jsx)(Ke,{text:r??J(o,e,t),onDone:()=>c(!1),className:i}):null}function $(e,t=!0,n){let{ready:r}=G(),[i,a]=(0,p.useState)(!1);return(0,p.useEffect)(()=>{t&&r&&!i&&We(e,n)&&(Ge(e,n),a(!0))},[t,r,e,n,i]),[i,a]}export{_ as A,be as C,ce as D,re as E,d as M,u as N,le as O,he as S,h as T,Se as _,q as a,b,$ as c,L as d,v as f,we as g,ge as h,K as i,f as j,se as k,Q as l,ye as m,Ue as n,J as o,me as p,He as r,Z as s,qe as t,ze as u,_e as v,Ce as w,S as x,pe as y}; \ No newline at end of file diff --git a/nanomuse/server/static/assets/clapperboard-90G9CI1B.js b/nanomuse/server/static/assets/clapperboard-CuoVHGrc.js similarity index 81% rename from nanomuse/server/static/assets/clapperboard-90G9CI1B.js rename to nanomuse/server/static/assets/clapperboard-CuoVHGrc.js index 8ba9caf83..6452d0c3a 100644 --- a/nanomuse/server/static/assets/clapperboard-90G9CI1B.js +++ b/nanomuse/server/static/assets/clapperboard-CuoVHGrc.js @@ -1 +1 @@ -import{J as e}from"./MuseHeader-BvAlmxiL.js";var t=e(`clapperboard`,[[`path`,{d:`m12.296 3.464 3.02 3.956`,key:`qash78`}],[`path`,{d:`M20.2 6 3 11l-.9-2.4c-.3-1.1.3-2.2 1.3-2.5l13.5-4c1.1-.3 2.2.3 2.5 1.3z`,key:`1h7j8b`}],[`path`,{d:`M3 11h18v8a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z`,key:`4lm6w1`}],[`path`,{d:`m6.18 5.276 3.1 3.899`,key:`zjj9t3`}]]);export{t}; \ No newline at end of file +import{J as e}from"./MuseHeader-RC--uR8o.js";var t=e(`clapperboard`,[[`path`,{d:`m12.296 3.464 3.02 3.956`,key:`qash78`}],[`path`,{d:`M20.2 6 3 11l-.9-2.4c-.3-1.1.3-2.2 1.3-2.5l13.5-4c1.1-.3 2.2.3 2.5 1.3z`,key:`1h7j8b`}],[`path`,{d:`M3 11h18v8a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z`,key:`4lm6w1`}],[`path`,{d:`m6.18 5.276 3.1 3.899`,key:`zjj9t3`}]]);export{t}; \ No newline at end of file diff --git a/nanomuse/server/static/assets/database-zap-Bv9NPF9E.js b/nanomuse/server/static/assets/database-zap-Bce5E3JJ.js similarity index 80% rename from nanomuse/server/static/assets/database-zap-Bv9NPF9E.js rename to nanomuse/server/static/assets/database-zap-Bce5E3JJ.js index ef2d1d3ff..0e3171809 100644 --- a/nanomuse/server/static/assets/database-zap-Bv9NPF9E.js +++ b/nanomuse/server/static/assets/database-zap-Bce5E3JJ.js @@ -1 +1 @@ -import{J as e}from"./MuseHeader-BvAlmxiL.js";var t=e(`database-zap`,[[`ellipse`,{cx:`12`,cy:`5`,rx:`9`,ry:`3`,key:`msslwz`}],[`path`,{d:`M3 5V19A9 3 0 0 0 15 21.84`,key:`14ibmq`}],[`path`,{d:`M21 5V8`,key:`1marbg`}],[`path`,{d:`M21 12L18 17H22L19 22`,key:`zafso`}],[`path`,{d:`M3 12A9 3 0 0 0 14.59 14.87`,key:`1y4wr8`}]]);export{t}; \ No newline at end of file +import{J as e}from"./MuseHeader-RC--uR8o.js";var t=e(`database-zap`,[[`ellipse`,{cx:`12`,cy:`5`,rx:`9`,ry:`3`,key:`msslwz`}],[`path`,{d:`M3 5V19A9 3 0 0 0 15 21.84`,key:`14ibmq`}],[`path`,{d:`M21 5V8`,key:`1marbg`}],[`path`,{d:`M21 12L18 17H22L19 22`,key:`zafso`}],[`path`,{d:`M3 12A9 3 0 0 0 14.59 14.87`,key:`1y4wr8`}]]);export{t}; \ No newline at end of file diff --git a/nanomuse/server/static/assets/external-link-V2ISE5bW.js b/nanomuse/server/static/assets/external-link-TvxP_dKX.js similarity index 79% rename from nanomuse/server/static/assets/external-link-V2ISE5bW.js rename to nanomuse/server/static/assets/external-link-TvxP_dKX.js index 97e22c152..39f8f3256 100644 --- a/nanomuse/server/static/assets/external-link-V2ISE5bW.js +++ b/nanomuse/server/static/assets/external-link-TvxP_dKX.js @@ -1 +1 @@ -import{J as e}from"./MuseHeader-BvAlmxiL.js";var t=e(`check`,[[`path`,{d:`M20 6 9 17l-5-5`,key:`1gmf2c`}]]),n=e(`external-link`,[[`path`,{d:`M15 3h6v6`,key:`1q9fwt`}],[`path`,{d:`M10 14 21 3`,key:`gplh6r`}],[`path`,{d:`M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6`,key:`a6xqqp`}]]);export{t as n,n as t}; \ No newline at end of file +import{J as e}from"./MuseHeader-RC--uR8o.js";var t=e(`check`,[[`path`,{d:`M20 6 9 17l-5-5`,key:`1gmf2c`}]]),n=e(`external-link`,[[`path`,{d:`M15 3h6v6`,key:`1q9fwt`}],[`path`,{d:`M10 14 21 3`,key:`gplh6r`}],[`path`,{d:`M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6`,key:`a6xqqp`}]]);export{t as n,n as t}; \ No newline at end of file diff --git a/nanomuse/server/static/assets/image-Cn9LGhlN.js b/nanomuse/server/static/assets/image-nIygWCIp.js similarity index 75% rename from nanomuse/server/static/assets/image-Cn9LGhlN.js rename to nanomuse/server/static/assets/image-nIygWCIp.js index 896e9dba8..365982c6d 100644 --- a/nanomuse/server/static/assets/image-Cn9LGhlN.js +++ b/nanomuse/server/static/assets/image-nIygWCIp.js @@ -1 +1 @@ -import{J as e}from"./MuseHeader-BvAlmxiL.js";var t=e(`image`,[[`rect`,{width:`18`,height:`18`,x:`3`,y:`3`,rx:`2`,ry:`2`,key:`1m3agn`}],[`circle`,{cx:`9`,cy:`9`,r:`2`,key:`af1f0g`}],[`path`,{d:`m21 15-3.086-3.086a2 2 0 0 0-2.828 0L6 21`,key:`1xmnt7`}]]);export{t}; \ No newline at end of file +import{J as e}from"./MuseHeader-RC--uR8o.js";var t=e(`image`,[[`rect`,{width:`18`,height:`18`,x:`3`,y:`3`,rx:`2`,ry:`2`,key:`1m3agn`}],[`circle`,{cx:`9`,cy:`9`,r:`2`,key:`af1f0g`}],[`path`,{d:`m21 15-3.086-3.086a2 2 0 0 0-2.828 0L6 21`,key:`1xmnt7`}]]);export{t}; \ No newline at end of file diff --git a/nanomuse/server/static/assets/index-tYqPtwPX.js b/nanomuse/server/static/assets/index-tYqPtwPX.js new file mode 100644 index 000000000..db4803d14 --- /dev/null +++ b/nanomuse/server/static/assets/index-tYqPtwPX.js @@ -0,0 +1,44 @@ +const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["assets/AccountScreen-Bws27b-C.js","assets/MuseHeader-RC--uR8o.js","assets/StarNudge-Df6LQyo9.js","assets/external-link-TvxP_dKX.js","assets/Form-H3s9oTHq.js","assets/clapperboard-CuoVHGrc.js","assets/database-zap-Bce5E3JJ.js","assets/image-nIygWCIp.js","assets/BackBar-JEuC8Q_e.js","assets/AvatarStudioScreen-Dgqo0TEO.js","assets/refresh-cw-CxZ3ZdI3.js","assets/AvatarPicker-BCihUURa.js","assets/ChannelsScreen-D_7Ynsew.js","assets/CodingScreen-BLVF-Er8.js","assets/ConnectionsScreen-CuIVN07d.js","assets/plug-DV_c5_Ny.js","assets/CloudCard-D5foJm1I.js","assets/DevicesScreen-BkPa89LS.js","assets/GoalsScreen-yUUdUKV2.js","assets/IdeasScreen-CmecfnoP.js","assets/LibraryScreen-BoofKOos.js","assets/MemoryScreen-DHNxjNpq.js","assets/Onboarding-DBBDNzyW.js","assets/IdentityForm-g-zvQ2IC.js","assets/SettingsScreen-B84xmoRg.js","assets/SkillsScreen-DsMpJe1f.js"])))=>i.map(i=>d[i]); +import{A as e,B as t,C as n,D as r,E as i,I as a,J as o,K as s,L as c,M as l,N as u,O as d,P as f,Q as p,R as m,S as h,T as g,U as _,V as v,W as y,X as b,Y as x,Z as S,b as C,c as w,d as T,f as E,i as D,j as O,n as k,p as ee,q as A,r as te,s as j,t as ne,u as re,x as M,y as ie,z as N}from"./MuseHeader-RC--uR8o.js";import{A as ae,E as oe,M as se,N as ce,S as le,T as ue,_ as de,a as fe,b as pe,c as me,i as he,j as ge,k as _e,l as ve,m as ye,n as be,o as xe,r as Se,s as Ce,t as we,u as Te,v as Ee,x as De,y as Oe}from"./StarNudge-Df6LQyo9.js";import{n as ke,t as Ae}from"./external-link-TvxP_dKX.js";import{a as je,c as Me,i as Ne,n as Pe,o as Fe,r as Ie,s as Le}from"./Form-H3s9oTHq.js";import{t as Re}from"./refresh-cw-CxZ3ZdI3.js";(function(){let e=document.createElement(`link`).relList;if(e&&e.supports&&e.supports(`modulepreload`))return;for(let e of document.querySelectorAll(`link[rel="modulepreload"]`))n(e);new MutationObserver(e=>{for(let t of e)if(t.type===`childList`)for(let e of t.addedNodes)e.tagName===`LINK`&&e.rel===`modulepreload`&&n(e)}).observe(document,{childList:!0,subtree:!0});function t(e){let t={};return e.integrity&&(t.integrity=e.integrity),e.referrerPolicy&&(t.referrerPolicy=e.referrerPolicy),t.credentials=e.crossOrigin===`use-credentials`?`include`:e.crossOrigin===`anonymous`?`omit`:`same-origin`,t}function n(e){if(e.ep)return;e.ep=!0;let n=t(e);fetch(e.href,n)}})();var ze=b((e=>{function t(e,t){var n=e.length;e.push(t);a:for(;0>>1,a=e[r];if(0>>1;ri(c,n))li(u,c)?(e[r]=u,e[l]=n,r=l):(e[r]=c,e[s]=n,r=s);else if(li(u,n))e[r]=u,e[l]=n,r=l;else break a}}return t}function i(e,t){var n=e.sortIndex-t.sortIndex;return n===0?e.id-t.id:n}if(typeof performance==`object`&&typeof performance.now==`function`){var a=performance;e.unstable_now=function(){return a.now()}}else{var o=Date,s=o.now();e.unstable_now=function(){return o.now()-s}}var c=[],l=[],u=1,d=null,f=3,p=!1,m=!1,h=!1,g=typeof setTimeout==`function`?setTimeout:null,_=typeof clearTimeout==`function`?clearTimeout:null,v=typeof setImmediate<`u`?setImmediate:null;typeof navigator<`u`&&navigator.scheduling!==void 0&&navigator.scheduling.isInputPending!==void 0&&navigator.scheduling.isInputPending.bind(navigator.scheduling);function y(e){for(var i=n(l);i!==null;){if(i.callback===null)r(l);else if(i.startTime<=e)r(l),i.sortIndex=i.expirationTime,t(c,i);else break;i=n(l)}}function b(e){if(h=!1,y(e),!m){if(n(c)!==null)m=!0,te(x);else{var t=n(l);t!==null&&j(b,t.startTime-e)}}}function x(t,i){m=!1,h&&(h=!1,_(w),w=-1),p=!0;var a=f;try{for(y(i),d=n(c);d!==null&&(!(d.expirationTime>i)||t&&!D());){var o=d.callback;if(typeof o==`function`){d.callback=null,f=d.priorityLevel;var s=o(d.expirationTime<=i);i=e.unstable_now(),typeof s==`function`?d.callback=s:d===n(c)&&r(c),y(i)}else r(c);d=n(c)}if(d!==null)var u=!0;else{var g=n(l);g!==null&&j(b,g.startTime-i),u=!1}return u}finally{d=null,f=a,p=!1}}var S=!1,C=null,w=-1,T=5,E=-1;function D(){return!(e.unstable_now()-Ee||125o?(r.sortIndex=a,t(l,r),n(c)===null&&r===n(l)&&(h?(_(w),w=-1):h=!0,j(b,a-o))):(r.sortIndex=s,t(c,r),m||p||(m=!0,te(x))),r},e.unstable_shouldYield=D,e.unstable_wrapCallback=function(e){var t=f;return function(){var n=f;f=t;try{return e.apply(this,arguments)}finally{f=n}}}})),Be=b(((e,t)=>{t.exports=ze()})),Ve=b((e=>{var t=x(),n=Be();function r(e){for(var t=`https://reactjs.org/docs/error-decoder.html?invariant=`+e,n=1;nt}return!1}function g(e,t,n,r,i,a,o){this.acceptsBooleans=t===2||t===3||t===4,this.attributeName=r,this.attributeNamespace=i,this.mustUseProperty=n,this.propertyName=e,this.type=t,this.sanitizeURL=a,this.removeEmptyString=o}var _={};`children dangerouslySetInnerHTML defaultValue defaultChecked innerHTML suppressContentEditableWarning suppressHydrationWarning style`.split(` `).forEach(function(e){_[e]=new g(e,0,!1,e,null,!1,!1)}),[[`acceptCharset`,`accept-charset`],[`className`,`class`],[`htmlFor`,`for`],[`httpEquiv`,`http-equiv`]].forEach(function(e){var t=e[0];_[t]=new g(t,1,!1,e[1],null,!1,!1)}),[`contentEditable`,`draggable`,`spellCheck`,`value`].forEach(function(e){_[e]=new g(e,2,!1,e.toLowerCase(),null,!1,!1)}),[`autoReverse`,`externalResourcesRequired`,`focusable`,`preserveAlpha`].forEach(function(e){_[e]=new g(e,2,!1,e,null,!1,!1)}),`allowFullScreen async autoFocus autoPlay controls default defer disabled disablePictureInPicture disableRemotePlayback formNoValidate hidden loop noModule noValidate open playsInline readOnly required reversed scoped seamless itemScope`.split(` `).forEach(function(e){_[e]=new g(e,3,!1,e.toLowerCase(),null,!1,!1)}),[`checked`,`multiple`,`muted`,`selected`].forEach(function(e){_[e]=new g(e,3,!0,e,null,!1,!1)}),[`capture`,`download`].forEach(function(e){_[e]=new g(e,4,!1,e,null,!1,!1)}),[`cols`,`rows`,`size`,`span`].forEach(function(e){_[e]=new g(e,6,!1,e,null,!1,!1)}),[`rowSpan`,`start`].forEach(function(e){_[e]=new g(e,5,!1,e.toLowerCase(),null,!1,!1)});var v=/[\-:]([a-z])/g;function y(e){return e[1].toUpperCase()}`accent-height alignment-baseline arabic-form baseline-shift cap-height clip-path clip-rule color-interpolation color-interpolation-filters color-profile color-rendering dominant-baseline enable-background fill-opacity fill-rule flood-color flood-opacity font-family font-size font-size-adjust font-stretch font-style font-variant font-weight glyph-name glyph-orientation-horizontal glyph-orientation-vertical horiz-adv-x horiz-origin-x image-rendering letter-spacing lighting-color marker-end marker-mid marker-start overline-position overline-thickness paint-order panose-1 pointer-events rendering-intent shape-rendering stop-color stop-opacity strikethrough-position strikethrough-thickness stroke-dasharray stroke-dashoffset stroke-linecap stroke-linejoin stroke-miterlimit stroke-opacity stroke-width text-anchor text-decoration text-rendering underline-position underline-thickness unicode-bidi unicode-range units-per-em v-alphabetic v-hanging v-ideographic v-mathematical vector-effect vert-adv-y vert-origin-x vert-origin-y word-spacing writing-mode xmlns:xlink x-height`.split(` `).forEach(function(e){var t=e.replace(v,y);_[t]=new g(t,1,!1,e,null,!1,!1)}),`xlink:actuate xlink:arcrole xlink:role xlink:show xlink:title xlink:type`.split(` `).forEach(function(e){var t=e.replace(v,y);_[t]=new g(t,1,!1,e,`http://www.w3.org/1999/xlink`,!1,!1)}),[`xml:base`,`xml:lang`,`xml:space`].forEach(function(e){var t=e.replace(v,y);_[t]=new g(t,1,!1,e,`http://www.w3.org/XML/1998/namespace`,!1,!1)}),[`tabIndex`,`crossOrigin`].forEach(function(e){_[e]=new g(e,1,!1,e.toLowerCase(),null,!1,!1)}),_.xlinkHref=new g(`xlinkHref`,1,!1,`xlink:href`,`http://www.w3.org/1999/xlink`,!0,!1),[`src`,`href`,`action`,`formAction`].forEach(function(e){_[e]=new g(e,1,!1,e.toLowerCase(),null,!0,!0)});function b(e,t,n,r){var i=_.hasOwnProperty(t)?_[t]:null;(i===null?r||!(2s||i[o]!==a[s]){var c=` +`+i[o].replace(` at new `,` at `);return e.displayName&&c.includes(``)&&(c=c.replace(``,e.displayName)),c}while(1<=o&&0<=s);break}}}finally{se=!1,Error.prepareStackTrace=n}return(e=e?e.displayName||e.name:``)?oe(e):``}function le(e){switch(e.tag){case 5:return oe(e.type);case 16:return oe(`Lazy`);case 13:return oe(`Suspense`);case 19:return oe(`SuspenseList`);case 0:case 2:case 15:return e=ce(e.type,!1),e;case 11:return e=ce(e.type.render,!1),e;case 1:return e=ce(e.type,!0),e;default:return``}}function ue(e){if(e==null)return null;if(typeof e==`function`)return e.displayName||e.name||null;if(typeof e==`string`)return e;switch(e){case T:return`Fragment`;case w:return`Portal`;case D:return`Profiler`;case E:return`StrictMode`;case A:return`Suspense`;case te:return`SuspenseList`}if(typeof e==`object`)switch(e.$$typeof){case k:return(e.displayName||`Context`)+`.Consumer`;case O:return(e._context.displayName||`Context`)+`.Provider`;case ee:var t=e.render;return e=e.displayName,e||=(e=t.displayName||t.name||``,e===``?`ForwardRef`:`ForwardRef(`+e+`)`),e;case j:return t=e.displayName||null,t===null?ue(e.type)||`Memo`:t;case ne:t=e._payload,e=e._init;try{return ue(e(t))}catch{}}return null}function de(e){var t=e.type;switch(e.tag){case 24:return`Cache`;case 9:return(t.displayName||`Context`)+`.Consumer`;case 10:return(t._context.displayName||`Context`)+`.Provider`;case 18:return`DehydratedFragment`;case 11:return e=t.render,e=e.displayName||e.name||``,t.displayName||(e===``?`ForwardRef`:`ForwardRef(`+e+`)`);case 7:return`Fragment`;case 5:return t;case 4:return`Portal`;case 3:return`Root`;case 6:return`Text`;case 16:return ue(t);case 8:return t===E?`StrictMode`:`Mode`;case 22:return`Offscreen`;case 12:return`Profiler`;case 21:return`Scope`;case 13:return`Suspense`;case 19:return`SuspenseList`;case 25:return`TracingMarker`;case 1:case 0:case 17:case 2:case 14:case 15:if(typeof t==`function`)return t.displayName||t.name||null;if(typeof t==`string`)return t}return null}function fe(e){switch(typeof e){case`boolean`:case`number`:case`string`:case`undefined`:return e;case`object`:return e;default:return``}}function pe(e){var t=e.type;return(e=e.nodeName)&&e.toLowerCase()===`input`&&(t===`checkbox`||t===`radio`)}function me(e){var t=pe(e)?`checked`:`value`,n=Object.getOwnPropertyDescriptor(e.constructor.prototype,t),r=``+e[t];if(!e.hasOwnProperty(t)&&n!==void 0&&typeof n.get==`function`&&typeof n.set==`function`){var i=n.get,a=n.set;return Object.defineProperty(e,t,{configurable:!0,get:function(){return i.call(this)},set:function(e){r=``+e,a.call(this,e)}}),Object.defineProperty(e,t,{enumerable:n.enumerable}),{getValue:function(){return r},setValue:function(e){r=``+e},stopTracking:function(){e._valueTracker=null,delete e[t]}}}}function he(e){e._valueTracker||=me(e)}function ge(e){if(!e)return!1;var t=e._valueTracker;if(!t)return!0;var n=t.getValue(),r=``;return e&&(r=pe(e)?e.checked?`true`:`false`:e.value),e=r,e!==n&&(t.setValue(e),!0)}function _e(e){if(e||=typeof document<`u`?document:void 0,e===void 0)return null;try{return e.activeElement||e.body}catch{return e.body}}function ve(e,t){var n=t.checked;return N({},t,{defaultChecked:void 0,defaultValue:void 0,value:void 0,checked:n??e._wrapperState.initialChecked})}function ye(e,t){var n=t.defaultValue==null?``:t.defaultValue,r=t.checked==null?t.defaultChecked:t.checked;n=fe(t.value==null?n:t.value),e._wrapperState={initialChecked:r,initialValue:n,controlled:t.type===`checkbox`||t.type===`radio`?t.checked!=null:t.value!=null}}function be(e,t){t=t.checked,t!=null&&b(e,`checked`,t,!1)}function xe(e,t){be(e,t);var n=fe(t.value),r=t.type;if(n!=null)r===`number`?(n===0&&e.value===``||e.value!=n)&&(e.value=``+n):e.value!==``+n&&(e.value=``+n);else if(r===`submit`||r===`reset`){e.removeAttribute(`value`);return}t.hasOwnProperty(`value`)?Ce(e,t.type,n):t.hasOwnProperty(`defaultValue`)&&Ce(e,t.type,fe(t.defaultValue)),t.checked==null&&t.defaultChecked!=null&&(e.defaultChecked=!!t.defaultChecked)}function Se(e,t,n){if(t.hasOwnProperty(`value`)||t.hasOwnProperty(`defaultValue`)){var r=t.type;if(!(r!==`submit`&&r!==`reset`||t.value!==void 0&&t.value!==null))return;t=``+e._wrapperState.initialValue,n||t===e.value||(e.value=t),e.defaultValue=t}n=e.name,n!==``&&(e.name=``),e.defaultChecked=!!e._wrapperState.initialChecked,n!==``&&(e.name=n)}function Ce(e,t,n){(t!==`number`||_e(e.ownerDocument)!==e)&&(n==null?e.defaultValue=``+e._wrapperState.initialValue:e.defaultValue!==``+n&&(e.defaultValue=``+n))}var we=Array.isArray;function Te(e,t,n,r){if(e=e.options,t){t={};for(var i=0;i`+t.valueOf().toString()+``,t=Me.firstChild;e.firstChild;)e.removeChild(e.firstChild);for(;t.firstChild;)e.appendChild(t.firstChild)}});function Pe(e,t){if(t){var n=e.firstChild;if(n&&n===e.lastChild&&n.nodeType===3){n.nodeValue=t;return}}e.textContent=t}var Fe={animationIterationCount:!0,aspectRatio:!0,borderImageOutset:!0,borderImageSlice:!0,borderImageWidth:!0,boxFlex:!0,boxFlexGroup:!0,boxOrdinalGroup:!0,columnCount:!0,columns:!0,flex:!0,flexGrow:!0,flexPositive:!0,flexShrink:!0,flexNegative:!0,flexOrder:!0,gridArea:!0,gridRow:!0,gridRowEnd:!0,gridRowSpan:!0,gridRowStart:!0,gridColumn:!0,gridColumnEnd:!0,gridColumnSpan:!0,gridColumnStart:!0,fontWeight:!0,lineClamp:!0,lineHeight:!0,opacity:!0,order:!0,orphans:!0,tabSize:!0,widows:!0,zIndex:!0,zoom:!0,fillOpacity:!0,floodOpacity:!0,stopOpacity:!0,strokeDasharray:!0,strokeDashoffset:!0,strokeMiterlimit:!0,strokeOpacity:!0,strokeWidth:!0},Ie=[`Webkit`,`ms`,`Moz`,`O`];Object.keys(Fe).forEach(function(e){Ie.forEach(function(t){t=t+e.charAt(0).toUpperCase()+e.substring(1),Fe[t]=Fe[e]})});function Le(e,t,n){return t==null||typeof t==`boolean`||t===``?``:n||typeof t!=`number`||t===0||Fe.hasOwnProperty(e)&&Fe[e]?(``+t).trim():t+`px`}function Re(e,t){for(var n in e=e.style,t)if(t.hasOwnProperty(n)){var r=n.indexOf(`--`)===0,i=Le(n,t[n],r);n===`float`&&(n=`cssFloat`),r?e.setProperty(n,i):e[n]=i}}var ze=N({menuitem:!0},{area:!0,base:!0,br:!0,col:!0,embed:!0,hr:!0,img:!0,input:!0,keygen:!0,link:!0,meta:!0,param:!0,source:!0,track:!0,wbr:!0});function Ve(e,t){if(t){if(ze[e]&&(t.children!=null||t.dangerouslySetInnerHTML!=null))throw Error(r(137,e));if(t.dangerouslySetInnerHTML!=null){if(t.children!=null)throw Error(r(60));if(typeof t.dangerouslySetInnerHTML!=`object`||!(`__html`in t.dangerouslySetInnerHTML))throw Error(r(61))}if(t.style!=null&&typeof t.style!=`object`)throw Error(r(62))}}function He(e,t){if(e.indexOf(`-`)===-1)return typeof t.is==`string`;switch(e){case`annotation-xml`:case`color-profile`:case`font-face`:case`font-face-src`:case`font-face-uri`:case`font-face-format`:case`font-face-name`:case`missing-glyph`:return!1;default:return!0}}var Ue=null;function We(e){return e=e.target||e.srcElement||window,e.correspondingUseElement&&(e=e.correspondingUseElement),e.nodeType===3?e.parentNode:e}var Ge=null,Ke=null,qe=null;function Je(e){if(e=Li(e)){if(typeof Ge!=`function`)throw Error(r(280));var t=e.stateNode;t&&(t=zi(t),Ge(e.stateNode,e.type,t))}}function Ye(e){Ke?qe?qe.push(e):qe=[e]:Ke=e}function Xe(){if(Ke){var e=Ke,t=qe;if(qe=Ke=null,Je(e),t)for(e=0;e>>=0,e===0?32:31-(Mt(e)/Nt|0)|0}var Ft=64,It=4194304;function Lt(e){switch(e&-e){case 1:return 1;case 2:return 2;case 4:return 4;case 8:return 8;case 16:return 16;case 32:return 32;case 64:case 128:case 256:case 512:case 1024:case 2048:case 4096:case 8192:case 16384:case 32768:case 65536:case 131072:case 262144:case 524288:case 1048576:case 2097152:return e&4194240;case 4194304:case 8388608:case 16777216:case 33554432:case 67108864:return e&130023424;case 134217728:return 134217728;case 268435456:return 268435456;case 536870912:return 536870912;case 1073741824:return 1073741824;default:return e}}function Rt(e,t){var n=e.pendingLanes;if(n===0)return 0;var r=0,i=e.suspendedLanes,a=e.pingedLanes,o=n&268435455;if(o!==0){var s=o&~i;s===0?(a&=o,a!==0&&(r=Lt(a))):r=Lt(s)}else o=n&~i,o===0?a!==0&&(r=Lt(a)):r=Lt(o);if(r===0)return 0;if(t!==0&&t!==r&&(t&i)===0&&(i=r&-r,a=t&-t,i>=a||i===16&&a&4194240))return t;if(r&4&&(r|=n&16),t=e.entangledLanes,t!==0)for(e=e.entanglements,t&=r;0n;n++)t.push(e);return t}function Wt(e,t,n){e.pendingLanes|=t,t!==536870912&&(e.suspendedLanes=0,e.pingedLanes=0),e=e.eventTimes,t=31-jt(t),e[t]=n}function Gt(e,t){var n=e.pendingLanes&~t;e.pendingLanes=t,e.suspendedLanes=0,e.pingedLanes=0,e.expiredLanes&=t,e.mutableReadLanes&=t,e.entangledLanes&=t,t=e.entanglements;var r=e.eventTimes;for(e=e.expirationTimes;0=tr),ir=` `,ar=!1;function or(e,t){switch(e){case`keyup`:return $n.indexOf(t.keyCode)!==-1;case`keydown`:return t.keyCode!==229;case`keypress`:case`mousedown`:case`focusout`:return!0;default:return!1}}function sr(e){return e=e.detail,typeof e==`object`&&`data`in e?e.data:null}var cr=!1;function lr(e,t){switch(e){case`compositionend`:return sr(t);case`keypress`:return t.which===32?(ar=!0,ir):null;case`textInput`:return e=t.data,e===ir&&ar?null:e;default:return null}}function ur(e,t){if(cr)return e===`compositionend`||!er&&or(e,t)?(e=Dn(),En=Tn=wn=null,cr=!1,e):null;switch(e){case`paste`:return null;case`keypress`:if(!(t.ctrlKey||t.altKey||t.metaKey)||t.ctrlKey&&t.altKey){if(t.char&&1=t)return{node:n,offset:t-e};e=r}a:{for(;n;){if(n.nextSibling){n=n.nextSibling;break a}n=n.parentNode}n=void 0}n=Mr(n)}}function Pr(e,t){return e&&t?e===t?!0:e&&e.nodeType===3?!1:t&&t.nodeType===3?Pr(e,t.parentNode):`contains`in e?e.contains(t):e.compareDocumentPosition?!!(e.compareDocumentPosition(t)&16):!1:!1}function Fr(){for(var e=window,t=_e();t instanceof e.HTMLIFrameElement;){try{var n=typeof t.contentWindow.location.href==`string`}catch{n=!1}if(n)e=t.contentWindow;else break;t=_e(e.document)}return t}function Ir(e){var t=e&&e.nodeName&&e.nodeName.toLowerCase();return t&&(t===`input`&&(e.type===`text`||e.type===`search`||e.type===`tel`||e.type===`url`||e.type===`password`)||t===`textarea`||e.contentEditable===`true`)}function Lr(e){var t=Fr(),n=e.focusedElem,r=e.selectionRange;if(t!==n&&n&&n.ownerDocument&&Pr(n.ownerDocument.documentElement,n)){if(r!==null&&Ir(n)){if(t=r.start,e=r.end,e===void 0&&(e=t),`selectionStart`in n)n.selectionStart=t,n.selectionEnd=Math.min(e,n.value.length);else if(e=(t=n.ownerDocument||document)&&t.defaultView||window,e.getSelection){e=e.getSelection();var i=n.textContent.length,a=Math.min(r.start,i);r=r.end===void 0?a:Math.min(r.end,i),!e.extend&&a>r&&(i=r,r=a,a=i),i=Nr(n,a);var o=Nr(n,r);i&&o&&(e.rangeCount!==1||e.anchorNode!==i.node||e.anchorOffset!==i.offset||e.focusNode!==o.node||e.focusOffset!==o.offset)&&(t=t.createRange(),t.setStart(i.node,i.offset),e.removeAllRanges(),a>r?(e.addRange(t),e.extend(o.node,o.offset)):(t.setEnd(o.node,o.offset),e.addRange(t)))}}for(t=[],e=n;e=e.parentNode;)e.nodeType===1&&t.push({element:e,left:e.scrollLeft,top:e.scrollTop});for(typeof n.focus==`function`&&n.focus(),n=0;n=document.documentMode,zr=null,Br=null,Vr=null,Hr=!1;function Ur(e,t,n){var r=n.window===n?n.document:n.nodeType===9?n:n.ownerDocument;Hr||zr==null||zr!==_e(r)||(r=zr,`selectionStart`in r&&Ir(r)?r={start:r.selectionStart,end:r.selectionEnd}:(r=(r.ownerDocument&&r.ownerDocument.defaultView||window).getSelection(),r={anchorNode:r.anchorNode,anchorOffset:r.anchorOffset,focusNode:r.focusNode,focusOffset:r.focusOffset}),Vr&&jr(Vr,r)||(Vr=r,r=mi(Br,`onSelect`),0Vi||(e.current=Bi[Vi],Bi[Vi]=null,Vi--)}function q(e,t){Vi++,Bi[Vi]=e.current,e.current=t}var Ui={},Wi=Hi(Ui),Gi=Hi(!1),Ki=Ui;function qi(e,t){var n=e.type.contextTypes;if(!n)return Ui;var r=e.stateNode;if(r&&r.__reactInternalMemoizedUnmaskedChildContext===t)return r.__reactInternalMemoizedMaskedChildContext;var i={},a;for(a in n)i[a]=t[a];return r&&(e=e.stateNode,e.__reactInternalMemoizedUnmaskedChildContext=t,e.__reactInternalMemoizedMaskedChildContext=i),i}function Ji(e){return e=e.childContextTypes,e!=null}function Yi(){K(Gi),K(Wi)}function Xi(e,t,n){if(Wi.current!==Ui)throw Error(r(168));q(Wi,t),q(Gi,n)}function Zi(e,t,n){var i=e.stateNode;if(t=t.childContextTypes,typeof i.getChildContext!=`function`)return n;for(var a in i=i.getChildContext(),i)if(!(a in t))throw Error(r(108,de(e)||`Unknown`,a));return N({},n,i)}function Qi(e){return e=(e=e.stateNode)&&e.__reactInternalMemoizedMergedChildContext||Ui,Ki=Wi.current,q(Wi,e),q(Gi,Gi.current),!0}function $i(e,t,n){var i=e.stateNode;if(!i)throw Error(r(169));n?(e=Zi(e,t,Ki),i.__reactInternalMemoizedMergedChildContext=e,K(Gi),K(Wi),q(Wi,e)):K(Gi),q(Gi,n)}var ea=null,ta=!1,na=!1;function ra(e){ea===null?ea=[e]:ea.push(e)}function ia(e){ta=!0,ra(e)}function aa(){if(!na&&ea!==null){na=!0;var e=0,t=F;try{var n=ea;for(F=1;e>=o,i-=o,pa=1<<32-jt(t)+i|n<h?(g=d,d=null):g=d.sibling;var _=p(r,d,s[h],c);if(_===null){d===null&&(d=g);break}e&&d&&_.alternate===null&&t(r,d),a=o(_,a,h),u===null?l=_:u.sibling=_,u=_,d=g}if(h===s.length)return n(r,d),J&&ha(r,h),l;if(d===null){for(;hg?(_=h,h=null):_=h.sibling;var y=p(a,h,v.value,l);if(y===null){h===null&&(h=_);break}e&&h&&y.alternate===null&&t(a,h),s=o(y,s,g),d===null?u=y:d.sibling=y,d=y,h=_}if(v.done)return n(a,h),J&&ha(a,g),u;if(h===null){for(;!v.done;g++,v=c.next())v=f(a,v.value,l),v!==null&&(s=o(v,s,g),d===null?u=v:d.sibling=v,d=v);return J&&ha(a,g),u}for(h=i(a,h);!v.done;g++,v=c.next())v=m(h,a,g,v.value,l),v!==null&&(e&&v.alternate!==null&&h.delete(v.key===null?g:v.key),s=o(v,s,g),d===null?u=v:d.sibling=v,d=v);return e&&h.forEach(function(e){return t(a,e)}),J&&ha(a,g),u}function _(e,r,i,o){if(typeof i==`object`&&i&&i.type===T&&i.key===null&&(i=i.props.children),typeof i==`object`&&i){switch(i.$$typeof){case C:a:{for(var c=i.key,l=r;l!==null;){if(l.key===c){if(c=i.type,c===T){if(l.tag===7){n(e,l.sibling),r=a(l,i.props.children),r.return=e,e=r;break a}}else if(l.elementType===c||typeof c==`object`&&c&&c.$$typeof===ne&&Pa(c)===l.type){n(e,l.sibling),r=a(l,i.props),r.ref=Ma(e,l,i),r.return=e,e=r;break a}n(e,l);break}t(e,l),l=l.sibling}i.type===T?(r=Zl(i.props.children,e.mode,o,i.key),r.return=e,e=r):(o=Xl(i.type,i.key,i.props,null,e.mode,o),o.ref=Ma(e,r,i),o.return=e,e=o)}return s(e);case w:a:{for(l=i.key;r!==null;){if(r.key===l){if(r.tag===4&&r.stateNode.containerInfo===i.containerInfo&&r.stateNode.implementation===i.implementation){n(e,r.sibling),r=a(r,i.children||[]),r.return=e,e=r;break a}n(e,r);break}t(e,r),r=r.sibling}r=eu(i,e.mode,o),r.return=e,e=r}return s(e);case ne:return l=i._init,_(e,r,l(i._payload),o)}if(we(i))return h(e,r,i,o);if(ie(i))return g(e,r,i,o);Na(e,i)}return typeof i==`string`&&i!==``||typeof i==`number`?(i=``+i,r!==null&&r.tag===6?(n(e,r.sibling),r=a(r,i),r.return=e,e=r):(n(e,r),r=$l(i,e.mode,o),r.return=e,e=r),s(e)):n(e,r)}return _}var Ia=Fa(!0),La=Fa(!1),Ra=Hi(null),za=null,Ba=null,Va=null;function Ha(){Va=Ba=za=null}function Ua(e){var t=Ra.current;K(Ra),e._currentValue=t}function Wa(e,t,n){for(;e!==null;){var r=e.alternate;if((e.childLanes&t)===t?r!==null&&(r.childLanes&t)!==t&&(r.childLanes|=t):(e.childLanes|=t,r!==null&&(r.childLanes|=t)),e===n)break;e=e.return}}function Ga(e,t){za=e,Va=Ba=null,e=e.dependencies,e!==null&&e.firstContext!==null&&((e.lanes&t)!==0&&(Ns=!0),e.firstContext=null)}function Ka(e){var t=e._currentValue;if(Va!==e){if(e={context:e,memoizedValue:t,next:null},Ba===null){if(za===null)throw Error(r(308));Ba=e,za.dependencies={lanes:0,firstContext:e}}else Ba=Ba.next=e}return t}var qa=null;function Ja(e){qa===null?qa=[e]:qa.push(e)}function Ya(e,t,n,r){var i=t.interleaved;return i===null?(n.next=n,Ja(t)):(n.next=i.next,i.next=n),t.interleaved=n,Xa(e,r)}function Xa(e,t){e.lanes|=t;var n=e.alternate;for(n!==null&&(n.lanes|=t),n=e,e=e.return;e!==null;)e.childLanes|=t,n=e.alternate,n!==null&&(n.childLanes|=t),n=e,e=e.return;return n.tag===3?n.stateNode:null}var Za=!1;function Qa(e){e.updateQueue={baseState:e.memoizedState,firstBaseUpdate:null,lastBaseUpdate:null,shared:{pending:null,interleaved:null,lanes:0},effects:null}}function $a(e,t){e=e.updateQueue,t.updateQueue===e&&(t.updateQueue={baseState:e.baseState,firstBaseUpdate:e.firstBaseUpdate,lastBaseUpdate:e.lastBaseUpdate,shared:e.shared,effects:e.effects})}function eo(e,t){return{eventTime:e,lane:t,tag:0,payload:null,callback:null,next:null}}function to(e,t,n){var r=e.updateQueue;if(r===null)return null;if(r=r.shared,Q&2){var i=r.pending;return i===null?t.next=t:(t.next=i.next,i.next=t),r.pending=t,Xa(e,n)}return i=r.interleaved,i===null?(t.next=t,Ja(r)):(t.next=i.next,i.next=t),r.interleaved=t,Xa(e,n)}function no(e,t,n){if(t=t.updateQueue,t!==null&&(t=t.shared,n&4194240)){var r=t.lanes;r&=e.pendingLanes,n|=r,t.lanes=n,Kt(e,n)}}function ro(e,t){var n=e.updateQueue,r=e.alternate;if(r!==null&&(r=r.updateQueue,n===r)){var i=null,a=null;if(n=n.firstBaseUpdate,n!==null){do{var o={eventTime:n.eventTime,lane:n.lane,tag:n.tag,payload:n.payload,callback:n.callback,next:null};a===null?i=a=o:a=a.next=o,n=n.next}while(n!==null);a===null?i=a=t:a=a.next=t}else i=a=t;n={baseState:r.baseState,firstBaseUpdate:i,lastBaseUpdate:a,shared:r.shared,effects:r.effects},e.updateQueue=n;return}e=n.lastBaseUpdate,e===null?n.firstBaseUpdate=t:e.next=t,n.lastBaseUpdate=t}function io(e,t,n,r){var i=e.updateQueue;Za=!1;var a=i.firstBaseUpdate,o=i.lastBaseUpdate,s=i.shared.pending;if(s!==null){i.shared.pending=null;var c=s,l=c.next;c.next=null,o===null?a=l:o.next=l,o=c;var u=e.alternate;u!==null&&(u=u.updateQueue,s=u.lastBaseUpdate,s!==o&&(s===null?u.firstBaseUpdate=l:s.next=l,u.lastBaseUpdate=c))}if(a!==null){var d=i.baseState;o=0,u=l=c=null,s=a;do{var f=s.lane,p=s.eventTime;if((r&f)===f){u!==null&&(u=u.next={eventTime:p,lane:0,tag:s.tag,payload:s.payload,callback:s.callback,next:null});a:{var m=e,h=s;switch(f=t,p=n,h.tag){case 1:if(m=h.payload,typeof m==`function`){d=m.call(p,d,f);break a}d=m;break a;case 3:m.flags=m.flags&-65537|128;case 0:if(m=h.payload,f=typeof m==`function`?m.call(p,d,f):m,f==null)break a;d=N({},d,f);break a;case 2:Za=!0}}s.callback!==null&&s.lane!==0&&(e.flags|=64,f=i.effects,f===null?i.effects=[s]:f.push(s))}else p={eventTime:p,lane:f,tag:s.tag,payload:s.payload,callback:s.callback,next:null},u===null?(l=u=p,c=d):u=u.next=p,o|=f;if(s=s.next,s===null){if(s=i.shared.pending,s===null)break;f=s,s=f.next,f.next=null,i.lastBaseUpdate=f,i.shared.pending=null}}while(1);if(u===null&&(c=d),i.baseState=c,i.firstBaseUpdate=l,i.lastBaseUpdate=u,t=i.shared.interleaved,t!==null){i=t;do o|=i.lane,i=i.next;while(i!==t)}else a===null&&(i.shared.lanes=0);Yc|=o,e.lanes=o,e.memoizedState=d}}function ao(e,t,n){if(e=t.effects,t.effects=null,e!==null)for(t=0;tn?n:4,e(!0);var r=bo.transition;bo.transition={};try{e(!1),t()}finally{F=n,bo.transition=r}}function os(){return No().memoizedState}function ss(e,t,n){var r=ml(e);if(n={lane:r,action:n,hasEagerState:!1,eagerState:null,next:null},ls(e))us(t,n);else if(n=Ya(e,t,n,r),n!==null){var i=pl();hl(n,e,r,i),ds(n,t,r)}}function cs(e,t,n){var r=ml(e),i={lane:r,action:n,hasEagerState:!1,eagerState:null,next:null};if(ls(e))us(t,i);else{var a=e.alternate;if(e.lanes===0&&(a===null||a.lanes===0)&&(a=t.lastRenderedReducer,a!==null))try{var o=t.lastRenderedState,s=a(o,n);if(i.hasEagerState=!0,i.eagerState=s,Ar(s,o)){var c=t.interleaved;c===null?(i.next=i,Ja(t)):(i.next=c.next,c.next=i),t.interleaved=i;return}}catch{}n=Ya(e,t,i,r),n!==null&&(i=pl(),hl(n,e,r,i),ds(n,t,r))}}function ls(e){var t=e.alternate;return e===X||t!==null&&t===X}function us(e,t){To=wo=!0;var n=e.pending;n===null?t.next=t:(t.next=n.next,n.next=t),e.pending=t}function ds(e,t,n){if(n&4194240){var r=t.lanes;r&=e.pendingLanes,n|=r,t.lanes=n,Kt(e,n)}}var fs={readContext:Ka,useCallback:Oo,useContext:Oo,useEffect:Oo,useImperativeHandle:Oo,useInsertionEffect:Oo,useLayoutEffect:Oo,useMemo:Oo,useReducer:Oo,useRef:Oo,useState:Oo,useDebugValue:Oo,useDeferredValue:Oo,useTransition:Oo,useMutableSource:Oo,useSyncExternalStore:Oo,useId:Oo,unstable_isNewReconciler:!1},ps={readContext:Ka,useCallback:function(e,t){return Mo().memoizedState=[e,t===void 0?null:t],e},useContext:Ka,useEffect:Yo,useImperativeHandle:function(e,t,n){return n=n==null?null:n.concat([e]),qo(4194308,4,$o.bind(null,t,e),n)},useLayoutEffect:function(e,t){return qo(4194308,4,e,t)},useInsertionEffect:function(e,t){return qo(4,2,e,t)},useMemo:function(e,t){var n=Mo();return t=t===void 0?null:t,e=e(),n.memoizedState=[e,t],e},useReducer:function(e,t,n){var r=Mo();return t=n===void 0?t:n(t),r.memoizedState=r.baseState=t,e={pending:null,interleaved:null,lanes:0,dispatch:null,lastRenderedReducer:e,lastRenderedState:t},r.queue=e,e=e.dispatch=ss.bind(null,X,e),[r.memoizedState,e]},useRef:function(e){var t=Mo();return e={current:e},t.memoizedState=e},useState:Wo,useDebugValue:ts,useDeferredValue:function(e){return Mo().memoizedState=e},useTransition:function(){var e=Wo(!1),t=e[0];return e=as.bind(null,e[1]),Mo().memoizedState=e,[t,e]},useMutableSource:function(){},useSyncExternalStore:function(e,t,n){var i=X,a=Mo();if(J){if(n===void 0)throw Error(r(407));n=n()}else{if(n=t(),Hc===null)throw Error(r(349));xo&30||zo(i,t,n)}a.memoizedState=n;var o={value:n,getSnapshot:t};return a.queue=o,Yo(Vo.bind(null,i,o,e),[e]),i.flags|=2048,Go(9,Bo.bind(null,i,o,n,t),void 0,null),n},useId:function(){var e=Mo(),t=Hc.identifierPrefix;if(J){var n=ma,r=pa;n=(r&~(1<<32-jt(r)-1)).toString(32)+n,t=`:`+t+`R`+n,n=Eo++,0<\/script>`,e=e.removeChild(e.firstChild)):typeof i.is==`string`?e=c.createElement(n,{is:i.is}):(e=c.createElement(n),n===`select`&&(c=e,i.multiple?c.multiple=!0:i.size&&(c.size=i.size))):e=c.createElementNS(e,n),e[ji]=t,e[Mi]=i,rc(e,t,!1,!1),t.stateNode=e;a:{switch(c=He(n,i),n){case`dialog`:V(`cancel`,e),V(`close`,e),o=i;break;case`iframe`:case`object`:case`embed`:V(`load`,e),o=i;break;case`video`:case`audio`:for(o=0;otl&&(t.flags|=128,i=!0,oc(s,!1),t.lanes=4194304)}}else{if(!i){if(e=go(c),e!==null){if(t.flags|=128,i=!0,n=e.updateQueue,n!==null&&(t.updateQueue=n,t.flags|=4),oc(s,!0),s.tail===null&&s.tailMode===`hidden`&&!c.alternate&&!J)return sc(t),null}else 2*P()-s.renderingStartTime>tl&&n!==1073741824&&(t.flags|=128,i=!0,oc(s,!1),t.lanes=4194304)}s.isBackwards?(c.sibling=t.child,t.child=c):(n=s.last,n===null?t.child=c:n.sibling=c,s.last=c)}return s.tail===null?(sc(t),null):(t=s.tail,s.rendering=t,s.tail=t.sibling,s.renderingStartTime=P(),t.sibling=null,n=Y.current,q(Y,i?n&1|2:n&1),t);case 22:case 23:return Tl(),i=t.memoizedState!==null,e!==null&&e.memoizedState!==null!==i&&(t.flags|=8192),i&&t.mode&1?Gc&1073741824&&(sc(t),t.subtreeFlags&6&&(t.flags|=8192)):sc(t),null;case 24:return null;case 25:return null}throw Error(r(156,t.tag))}function lc(e,t){switch(va(t),t.tag){case 1:return Ji(t.type)&&Yi(),e=t.flags,e&65536?(t.flags=e&-65537|128,t):null;case 3:return po(),K(Gi),K(Wi),vo(),e=t.flags,e&65536&&!(e&128)?(t.flags=e&-65537|128,t):null;case 5:return ho(t),null;case 13:if(K(Y),e=t.memoizedState,e!==null&&e.dehydrated!==null){if(t.alternate===null)throw Error(r(340));ka()}return e=t.flags,e&65536?(t.flags=e&-65537|128,t):null;case 19:return K(Y),null;case 4:return po(),null;case 10:return Ua(t.type._context),null;case 22:case 23:return Tl(),null;case 24:return null;default:return null}}var uc=!1,dc=!1,fc=typeof WeakSet==`function`?WeakSet:Set,Z=null;function pc(e,t){var n=e.ref;if(n!==null){if(typeof n==`function`)try{n(null)}catch(n){$(e,t,n)}else n.current=null}}function mc(e,t,n){try{n()}catch(n){$(e,t,n)}}var hc=!1;function gc(e,t){if(Si=yn,e=Fr(),Ir(e)){if(`selectionStart`in e)var n={start:e.selectionStart,end:e.selectionEnd};else a:{n=(n=e.ownerDocument)&&n.defaultView||window;var i=n.getSelection&&n.getSelection();if(i&&i.rangeCount!==0){n=i.anchorNode;var a=i.anchorOffset,o=i.focusNode;i=i.focusOffset;try{n.nodeType,o.nodeType}catch{n=null;break a}var s=0,c=-1,l=-1,u=0,d=0,f=e,p=null;b:for(;;){for(var m;f!==n||a!==0&&f.nodeType!==3||(c=s+a),f!==o||i!==0&&f.nodeType!==3||(l=s+i),f.nodeType===3&&(s+=f.nodeValue.length),(m=f.firstChild)!==null;)p=f,f=m;for(;;){if(f===e)break b;if(p===n&&++u===a&&(c=s),p===o&&++d===i&&(l=s),(m=f.nextSibling)!==null)break;f=p,p=f.parentNode}f=m}n=c===-1||l===-1?null:{start:c,end:l}}else n=null}n||={start:0,end:0}}else n=null;for(Ci={focusedElem:e,selectionRange:n},yn=!1,Z=t;Z!==null;)if(t=Z,e=t.child,t.subtreeFlags&1028&&e!==null)e.return=t,Z=e;else for(;Z!==null;){t=Z;try{var h=t.alternate;if(t.flags&1024)switch(t.tag){case 0:case 11:case 15:break;case 1:if(h!==null){var g=h.memoizedProps,_=h.memoizedState,v=t.stateNode;v.__reactInternalSnapshotBeforeUpdate=v.getSnapshotBeforeUpdate(t.elementType===t.type?g:gs(t.type,g),_)}break;case 3:var y=t.stateNode.containerInfo;y.nodeType===1?y.textContent=``:y.nodeType===9&&y.documentElement&&y.removeChild(y.documentElement);break;case 5:case 6:case 4:case 17:break;default:throw Error(r(163))}}catch(e){$(t,t.return,e)}if(e=t.sibling,e!==null){e.return=t.return,Z=e;break}Z=t.return}return h=hc,hc=!1,h}function _c(e,t,n){var r=t.updateQueue;if(r=r===null?null:r.lastEffect,r!==null){var i=r=r.next;do{if((i.tag&e)===e){var a=i.destroy;i.destroy=void 0,a!==void 0&&mc(t,n,a)}i=i.next}while(i!==r)}}function vc(e,t){if(t=t.updateQueue,t=t===null?null:t.lastEffect,t!==null){var n=t=t.next;do{if((n.tag&e)===e){var r=n.create;n.destroy=r()}n=n.next}while(n!==t)}}function yc(e){var t=e.ref;if(t!==null){var n=e.stateNode;switch(e.tag){case 5:e=n;break;default:e=n}typeof t==`function`?t(e):t.current=e}}function bc(e){var t=e.alternate;t!==null&&(e.alternate=null,bc(t)),e.child=null,e.deletions=null,e.sibling=null,e.tag===5&&(t=e.stateNode,t!==null&&(delete t[ji],delete t[Mi],delete t[G],delete t[Pi],delete t[Fi])),e.stateNode=null,e.return=null,e.dependencies=null,e.memoizedProps=null,e.memoizedState=null,e.pendingProps=null,e.stateNode=null,e.updateQueue=null}function xc(e){return e.tag===5||e.tag===3||e.tag===4}function Sc(e){a:for(;;){for(;e.sibling===null;){if(e.return===null||xc(e.return))return null;e=e.return}for(e.sibling.return=e.return,e=e.sibling;e.tag!==5&&e.tag!==6&&e.tag!==18;){if(e.flags&2||e.child===null||e.tag===4)continue a;e.child.return=e,e=e.child}if(!(e.flags&2))return e.stateNode}}function Cc(e,t,n){var r=e.tag;if(r===5||r===6)e=e.stateNode,t?n.nodeType===8?n.parentNode.insertBefore(e,t):n.insertBefore(e,t):(n.nodeType===8?(t=n.parentNode,t.insertBefore(e,n)):(t=n,t.appendChild(e)),n=n._reactRootContainer,n!=null||t.onclick!==null||(t.onclick=xi));else if(r!==4&&(e=e.child,e!==null))for(Cc(e,t,n),e=e.sibling;e!==null;)Cc(e,t,n),e=e.sibling}function wc(e,t,n){var r=e.tag;if(r===5||r===6)e=e.stateNode,t?n.insertBefore(e,t):n.appendChild(e);else if(r!==4&&(e=e.child,e!==null))for(wc(e,t,n),e=e.sibling;e!==null;)wc(e,t,n),e=e.sibling}var Tc=null,Ec=!1;function Dc(e,t,n){for(n=n.child;n!==null;)Oc(e,t,n),n=n.sibling}function Oc(e,t,n){if(kt&&typeof kt.onCommitFiberUnmount==`function`)try{kt.onCommitFiberUnmount(Ot,n)}catch{}switch(n.tag){case 5:dc||pc(n,t);case 6:var r=Tc,i=Ec;Tc=null,Dc(e,t,n),Tc=r,Ec=i,Tc!==null&&(Ec?(e=Tc,n=n.stateNode,e.nodeType===8?e.parentNode.removeChild(n):e.removeChild(n)):Tc.removeChild(n.stateNode));break;case 18:Tc!==null&&(Ec?(e=Tc,n=n.stateNode,e.nodeType===8?H(e.parentNode,n):e.nodeType===1&&H(e,n),_n(e)):H(Tc,n.stateNode));break;case 4:r=Tc,i=Ec,Tc=n.stateNode.containerInfo,Ec=!0,Dc(e,t,n),Tc=r,Ec=i;break;case 0:case 11:case 14:case 15:if(!dc&&(r=n.updateQueue,r!==null&&(r=r.lastEffect,r!==null))){i=r=r.next;do{var a=i,o=a.destroy;a=a.tag,o!==void 0&&(a&2||a&4)&&mc(n,t,o),i=i.next}while(i!==r)}Dc(e,t,n);break;case 1:if(!dc&&(pc(n,t),r=n.stateNode,typeof r.componentWillUnmount==`function`))try{r.props=n.memoizedProps,r.state=n.memoizedState,r.componentWillUnmount()}catch(e){$(n,t,e)}Dc(e,t,n);break;case 21:Dc(e,t,n);break;case 22:n.mode&1?(dc=(r=dc)||n.memoizedState!==null,Dc(e,t,n),dc=r):Dc(e,t,n);break;default:Dc(e,t,n)}}function kc(e){var t=e.updateQueue;if(t!==null){e.updateQueue=null;var n=e.stateNode;n===null&&(n=e.stateNode=new fc),t.forEach(function(t){var r=Hl.bind(null,e,t);n.has(t)||(n.add(t),t.then(r,r))})}}function Ac(e,t){var n=t.deletions;if(n!==null)for(var i=0;ia&&(a=s),i&=~o}if(i=a,i=P()-i,i=(120>i?120:480>i?480:1080>i?1080:1920>i?1920:3e3>i?3e3:4320>i?4320:1960*Rc(i/1960))-i,10e?16:e,sl===null)var i=!1;else{if(e=sl,sl=null,cl=0,Q&6)throw Error(r(331));var a=Q;for(Q|=4,Z=e.current;Z!==null;){var o=Z,s=o.child;if(Z.flags&16){var c=o.deletions;if(c!==null){for(var l=0;lP()-el?El(e,0):Zc|=n),gl(e,t)}function Bl(e,t){t===0&&(e.mode&1?(t=It,It<<=1,!(It&130023424)&&(It=4194304)):t=1);var n=pl();e=Xa(e,t),e!==null&&(Wt(e,t,n),gl(e,n))}function Vl(e){var t=e.memoizedState,n=0;t!==null&&(n=t.retryLane),Bl(e,n)}function Hl(e,t){var n=0;switch(e.tag){case 13:var i=e.stateNode,a=e.memoizedState;a!==null&&(n=a.retryLane);break;case 19:i=e.stateNode;break;default:throw Error(r(314))}i!==null&&i.delete(t),Bl(e,n)}var Ul=function(e,t,n){if(e!==null){if(e.memoizedProps!==t.pendingProps||Gi.current)Ns=!0;else{if((e.lanes&n)===0&&!(t.flags&128))return Ns=!1,nc(e,t,n);Ns=!!(e.flags&131072)}}else Ns=!1,J&&t.flags&1048576&&ga(t,la,t.index);switch(t.lanes=0,t.tag){case 2:var i=t.type;ec(e,t),e=t.pendingProps;var a=qi(t,Wi.current);Ga(t,n),a=Ao(null,t,i,e,a,n);var o=jo();return t.flags|=1,typeof a==`object`&&a&&typeof a.render==`function`&&a.$$typeof===void 0?(t.tag=1,t.memoizedState=null,t.updateQueue=null,Ji(i)?(o=!0,Qi(t)):o=!1,t.memoizedState=a.state!==null&&a.state!==void 0?a.state:null,Qa(t),a.updater=vs,t.stateNode=a,a._reactInternals=t,Ss(t,i,e,n),t=Hs(null,t,i,!0,o,n)):(t.tag=0,J&&o&&_a(t),Ps(null,t,a,n),t=t.child),t;case 16:i=t.elementType;a:{switch(ec(e,t),e=t.pendingProps,a=i._init,i=a(i._payload),t.type=i,a=t.tag=Jl(i),e=gs(i,e),a){case 0:t=Bs(null,t,i,e,n);break a;case 1:t=Vs(null,t,i,e,n);break a;case 11:t=Fs(null,t,i,e,n);break a;case 14:t=Is(null,t,i,gs(i.type,e),n);break a}throw Error(r(306,i,``))}return t;case 0:return i=t.type,a=t.pendingProps,a=t.elementType===i?a:gs(i,a),Bs(e,t,i,a,n);case 1:return i=t.type,a=t.pendingProps,a=t.elementType===i?a:gs(i,a),Vs(e,t,i,a,n);case 3:a:{if(Us(t),e===null)throw Error(r(387));i=t.pendingProps,o=t.memoizedState,a=o.element,$a(e,t),io(t,i,null,n);var s=t.memoizedState;if(i=s.element,o.isDehydrated){if(o={element:i,isDehydrated:!1,cache:s.cache,pendingSuspenseBoundaries:s.pendingSuspenseBoundaries,transitions:s.transitions},t.updateQueue.baseState=o,t.memoizedState=o,t.flags&256){a=Cs(Error(r(423)),t),t=Ws(e,t,i,n,a);break a}if(i!==a){a=Cs(Error(r(424)),t),t=Ws(e,t,i,n,a);break a}for(ba=U(t.stateNode.containerInfo.firstChild),ya=t,J=!0,xa=null,n=La(t,null,i,n),t.child=n;n;)n.flags=n.flags&-3|4096,n=n.sibling}else{if(ka(),i===a){t=tc(e,t,n);break a}Ps(e,t,i,n)}t=t.child}return t;case 5:return mo(t),e===null&&Ta(t),i=t.type,a=t.pendingProps,o=e===null?null:e.memoizedProps,s=a.children,wi(i,a)?s=null:o!==null&&wi(i,o)&&(t.flags|=32),zs(e,t),Ps(e,t,s,n),t.child;case 6:return e===null&&Ta(t),null;case 13:return qs(e,t,n);case 4:return fo(t,t.stateNode.containerInfo),i=t.pendingProps,e===null?t.child=Ia(t,null,i,n):Ps(e,t,i,n),t.child;case 11:return i=t.type,a=t.pendingProps,a=t.elementType===i?a:gs(i,a),Fs(e,t,i,a,n);case 7:return Ps(e,t,t.pendingProps,n),t.child;case 8:return Ps(e,t,t.pendingProps.children,n),t.child;case 12:return Ps(e,t,t.pendingProps.children,n),t.child;case 10:a:{if(i=t.type._context,a=t.pendingProps,o=t.memoizedProps,s=a.value,q(Ra,i._currentValue),i._currentValue=s,o!==null){if(Ar(o.value,s)){if(o.children===a.children&&!Gi.current){t=tc(e,t,n);break a}}else for(o=t.child,o!==null&&(o.return=t);o!==null;){var c=o.dependencies;if(c!==null){s=o.child;for(var l=c.firstContext;l!==null;){if(l.context===i){if(o.tag===1){l=eo(-1,n&-n),l.tag=2;var u=o.updateQueue;if(u!==null){u=u.shared;var d=u.pending;d===null?l.next=l:(l.next=d.next,d.next=l),u.pending=l}}o.lanes|=n,l=o.alternate,l!==null&&(l.lanes|=n),Wa(o.return,n,t),c.lanes|=n;break}l=l.next}}else if(o.tag===10)s=o.type===t.type?null:o.child;else if(o.tag===18){if(s=o.return,s===null)throw Error(r(341));s.lanes|=n,c=s.alternate,c!==null&&(c.lanes|=n),Wa(s,n,t),s=o.sibling}else s=o.child;if(s!==null)s.return=o;else for(s=o;s!==null;){if(s===t){s=null;break}if(o=s.sibling,o!==null){o.return=s.return,s=o;break}s=s.return}o=s}}Ps(e,t,a.children,n),t=t.child}return t;case 9:return a=t.type,i=t.pendingProps.children,Ga(t,n),a=Ka(a),i=i(a),t.flags|=1,Ps(e,t,i,n),t.child;case 14:return i=t.type,a=gs(i,t.pendingProps),a=gs(i.type,a),Is(e,t,i,a,n);case 15:return Ls(e,t,t.type,t.pendingProps,n);case 17:return i=t.type,a=t.pendingProps,a=t.elementType===i?a:gs(i,a),ec(e,t),t.tag=1,Ji(i)?(e=!0,Qi(t)):e=!1,Ga(t,n),bs(t,i,a),Ss(t,i,a,n),Hs(null,t,i,!0,e,n);case 19:return $s(e,t,n);case 22:return Rs(e,t,n)}throw Error(r(156,t.tag))};function Wl(e,t){return vt(e,t)}function Gl(e,t,n,r){this.tag=e,this.key=n,this.sibling=this.child=this.return=this.stateNode=this.type=this.elementType=null,this.index=0,this.ref=null,this.pendingProps=t,this.dependencies=this.memoizedState=this.updateQueue=this.memoizedProps=null,this.mode=r,this.subtreeFlags=this.flags=0,this.deletions=null,this.childLanes=this.lanes=0,this.alternate=null}function Kl(e,t,n,r){return new Gl(e,t,n,r)}function ql(e){return e=e.prototype,!(!e||!e.isReactComponent)}function Jl(e){if(typeof e==`function`)return+!!ql(e);if(e!=null){if(e=e.$$typeof,e===ee)return 11;if(e===j)return 14}return 2}function Yl(e,t){var n=e.alternate;return n===null?(n=Kl(e.tag,t,e.key,e.mode),n.elementType=e.elementType,n.type=e.type,n.stateNode=e.stateNode,n.alternate=e,e.alternate=n):(n.pendingProps=t,n.type=e.type,n.flags=0,n.subtreeFlags=0,n.deletions=null),n.flags=e.flags&14680064,n.childLanes=e.childLanes,n.lanes=e.lanes,n.child=e.child,n.memoizedProps=e.memoizedProps,n.memoizedState=e.memoizedState,n.updateQueue=e.updateQueue,t=e.dependencies,n.dependencies=t===null?null:{lanes:t.lanes,firstContext:t.firstContext},n.sibling=e.sibling,n.index=e.index,n.ref=e.ref,n}function Xl(e,t,n,i,a,o){var s=2;if(i=e,typeof e==`function`)ql(e)&&(s=1);else if(typeof e==`string`)s=5;else a:switch(e){case T:return Zl(n.children,a,o,t);case E:s=8,a|=8;break;case D:return e=Kl(12,n,t,a|2),e.elementType=D,e.lanes=o,e;case A:return e=Kl(13,n,t,a),e.elementType=A,e.lanes=o,e;case te:return e=Kl(19,n,t,a),e.elementType=te,e.lanes=o,e;case re:return Ql(n,a,o,t);default:if(typeof e==`object`&&e)switch(e.$$typeof){case O:s=10;break a;case k:s=9;break a;case ee:s=11;break a;case j:s=14;break a;case ne:s=16,i=null;break a}throw Error(r(130,e==null?e:typeof e,``))}return t=Kl(s,n,t,a),t.elementType=e,t.type=i,t.lanes=o,t}function Zl(e,t,n,r){return e=Kl(7,e,r,t),e.lanes=n,e}function Ql(e,t,n,r){return e=Kl(22,e,r,t),e.elementType=re,e.lanes=n,e.stateNode={isHidden:!1},e}function $l(e,t,n){return e=Kl(6,e,null,t),e.lanes=n,e}function eu(e,t,n){return t=Kl(4,e.children===null?[]:e.children,e.key,t),t.lanes=n,t.stateNode={containerInfo:e.containerInfo,pendingChildren:null,implementation:e.implementation},t}function tu(e,t,n,r,i){this.tag=t,this.containerInfo=e,this.finishedWork=this.pingCache=this.current=this.pendingChildren=null,this.timeoutHandle=-1,this.callbackNode=this.pendingContext=this.context=null,this.callbackPriority=0,this.eventTimes=Ut(0),this.expirationTimes=Ut(-1),this.entangledLanes=this.finishedLanes=this.mutableReadLanes=this.expiredLanes=this.pingedLanes=this.suspendedLanes=this.pendingLanes=0,this.entanglements=Ut(0),this.identifierPrefix=r,this.onRecoverableError=i,this.mutableSourceEagerHydrationData=null}function nu(e,t,n,r,i,a,o,s,c){return e=new tu(e,t,n,s,c),t===1?(t=1,!0===a&&(t|=8)):t=0,a=Kl(3,null,null,t),e.current=a,a.stateNode=e,a.memoizedState={element:r,isDehydrated:n,cache:null,transitions:null,pendingSuspenseBoundaries:null},Qa(a),e}function ru(e,t,n){var r=3{function n(){if(typeof __REACT_DEVTOOLS_GLOBAL_HOOK__<`u`&&typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE==`function`)try{__REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE(n)}catch(e){console.error(e)}}n(),t.exports=Ve()})),Ue=b((e=>{var t=He();e.createRoot=t.createRoot,e.hydrateRoot=t.hydrateRoot})),We=o(`alarm-clock`,[[`circle`,{cx:`12`,cy:`13`,r:`8`,key:`3y4lt7`}],[`path`,{d:`M12 9v4l2 2`,key:`1c63tq`}],[`path`,{d:`M5 3 2 6`,key:`18tl5t`}],[`path`,{d:`m22 6-3-3`,key:`1opdir`}],[`path`,{d:`M6.38 18.7 4 21`,key:`17xu3x`}],[`path`,{d:`M17.64 18.67 20 21`,key:`kv2oe2`}]]),Ge=o(`arrow-down`,[[`path`,{d:`M12 5v14`,key:`s699le`}],[`path`,{d:`m19 12-7 7-7-7`,key:`1idqje`}]]),Ke=o(`arrow-left`,[[`path`,{d:`m12 19-7-7 7-7`,key:`1l729n`}],[`path`,{d:`M19 12H5`,key:`x3x0zl`}]]),qe=o(`arrow-right`,[[`path`,{d:`M5 12h14`,key:`1ays0h`}],[`path`,{d:`m12 5 7 7-7 7`,key:`xquz4c`}]]),Je=o(`arrow-up`,[[`path`,{d:`m5 12 7-7 7 7`,key:`hav0vg`}],[`path`,{d:`M12 19V5`,key:`x0mq9r`}]]),Ye=o(`ban`,[[`circle`,{cx:`12`,cy:`12`,r:`10`,key:`1mglay`}],[`path`,{d:`M4.929 4.929 19.07 19.071`,key:`196cmz`}]]),Xe=o(`bell`,[[`path`,{d:`M10.268 21a2 2 0 0 0 3.464 0`,key:`vwvbt9`}],[`path`,{d:`M3.262 15.326A1 1 0 0 0 4 17h16a1 1 0 0 0 .74-1.673C19.41 13.956 18 12.499 18 8A6 6 0 0 0 6 8c0 4.499-1.411 5.956-2.738 7.326`,key:`11g9vi`}]]),Ze=o(`bot`,[[`path`,{d:`M12 8V4H8`,key:`hb8ula`}],[`rect`,{width:`16`,height:`12`,x:`4`,y:`8`,rx:`2`,key:`enze0r`}],[`path`,{d:`M2 14h2`,key:`vft8re`}],[`path`,{d:`M20 14h2`,key:`4cs60a`}],[`path`,{d:`M15 13v2`,key:`1xurst`}],[`path`,{d:`M9 13v2`,key:`rq6x2g`}]]),Qe=o(`brain`,[[`path`,{d:`M12 18V5`,key:`adv99a`}],[`path`,{d:`M15 13a4.17 4.17 0 0 1-3-4 4.17 4.17 0 0 1-3 4`,key:`1e3is1`}],[`path`,{d:`M17.598 6.5A3 3 0 1 0 12 5a3 3 0 1 0-5.598 1.5`,key:`1gqd8o`}],[`path`,{d:`M17.997 5.125a4 4 0 0 1 2.526 5.77`,key:`iwvgf7`}],[`path`,{d:`M18 18a4 4 0 0 0 2-7.464`,key:`efp6ie`}],[`path`,{d:`M19.967 17.483A4 4 0 1 1 12 18a4 4 0 1 1-7.967-.517`,key:`1gq6am`}],[`path`,{d:`M6 18a4 4 0 0 1-2-7.464`,key:`k1g0md`}],[`path`,{d:`M6.003 5.125a4 4 0 0 0-2.526 5.77`,key:`q97ue3`}]]),$e=o(`briefcase`,[[`path`,{d:`M16 20V4a2 2 0 0 0-2-2h-4a2 2 0 0 0-2 2v16`,key:`jecpp`}],[`rect`,{width:`20`,height:`14`,x:`2`,y:`6`,rx:`2`,key:`i6l2r4`}]]),et=o(`calendar-clock`,[[`path`,{d:`M16 14v2.2l1.6 1`,key:`fo4ql5`}],[`path`,{d:`M16 2v4`,key:`4m81vk`}],[`path`,{d:`M21 7.5V6a2 2 0 0 0-2-2H5a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h3.5`,key:`1osxxc`}],[`path`,{d:`M3 10h5`,key:`r794hk`}],[`path`,{d:`M8 2v4`,key:`1cmpym`}],[`circle`,{cx:`16`,cy:`16`,r:`6`,key:`qoo3c4`}]]),tt=o(`calendar-days`,[[`path`,{d:`M8 2v4`,key:`1cmpym`}],[`path`,{d:`M16 2v4`,key:`4m81vk`}],[`rect`,{width:`18`,height:`18`,x:`3`,y:`4`,rx:`2`,key:`1hopcy`}],[`path`,{d:`M3 10h18`,key:`8toen8`}],[`path`,{d:`M8 14h.01`,key:`6423bh`}],[`path`,{d:`M12 14h.01`,key:`1etili`}],[`path`,{d:`M16 14h.01`,key:`1gbofw`}],[`path`,{d:`M8 18h.01`,key:`lrp35t`}],[`path`,{d:`M12 18h.01`,key:`mhygvu`}],[`path`,{d:`M16 18h.01`,key:`kzsmim`}]]),nt=o(`calendar-plus`,[[`path`,{d:`M16 19h6`,key:`xwg31i`}],[`path`,{d:`M16 2v4`,key:`4m81vk`}],[`path`,{d:`M19 16v6`,key:`tddt3s`}],[`path`,{d:`M21 12.598V6a2 2 0 0 0-2-2H5a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h8.5`,key:`1glfrc`}],[`path`,{d:`M3 10h18`,key:`8toen8`}],[`path`,{d:`M8 2v4`,key:`1cmpym`}]]),rt=o(`chevron-right`,[[`path`,{d:`m9 18 6-6-6-6`,key:`mthhwq`}]]),it=o(`clipboard-list`,[[`rect`,{width:`8`,height:`4`,x:`8`,y:`2`,rx:`1`,ry:`1`,key:`tgr4d6`}],[`path`,{d:`M16 4h2a2 2 0 0 1 2 2v14a2 2 0 0 1-2 2H6a2 2 0 0 1-2-2V6a2 2 0 0 1 2-2h2`,key:`116196`}],[`path`,{d:`M12 11h4`,key:`1jrz19`}],[`path`,{d:`M12 16h4`,key:`n85exb`}],[`path`,{d:`M8 11h.01`,key:`1dfujw`}],[`path`,{d:`M8 16h.01`,key:`18s6g9`}]]),at=o(`clock`,[[`circle`,{cx:`12`,cy:`12`,r:`10`,key:`1mglay`}],[`path`,{d:`M12 6v6l4 2`,key:`mmk7yg`}]]),ot=o(`cloud-cog`,[[`path`,{d:`m10.852 19.772-.383.924`,key:`r7sl7d`}],[`path`,{d:`m13.148 14.228.383-.923`,key:`1d5zpm`}],[`path`,{d:`M13.148 19.772a3 3 0 1 0-2.296-5.544l-.383-.923`,key:`1ydik7`}],[`path`,{d:`m13.53 20.696-.382-.924a3 3 0 1 1-2.296-5.544`,key:`1m1vsf`}],[`path`,{d:`m14.772 15.852.923-.383`,key:`660p6e`}],[`path`,{d:`m14.772 18.148.923.383`,key:`hrcpis`}],[`path`,{d:`M4.2 15.1a7 7 0 1 1 9.93-9.858A7 7 0 0 1 15.71 8h1.79a4.5 4.5 0 0 1 2.5 8.2`,key:`j2q98n`}],[`path`,{d:`m9.228 15.852-.923-.383`,key:`1p9ong`}],[`path`,{d:`m9.228 18.148-.923.383`,key:`6558rz`}]]),st=o(`cloud`,[[`path`,{d:`M17.5 19H9a7 7 0 1 1 6.71-9h1.79a4.5 4.5 0 1 1 0 9Z`,key:`p7xjir`}]]),ct=o(`code-xml`,[[`path`,{d:`m18 16 4-4-4-4`,key:`1inbqp`}],[`path`,{d:`m6 8-4 4 4 4`,key:`15zrgr`}],[`path`,{d:`m14.5 4-5 16`,key:`e7oirm`}]]),lt=o(`compass`,[[`circle`,{cx:`12`,cy:`12`,r:`10`,key:`1mglay`}],[`path`,{d:`m16.24 7.76-1.804 5.411a2 2 0 0 1-1.265 1.265L7.76 16.24l1.804-5.411a2 2 0 0 1 1.265-1.265z`,key:`9ktpf1`}]]),ut=o(`copy`,[[`rect`,{width:`14`,height:`14`,x:`8`,y:`8`,rx:`2`,ry:`2`,key:`17jyea`}],[`path`,{d:`M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2`,key:`zix9uf`}]]),dt=o(`corner-down-left`,[[`path`,{d:`M20 4v7a4 4 0 0 1-4 4H4`,key:`6o5b7l`}],[`path`,{d:`m9 10-5 5 5 5`,key:`1kshq7`}]]),ft=o(`download`,[[`path`,{d:`M12 15V3`,key:`m9g1x1`}],[`path`,{d:`M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4`,key:`ih7n3h`}],[`path`,{d:`m7 10 5 5 5-5`,key:`brsn70`}]]),pt=o(`ellipsis`,[[`circle`,{cx:`12`,cy:`12`,r:`1`,key:`41hilf`}],[`circle`,{cx:`19`,cy:`12`,r:`1`,key:`1wjl8i`}],[`circle`,{cx:`5`,cy:`12`,r:`1`,key:`1pcz8c`}]]),mt=o(`file-text`,[[`path`,{d:`M6 22a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h8a2.4 2.4 0 0 1 1.704.706l3.588 3.588A2.4 2.4 0 0 1 20 8v12a2 2 0 0 1-2 2z`,key:`1oefj6`}],[`path`,{d:`M14 2v5a1 1 0 0 0 1 1h5`,key:`wfsgrz`}],[`path`,{d:`M10 9H8`,key:`b1mrlr`}],[`path`,{d:`M16 13H8`,key:`t4e002`}],[`path`,{d:`M16 17H8`,key:`z1uh3a`}]]),ht=o(`fingerprint-pattern`,[[`path`,{d:`M12 10a2 2 0 0 0-2 2c0 1.02-.1 2.51-.26 4`,key:`1nerag`}],[`path`,{d:`M14 13.12c0 2.38 0 6.38-1 8.88`,key:`o46ks0`}],[`path`,{d:`M17.29 21.02c.12-.6.43-2.3.5-3.02`,key:`ptglia`}],[`path`,{d:`M2 12a10 10 0 0 1 18-6`,key:`ydlgp0`}],[`path`,{d:`M2 16h.01`,key:`1gqxmh`}],[`path`,{d:`M21.8 16c.2-2 .131-5.354 0-6`,key:`drycrb`}],[`path`,{d:`M5 19.5C5.5 18 6 15 6 12a6 6 0 0 1 .34-2`,key:`1tidbn`}],[`path`,{d:`M8.65 22c.21-.66.45-1.32.57-2`,key:`13wd9y`}],[`path`,{d:`M9 6.8a6 6 0 0 1 9 5.2v2`,key:`1fr1j5`}]]),gt=o(`globe`,[[`circle`,{cx:`12`,cy:`12`,r:`10`,key:`1mglay`}],[`path`,{d:`M12 2a14.5 14.5 0 0 0 0 20 14.5 14.5 0 0 0 0-20`,key:`13o1zl`}],[`path`,{d:`M2 12h20`,key:`9i4pu4`}]]),_t=o(`graduation-cap`,[[`path`,{d:`M21.42 10.922a1 1 0 0 0-.019-1.838L12.83 5.18a2 2 0 0 0-1.66 0L2.6 9.08a1 1 0 0 0 0 1.832l8.57 3.908a2 2 0 0 0 1.66 0z`,key:`j76jl0`}],[`path`,{d:`M22 10v6`,key:`1lu8f3`}],[`path`,{d:`M6 12.5V16a6 3 0 0 0 12 0v-3.5`,key:`1r8lef`}]]),vt=o(`hand`,[[`path`,{d:`M18 11V6a2 2 0 0 0-2-2a2 2 0 0 0-2 2`,key:`1fvzgz`}],[`path`,{d:`M14 10V4a2 2 0 0 0-2-2a2 2 0 0 0-2 2v2`,key:`1kc0my`}],[`path`,{d:`M10 10.5V6a2 2 0 0 0-2-2a2 2 0 0 0-2 2v8`,key:`10h0bg`}],[`path`,{d:`M18 8a2 2 0 1 1 4 0v6a8 8 0 0 1-8 8h-2c-2.8 0-4.5-.86-5.99-2.34l-3.6-3.6a2 2 0 0 1 2.83-2.82L7 15`,key:`1s1gnw`}]]),yt=o(`heart`,[[`path`,{d:`M2 9.5a5.5 5.5 0 0 1 9.591-3.676.56.56 0 0 0 .818 0A5.49 5.49 0 0 1 22 9.5c0 2.29-1.5 4-3 5.5l-5.492 5.313a2 2 0 0 1-3 .019L5 15c-1.5-1.5-3-3.2-3-5.5`,key:`mvr1a0`}]]),bt=o(`house`,[[`path`,{d:`M15 21v-8a1 1 0 0 0-1-1h-4a1 1 0 0 0-1 1v8`,key:`5wwlr5`}],[`path`,{d:`M3 10a2 2 0 0 1 .709-1.528l7-6a2 2 0 0 1 2.582 0l7 6A2 2 0 0 1 21 10v9a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z`,key:`r6nss1`}]]),xt=o(`info`,[[`circle`,{cx:`12`,cy:`12`,r:`10`,key:`1mglay`}],[`path`,{d:`M12 16v-4`,key:`1dtifu`}],[`path`,{d:`M12 8h.01`,key:`e9boi3`}]]),P=o(`key-round`,[[`path`,{d:`M2.586 17.414A2 2 0 0 0 2 18.828V21a1 1 0 0 0 1 1h3a1 1 0 0 0 1-1v-1a1 1 0 0 1 1-1h1a1 1 0 0 0 1-1v-1a1 1 0 0 1 1-1h.172a2 2 0 0 0 1.414-.586l.814-.814a6.5 6.5 0 1 0-4-4z`,key:`1s6t7t`}],[`circle`,{cx:`16.5`,cy:`7.5`,r:`.5`,fill:`currentColor`,key:`w0ekpg`}]]),St=o(`layout-grid`,[[`rect`,{width:`7`,height:`7`,x:`3`,y:`3`,rx:`1`,key:`1g98yp`}],[`rect`,{width:`7`,height:`7`,x:`14`,y:`3`,rx:`1`,key:`6d4xhi`}],[`rect`,{width:`7`,height:`7`,x:`14`,y:`14`,rx:`1`,key:`nxv5o0`}],[`rect`,{width:`7`,height:`7`,x:`3`,y:`14`,rx:`1`,key:`1bb6yr`}]]),Ct=o(`lightbulb`,[[`path`,{d:`M15 14c.2-1 .7-1.7 1.5-2.5 1-.9 1.5-2.2 1.5-3.5A6 6 0 0 0 6 8c0 1 .2 2.2 1.5 3.5.7.7 1.3 1.5 1.5 2.5`,key:`1gvzjb`}],[`path`,{d:`M9 18h6`,key:`x1upvd`}],[`path`,{d:`M10 22h4`,key:`ceow96`}]]),wt=o(`log-in`,[[`path`,{d:`m10 17 5-5-5-5`,key:`1bsop3`}],[`path`,{d:`M15 12H3`,key:`6jk70r`}],[`path`,{d:`M15 3h4a2 2 0 0 1 2 2v14a2 2 0 0 1-2 2h-4`,key:`u53s6r`}]]),Tt=o(`log-out`,[[`path`,{d:`m16 17 5-5-5-5`,key:`1bji2h`}],[`path`,{d:`M21 12H9`,key:`dn1m92`}],[`path`,{d:`M9 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h4`,key:`1uf3rs`}]]),Et=o(`mail`,[[`path`,{d:`m22 7-8.991 5.727a2 2 0 0 1-2.009 0L2 7`,key:`132q7q`}],[`rect`,{x:`2`,y:`4`,width:`20`,height:`16`,rx:`2`,key:`izxlao`}]]),Dt=o(`map-pin`,[[`path`,{d:`M20 10c0 4.993-5.539 10.193-7.399 11.799a1 1 0 0 1-1.202 0C9.539 20.193 4 14.993 4 10a8 8 0 0 1 16 0`,key:`1r0f0z`}],[`circle`,{cx:`12`,cy:`10`,r:`3`,key:`ilqhr7`}]]),Ot=o(`menu`,[[`path`,{d:`M4 5h16`,key:`1tepv9`}],[`path`,{d:`M4 12h16`,key:`1lakjw`}],[`path`,{d:`M4 19h16`,key:`1djgab`}]]),kt=o(`message-circle-question-mark`,[[`path`,{d:`M2.992 16.342a2 2 0 0 1 .094 1.167l-1.065 3.29a1 1 0 0 0 1.236 1.168l3.413-.998a2 2 0 0 1 1.099.092 10 10 0 1 0-4.777-4.719`,key:`1sd12s`}],[`path`,{d:`M9.09 9a3 3 0 0 1 5.83 1c0 2-3 3-3 3`,key:`1u773s`}],[`path`,{d:`M12 17h.01`,key:`p32p05`}]]),At=o(`message-circle`,[[`path`,{d:`M2.992 16.342a2 2 0 0 1 .094 1.167l-1.065 3.29a1 1 0 0 0 1.236 1.168l3.413-.998a2 2 0 0 1 1.099.092 10 10 0 1 0-4.777-4.719`,key:`1sd12s`}]]),jt=o(`message-square-plus`,[[`path`,{d:`M22 17a2 2 0 0 1-2 2H6.828a2 2 0 0 0-1.414.586l-2.202 2.202A.71.71 0 0 1 2 21.286V5a2 2 0 0 1 2-2h16a2 2 0 0 1 2 2z`,key:`18887p`}],[`path`,{d:`M12 8v6`,key:`1ib9pf`}],[`path`,{d:`M9 11h6`,key:`1fldmi`}]]),Mt=o(`message-square-text`,[[`path`,{d:`M22 17a2 2 0 0 1-2 2H6.828a2 2 0 0 0-1.414.586l-2.202 2.202A.71.71 0 0 1 2 21.286V5a2 2 0 0 1 2-2h16a2 2 0 0 1 2 2z`,key:`18887p`}],[`path`,{d:`M7 11h10`,key:`1twpyw`}],[`path`,{d:`M7 15h6`,key:`d9of3u`}],[`path`,{d:`M7 7h8`,key:`af5zfr`}]]),Nt=o(`message-square`,[[`path`,{d:`M22 17a2 2 0 0 1-2 2H6.828a2 2 0 0 0-1.414.586l-2.202 2.202A.71.71 0 0 1 2 21.286V5a2 2 0 0 1 2-2h16a2 2 0 0 1 2 2z`,key:`18887p`}]]),Pt=o(`mic-off`,[[`path`,{d:`M12 19v3`,key:`npa21l`}],[`path`,{d:`M15 9.34V5a3 3 0 0 0-5.68-1.33`,key:`1gzdoj`}],[`path`,{d:`M16.95 16.95A7 7 0 0 1 5 12v-2`,key:`cqa7eg`}],[`path`,{d:`M18.89 13.23A7 7 0 0 0 19 12v-2`,key:`16hl24`}],[`path`,{d:`m2 2 20 20`,key:`1ooewy`}],[`path`,{d:`M9 9v3a3 3 0 0 0 5.12 2.12`,key:`r2i35w`}]]),Ft=o(`mic`,[[`path`,{d:`M12 19v3`,key:`npa21l`}],[`path`,{d:`M19 10v2a7 7 0 0 1-14 0v-2`,key:`1vc78b`}],[`rect`,{x:`9`,y:`2`,width:`6`,height:`13`,rx:`3`,key:`s6n7sd`}]]),It=o(`monitor-smartphone`,[[`path`,{d:`M18 8V6a2 2 0 0 0-2-2H4a2 2 0 0 0-2 2v7a2 2 0 0 0 2 2h8`,key:`10dyio`}],[`path`,{d:`M10 19v-3.96 3.15`,key:`1irgej`}],[`path`,{d:`M7 19h5`,key:`qswx4l`}],[`rect`,{width:`6`,height:`10`,x:`16`,y:`12`,rx:`2`,key:`1egngj`}]]),Lt=o(`monitor`,[[`rect`,{width:`20`,height:`14`,x:`2`,y:`3`,rx:`2`,key:`48i651`}],[`line`,{x1:`8`,x2:`16`,y1:`21`,y2:`21`,key:`1svkeh`}],[`line`,{x1:`12`,x2:`12`,y1:`17`,y2:`21`,key:`vw1qmm`}]]),Rt=o(`moon`,[[`path`,{d:`M20.985 12.486a9 9 0 1 1-9.473-9.472c.405-.022.617.46.402.803a6 6 0 0 0 8.268 8.268c.344-.215.825-.004.803.401`,key:`kfwtm`}]]),zt=o(`mouse-pointer-click`,[[`path`,{d:`M14 4.1 12 6`,key:`ita8i4`}],[`path`,{d:`m5.1 8-2.9-.8`,key:`1go3kf`}],[`path`,{d:`m6 12-1.9 2`,key:`mnht97`}],[`path`,{d:`M7.2 2.2 8 5.1`,key:`1cfko1`}],[`path`,{d:`M9.037 9.69a.498.498 0 0 1 .653-.653l11 4.5a.5.5 0 0 1-.074.949l-4.349 1.041a1 1 0 0 0-.74.739l-1.04 4.35a.5.5 0 0 1-.95.074z`,key:`s0h3yz`}]]),Bt=o(`newspaper`,[[`path`,{d:`M15 18h-5`,key:`95g1m2`}],[`path`,{d:`M18 14h-8`,key:`sponae`}],[`path`,{d:`M4 22h16a2 2 0 0 0 2-2V4a2 2 0 0 0-2-2H8a2 2 0 0 0-2 2v16a2 2 0 0 1-4 0v-9a2 2 0 0 1 2-2h2`,key:`39pd36`}],[`rect`,{width:`8`,height:`4`,x:`10`,y:`6`,rx:`1`,key:`aywv1n`}]]),Vt=o(`palette`,[[`path`,{d:`M12 22a1 1 0 0 1 0-20 10 9 0 0 1 10 9 5 5 0 0 1-5 5h-2.25a1.75 1.75 0 0 0-1.4 2.8l.3.4a1.75 1.75 0 0 1-1.4 2.8z`,key:`e79jfc`}],[`circle`,{cx:`13.5`,cy:`6.5`,r:`.5`,fill:`currentColor`,key:`1okk4w`}],[`circle`,{cx:`17.5`,cy:`10.5`,r:`.5`,fill:`currentColor`,key:`f64h9f`}],[`circle`,{cx:`6.5`,cy:`12.5`,r:`.5`,fill:`currentColor`,key:`qy21gx`}],[`circle`,{cx:`8.5`,cy:`7.5`,r:`.5`,fill:`currentColor`,key:`fotxhn`}]]),Ht=o(`pencil`,[[`path`,{d:`M21.174 6.812a1 1 0 0 0-3.986-3.987L3.842 16.174a2 2 0 0 0-.5.83l-1.321 4.352a.5.5 0 0 0 .623.622l4.353-1.32a2 2 0 0 0 .83-.497z`,key:`1a8usu`}],[`path`,{d:`m15 5 4 4`,key:`1mk7zo`}]]),Ut=o(`phone`,[[`path`,{d:`M13.832 16.568a1 1 0 0 0 1.213-.303l.355-.465A2 2 0 0 1 17 15h3a2 2 0 0 1 2 2v3a2 2 0 0 1-2 2A18 18 0 0 1 2 4a2 2 0 0 1 2-2h3a2 2 0 0 1 2 2v3a2 2 0 0 1-.8 1.6l-.468.351a1 1 0 0 0-.292 1.233 14 14 0 0 0 6.392 6.384`,key:`9njp5v`}]]),Wt=o(`piggy-bank`,[[`path`,{d:`M11 17h3v2a1 1 0 0 0 1 1h2a1 1 0 0 0 1-1v-3a3.16 3.16 0 0 0 2-2h1a1 1 0 0 0 1-1v-2a1 1 0 0 0-1-1h-1a5 5 0 0 0-2-4V3a4 4 0 0 0-3.2 1.6l-.3.4H11a6 6 0 0 0-6 6v1a5 5 0 0 0 2 4v3a1 1 0 0 0 1 1h2a1 1 0 0 0 1-1z`,key:`1piglc`}],[`path`,{d:`M16 10h.01`,key:`1m94wz`}],[`path`,{d:`M2 8v1a2 2 0 0 0 2 2h1`,key:`1env43`}]]),Gt=o(`play`,[[`path`,{d:`M5 5a2 2 0 0 1 3.008-1.728l11.997 6.998a2 2 0 0 1 .003 3.458l-12 7A2 2 0 0 1 5 19z`,key:`10ikf1`}]]),Kt=o(`plus`,[[`path`,{d:`M5 12h14`,key:`1ays0h`}],[`path`,{d:`M12 5v14`,key:`s699le`}]]),F=o(`repeat`,[[`path`,{d:`m17 2 4 4-4 4`,key:`nntrym`}],[`path`,{d:`M3 11v-1a4 4 0 0 1 4-4h14`,key:`84bu3i`}],[`path`,{d:`m7 22-4-4 4-4`,key:`1wqhfi`}],[`path`,{d:`M21 13v1a4 4 0 0 1-4 4H3`,key:`1rx37r`}]]),qt=o(`search`,[[`path`,{d:`m21 21-4.34-4.34`,key:`14j7rj`}],[`circle`,{cx:`11`,cy:`11`,r:`8`,key:`4ej97u`}]]),Jt=o(`send`,[[`path`,{d:`M14.536 21.686a.5.5 0 0 0 .937-.024l6.5-19a.496.496 0 0 0-.635-.635l-19 6.5a.5.5 0 0 0-.024.937l7.93 3.18a2 2 0 0 1 1.112 1.11z`,key:`1ffxy3`}],[`path`,{d:`m21.854 2.147-10.94 10.939`,key:`12cjpa`}]]),Yt=o(`settings`,[[`path`,{d:`M9.671 4.136a2.34 2.34 0 0 1 4.659 0 2.34 2.34 0 0 0 3.319 1.915 2.34 2.34 0 0 1 2.33 4.033 2.34 2.34 0 0 0 0 3.831 2.34 2.34 0 0 1-2.33 4.033 2.34 2.34 0 0 0-3.319 1.915 2.34 2.34 0 0 1-4.659 0 2.34 2.34 0 0 0-3.32-1.915 2.34 2.34 0 0 1-2.33-4.033 2.34 2.34 0 0 0 0-3.831A2.34 2.34 0 0 1 6.35 6.051a2.34 2.34 0 0 0 3.319-1.915`,key:`1i5ecw`}],[`circle`,{cx:`12`,cy:`12`,r:`3`,key:`1v7zrd`}]]),Xt=o(`share-2`,[[`circle`,{cx:`18`,cy:`5`,r:`3`,key:`gq8acd`}],[`circle`,{cx:`6`,cy:`12`,r:`3`,key:`w7nqdw`}],[`circle`,{cx:`18`,cy:`19`,r:`3`,key:`1xt0gg`}],[`line`,{x1:`8.59`,x2:`15.42`,y1:`13.51`,y2:`17.49`,key:`47mynk`}],[`line`,{x1:`15.41`,x2:`8.59`,y1:`6.51`,y2:`10.49`,key:`1n3mei`}]]),Zt=o(`shield-alert`,[[`path`,{d:`M20 13c0 5-3.5 7.5-7.66 8.95a1 1 0 0 1-.67-.01C7.5 20.5 4 18 4 13V6a1 1 0 0 1 1-1c2 0 4.5-1.2 6.24-2.72a1.17 1.17 0 0 1 1.52 0C14.51 3.81 17 5 19 5a1 1 0 0 1 1 1z`,key:`oel41y`}],[`path`,{d:`M12 8v4`,key:`1got3b`}],[`path`,{d:`M12 16h.01`,key:`1drbdi`}]]),Qt=o(`shield-check`,[[`path`,{d:`M20 13c0 5-3.5 7.5-7.66 8.95a1 1 0 0 1-.67-.01C7.5 20.5 4 18 4 13V6a1 1 0 0 1 1-1c2 0 4.5-1.2 6.24-2.72a1.17 1.17 0 0 1 1.52 0C14.51 3.81 17 5 19 5a1 1 0 0 1 1 1z`,key:`oel41y`}],[`path`,{d:`m9 12 2 2 4-4`,key:`dzmm74`}]]),$t=o(`shield-off`,[[`path`,{d:`m2 2 20 20`,key:`1ooewy`}],[`path`,{d:`M5 5a1 1 0 0 0-1 1v7c0 5 3.5 7.5 7.67 8.94a1 1 0 0 0 .67.01c2.35-.82 4.48-1.97 5.9-3.71`,key:`1jlk70`}],[`path`,{d:`M9.309 3.652A12.252 12.252 0 0 0 11.24 2.28a1.17 1.17 0 0 1 1.52 0C14.51 3.81 17 5 19 5a1 1 0 0 1 1 1v7a9.784 9.784 0 0 1-.08 1.264`,key:`18rp1v`}]]),en=o(`sliders-horizontal`,[[`path`,{d:`M10 5H3`,key:`1qgfaw`}],[`path`,{d:`M12 19H3`,key:`yhmn1j`}],[`path`,{d:`M14 3v4`,key:`1sua03`}],[`path`,{d:`M16 17v4`,key:`1q0r14`}],[`path`,{d:`M21 12h-9`,key:`1o4lsq`}],[`path`,{d:`M21 19h-5`,key:`1rlt1p`}],[`path`,{d:`M21 5h-7`,key:`1oszz2`}],[`path`,{d:`M8 10v4`,key:`tgpxqk`}],[`path`,{d:`M8 12H3`,key:`a7s4jb`}]]),tn=o(`smartphone`,[[`rect`,{width:`14`,height:`20`,x:`5`,y:`2`,rx:`2`,ry:`2`,key:`1yt0o3`}],[`path`,{d:`M12 18h.01`,key:`mhygvu`}]]),nn=o(`sparkles`,[[`path`,{d:`M11.017 2.814a1 1 0 0 1 1.966 0l1.051 5.558a2 2 0 0 0 1.594 1.594l5.558 1.051a1 1 0 0 1 0 1.966l-5.558 1.051a2 2 0 0 0-1.594 1.594l-1.051 5.558a1 1 0 0 1-1.966 0l-1.051-5.558a2 2 0 0 0-1.594-1.594l-5.558-1.051a1 1 0 0 1 0-1.966l5.558-1.051a2 2 0 0 0 1.594-1.594z`,key:`1s2grr`}],[`path`,{d:`M20 2v4`,key:`1rf3ol`}],[`path`,{d:`M22 4h-4`,key:`gwowj6`}],[`circle`,{cx:`4`,cy:`20`,r:`2`,key:`6kqj1y`}]]),rn=o(`square-check-big`,[[`path`,{d:`M21 10.656V19a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h12.344`,key:`2acyp4`}],[`path`,{d:`m9 11 3 3L22 4`,key:`1pflzl`}]]),an=o(`square-pen`,[[`path`,{d:`M12 3H5a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-7`,key:`1m0v6g`}],[`path`,{d:`M18.375 2.625a1 1 0 0 1 3 3l-9.013 9.014a2 2 0 0 1-.853.505l-2.873.84a.5.5 0 0 1-.62-.62l.84-2.873a2 2 0 0 1 .506-.852z`,key:`ohrbg2`}]]),on=o(`square-terminal`,[[`path`,{d:`m7 11 2-2-2-2`,key:`1lz0vl`}],[`path`,{d:`M11 13h4`,key:`1p7l4v`}],[`rect`,{width:`18`,height:`18`,x:`3`,y:`3`,rx:`2`,ry:`2`,key:`1m3agn`}]]),sn=o(`square`,[[`rect`,{width:`18`,height:`18`,x:`3`,y:`3`,rx:`2`,key:`afitv7`}]]),cn=o(`table-2`,[[`path`,{d:`M9 3H5a2 2 0 0 0-2 2v4m6-6h10a2 2 0 0 1 2 2v4M9 3v18m0 0h10a2 2 0 0 0 2-2V9M9 21H5a2 2 0 0 1-2-2V9m0 0h18`,key:`gugj83`}]]),ln=o(`tag`,[[`path`,{d:`M12.586 2.586A2 2 0 0 0 11.172 2H4a2 2 0 0 0-2 2v7.172a2 2 0 0 0 .586 1.414l8.704 8.704a2.426 2.426 0 0 0 3.42 0l6.58-6.58a2.426 2.426 0 0 0 0-3.42z`,key:`vktsd0`}],[`circle`,{cx:`7.5`,cy:`7.5`,r:`.5`,fill:`currentColor`,key:`kqv944`}]]),un=o(`target`,[[`circle`,{cx:`12`,cy:`12`,r:`10`,key:`1mglay`}],[`circle`,{cx:`12`,cy:`12`,r:`6`,key:`1vlfrh`}],[`circle`,{cx:`12`,cy:`12`,r:`2`,key:`1c9p78`}]]),dn=o(`terminal`,[[`path`,{d:`M12 19h8`,key:`baeox8`}],[`path`,{d:`m4 17 6-6-6-6`,key:`1yngyt`}]]),fn=o(`trash-2`,[[`path`,{d:`M10 11v6`,key:`nco0om`}],[`path`,{d:`M14 11v6`,key:`outv1u`}],[`path`,{d:`M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6`,key:`miytrc`}],[`path`,{d:`M3 6h18`,key:`d0wm0j`}],[`path`,{d:`M8 6V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2`,key:`e791ji`}]]),pn=o(`triangle-alert`,[[`path`,{d:`m21.73 18-8-14a2 2 0 0 0-3.48 0l-8 14A2 2 0 0 0 4 21h16a2 2 0 0 0 1.73-3`,key:`wmoenq`}],[`path`,{d:`M12 9v4`,key:`juzpu7`}],[`path`,{d:`M12 17h.01`,key:`p32p05`}]]),mn=o(`user-round`,[[`circle`,{cx:`12`,cy:`8`,r:`5`,key:`1hypcn`}],[`path`,{d:`M20 21a8 8 0 0 0-16 0`,key:`rfgkzh`}]]),hn=o(`users`,[[`path`,{d:`M16 21v-2a4 4 0 0 0-4-4H6a4 4 0 0 0-4 4v2`,key:`1yyitq`}],[`path`,{d:`M16 3.128a4 4 0 0 1 0 7.744`,key:`16gr8j`}],[`path`,{d:`M22 21v-2a4 4 0 0 0-3-3.87`,key:`kshegd`}],[`circle`,{cx:`9`,cy:`7`,r:`4`,key:`nufk8`}]]),gn=o(`wand-sparkles`,[[`path`,{d:`m21.64 3.64-1.28-1.28a1.21 1.21 0 0 0-1.72 0L2.36 18.64a1.21 1.21 0 0 0 0 1.72l1.28 1.28a1.2 1.2 0 0 0 1.72 0L21.64 5.36a1.2 1.2 0 0 0 0-1.72`,key:`ul74o6`}],[`path`,{d:`m14 7 3 3`,key:`1r5n42`}],[`path`,{d:`M5 6v4`,key:`ilb8ba`}],[`path`,{d:`M19 14v4`,key:`blhpug`}],[`path`,{d:`M10 2v2`,key:`7u0qdc`}],[`path`,{d:`M7 8H3`,key:`zfb6yr`}],[`path`,{d:`M21 16h-4`,key:`1cnmox`}],[`path`,{d:`M11 3H9`,key:`1obp7u`}]]),_n=o(`webhook`,[[`path`,{d:`M18 16.98h-5.99c-1.1 0-1.95.94-2.48 1.9A4 4 0 0 1 2 17c.01-.7.2-1.4.57-2`,key:`q3hayz`}],[`path`,{d:`m6 17 3.13-5.78c.53-.97.1-2.18-.5-3.1a4 4 0 1 1 6.89-4.06`,key:`1go1hn`}],[`path`,{d:`m12 6 3.13 5.73C15.66 12.7 16.9 13 18 13a4 4 0 0 1 0 8`,key:`qlwsc0`}]]),vn=o(`wifi-off`,[[`path`,{d:`M12 20h.01`,key:`zekei9`}],[`path`,{d:`M8.5 16.429a5 5 0 0 1 7 0`,key:`1bycff`}],[`path`,{d:`M5 12.859a10 10 0 0 1 5.17-2.69`,key:`1dl1wf`}],[`path`,{d:`M19 12.859a10 10 0 0 0-2.007-1.523`,key:`4k23kn`}],[`path`,{d:`M2 8.82a15 15 0 0 1 4.177-2.643`,key:`1grhjp`}],[`path`,{d:`M22 8.82a15 15 0 0 0-11.288-3.764`,key:`z3jwby`}],[`path`,{d:`m2 2 20 20`,key:`1ooewy`}]]),yn=o(`wrench`,[[`path`,{d:`M14.7 6.3a1 1 0 0 0 0 1.4l1.6 1.6a1 1 0 0 0 1.4 0l3.106-3.105c.32-.322.863-.22.983.218a6 6 0 0 1-8.259 7.057l-7.91 7.91a1 1 0 0 1-2.999-3l7.91-7.91a6 6 0 0 1 7.057-8.259c.438.12.54.662.219.984z`,key:`1ngwbx`}]]),I=p(x(),1),bn=p(Ue(),1),L=C();function xn({size:e=72,className:t}){return(0,L.jsx)(`img`,{src:`/icon.svg`,alt:`nanoMuse`,width:e,height:e,draggable:!1,className:i(`block shrink-0 select-none`,t),style:{width:e,height:e}})}function Sn(){return window.nanomuseDesktop??null}function Cn(){return!!window.nanomuseDesktop}function wn(){let e=Sn();e&&(document.documentElement.classList.add(`desktop`),document.documentElement.dataset.platform=e.platform)}var Tn=`nm.desktop.remote_hint`;function En(){let{state:e,setTab:t}=E(),n=s(),[r,i]=(0,I.useState)(()=>!Cn()||d(Tn)===`1`),a=e.hub,o=!r&&!!a&&a.state===`connected`&&a.remote_control&&a.account.signed_in;if((0,I.useEffect)(()=>{o&&f(Tn,`1`)},[o]),!o)return null;let c=()=>i(!0);return(0,L.jsxs)(`div`,{className:`flex items-center gap-2.5 border-b border-border bg-accent/10 px-4 py-2 text-[12.5px] text-fg`,children:[(0,L.jsx)(It,{size:16,className:`shrink-0 text-accent`}),(0,L.jsx)(`span`,{className:`min-w-0 flex-1`,children:n(`Your phone can now operate this computer: run commands, fetch files, hand over whole tasks. Each risky step still asks here first.`)}),(0,L.jsx)(`button`,{type:`button`,onClick:()=>{c(),t(`devices`)},className:`shrink-0 rounded-full border border-border bg-surface px-2.5 py-1 text-[12px] font-medium hover:bg-surface-2`,children:n(`Devices`)}),(0,L.jsx)(`button`,{type:`button`,onClick:c,"aria-label":n(`Dismiss`),className:`shrink-0 rounded-full p-1 text-muted hover:text-fg`,children:(0,L.jsx)(Fe,{size:15})})]})}var Dn=`a[href], button:not([disabled]), input:not([disabled]):not([type="hidden"]), select:not([disabled]), textarea:not([disabled]), [tabindex]:not([tabindex="-1"])`;function On(e,t){(0,I.useEffect)(()=>{if(!t)return;let n=e.current;if(!n)return;let r=document.activeElement,i=()=>Array.from(n.querySelectorAll(Dn)).filter(e=>e.offsetParent!==null||e===document.activeElement);if(!n.contains(document.activeElement)){let e=i()[0];e?e.focus():(n.tabIndex=-1,n.focus())}let a=e=>{if(e.key!==`Tab`)return;let t=i();if(t.length===0){e.preventDefault();return}let r=t[0],a=t[t.length-1],o=document.activeElement;e.shiftKey&&(o===r||!n.contains(o))?(e.preventDefault(),a.focus()):!e.shiftKey&&(o===a||!n.contains(o))&&(e.preventDefault(),r.focus())};return document.addEventListener(`keydown`,a,!0),()=>{document.removeEventListener(`keydown`,a,!0),r&&r.isConnected&&typeof r.focus==`function`&&r.focus()}},[e,t])}function kn(){let{state:e,setDrawer:t,setTab:n,openThread:r,toast:i,dispatch:a}=E(),o=s(),c=e.drawer,[l,u]=(0,I.useState)(``),[d,f]=(0,I.useState)(null),p=(0,I.useRef)(null);On(p,c),(0,I.useEffect)(()=>{if(!c)return;let e=e=>e.key===`Escape`&&t(!1);return window.addEventListener(`keydown`,e),()=>window.removeEventListener(`keydown`,e)},[c,t]),(0,I.useEffect)(()=>{c||(u(``),f(null))},[c]);let m=e.profile?.name||`nanoMuse`,h=(0,I.useMemo)(()=>{let t=l.trim().toLowerCase();return e.threads.filter(e=>e.id!==`main`).filter(e=>!t||(e.title||``).toLowerCase().includes(t)).sort((e,t)=>(t.updated_at||``).localeCompare(e.updated_at||``))},[e.threads,l]),g=(e.hub?.devices??[]).filter(e=>!e.this&&e.kind!==`web`),_=g.filter(e=>e.online).length,v=e.hub?.state===`connected`,y=g.some(e=>e.online&&e.kind===`computer`),b=e.tab===`chat`,x=e=>{r(e),n(`chat`),t(!1)},S=e=>{n(e),t(!1)},C=async()=>{try{let e=await M.createThread(o(`New chat`));a({type:`ws`,msg:{kind:`thread`,thread:e}}),x(e.id)}catch(e){i(e.message)}},w=async t=>{try{await M.deleteThread(t),a({type:`ws`,msg:{kind:`thread_deleted`,thread:t}}),e.activeThread===t&&r(`main`)}catch(e){i(e.message)}finally{f(null)}},T=t=>e.hub?.devices.find(e=>e.id===t)?.kind??`phone`,D=v?_===0?o(`Only this one`):o(`{n} online`,{n:_}):o(`Off`);return c?(0,L.jsxs)(`div`,{className:`fixed inset-0 z-50`,children:[(0,L.jsx)(`div`,{className:`rise absolute inset-0 bg-black/40`,onClick:()=>t(!1)}),(0,L.jsxs)(`nav`,{ref:p,role:`dialog`,"aria-modal":`true`,"aria-label":o(`Chats`),className:`drawer-in safe-top safe-bottom absolute inset-y-0 left-0 flex w-[82vw] max-w-[320px] flex-col bg-bg shadow-2xl`,children:[(0,L.jsx)(`div`,{className:`px-5 pt-5 pb-2 text-[24px] font-bold leading-7 tracking-tight`,children:m}),(0,L.jsx)(An,{icon:(0,L.jsx)(bt,{size:20}),label:o(`Main chat`),selected:b&&e.activeThread===`main`,onClick:()=>x(`main`)}),(0,L.jsx)(An,{icon:(0,L.jsx)(It,{size:20}),label:o(`Devices`),detail:D,selected:e.tab===`devices`,onClick:()=>S(`devices`)}),y&&(0,L.jsx)(An,{icon:(0,L.jsx)(dn,{size:20}),label:o(`Coding agents`),selected:e.tab===`coding`,onClick:()=>S(`coding`)}),(0,L.jsx)(`div`,{className:`mt-3 px-5 pb-1`,children:(0,L.jsx)(`span`,{className:`text-[14px] font-medium text-muted`,children:o(`Side chats`)})}),h.length===0&&!l?(0,L.jsxs)(`div`,{className:`flex flex-1 flex-col items-center justify-center px-8 text-center`,children:[(0,L.jsx)(Nt,{size:28,className:`mb-3 text-muted/70`}),(0,L.jsx)(`div`,{className:`text-[17px] font-semibold`,children:o(`Start a side chat`)}),(0,L.jsx)(`div`,{className:`mt-1 text-[13px] leading-snug text-muted`,children:o(`Side chats are an optional way to keep conversations organised by topic.`)})]}):(0,L.jsxs)(`ul`,{className:`min-h-0 flex-1 overflow-y-auto py-1`,children:[h.map(t=>(0,L.jsx)(jn,{thread:t,kind:t.device?T(t.device):void 0,selected:b&&e.activeThread===t.id,confirming:d===t.id,onPick:()=>x(t.id),onAskDelete:()=>f(t.id),onDelete:()=>void w(t.id),onKeep:()=>f(null)},t.id)),h.length===0&&(0,L.jsx)(`li`,{className:`px-5 py-3 text-[13px] text-muted`,children:o(`No chats match.`)})]}),(0,L.jsxs)(`div`,{className:`flex items-center gap-2 border-t border-border px-3 pt-2 pb-2`,children:[(0,L.jsx)(`button`,{type:`button`,onClick:()=>S(`you`),"aria-label":o(`Settings`),className:`flex h-10 w-10 items-center justify-center rounded-full text-fg hover:bg-surface-2`,children:(0,L.jsx)(Yt,{size:20})}),(0,L.jsx)(`button`,{type:`button`,onClick:()=>S(`memory`),"aria-label":o(`Memory`),className:`-ml-1 flex h-10 w-10 items-center justify-center rounded-full text-fg hover:bg-surface-2`,children:(0,L.jsx)(mt,{size:20})}),(0,L.jsxs)(`label`,{className:`flex min-w-0 flex-1 items-center gap-2 rounded-full bg-surface-2 px-3 py-2`,children:[(0,L.jsx)(qt,{size:16,className:`shrink-0 text-muted`}),(0,L.jsx)(`input`,{value:l,onChange:e=>u(e.target.value),placeholder:o(`Search`),className:`min-w-0 flex-1 bg-transparent text-[15px] outline-none placeholder:text-muted`}),l&&(0,L.jsx)(`button`,{type:`button`,onClick:()=>u(``),"aria-label":o(`Clear`),className:`text-muted`,children:(0,L.jsx)(Fe,{size:14})})]}),(0,L.jsx)(`button`,{type:`button`,onClick:()=>void C(),"aria-label":o(`New side chat`),className:`flex h-10 w-10 items-center justify-center rounded-full text-fg hover:bg-surface-2`,children:(0,L.jsx)(an,{size:20})})]})]})]}):null}function An({icon:e,label:t,detail:n,selected:r,onClick:a}){return(0,L.jsxs)(`button`,{type:`button`,onClick:a,className:i(`mx-2 flex items-center gap-3 rounded-2xl px-3 py-2.5 text-left`,r?`bg-surface-2`:`hover:bg-surface-2/60`),children:[(0,L.jsx)(`span`,{className:`text-fg`,children:e}),(0,L.jsx)(`span`,{className:`min-w-0 flex-1 truncate text-[16px]`,children:t}),n&&(0,L.jsx)(`span`,{className:`shrink-0 text-[13px] text-muted`,children:n})]})}function jn({thread:e,kind:t,selected:n,confirming:r,onPick:a,onAskDelete:o,onDelete:c,onKeep:l}){let u=s();return r?(0,L.jsxs)(`li`,{className:`mx-2 flex items-center gap-2 rounded-2xl bg-surface-2 px-3 py-2`,children:[(0,L.jsx)(`span`,{className:`min-w-0 flex-1 truncate text-[13.5px]`,children:u(`Delete this side chat and its history?`)}),(0,L.jsx)(`button`,{type:`button`,onClick:c,className:`rounded-full bg-rose-500 px-3 py-1 text-[12.5px] font-semibold text-white`,children:u(`Delete`)}),(0,L.jsx)(`button`,{type:`button`,onClick:l,className:`rounded-full px-2 py-1 text-[12.5px] text-muted`,children:u(`Keep`)})]}):(0,L.jsxs)(`li`,{className:i(`group mx-2 flex items-center gap-2 rounded-2xl px-3`,n?`bg-surface-2`:`hover:bg-surface-2/60`),children:[(0,L.jsxs)(`button`,{type:`button`,onClick:a,className:`flex min-w-0 flex-1 items-center gap-2 py-2.5 text-left`,children:[e.device?(0,L.jsx)(`span`,{className:`shrink-0 text-accent`,children:t===`computer`?(0,L.jsx)(Lt,{size:15}):(0,L.jsx)(tn,{size:15})}):e.remote_from?(0,L.jsx)(It,{size:15,className:`shrink-0 text-muted`}):null,(0,L.jsx)(`span`,{className:`min-w-0 flex-1 truncate text-[15px]`,children:e.title||u(`New chat`)}),e.busy&&(0,L.jsx)(`span`,{className:`h-1.5 w-1.5 shrink-0 animate-pulse rounded-full bg-amber-400`}),(0,L.jsx)(`span`,{className:`shrink-0 text-[12px] text-muted`,children:Mn(e.updated_at)})]}),(0,L.jsx)(`button`,{type:`button`,"aria-label":u(`Delete`),onClick:o,className:`p-1.5 text-muted/70 opacity-0 hover:text-rose-500 focus:opacity-100 group-hover:opacity-100`,children:(0,L.jsx)(fn,{size:15})})]})}function Mn(e,t=new Date){if(!e)return``;let n=new Date(e);if(Number.isNaN(n.getTime()))return``;let r=t.getTime()-n.getTime();return n.toDateString()===t.toDateString()?n.toLocaleTimeString(m(),{hour:`2-digit`,minute:`2-digit`}):r<6048e5?n.toLocaleDateString(m(),{weekday:`short`}):n.toLocaleDateString(m(),{month:`short`,day:`numeric`})}function Nn(e,t){let n=t||{};return(e[e.length-1]===``?[...e,``]:e).join((n.padRight?` `:``)+`,`+(n.padLeft===!1?``:` `)).trim()}var Pn=/^[$_\p{ID_Start}][$_\u{200C}\u{200D}\p{ID_Continue}]*$/u,Fn=/^[$_\p{ID_Start}][-$_\u{200C}\u{200D}\p{ID_Continue}]*$/u,In={};function Ln(e,t){return((t||In).jsx?Fn:Pn).test(e)}var Rn=/[ \t\n\f\r]/g;function zn(e){return typeof e==`object`?e.type===`text`&&Bn(e.value):Bn(e)}function Bn(e){return e.replace(Rn,``)===``}var Vn=class{constructor(e,t,n){this.normal=t,this.property=e,n&&(this.space=n)}};Vn.prototype.normal={},Vn.prototype.property={},Vn.prototype.space=void 0;function Hn(e,t){let n={},r={};for(let t of e)Object.assign(n,t.property),Object.assign(r,t.normal);return new Vn(n,r,t)}function Un(e){return e.toLowerCase()}var Wn=class{constructor(e,t){this.attribute=t,this.property=e}};Wn.prototype.attribute=``,Wn.prototype.booleanish=!1,Wn.prototype.boolean=!1,Wn.prototype.commaOrSpaceSeparated=!1,Wn.prototype.commaSeparated=!1,Wn.prototype.defined=!1,Wn.prototype.mustUseProperty=!1,Wn.prototype.number=!1,Wn.prototype.overloadedBoolean=!1,Wn.prototype.property=``,Wn.prototype.spaceSeparated=!1,Wn.prototype.space=void 0;var Gn=S({boolean:()=>R,booleanish:()=>qn,commaOrSpaceSeparated:()=>Xn,commaSeparated:()=>Yn,number:()=>z,overloadedBoolean:()=>Jn,spaceSeparated:()=>B}),Kn=0,R=Zn(),qn=Zn(),Jn=Zn(),z=Zn(),B=Zn(),Yn=Zn(),Xn=Zn();function Zn(){return 2**++Kn}var Qn=Object.keys(Gn),$n=class extends Wn{constructor(e,t,n,r){let i=-1;if(super(e,t),er(this,`space`,r),typeof n==`number`)for(;++i4&&n.slice(0,4)===`data`&&pr.test(t)){if(t.charAt(4)===`-`){let e=t.slice(5).replace(fr,gr);r=`data`+e.charAt(0).toUpperCase()+e.slice(1)}else{let e=t.slice(4);if(!fr.test(e)){let n=e.replace(dr,hr);n.charAt(0)!==`-`&&(n=`-`+n),t=`data`+n}}i=$n}return new i(r,t)}function hr(e){return`-`+e.toLowerCase()}function gr(e){return e.charAt(1).toUpperCase()}var _r=Hn([nr,ar,sr,cr,lr],`html`),vr=Hn([nr,or,sr,cr,lr],`svg`);function yr(e){return e.join(` `).trim()}var br=b(((e,t)=>{var n=/\/\*[^*]*\*+([^/*][^*]*\*+)*\//g,r=/\n/g,i=/^\s*/,a=/^(\*?[-#/*\\\w]+(\[[0-9a-z_-]+\])?)\s*/,o=/^:\s*/,s=/^((?:'(?:\\'|.)*?'|"(?:\\"|.)*?"|\([^)]*?\)|[^};])+)/,c=/^[;\s]*/,l=/^\s+|\s+$/g;function u(e,t){if(typeof e!=`string`)throw TypeError(`First argument must be a string`);if(!e)return[];t||={};var l=1,u=1;function f(e){var t=e.match(r);t&&(l+=t.length);var n=e.lastIndexOf(` +`);u=~n?e.length-n:u+e.length}function p(){var e={line:l,column:u};return function(t){return t.position=new m(e),_(),t}}function m(e){this.start=e,this.end={line:l,column:u},this.source=t.source}m.prototype.content=e;function h(n){var r=Error(t.source+`:`+l+`:`+u+`: `+n);if(r.reason=n,r.filename=t.source,r.line=l,r.column=u,r.source=e,!t.silent)throw r}function g(t){var n=t.exec(e);if(n){var r=n[0];return f(r),e=e.slice(r.length),n}}function _(){g(i)}function v(e){var t;for(e||=[];t=y();)t!==!1&&e.push(t);return e}function y(){var t=p();if(e.charAt(0)==`/`&&e.charAt(1)==`*`){for(var n=2;e.charAt(n)!=``&&(e.charAt(n)!=`*`||e.charAt(n+1)!=`/`);)++n;if(n+=2,e.charAt(n-1)===``)return h(`End of comment missing`);var r=e.slice(2,n-2);return u+=2,f(r),e=e.slice(n),u+=2,t({type:`comment`,comment:r})}}function b(){var e=p(),t=g(a);if(t){if(y(),!g(o))return h(`property missing ':'`);var r=g(s),i=e({type:`declaration`,property:d(t[0].replace(n,``)),value:r?d(r[0].replace(n,``)):``});return g(c),i}}function x(){var e=[];v(e);for(var t;t=b();)t!==!1&&(e.push(t),v(e));return e}return _(),x()}function d(e){return e?e.replace(l,``):``}t.exports=u})),xr=b((e=>{var t=e&&e.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};Object.defineProperty(e,"__esModule",{value:!0}),e.default=r;var n=t(br());function r(e,t){let r=null;if(!e||typeof e!=`string`)return r;let i=(0,n.default)(e),a=typeof t==`function`;return i.forEach(e=>{if(e.type!==`declaration`)return;let{property:n,value:i}=e;a?t(n,i,e):i&&(r||={},r[n]=i)}),r}})),Sr=b((e=>{Object.defineProperty(e,"__esModule",{value:!0}),e.camelCase=void 0;var t=/^--[a-zA-Z0-9_-]+$/,n=/-([a-z])/g,r=/^[^-]+$/,i=/^-(webkit|moz|ms|o|khtml)-/,a=/^-(ms)-/,o=function(e){return!e||r.test(e)||t.test(e)},s=function(e,t){return t.toUpperCase()},c=function(e,t){return`${t}-`};e.camelCase=function(e,t){return t===void 0&&(t={}),o(e)?e:(e=e.toLowerCase(),e=t.reactCompat?e.replace(a,c):e.replace(i,c),e.replace(n,s))}})),Cr=b(((e,t)=>{var n=(e&&e.__importDefault||function(e){return e&&e.__esModule?e:{default:e}})(xr()),r=Sr();function i(e,t){var i={};return!e||typeof e!=`string`||(0,n.default)(e,function(e,n){e&&n&&(i[(0,r.camelCase)(e,t)]=n)}),i}i.default=i,t.exports=i})),wr=Er(`end`),Tr=Er(`start`);function Er(e){return t;function t(t){let n=t&&t.position&&t.position[e]||{};if(typeof n.line==`number`&&n.line>0&&typeof n.column==`number`&&n.column>0)return{line:n.line,column:n.column,offset:typeof n.offset==`number`&&n.offset>-1?n.offset:void 0}}}function Dr(e){let t=Tr(e),n=wr(e);if(t&&n)return{start:t,end:n}}function Or(e){return!e||typeof e!=`object`?``:`position`in e||`type`in e?Ar(e.position):`start`in e||`end`in e?Ar(e):`line`in e||`column`in e?kr(e):``}function kr(e){return jr(e&&e.line)+`:`+jr(e&&e.column)}function Ar(e){return kr(e&&e.start)+`-`+kr(e&&e.end)}function jr(e){return e&&typeof e==`number`?e:1}var Mr=class extends Error{constructor(e,t,n){super(),typeof t==`string`&&(n=t,t=void 0);let r=``,i={},a=!1;if(t&&(i=`line`in t&&`column`in t||`start`in t&&`end`in t?{place:t}:`type`in t?{ancestors:[t],place:t.position}:{...t}),typeof e==`string`?r=e:!i.cause&&e&&(a=!0,r=e.message,i.cause=e),!i.ruleId&&!i.source&&typeof n==`string`){let e=n.indexOf(`:`);e===-1?i.ruleId=n:(i.source=n.slice(0,e),i.ruleId=n.slice(e+1))}if(!i.place&&i.ancestors&&i.ancestors){let e=i.ancestors[i.ancestors.length-1];e&&(i.place=e.position)}let o=i.place&&`start`in i.place?i.place.start:i.place;this.ancestors=i.ancestors||void 0,this.cause=i.cause||void 0,this.column=o?o.column:void 0,this.fatal=void 0,this.file=``,this.message=r,this.line=o?o.line:void 0,this.name=Or(i.place)||`1:1`,this.place=i.place||void 0,this.reason=this.message,this.ruleId=i.ruleId||void 0,this.source=i.source||void 0,this.stack=a&&i.cause&&typeof i.cause.stack==`string`?i.cause.stack:``,this.actual=void 0,this.expected=void 0,this.note=void 0,this.url=void 0}};Mr.prototype.file=``,Mr.prototype.name=``,Mr.prototype.reason=``,Mr.prototype.message=``,Mr.prototype.stack=``,Mr.prototype.column=void 0,Mr.prototype.line=void 0,Mr.prototype.ancestors=void 0,Mr.prototype.cause=void 0,Mr.prototype.fatal=void 0,Mr.prototype.place=void 0,Mr.prototype.ruleId=void 0,Mr.prototype.source=void 0;var Nr=p(Cr(),1),Pr={}.hasOwnProperty,Fr=new Map,Ir=/[A-Z]/g,Lr=new Set([`table`,`tbody`,`thead`,`tfoot`,`tr`]),Rr=new Set([`td`,`th`]),zr=`https://github.com/syntax-tree/hast-util-to-jsx-runtime`;function Br(e,t){if(!t||t.Fragment===void 0)throw TypeError("Expected `Fragment` in options");let n=t.filePath||void 0,r;if(t.development){if(typeof t.jsxDEV!=`function`)throw TypeError("Expected `jsxDEV` in options when `development: true`");r=Zr(n,t.jsxDEV)}else{if(typeof t.jsx!=`function`)throw TypeError("Expected `jsx` in production options");if(typeof t.jsxs!=`function`)throw TypeError("Expected `jsxs` in production options");r=Xr(n,t.jsx,t.jsxs)}let i={Fragment:t.Fragment,ancestors:[],components:t.components||{},create:r,elementAttributeNameCase:t.elementAttributeNameCase||`react`,evaluater:t.createEvaluater?t.createEvaluater():void 0,filePath:n,ignoreInvalidStyle:t.ignoreInvalidStyle||!1,passKeys:t.passKeys!==!1,passNode:t.passNode||!1,schema:t.space===`svg`?vr:_r,stylePropertyNameCase:t.stylePropertyNameCase||`dom`,tableCellAlignToStyle:t.tableCellAlignToStyle!==!1},a=Vr(i,e,void 0);return a&&typeof a!=`string`?a:i.create(e,i.Fragment,{children:a||void 0},void 0)}function Vr(e,t,n){if(t.type===`element`)return Hr(e,t,n);if(t.type===`mdxFlowExpression`||t.type===`mdxTextExpression`)return Ur(e,t);if(t.type===`mdxJsxFlowElement`||t.type===`mdxJsxTextElement`)return Gr(e,t,n);if(t.type===`mdxjsEsm`)return Wr(e,t);if(t.type===`root`)return Kr(e,t,n);if(t.type===`text`)return qr(e,t)}function Hr(e,t,n){let r=e.schema,i=r;t.tagName.toLowerCase()===`svg`&&r.space===`html`&&(i=vr,e.schema=i),e.ancestors.push(t);let a=ri(e,t.tagName,!1),o=Qr(e,t),s=ei(e,t);return Lr.has(t.tagName)&&(s=s.filter(function(e){return typeof e!=`string`||!zn(e)})),Jr(e,o,a,t),Yr(o,s),e.ancestors.pop(),e.schema=r,e.create(t,a,o,n)}function Ur(e,t){if(t.data&&t.data.estree&&e.evaluater){let n=t.data.estree.body[0];return n.type,e.evaluater.evaluateExpression(n.expression)}ii(e,t.position)}function Wr(e,t){if(t.data&&t.data.estree&&e.evaluater)return e.evaluater.evaluateProgram(t.data.estree);ii(e,t.position)}function Gr(e,t,n){let r=e.schema,i=r;t.name===`svg`&&r.space===`html`&&(i=vr,e.schema=i),e.ancestors.push(t);let a=t.name===null?e.Fragment:ri(e,t.name,!0),o=$r(e,t),s=ei(e,t);return Jr(e,o,a,t),Yr(o,s),e.ancestors.pop(),e.schema=r,e.create(t,a,o,n)}function Kr(e,t,n){let r={};return Yr(r,ei(e,t)),e.create(t,e.Fragment,r,n)}function qr(e,t){return t.value}function Jr(e,t,n,r){typeof n!=`string`&&n!==e.Fragment&&e.passNode&&(t.node=r)}function Yr(e,t){if(t.length>0){let n=t.length>1?t:t[0];n&&(e.children=n)}}function Xr(e,t,n){return r;function r(e,r,i,a){let o=Array.isArray(i.children)?n:t;return a?o(r,i,a):o(r,i)}}function Zr(e,t){return n;function n(n,r,i,a){let o=Array.isArray(i.children),s=Tr(n);return t(r,i,a,o,{columnNumber:s?s.column-1:void 0,fileName:e,lineNumber:s?s.line:void 0},void 0)}}function Qr(e,t){let n={},r,i;for(i in t.properties)if(i!==`children`&&Pr.call(t.properties,i)){let a=ti(e,i,t.properties[i]);if(a){let[i,o]=a;e.tableCellAlignToStyle&&i===`align`&&typeof o==`string`&&Rr.has(t.tagName)?r=o:n[i]=o}}if(r){let t=n.style||={};t[e.stylePropertyNameCase===`css`?`text-align`:`textAlign`]=r}return n}function $r(e,t){let n={};for(let r of t.attributes)if(r.type===`mdxJsxExpressionAttribute`){if(r.data&&r.data.estree&&e.evaluater){let t=r.data.estree.body[0];t.type;let i=t.expression;i.type;let a=i.properties[0];a.type,Object.assign(n,e.evaluater.evaluateExpression(a.argument))}else ii(e,t.position)}else{let i=r.name,a;if(r.value&&typeof r.value==`object`){if(r.value.data&&r.value.data.estree&&e.evaluater){let t=r.value.data.estree.body[0];t.type,a=e.evaluater.evaluateExpression(t.expression)}else ii(e,t.position)}else a=r.value===null||r.value;n[i]=a}return n}function ei(e,t){let n=[],r=-1,i=e.passKeys?new Map:Fr;for(;++ri?0:i+t:t>i?i:t,n=n>0?n:0,r.length<1e4)o=Array.from(r),o.unshift(t,n),e.splice(...o);else for(n&&e.splice(t,n);a0?(hi(e,e.length,0,t),e):t}var _i={}.hasOwnProperty;function vi(e){let t={},n=-1;for(;++n13&&n<32||n>126&&n<160||n>55295&&n<57344||n>64975&&n<65008||(n&65535)==65535||(n&65535)==65534||n>1114111?`�`:String.fromCodePoint(n)}function Si(e){return e.replace(/[\t\n\r ]+/g,` `).replace(/^ | $/g,``).toLowerCase().toUpperCase()}var Ci=Mi(/[A-Za-z]/),wi=Mi(/[\dA-Za-z]/),Ti=Mi(/[#-'*+\--9=?A-Z^-~]/);function Ei(e){return e!==null&&(e<32||e===127)}var Di=Mi(/\d/),Oi=Mi(/[\dA-Fa-f]/),ki=Mi(/[!-/:-@[-`{-~]/);function H(e){return e!==null&&e<-2}function U(e){return e!==null&&(e<0||e===32)}function W(e){return e===-2||e===-1||e===32}var Ai=Mi(/\p{P}|\p{S}/u),ji=Mi(/\s/);function Mi(e){return t;function t(t){return t!==null&&t>-1&&e.test(String.fromCharCode(t))}}function Ni(e){let t=[],n=-1,r=0,i=0;for(;++n55295&&a<57344){let t=e.charCodeAt(n+1);a<56320&&t>56319&&t<57344?(o=String.fromCharCode(a,t),i=1):o=`�`}else o=String.fromCharCode(a);o&&=(t.push(e.slice(r,n),encodeURIComponent(o)),r=n+i+1,``),i&&=(n+=i,0)}return t.join(``)+e.slice(r)}function G(e,t,n,r){let i=r?r-1:1/0,a=0;return o;function o(r){return W(r)?(e.enter(n),s(r)):t(r)}function s(r){return W(r)&&a++o))return;let n=t.events.length,a=n,s,c;for(;a--;)if(t.events[a][0]===`exit`&&t.events[a][1].type===`chunkFlow`){if(s){c=t.events[a][1].end;break}s=!0}for(_(r),e=n;er;){let r=n[i];t.containerState=r[1],r[0].exit.call(t,e)}n.length=r}function v(){i.write([null]),a=void 0,i=void 0,t.containerState._closeFlow=void 0}}function zi(e,t,n){return G(e,e.attempt(this.parser.constructs.document,t,n),`linePrefix`,this.parser.constructs.disable.null.includes(`codeIndented`)?void 0:4)}function Bi(e){if(e===null||U(e)||ji(e))return 1;if(Ai(e))return 2}function Vi(e,t,n){let r=[],i=-1;for(;++i1&&e[n][1].end.offset-e[n][1].start.offset>1?2:1;let d={...e[r][1].end},f={...e[n][1].start};Ui(d,-c),Ui(f,c),o={type:c>1?`strongSequence`:`emphasisSequence`,start:d,end:{...e[r][1].end}},s={type:c>1?`strongSequence`:`emphasisSequence`,start:{...e[n][1].start},end:f},a={type:c>1?`strongText`:`emphasisText`,start:{...e[r][1].end},end:{...e[n][1].start}},i={type:c>1?`strong`:`emphasis`,start:{...o.start},end:{...s.end}},e[r][1].end={...o.start},e[n][1].start={...s.end},l=[],e[r][1].end.offset-e[r][1].start.offset&&(l=gi(l,[[`enter`,e[r][1],t],[`exit`,e[r][1],t]])),l=gi(l,[[`enter`,i,t],[`enter`,o,t],[`exit`,o,t],[`enter`,a,t]]),l=gi(l,Vi(t.parser.constructs.insideSpan.null,e.slice(r+1,n),t)),l=gi(l,[[`exit`,a,t],[`enter`,s,t],[`exit`,s,t],[`exit`,i,t]]),e[n][1].end.offset-e[n][1].start.offset?(u=2,l=gi(l,[[`enter`,e[n][1],t],[`exit`,e[n][1],t]])):u=0,hi(e,r-1,n-r+3,l),n=r+l.length-u-2;break}}for(n=-1;++n0&&W(t)?G(e,v,`linePrefix`,a+1)(t):v(t)}function v(t){return t===null||H(t)?e.check(na,h,b)(t):(e.enter(`codeFlowValue`),y(t))}function y(t){return t===null||H(t)?(e.exit(`codeFlowValue`),v(t)):(e.consume(t),y)}function b(n){return e.exit(`codeFenced`),t(n)}function x(e,t,n){let i=0;return a;function a(t){return e.enter(`lineEnding`),e.consume(t),e.exit(`lineEnding`),c}function c(t){return e.enter(`codeFencedFence`),W(t)?G(e,l,`linePrefix`,r.parser.constructs.disable.null.includes(`codeIndented`)?void 0:4)(t):l(t)}function l(t){return t===s?(e.enter(`codeFencedFenceSequence`),u(t)):n(t)}function u(t){return t===s?(i++,e.consume(t),u):i>=o?(e.exit(`codeFencedFenceSequence`),W(t)?G(e,d,`whitespace`)(t):d(t)):n(t)}function d(r){return r===null||H(r)?(e.exit(`codeFencedFence`),t(r)):n(r)}}}function aa(e,t,n){let r=this;return i;function i(t){return t===null?n(t):(e.enter(`lineEnding`),e.consume(t),e.exit(`lineEnding`),a)}function a(e){return r.parser.lazy[r.now().line]?n(e):t(e)}}var oa={name:`codeIndented`,tokenize:ca},sa={partial:!0,tokenize:la};function ca(e,t,n){let r=this;return i;function i(t){return e.enter(`codeIndented`),G(e,a,`linePrefix`,5)(t)}function a(e){let t=r.events[r.events.length-1];return t&&t[1].type===`linePrefix`&&t[2].sliceSerialize(t[1],!0).length>=4?o(e):n(e)}function o(t){return t===null?c(t):H(t)?e.attempt(sa,o,c)(t):(e.enter(`codeFlowValue`),s(t))}function s(t){return t===null||H(t)?(e.exit(`codeFlowValue`),o(t)):(e.consume(t),s)}function c(n){return e.exit(`codeIndented`),t(n)}}function la(e,t,n){let r=this;return i;function i(t){return r.parser.lazy[r.now().line]?n(t):H(t)?(e.enter(`lineEnding`),e.consume(t),e.exit(`lineEnding`),i):G(e,a,`linePrefix`,5)(t)}function a(e){let a=r.events[r.events.length-1];return a&&a[1].type===`linePrefix`&&a[2].sliceSerialize(a[1],!0).length>=4?t(e):H(e)?i(e):n(e)}}var ua={name:`codeText`,previous:fa,resolve:da,tokenize:pa};function da(e){let t=e.length-4,n=3,r,i;if((e[n][1].type===`lineEnding`||e[n][1].type===`space`)&&(e[t][1].type===`lineEnding`||e[t][1].type===`space`)){for(r=n;++r=this.left.length+this.right.length)throw RangeError("Cannot access index `"+e+"` in a splice buffer of size `"+(this.left.length+this.right.length)+"`");return ethis.left.length?this.right.slice(this.right.length-n+this.left.length,this.right.length-e+this.left.length).reverse():this.left.slice(e).concat(this.right.slice(this.right.length-n+this.left.length).reverse())}splice(e,t,n){let r=t||0;this.setCursor(Math.trunc(e));let i=this.right.splice(this.right.length-r,1/0);return n&&ha(this.left,n),i.reverse()}pop(){return this.setCursor(1/0),this.left.pop()}push(e){this.setCursor(1/0),this.left.push(e)}pushMany(e){this.setCursor(1/0),ha(this.left,e)}unshift(e){this.setCursor(0),this.right.push(e)}unshiftMany(e){this.setCursor(0),ha(this.right,e.reverse())}setCursor(e){if(!(e===this.left.length||e>this.left.length&&this.right.length===0||e<0&&this.left.length===0)){if(e=4?t(i):e.interrupt(r.parser.constructs.flow,n,t)(i)}}function Sa(e,t,n,r,i,a,o,s,c){let l=c||1/0,u=0;return d;function d(t){return t===60?(e.enter(r),e.enter(i),e.enter(a),e.consume(t),e.exit(a),f):t===null||t===32||t===41||Ei(t)?n(t):(e.enter(r),e.enter(o),e.enter(s),e.enter(`chunkString`,{contentType:`string`}),h(t))}function f(n){return n===62?(e.enter(a),e.consume(n),e.exit(a),e.exit(i),e.exit(r),t):(e.enter(s),e.enter(`chunkString`,{contentType:`string`}),p(n))}function p(t){return t===62?(e.exit(`chunkString`),e.exit(s),f(t)):t===null||t===60||H(t)?n(t):(e.consume(t),t===92?m:p)}function m(t){return t===60||t===62||t===92?(e.consume(t),p):p(t)}function h(i){return!u&&(i===null||i===41||U(i))?(e.exit(`chunkString`),e.exit(s),e.exit(o),e.exit(r),t(i)):u999||l===null||l===91||l===93&&!c||l===94&&!s&&`_hiddenFootnoteSupport`in o.parser.constructs?n(l):l===93?(e.exit(a),e.enter(i),e.consume(l),e.exit(i),e.exit(r),t):H(l)?(e.enter(`lineEnding`),e.consume(l),e.exit(`lineEnding`),u):(e.enter(`chunkString`,{contentType:`string`}),d(l))}function d(t){return t===null||t===91||t===93||H(t)||s++>999?(e.exit(`chunkString`),u(t)):(e.consume(t),c||=!W(t),t===92?f:d)}function f(t){return t===91||t===92||t===93?(e.consume(t),s++,d):d(t)}}function wa(e,t,n,r,i,a){let o;return s;function s(t){return t===34||t===39||t===40?(e.enter(r),e.enter(i),e.consume(t),e.exit(i),o=t===40?41:t,c):n(t)}function c(n){return n===o?(e.enter(i),e.consume(n),e.exit(i),e.exit(r),t):(e.enter(a),l(n))}function l(t){return t===o?(e.exit(a),c(o)):t===null?n(t):H(t)?(e.enter(`lineEnding`),e.consume(t),e.exit(`lineEnding`),G(e,l,`linePrefix`)):(e.enter(`chunkString`,{contentType:`string`}),u(t))}function u(t){return t===o||t===null||H(t)?(e.exit(`chunkString`),l(t)):(e.consume(t),t===92?d:u)}function d(t){return t===o||t===92?(e.consume(t),u):u(t)}}function Ta(e,t){let n;return r;function r(i){return H(i)?(e.enter(`lineEnding`),e.consume(i),e.exit(`lineEnding`),n=!0,r):W(i)?G(e,r,n?`linePrefix`:`lineSuffix`)(i):t(i)}}var Ea={name:`definition`,tokenize:Oa},Da={partial:!0,tokenize:ka};function Oa(e,t,n){let r=this,i;return a;function a(t){return e.enter(`definition`),o(t)}function o(t){return Ca.call(r,e,s,n,`definitionLabel`,`definitionLabelMarker`,`definitionLabelString`)(t)}function s(t){return i=Si(r.sliceSerialize(r.events[r.events.length-1][1]).slice(1,-1)),t===58?(e.enter(`definitionMarker`),e.consume(t),e.exit(`definitionMarker`),c):n(t)}function c(t){return U(t)?Ta(e,l)(t):l(t)}function l(t){return Sa(e,u,n,`definitionDestination`,`definitionDestinationLiteral`,`definitionDestinationLiteralMarker`,`definitionDestinationRaw`,`definitionDestinationString`)(t)}function u(t){return e.attempt(Da,d,d)(t)}function d(t){return W(t)?G(e,f,`whitespace`)(t):f(t)}function f(a){return a===null||H(a)?(e.exit(`definition`),r.parser.defined.push(i),t(a)):n(a)}}function ka(e,t,n){return r;function r(t){return U(t)?Ta(e,i)(t):n(t)}function i(t){return wa(e,a,n,`definitionTitle`,`definitionTitleMarker`,`definitionTitleString`)(t)}function a(t){return W(t)?G(e,o,`whitespace`)(t):o(t)}function o(e){return e===null||H(e)?t(e):n(e)}}var Aa={name:`hardBreakEscape`,tokenize:ja};function ja(e,t,n){return r;function r(t){return e.enter(`hardBreakEscape`),e.consume(t),i}function i(r){return H(r)?(e.exit(`hardBreakEscape`),t(r)):n(r)}}var Ma={name:`headingAtx`,resolve:Na,tokenize:Pa};function Na(e,t){let n=e.length-2,r=3,i,a;return e[r][1].type===`whitespace`&&(r+=2),n-2>r&&e[n][1].type===`whitespace`&&(n-=2),e[n][1].type===`atxHeadingSequence`&&(r===n-1||n-4>r&&e[n-2][1].type===`whitespace`)&&(n-=r+1===n?2:4),n>r&&(i={type:`atxHeadingText`,start:e[r][1].start,end:e[n][1].end},a={type:`chunkText`,start:e[r][1].start,end:e[n][1].end,contentType:`text`},hi(e,r,n-r+1,[[`enter`,i,t],[`enter`,a,t],[`exit`,a,t],[`exit`,i,t]])),e}function Pa(e,t,n){let r=0;return i;function i(t){return e.enter(`atxHeading`),a(t)}function a(t){return e.enter(`atxHeadingSequence`),o(t)}function o(t){return t===35&&r++<6?(e.consume(t),o):t===null||U(t)?(e.exit(`atxHeadingSequence`),s(t)):n(t)}function s(n){return n===35?(e.enter(`atxHeadingSequence`),c(n)):n===null||H(n)?(e.exit(`atxHeading`),t(n)):W(n)?G(e,s,`whitespace`)(n):(e.enter(`atxHeadingText`),l(n))}function c(t){return t===35?(e.consume(t),c):(e.exit(`atxHeadingSequence`),s(t))}function l(t){return t===null||t===35||U(t)?(e.exit(`atxHeadingText`),s(t)):(e.consume(t),l)}}var Fa=`address.article.aside.base.basefont.blockquote.body.caption.center.col.colgroup.dd.details.dialog.dir.div.dl.dt.fieldset.figcaption.figure.footer.form.frame.frameset.h1.h2.h3.h4.h5.h6.head.header.hr.html.iframe.legend.li.link.main.menu.menuitem.nav.noframes.ol.optgroup.option.p.param.search.section.summary.table.tbody.td.tfoot.th.thead.title.tr.track.ul`.split(`.`),Ia=[`pre`,`script`,`style`,`textarea`],La={concrete:!0,name:`htmlFlow`,resolveTo:Ba,tokenize:Va},Ra={partial:!0,tokenize:Ua},za={partial:!0,tokenize:Ha};function Ba(e){let t=e.length;for(;t--&&(e[t][0]!==`enter`||e[t][1].type!==`htmlFlow`););return t>1&&e[t-2][1].type===`linePrefix`&&(e[t][1].start=e[t-2][1].start,e[t+1][1].start=e[t-2][1].start,e.splice(t-2,2)),e}function Va(e,t,n){let r=this,i,a,o,s,c;return l;function l(e){return u(e)}function u(t){return e.enter(`htmlFlow`),e.enter(`htmlFlowData`),e.consume(t),d}function d(s){return s===33?(e.consume(s),f):s===47?(e.consume(s),a=!0,h):s===63?(e.consume(s),i=3,r.interrupt?t:M):Ci(s)?(e.consume(s),o=String.fromCharCode(s),g):n(s)}function f(a){return a===45?(e.consume(a),i=2,p):a===91?(e.consume(a),i=5,s=0,m):Ci(a)?(e.consume(a),i=4,r.interrupt?t:M):n(a)}function p(i){return i===45?(e.consume(i),r.interrupt?t:M):n(i)}function m(i){return i===`CDATA[`.charCodeAt(s++)?(e.consume(i),s===6?r.interrupt?t:O:m):n(i)}function h(t){return Ci(t)?(e.consume(t),o=String.fromCharCode(t),g):n(t)}function g(s){if(s===null||s===47||s===62||U(s)){let c=s===47,l=o.toLowerCase();return!c&&!a&&Ia.includes(l)?(i=1,r.interrupt?t(s):O(s)):Fa.includes(o.toLowerCase())?(i=6,c?(e.consume(s),_):r.interrupt?t(s):O(s)):(i=7,r.interrupt&&!r.parser.lazy[r.now().line]?n(s):a?v(s):y(s))}return s===45||wi(s)?(e.consume(s),o+=String.fromCharCode(s),g):n(s)}function _(i){return i===62?(e.consume(i),r.interrupt?t:O):n(i)}function v(t){return W(t)?(e.consume(t),v):E(t)}function y(t){return t===47?(e.consume(t),E):t===58||t===95||Ci(t)?(e.consume(t),b):W(t)?(e.consume(t),y):E(t)}function b(t){return t===45||t===46||t===58||t===95||wi(t)?(e.consume(t),b):x(t)}function x(t){return t===61?(e.consume(t),S):W(t)?(e.consume(t),x):y(t)}function S(t){return t===null||t===60||t===61||t===62||t===96?n(t):t===34||t===39?(e.consume(t),c=t,C):W(t)?(e.consume(t),S):w(t)}function C(t){return t===c?(e.consume(t),c=null,T):t===null||H(t)?n(t):(e.consume(t),C)}function w(t){return t===null||t===34||t===39||t===47||t===60||t===61||t===62||t===96||U(t)?x(t):(e.consume(t),w)}function T(e){return e===47||e===62||W(e)?y(e):n(e)}function E(t){return t===62?(e.consume(t),D):n(t)}function D(t){return t===null||H(t)?O(t):W(t)?(e.consume(t),D):n(t)}function O(t){return t===45&&i===2?(e.consume(t),te):t===60&&i===1?(e.consume(t),j):t===62&&i===4?(e.consume(t),ie):t===63&&i===3?(e.consume(t),M):t===93&&i===5?(e.consume(t),re):H(t)&&(i===6||i===7)?(e.exit(`htmlFlowData`),e.check(Ra,N,k)(t)):t===null||H(t)?(e.exit(`htmlFlowData`),k(t)):(e.consume(t),O)}function k(t){return e.check(za,ee,N)(t)}function ee(t){return e.enter(`lineEnding`),e.consume(t),e.exit(`lineEnding`),A}function A(t){return t===null||H(t)?k(t):(e.enter(`htmlFlowData`),O(t))}function te(t){return t===45?(e.consume(t),M):O(t)}function j(t){return t===47?(e.consume(t),o=``,ne):O(t)}function ne(t){if(t===62){let n=o.toLowerCase();return Ia.includes(n)?(e.consume(t),ie):O(t)}return Ci(t)&&o.length<8?(e.consume(t),o+=String.fromCharCode(t),ne):O(t)}function re(t){return t===93?(e.consume(t),M):O(t)}function M(t){return t===62?(e.consume(t),ie):t===45&&i===2?(e.consume(t),M):O(t)}function ie(t){return t===null||H(t)?(e.exit(`htmlFlowData`),N(t)):(e.consume(t),ie)}function N(n){return e.exit(`htmlFlow`),t(n)}}function Ha(e,t,n){let r=this;return i;function i(t){return H(t)?(e.enter(`lineEnding`),e.consume(t),e.exit(`lineEnding`),a):n(t)}function a(e){return r.parser.lazy[r.now().line]?n(e):t(e)}}function Ua(e,t,n){return r;function r(r){return e.enter(`lineEnding`),e.consume(r),e.exit(`lineEnding`),e.attempt(Ki,t,n)}}var Wa={name:`htmlText`,tokenize:Ga};function Ga(e,t,n){let r=this,i,a,o;return s;function s(t){return e.enter(`htmlText`),e.enter(`htmlTextData`),e.consume(t),c}function c(t){return t===33?(e.consume(t),l):t===47?(e.consume(t),x):t===63?(e.consume(t),y):Ci(t)?(e.consume(t),w):n(t)}function l(t){return t===45?(e.consume(t),u):t===91?(e.consume(t),a=0,m):Ci(t)?(e.consume(t),v):n(t)}function u(t){return t===45?(e.consume(t),p):n(t)}function d(t){return t===null?n(t):t===45?(e.consume(t),f):H(t)?(o=d,j(t)):(e.consume(t),d)}function f(t){return t===45?(e.consume(t),p):d(t)}function p(e){return e===62?te(e):e===45?f(e):d(e)}function m(t){return t===`CDATA[`.charCodeAt(a++)?(e.consume(t),a===6?h:m):n(t)}function h(t){return t===null?n(t):t===93?(e.consume(t),g):H(t)?(o=h,j(t)):(e.consume(t),h)}function g(t){return t===93?(e.consume(t),_):h(t)}function _(t){return t===62?te(t):t===93?(e.consume(t),_):h(t)}function v(t){return t===null||t===62?te(t):H(t)?(o=v,j(t)):(e.consume(t),v)}function y(t){return t===null?n(t):t===63?(e.consume(t),b):H(t)?(o=y,j(t)):(e.consume(t),y)}function b(e){return e===62?te(e):y(e)}function x(t){return Ci(t)?(e.consume(t),S):n(t)}function S(t){return t===45||wi(t)?(e.consume(t),S):C(t)}function C(t){return H(t)?(o=C,j(t)):W(t)?(e.consume(t),C):te(t)}function w(t){return t===45||wi(t)?(e.consume(t),w):t===47||t===62||U(t)?T(t):n(t)}function T(t){return t===47?(e.consume(t),te):t===58||t===95||Ci(t)?(e.consume(t),E):H(t)?(o=T,j(t)):W(t)?(e.consume(t),T):te(t)}function E(t){return t===45||t===46||t===58||t===95||wi(t)?(e.consume(t),E):D(t)}function D(t){return t===61?(e.consume(t),O):H(t)?(o=D,j(t)):W(t)?(e.consume(t),D):T(t)}function O(t){return t===null||t===60||t===61||t===62||t===96?n(t):t===34||t===39?(e.consume(t),i=t,k):H(t)?(o=O,j(t)):W(t)?(e.consume(t),O):(e.consume(t),ee)}function k(t){return t===i?(e.consume(t),i=void 0,A):t===null?n(t):H(t)?(o=k,j(t)):(e.consume(t),k)}function ee(t){return t===null||t===34||t===39||t===60||t===61||t===96?n(t):t===47||t===62||U(t)?T(t):(e.consume(t),ee)}function A(e){return e===47||e===62||U(e)?T(e):n(e)}function te(r){return r===62?(e.consume(r),e.exit(`htmlTextData`),e.exit(`htmlText`),t):n(r)}function j(t){return e.exit(`htmlTextData`),e.enter(`lineEnding`),e.consume(t),e.exit(`lineEnding`),ne}function ne(t){return W(t)?G(e,re,`linePrefix`,r.parser.constructs.disable.null.includes(`codeIndented`)?void 0:4)(t):re(t)}function re(t){return e.enter(`htmlTextData`),o(t)}}var Ka={name:`labelEnd`,resolveAll:Xa,resolveTo:Za,tokenize:Qa},qa={tokenize:$a},Ja={tokenize:eo},Ya={tokenize:to};function Xa(e){let t=-1,n=[];for(;++t=3&&(a===null||H(a))?(e.exit(`thematicBreak`),t(a)):n(a)}function c(t){return t===i?(e.consume(t),r++,c):(e.exit(`thematicBreakSequence`),W(t)?G(e,s,`whitespace`)(t):s(t))}}var uo={continuation:{tokenize:ho},exit:go,name:`list`,tokenize:mo},fo={partial:!0,tokenize:_o},po={partial:!0,tokenize:Y};function mo(e,t,n){let r=this,i=r.events[r.events.length-1],a=i&&i[1].type===`linePrefix`?i[2].sliceSerialize(i[1],!0).length:0,o=0;return s;function s(t){let i=r.containerState.type||(t===42||t===43||t===45?`listUnordered`:`listOrdered`);if(i===`listUnordered`?!r.containerState.marker||t===r.containerState.marker:Di(t)){if(r.containerState.type||(r.containerState.type=i,e.enter(i,{_container:!0})),i===`listUnordered`)return e.enter(`listItemPrefix`),t===42||t===45?e.check(co,n,l)(t):l(t);if(!r.interrupt||t===49)return e.enter(`listItemPrefix`),e.enter(`listItemValue`),c(t)}return n(t)}function c(t){return Di(t)&&++o<10?(e.consume(t),c):(!r.interrupt||o<2)&&(r.containerState.marker?t===r.containerState.marker:t===41||t===46)?(e.exit(`listItemValue`),l(t)):n(t)}function l(t){return e.enter(`listItemMarker`),e.consume(t),e.exit(`listItemMarker`),r.containerState.marker=r.containerState.marker||t,e.check(Ki,r.interrupt?n:u,e.attempt(fo,f,d))}function u(e){return r.containerState.initialBlankLine=!0,a++,f(e)}function d(t){return W(t)?(e.enter(`listItemPrefixWhitespace`),e.consume(t),e.exit(`listItemPrefixWhitespace`),f):n(t)}function f(n){return r.containerState.size=a+r.sliceSerialize(e.exit(`listItemPrefix`),!0).length,t(n)}}function ho(e,t,n){let r=this;return r.containerState._closeFlow=void 0,e.check(Ki,i,a);function i(n){return r.containerState.furtherBlankLines=r.containerState.furtherBlankLines||r.containerState.initialBlankLine,G(e,t,`listItemIndent`,r.containerState.size+1)(n)}function a(n){return r.containerState.furtherBlankLines||!W(n)?(r.containerState.furtherBlankLines=void 0,r.containerState.initialBlankLine=void 0,o(n)):(r.containerState.furtherBlankLines=void 0,r.containerState.initialBlankLine=void 0,e.attempt(po,t,o)(n))}function o(i){return r.containerState._closeFlow=!0,r.interrupt=void 0,G(e,e.attempt(uo,t,n),`linePrefix`,r.parser.constructs.disable.null.includes(`codeIndented`)?void 0:4)(i)}}function Y(e,t,n){let r=this;return G(e,i,`listItemIndent`,r.containerState.size+1);function i(e){let i=r.events[r.events.length-1];return i&&i[1].type===`listItemIndent`&&i[2].sliceSerialize(i[1],!0).length===r.containerState.size?t(e):n(e)}}function go(e){e.exit(this.containerState.type)}function _o(e,t,n){let r=this;return G(e,i,`listItemPrefixWhitespace`,r.parser.constructs.disable.null.includes(`codeIndented`)?void 0:5);function i(e){let i=r.events[r.events.length-1];return!W(e)&&i&&i[1].type===`listItemPrefixWhitespace`?t(e):n(e)}}var vo={name:`setextUnderline`,resolveTo:yo,tokenize:bo};function yo(e,t){let n=e.length,r,i,a;for(;n--;)if(e[n][0]===`enter`){if(e[n][1].type===`content`){r=n;break}e[n][1].type===`paragraph`&&(i=n)}else e[n][1].type===`content`&&e.splice(n,1),!a&&e[n][1].type===`definition`&&(a=n);let o={type:`setextHeading`,start:{...e[r][1].start},end:{...e[e.length-1][1].end}};return e[i][1].type=`setextHeadingText`,a?(e.splice(i,0,[`enter`,o,t]),e.splice(a+1,0,[`exit`,e[r][1],t]),e[r][1].end={...e[a][1].end}):e[r][1]=o,e.push([`exit`,o,t]),e}function bo(e,t,n){let r=this,i;return a;function a(t){let a=r.events.length,s;for(;a--;)if(r.events[a][1].type!==`lineEnding`&&r.events[a][1].type!==`linePrefix`&&r.events[a][1].type!==`content`){s=r.events[a][1].type===`paragraph`;break}return!r.parser.lazy[r.now().line]&&(r.interrupt||s)?(e.enter(`setextHeadingLine`),i=t,o(t)):n(t)}function o(t){return e.enter(`setextHeadingLineSequence`),s(t)}function s(t){return t===i?(e.consume(t),s):(e.exit(`setextHeadingLineSequence`),W(t)?G(e,c,`lineSuffix`)(t):c(t))}function c(r){return r===null||H(r)?(e.exit(`setextHeadingLine`),t(r)):n(r)}}var xo={tokenize:X};function X(e){let t=this,n=e.attempt(Ki,r,e.attempt(this.parser.constructs.flowInitial,i,G(e,e.attempt(this.parser.constructs.flow,i,e.attempt(va,i)),`linePrefix`)));return n;function r(r){if(r===null){e.consume(r);return}return e.enter(`lineEndingBlank`),e.consume(r),e.exit(`lineEndingBlank`),t.currentConstruct=void 0,n}function i(r){if(r===null){e.consume(r);return}return e.enter(`lineEnding`),e.consume(r),e.exit(`lineEnding`),t.currentConstruct=void 0,n}}var So={resolveAll:Eo()},Co=To(`string`),wo=To(`text`);function To(e){return{resolveAll:Eo(e===`text`?Do:void 0),tokenize:t};function t(t){let n=this,r=this.parser.constructs[e],i=t.attempt(r,a,o);return a;function a(e){return c(e)?i(e):o(e)}function o(e){if(e===null){t.consume(e);return}return t.enter(`data`),t.consume(e),s}function s(e){return c(e)?(t.exit(`data`),i(e)):(t.consume(e),s)}function c(e){if(e===null)return!0;let t=r[e],i=-1;if(t)for(;++iIo,contentInitial:()=>Ao,disable:()=>Lo,document:()=>ko,flow:()=>Mo,flowInitial:()=>jo,insideSpan:()=>Fo,string:()=>No,text:()=>Po}),ko={42:uo,43:uo,45:uo,48:uo,49:uo,50:uo,51:uo,52:uo,53:uo,54:uo,55:uo,56:uo,57:uo,62:Ji},Ao={91:Ea},jo={[-2]:oa,[-1]:oa,32:oa},Mo={35:Ma,42:co,45:[vo,co],60:La,61:vo,95:co,96:ra,126:ra},No={38:ea,92:Qi},Po={[-5]:oo,[-4]:oo,[-3]:oo,33:no,38:ea,42:Hi,60:[Wi,Wa],91:io,92:[Aa,Qi],93:Ka,95:Hi,96:ua},Fo={null:[Hi,So]},Io={null:[42,95]},Lo={null:[]};function Ro(e,t,n){let r={_bufferIndex:-1,_index:0,line:n&&n.line||1,column:n&&n.column||1,offset:n&&n.offset||0},i={},a=[],o=[],s=[],c={attempt:C(x),check:C(S),consume:v,enter:y,exit:b,interrupt:C(S,{interrupt:!0})},l={code:null,containerState:{},defineSkip:h,events:[],now:m,parser:e,previous:null,sliceSerialize:f,sliceStream:p,write:d},u=t.tokenize.call(l,c);return t.resolveAll&&a.push(t),l;function d(e){return o=gi(o,e),g(),o[o.length-1]===null?(w(t,0),l.events=Vi(a,l.events,l),l.events):[]}function f(e,t){return Bo(p(e),t)}function p(e){return zo(o,e)}function m(){let{_bufferIndex:e,_index:t,line:n,column:i,offset:a}=r;return{_bufferIndex:e,_index:t,line:n,column:i,offset:a}}function h(e){i[e.line]=e.column,E()}function g(){let e;for(;r._index-1){let e=o[0];typeof e==`string`?o[0]=e.slice(r):o.shift()}a>0&&o.push(e[i].slice(0,a))}return o}function Bo(e,t){let n=-1,r=[],i;for(;++n0){let e=a.tokenStack[a.tokenStack.length-1];(e[1]||es).call(a,void 0,e[0])}for(r.position={start:Zo(e.length>0?e[0][1].start:{line:1,column:1,offset:0}),end:Zo(e.length>0?e[e.length-2][1].end:{line:1,column:1,offset:0})},d=-1;++d0&&(r.className=[`language-`+i[0]]);let a={type:`element`,tagName:`code`,properties:r,children:[{type:`text`,value:n}]};return t.meta&&(a.data={meta:t.meta}),e.patch(t,a),a=e.applyData(t,a),a={type:`element`,tagName:`pre`,properties:{},children:[a]},e.patch(t,a),a}function as(e,t){let n={type:`element`,tagName:`del`,properties:{},children:e.all(t)};return e.patch(t,n),e.applyData(t,n)}function os(e,t){let n={type:`element`,tagName:`em`,properties:{},children:e.all(t)};return e.patch(t,n),e.applyData(t,n)}function ss(e,t){let n=typeof e.options.clobberPrefix==`string`?e.options.clobberPrefix:`user-content-`,r=String(t.identifier).toUpperCase(),i=Ni(r.toLowerCase()),a=e.footnoteOrder.indexOf(r),o,s=e.footnoteCounts.get(r);s===void 0?(s=0,e.footnoteOrder.push(r),o=e.footnoteOrder.length):o=a+1,s+=1,e.footnoteCounts.set(r,s);let c={type:`element`,tagName:`a`,properties:{href:`#`+n+`fn-`+i,id:n+`fnref-`+i+(s>1?`-`+s:``),dataFootnoteRef:!0,ariaDescribedBy:[`footnote-label`]},children:[{type:`text`,value:String(o)}]};e.patch(t,c);let l={type:`element`,tagName:`sup`,properties:{},children:[c]};return e.patch(t,l),e.applyData(t,l)}function cs(e,t){let n={type:`element`,tagName:`h`+t.depth,properties:{},children:e.all(t)};return e.patch(t,n),e.applyData(t,n)}function ls(e,t){if(e.options.allowDangerousHtml){let n={type:`raw`,value:t.value};return e.patch(t,n),e.applyData(t,n)}}function us(e,t){let n=t.referenceType,r=`]`;if(n===`collapsed`?r+=`[]`:n===`full`&&(r+=`[`+(t.label||t.identifier)+`]`),t.type===`imageReference`)return[{type:`text`,value:`![`+t.alt+r}];let i=e.all(t),a=i[0];a&&a.type===`text`?a.value=`[`+a.value:i.unshift({type:`text`,value:`[`});let o=i[i.length-1];return o&&o.type===`text`?o.value+=r:i.push({type:`text`,value:r}),i}function ds(e,t){let n=String(t.identifier).toUpperCase(),r=e.definitionById.get(n);if(!r)return us(e,t);let i={src:Ni(r.url||``),alt:t.alt};r.title!==null&&r.title!==void 0&&(i.title=r.title);let a={type:`element`,tagName:`img`,properties:i,children:[]};return e.patch(t,a),e.applyData(t,a)}function fs(e,t){let n={src:Ni(t.url)};t.alt!==null&&t.alt!==void 0&&(n.alt=t.alt),t.title!==null&&t.title!==void 0&&(n.title=t.title);let r={type:`element`,tagName:`img`,properties:n,children:[]};return e.patch(t,r),e.applyData(t,r)}function ps(e,t){let n={type:`text`,value:t.value.replace(/\r?\n|\r/g,` `)};e.patch(t,n);let r={type:`element`,tagName:`code`,properties:{},children:[n]};return e.patch(t,r),e.applyData(t,r)}function ms(e,t){let n=String(t.identifier).toUpperCase(),r=e.definitionById.get(n);if(!r)return us(e,t);let i={href:Ni(r.url||``)};r.title!==null&&r.title!==void 0&&(i.title=r.title);let a={type:`element`,tagName:`a`,properties:i,children:e.all(t)};return e.patch(t,a),e.applyData(t,a)}function hs(e,t){let n={href:Ni(t.url)};t.title!==null&&t.title!==void 0&&(n.title=t.title);let r={type:`element`,tagName:`a`,properties:n,children:e.all(t)};return e.patch(t,r),e.applyData(t,r)}function gs(e,t,n){let r=e.all(t),i=n?_s(n):vs(t),a={},o=[];if(typeof t.checked==`boolean`){let e=r[0],n;e&&e.type===`element`&&e.tagName===`p`?n=e:(n={type:`element`,tagName:`p`,properties:{},children:[]},r.unshift(n)),n.children.length>0&&n.children.unshift({type:`text`,value:` `}),n.children.unshift({type:`element`,tagName:`input`,properties:{type:`checkbox`,checked:t.checked,disabled:!0},children:[]}),a.className=[`task-list-item`]}let s=-1;for(;++s1}function ys(e,t){let n={},r=e.all(t),i=-1;for(typeof t.start==`number`&&t.start!==1&&(n.start=t.start);++i0){let r={type:`element`,tagName:`tbody`,properties:{},children:e.wrap(n,!0)},a=Tr(t.children[1]),o=wr(t.children[t.children.length-1]);a&&o&&(r.position={start:a,end:o}),i.push(r)}let a={type:`element`,tagName:`table`,properties:{},children:e.wrap(i,!0)};return e.patch(t,a),e.applyData(t,a)}function ws(e,t,n){let r=n?n.children:void 0,i=(r?r.indexOf(t):1)===0?`th`:`td`,a=n&&n.type===`table`?n.align:void 0,o=a?a.length:t.children.length,s=-1,c=[];for(;++s0,!0),r[0]),i=r.index+r[0].length,r=n.exec(t);return a.push(ks(t.slice(i),i>0,!1)),a.join(``)}function ks(e,t,n){let r=0,i=e.length;if(t){let t=e.codePointAt(r);for(;t===Es||t===Ds;)r++,t=e.codePointAt(r)}if(n){let t=e.codePointAt(i-1);for(;t===Es||t===Ds;)i--,t=e.codePointAt(i-1)}return i>r?e.slice(r,i):``}function As(e,t){let n={type:`text`,value:Os(String(t.value))};return e.patch(t,n),e.applyData(t,n)}function js(e,t){let n={type:`element`,tagName:`hr`,properties:{},children:[]};return e.patch(t,n),e.applyData(t,n)}var Ms={blockquote:ns,break:rs,code:is,delete:as,emphasis:os,footnoteReference:ss,heading:cs,html:ls,imageReference:ds,image:fs,inlineCode:ps,linkReference:ms,link:hs,listItem:gs,list:ys,paragraph:bs,root:xs,strong:Ss,table:Cs,tableCell:Ts,tableRow:ws,text:As,thematicBreak:js,toml:Ns,yaml:Ns,definition:Ns,footnoteDefinition:Ns};function Ns(){}var{defineProperty:Ps}=Object,Fs=typeof self==`object`?self:globalThis,Is=(e,t)=>{switch(e){case`Function`:case`SharedWorker`:case`Worker`:case`eval`:case`setInterval`:case`setTimeout`:throw TypeError(`unable to deserialize `+e)}return new Fs[e](t)},Ls=(e,t)=>{let n=(t,n)=>(e.set(n,t),t),r=i=>{if(e.has(i))return e.get(i);let[a,o]=t[i];switch(a){case 0:case-1:return n(o,i);case 1:{let e=n([],i);for(let t of o)e.push(r(t));return e}case 2:{let e=n({},i);for(let[t,n]of o){let i=r(t),a=r(n);i===`__proto__`?Ps(e,i,{value:a,configurable:!0,enumerable:!0,writable:!0}):e[i]=a}return e}case 3:return n(new Date(o),i);case 4:{let{source:e,flags:t}=o;return n(new RegExp(e,t),i)}case 5:{let e=n(new Map,i);for(let[t,n]of o)e.set(r(t),r(n));return e}case 6:{let e=n(new Set,i);for(let t of o)e.add(r(t));return e}case 7:{let{name:e,message:t}=o;return n(typeof Fs[e]==`function`?Is(e,t):Error(t),i)}case 8:return n(BigInt(o),i);case`BigInt`:return n(Object(BigInt(o)),i);case`ArrayBuffer`:return n(new Uint8Array(o).buffer,o);case`DataView`:{let{buffer:e}=new Uint8Array(o);return n(new DataView(e),o)}case`-0`:return-0}return n(Is(a,o),i)};return r},Rs=e=>Ls(new Map,e)(0),zs=``,{toString:Bs}={},{keys:Vs,is:Hs}=Object,Us=e=>{let t=typeof e;if(t!==`object`||!e)return[0,t];let n=Bs.call(e).slice(8,-1);switch(n){case`Array`:return[1,zs];case`Object`:return[2,zs];case`Date`:return[3,zs];case`RegExp`:return[4,zs];case`Map`:return[5,zs];case`Set`:return[6,zs];case`DataView`:return[1,n]}return n.includes(`Array`)?[1,n]:e instanceof Error?[7,e.name||`Error`]:[2,n]},Ws=([e,t])=>e===0&&(t===`function`||t===`symbol`),Gs=(e,t,n,r)=>{let i=(e,t)=>{let i=r.push(e)-1;return n.set(t,i),i},a=o=>{if(n.has(o))return n.get(o);let[s,c]=Us(o);switch(s){case 0:{let t=o;switch(c){case`bigint`:s=8,t=o.toString();break;case`number`:if(!o&&Hs(o,-0))return r.push([`-0`])-1;break;case`function`:case`symbol`:if(e)throw TypeError(`unable to serialize `+c);t=null;break;case`undefined`:return i([-1],o)}return i([s,t],o)}case 1:{if(c){let e=o;return c===`DataView`?e=new Uint8Array(o.buffer):c===`ArrayBuffer`&&(e=new Uint8Array(o)),i([c,[...e]],o)}let e=[],t=i([s,e],o);for(let t of o)e.push(a(t));return t}case 2:{if(c)switch(c){case`BigInt`:return i([c,o.toString()],o);case`Boolean`:case`Number`:case`String`:return i([c,o.valueOf()],o)}if(t&&`toJSON`in o)return a(o.toJSON());let n=[],r=i([s,n],o);for(let t of Vs(o))(e||!Ws(Us(o[t])))&&n.push([a(t),a(o[t])]);return r}case 3:return i([s,isNaN(o.getTime())?zs:o.toISOString()],o);case 4:{let{source:e,flags:t}=o;return i([s,{source:e,flags:t}],o)}case 5:{let t=[],n=i([s,t],o);for(let[n,r]of o)(e||!(Ws(Us(n))||Ws(Us(r))))&&t.push([a(n),a(r)]);return n}case 6:{let t=[],n=i([s,t],o);for(let n of o)(e||!Ws(Us(n)))&&t.push(a(n));return n}}let{message:l}=o;return i([s,{name:c,message:l}],o)};return a},Ks=(e,{json:t,lossy:n}={})=>{let r=[];return Gs(!(t||n),!!t,new Map,r)(e),r},qs=typeof structuredClone==`function`?(e,t)=>t&&(`json`in t||`lossy`in t)?Rs(Ks(e,t)):structuredClone(e):(e,t)=>Rs(Ks(e,t));function Js(e,t){let n=[{type:`text`,value:`↩`}];return t>1&&n.push({type:`element`,tagName:`sup`,properties:{},children:[{type:`text`,value:String(t)}]}),n}function Ys(e,t){return`Back to reference `+(e+1)+(t>1?`-`+t:``)}function Xs(e){let t=typeof e.options.clobberPrefix==`string`?e.options.clobberPrefix:`user-content-`,n=e.options.footnoteBackContent||Js,r=e.options.footnoteBackLabel||Ys,i=e.options.footnoteLabel||`Footnotes`,a=e.options.footnoteLabelTagName||`h2`,o=e.options.footnoteLabelProperties||{className:[`sr-only`]},s=[],c=-1;for(;++c0&&d.push({type:`text`,value:` `});let e=typeof n==`string`?n:n(c,u);typeof e==`string`&&(e={type:`text`,value:e}),d.push({type:`element`,tagName:`a`,properties:{href:`#`+t+`fnref-`+l+(u>1?`-`+u:``),dataFootnoteBackref:``,ariaLabel:typeof r==`string`?r:r(c,u),className:[`data-footnote-backref`]},children:Array.isArray(e)?e:[e]})}let p=a[a.length-1];if(p&&p.type===`element`&&p.tagName===`p`){let e=p.children[p.children.length-1];e&&e.type===`text`?e.value+=` `:p.children.push({type:`text`,value:` `}),p.children.push(...d)}else a.push(...d);let m={type:`element`,tagName:`li`,properties:{id:t+`fn-`+l},children:e.wrap(a,!0)};e.patch(i,m),s.push(m)}if(s.length!==0)return{type:`element`,tagName:`section`,properties:{dataFootnotes:!0,className:[`footnotes`]},children:[{type:`element`,tagName:a,properties:{...qs(o),id:`footnote-label`},children:[{type:`text`,value:i}]},{type:`text`,value:` +`},{type:`element`,tagName:`ol`,properties:{},children:e.wrap(s,!0)},{type:`text`,value:` +`}]}}var Zs=(function(e){if(e==null)return nc;if(typeof e==`function`)return tc(e);if(typeof e==`object`)return Array.isArray(e)?Qs(e):$s(e);if(typeof e==`string`)return ec(e);throw Error(`Expected function, string, or object as test`)});function Qs(e){let t=[],n=-1;for(;++n`:``))+`)`})}return u;function u(){let l=ac,u,d,f;if((!t||a(e,i,c[c.length-1]||void 0))&&(l=sc(n(e,c)),l[0]===!1))return l;if(`children`in e&&e.children){let t=e;if(t.children&&l[0]!==`skip`)for(d=(r?t.children.length:-1)+o,f=c.concat(t);d>-1&&d0&&n.push({type:`text`,value:` +`}),n}function hc(e){let t=0,n=e.charCodeAt(t);for(;n===9||n===32;)t++,n=e.charCodeAt(t);return e.slice(t)}function gc(e,t){let n=dc(e,t),r=n.one(e,void 0),i=Xs(n),a=Array.isArray(r)?{type:`root`,children:r}:r||{type:`root`,children:[]};return i&&(`children`in a,a.children.push({type:`text`,value:` +`},i)),a}function _c(e,t){return e&&`run`in e?async function(n,r){let i=gc(n,{file:r,...t});await e.run(i,r)}:function(n,r){return gc(n,{file:r,...e||t})}}function vc(e){if(e)throw e}var yc=b(((e,t)=>{var n=Object.prototype.hasOwnProperty,r=Object.prototype.toString,i=Object.defineProperty,a=Object.getOwnPropertyDescriptor,o=function(e){return typeof Array.isArray==`function`?Array.isArray(e):r.call(e)===`[object Array]`},s=function(e){if(!e||r.call(e)!==`[object Object]`)return!1;var t=n.call(e,`constructor`),i=e.constructor&&e.constructor.prototype&&n.call(e.constructor.prototype,`isPrototypeOf`);if(e.constructor&&!t&&!i)return!1;for(var a in e);return a===void 0||n.call(e,a)},c=function(e,t){i&&t.name===`__proto__`?i(e,t.name,{enumerable:!0,configurable:!0,value:t.newValue,writable:!0}):e[t.name]=t.newValue},l=function(e,t){if(t===`__proto__`){if(!n.call(e,t))return;if(a)return a(e,t).value}return e[t]};t.exports=function e(){var t,n,r,i,a,u,d=arguments[0],f=1,p=arguments.length,m=!1;for(typeof d==`boolean`&&(m=d,d=arguments[1]||{},f=2),(d==null||typeof d!=`object`&&typeof d!=`function`)&&(d={});ft.length,o;r&&t.push(i);try{o=e.apply(this,t)}catch(e){let t=e;if(r&&n)throw t;return i(t)}r||(o&&o.then&&typeof o.then==`function`?o.then(a,i):o instanceof Error?i(o):a(o))}function i(e,...r){n||(n=!0,t(e,...r))}function a(e){i(null,e)}}var Cc={basename:wc,dirname:Tc,extname:Ec,join:Dc,sep:`/`};function wc(e,t){if(t!==void 0&&typeof t!=`string`)throw TypeError(`"ext" argument must be a string`);Ac(e);let n=0,r=-1,i=e.length,a;if(t===void 0||t.length===0||t.length>e.length){for(;i--;)if(e.codePointAt(i)===47){if(a){n=i+1;break}}else r<0&&(a=!0,r=i+1);return r<0?``:e.slice(n,r)}if(t===e)return``;let o=-1,s=t.length-1;for(;i--;)if(e.codePointAt(i)===47){if(a){n=i+1;break}}else o<0&&(a=!0,o=i+1),s>-1&&(e.codePointAt(i)===t.codePointAt(s--)?s<0&&(r=i):(s=-1,r=o));return n===r?r=o:r<0&&(r=e.length),e.slice(n,r)}function Tc(e){if(Ac(e),e.length===0)return`.`;let t=-1,n=e.length,r;for(;--n;)if(e.codePointAt(n)===47){if(r){t=n;break}}else r||=!0;return t<0?e.codePointAt(0)===47?`/`:`.`:t===1&&e.codePointAt(0)===47?`//`:e.slice(0,t)}function Ec(e){Ac(e);let t=e.length,n=-1,r=0,i=-1,a=0,o;for(;t--;){let s=e.codePointAt(t);if(s===47){if(o){r=t+1;break}continue}n<0&&(o=!0,n=t+1),s===46?i<0?i=t:a!==1&&(a=1):i>-1&&(a=-1)}return i<0||n<0||a===0||a===1&&i===n-1&&i===r+1?``:e.slice(i,n)}function Dc(...e){let t=-1,n;for(;++t0&&e.codePointAt(e.length-1)===47&&(n+=`/`),t?`/`+n:n}function kc(e,t){let n=``,r=0,i=-1,a=0,o=-1,s,c;for(;++o<=e.length;){if(o2){if(c=n.lastIndexOf(`/`),c!==n.length-1){c<0?(n=``,r=0):(n=n.slice(0,c),r=n.length-1-n.lastIndexOf(`/`)),i=o,a=0;continue}}else if(n.length>0){n=``,r=0,i=o,a=0;continue}}t&&(n=n.length>0?n+`/..`:`..`,r=2)}else n.length>0?n+=`/`+e.slice(i+1,o):n=e.slice(i+1,o),r=o-i-1}i=o,a=0}else s===46&&a>-1?a++:a=-1}return n}function Ac(e){if(typeof e!=`string`)throw TypeError(`Path must be a string. Received `+JSON.stringify(e))}var jc={cwd:Mc};function Mc(){return`/`}function Nc(e){return!!(typeof e==`object`&&e&&`href`in e&&e.href&&`protocol`in e&&e.protocol&&e.auth===void 0)}function Pc(e){if(typeof e==`string`)e=new URL(e);else if(!Nc(e)){let t=TypeError('The "path" argument must be of type string or an instance of URL. Received `'+e+"`");throw t.code=`ERR_INVALID_ARG_TYPE`,t}if(e.protocol!==`file:`){let e=TypeError(`The URL must be of scheme file`);throw e.code=`ERR_INVALID_URL_SCHEME`,e}return Fc(e)}function Fc(e){if(e.hostname!==``){let e=TypeError(`File URL host must be "localhost" or empty on darwin`);throw e.code=`ERR_INVALID_FILE_URL_HOST`,e}let t=e.pathname,n=-1;for(;++n0){let[r,...a]=t,o=n[i][1];bc(o)&&bc(r)&&(r=(0,Hc.default)(!0,o,r)),n[i]=[e,r,...a]}}}}().freeze();function Gc(e,t){if(typeof t!=`function`)throw TypeError("Cannot `"+e+"` without `parser`")}function Kc(e,t){if(typeof t!=`function`)throw TypeError("Cannot `"+e+"` without `compiler`")}function qc(e,t){if(t)throw Error("Cannot call `"+e+"` on a frozen processor.\nCreate a new processor first, by calling it: use `processor()` instead of `processor`.")}function Jc(e){if(!bc(e)||typeof e.type!=`string`)throw TypeError("Expected node, got `"+e+"`")}function Yc(e,t,n){if(!n)throw Error("`"+e+"` finished async. Use `"+t+"` instead")}function Xc(e){return Zc(e)?e:new Lc(e)}function Zc(e){return!!(e&&typeof e==`object`&&`message`in e&&`messages`in e)}function Qc(e){return typeof e==`string`||$c(e)}function $c(e){return!!(e&&typeof e==`object`&&`byteLength`in e&&`byteOffset`in e)}var el=[],tl={allowDangerousHtml:!0},nl=/^(https?|ircs?|mailto|xmpp)$/i,rl=[{from:`astPlugins`,id:`remove-buggy-html-in-markdown-parser`},{from:`allowDangerousHtml`,id:`remove-buggy-html-in-markdown-parser`},{from:`allowNode`,id:`replace-allownode-allowedtypes-and-disallowedtypes`,to:`allowElement`},{from:`allowedTypes`,id:`replace-allownode-allowedtypes-and-disallowedtypes`,to:`allowedElements`},{from:`disallowedTypes`,id:`replace-allownode-allowedtypes-and-disallowedtypes`,to:`disallowedElements`},{from:`escapeHtml`,id:`remove-buggy-html-in-markdown-parser`},{from:`includeElementIndex`,id:`#remove-includeelementindex`},{from:`includeNodeIndex`,id:`change-includenodeindex-to-includeelementindex`},{from:`linkTarget`,id:`remove-linktarget`},{from:`plugins`,id:`change-plugins-to-remarkplugins`,to:`remarkPlugins`},{from:`rawSourcePos`,id:`#remove-rawsourcepos`},{from:`renderers`,id:`change-renderers-to-components`,to:`components`},{from:`source`,id:`change-source-to-children`,to:`children`},{from:`sourcePos`,id:`#remove-sourcepos`},{from:`transformImageUri`,id:`#add-urltransform`,to:`urlTransform`},{from:`transformLinkUri`,id:`#add-urltransform`,to:`urlTransform`}];function il(e){let t=al(e),n=ol(e);return sl(t.runSync(t.parse(n),n),e)}function al(e){let t=e.rehypePlugins||el,n=e.remarkPlugins||el,r=e.remarkRehypeOptions?{...e.remarkRehypeOptions,...tl}:tl;return Wc().use(ts).use(n).use(_c,r).use(t)}function ol(e){let t=e.children||``,n=new Lc;return typeof t==`string`?n.value=t:``+t,n}function sl(e,t){let n=t.allowedElements,r=t.allowElement,i=t.components,a=t.disallowedElements,o=t.skipHtml,s=t.unwrapDisallowed,c=t.urlTransform||cl;for(let e of rl)Object.hasOwn(t,e.from)&&``+e.from+(e.to?"use `"+e.to+"` instead":`remove it`)+e.id;return t.className&&(e={type:`element`,tagName:`div`,properties:{className:t.className},children:e.type===`root`?e.children:[e]}),cc(e,l),Br(e,{Fragment:L.Fragment,components:i,ignoreInvalidStyle:!0,jsx:L.jsx,jsxs:L.jsxs,passKeys:!0,passNode:!0});function l(e,t,i){if(e.type===`raw`&&i&&typeof t==`number`)return o?i.children.splice(t,1):i.children[t]={type:`text`,value:e.value},t;if(e.type===`element`){let t;for(t in V)if(Object.hasOwn(V,t)&&Object.hasOwn(e.properties,t)){let n=e.properties[t],r=V[t];(r===null||r.includes(e.tagName))&&(e.properties[t]=c(String(n||``),t,e))}}if(e.type===`element`){let o=n?!n.includes(e.tagName):a?a.includes(e.tagName):!1;if(!o&&r&&typeof t==`number`&&(o=!r(e,t,i)),o&&i&&typeof t==`number`)return s&&e.children?i.children.splice(t,1,...e.children):i.children.splice(t,1),t}}}function cl(e){let t=e.indexOf(`:`),n=e.indexOf(`?`),r=e.indexOf(`#`),i=e.indexOf(`/`);return t===-1||i!==-1&&t>i||n!==-1&&t>n||r!==-1&&t>r||nl.test(e.slice(0,t))?e:``}function ll(e,t){let n=String(e);if(typeof t!=`string`)throw TypeError(`Expected character`);let r=0,i=n.indexOf(t);for(;i!==-1;)r++,i=n.indexOf(t,i+t.length);return r}function ul(e){if(typeof e!=`string`)throw TypeError(`Expected a string`);return e.replace(/[|\\{}()[\]^$+*?.]/g,`\\$&`).replace(/-/g,`\\x2d`)}function dl(e,t,n){let r=Zs((n||{}).ignore||[]),i=fl(t),a=-1;for(;++a0?{type:`text`,value:a}:void 0),a===!1?r.lastIndex=n+1:(s!==n&&u.push({type:`text`,value:e.value.slice(s,n)}),Array.isArray(a)?u.push(...a):a&&u.push(a),s=n+d[0].length,l=!0),!r.global)break;d=r.exec(e.value)}return l?(s?\]}]+$/.exec(e);if(!t)return[e,void 0];e=e.slice(0,t.index);let n=t[0],r=n.indexOf(`)`),i=ll(e,`(`),a=ll(e,`)`);for(;r!==-1&&i>a;)e+=n.slice(0,r+1),n=n.slice(r+1),r=n.indexOf(`)`),a++;return[e,n]}function Al(e,t){let n=e.input.charCodeAt(e.index-1);return(e.index===0||ji(n)||Ai(n))&&(!t||n!==47)}zl.peek=$;function jl(){this.buffer()}function Ml(e){this.enter({type:`footnoteReference`,identifier:``,label:``},e)}function Nl(){this.buffer()}function Pl(e){this.enter({type:`footnoteDefinition`,identifier:``,label:``,children:[]},e)}function Fl(e){let t=this.resume(),n=this.stack[this.stack.length-1];n.type,n.identifier=Si(this.sliceSerialize(e)).toLowerCase(),n.label=t}function Il(e){this.exit(e)}function Ll(e){let t=this.resume(),n=this.stack[this.stack.length-1];n.type,n.identifier=Si(this.sliceSerialize(e)).toLowerCase(),n.label=t}function Rl(e){this.exit(e)}function $(){return`[`}function zl(e,t,n,r){let i=n.createTracker(r),a=i.move(`[^`),o=n.enter(`footnoteReference`),s=n.enter(`reference`);return a+=i.move(n.safe(n.associationId(e),{after:`]`,before:a})),s(),o(),a+=i.move(`]`),a}function Bl(){return{enter:{gfmFootnoteCallString:jl,gfmFootnoteCall:Ml,gfmFootnoteDefinitionLabelString:Nl,gfmFootnoteDefinition:Pl},exit:{gfmFootnoteCallString:Fl,gfmFootnoteCall:Il,gfmFootnoteDefinitionLabelString:Ll,gfmFootnoteDefinition:Rl}}}function Vl(e){let t=!1;return e&&e.firstLineBlank&&(t=!0),{handlers:{footnoteDefinition:n,footnoteReference:zl},unsafe:[{character:`[`,inConstruct:[`label`,`phrasing`,`reference`]}]};function n(e,n,r,i){let a=r.createTracker(i),o=a.move(`[^`),s=r.enter(`footnoteDefinition`),c=r.enter(`label`);return o+=a.move(r.safe(r.associationId(e),{before:o,after:`]`})),c(),o+=a.move(`]:`),e.children&&e.children.length>0&&(a.shift(4),o+=a.move((t?` +`:` `)+r.indentLines(r.containerFlow(e,a.current()),t?Ul:Hl))),s(),o}}function Hl(e,t,n){return t===0?e:Ul(e,t,n)}function Ul(e,t,n){return(n?``:` `)+e}var Wl=[`autolink`,`destinationLiteral`,`destinationRaw`,`reference`,`titleQuote`,`titleApostrophe`];Yl.peek=Xl;function Gl(){return{canContainEols:[`delete`],enter:{strikethrough:ql},exit:{strikethrough:Jl}}}function Kl(){return{unsafe:[{character:`~`,inConstruct:`phrasing`,notInConstruct:Wl}],handlers:{delete:Yl}}}function ql(e){this.enter({type:`delete`,children:[]},e)}function Jl(e){this.exit(e)}function Yl(e,t,n,r){let i=n.createTracker(r),a=n.enter(`strikethrough`),o=i.move(`~~`);return o+=n.containerPhrasing(e,{...i.current(),before:o,after:`~`}),o+=i.move(`~~`),a(),o}function Xl(){return`~`}function Zl(e){return e.length}function Ql(e,t){let n=t||{},r=(n.align||[]).concat(),i=n.stringLength||Zl,a=[],o=[],s=[],c=[],l=0,u=-1;for(;++ul&&(l=e[u].length);++ac[a])&&(c[a]=e)}t.push(o)}o[u]=t,s[u]=r}let d=-1;if(typeof r==`object`&&`length`in r)for(;++dc[d]&&(c[d]=i),p[d]=i),f[d]=o}o.splice(1,0,f),s.splice(1,0,p),u=-1;let m=[];for(;++u `),a.shift(2);let o=n.indentLines(n.containerFlow(e,a.current()),nu);return i(),o}function nu(e,t,n){return`>`+(n?``:` `)+e}function ru(e,t){return iu(e,t.inConstruct,!0)&&!iu(e,t.notInConstruct,!1)}function iu(e,t,n){if(typeof t==`string`&&(t=[t]),!t||t.length===0)return n;let r=-1;for(;++ro&&(o=a):a=1,i=r+t.length,r=n.indexOf(t,i);return o}function su(e,t){return!(t.options.fences!==!1||!e.value||e.lang||!/[^ \r\n]/.test(e.value)||/^[\t ]*(?:[\r\n]|$)|(?:^|[\r\n])[\t ]*$/.test(e.value))}function cu(e){let t=e.options.fence||"`";if(t!=="`"&&t!==`~`)throw Error("Cannot serialize code with `"+t+"` for `options.fence`, expected `` ` `` or `~`");return t}function lu(e,t,n,r){let i=cu(n),a=e.value||``,o=i==="`"?`GraveAccent`:`Tilde`;if(su(e,n)){let e=n.enter(`codeIndented`),t=n.indentLines(a,uu);return e(),t}let s=n.createTracker(r),c=i.repeat(Math.max(ou(a,i)+1,3)),l=n.enter(`codeFenced`),u=s.move(c);if(e.lang){let t=n.enter(`codeFencedLang${o}`);u+=s.move(n.safe(e.lang,{before:u,after:` `,encode:["`"],...s.current()})),t()}if(e.lang&&e.meta){let t=n.enter(`codeFencedMeta${o}`);u+=s.move(` `),u+=s.move(n.safe(e.meta,{before:u,after:` +`,encode:["`"],...s.current()})),t()}return u+=s.move(` +`),a&&(u+=s.move(a+` +`)),u+=s.move(c),l(),u}function uu(e,t,n){return(n?``:` `)+e}function du(e){let t=e.options.quote||`"`;if(t!==`"`&&t!==`'`)throw Error("Cannot serialize title with `"+t+"` for `options.quote`, expected `\"`, or `'`");return t}function fu(e,t,n,r){let i=du(n),a=i===`"`?`Quote`:`Apostrophe`,o=n.enter(`definition`),s=n.enter(`label`),c=n.createTracker(r),l=c.move(`[`);return l+=c.move(n.safe(n.associationId(e),{before:l,after:`]`,...c.current()})),l+=c.move(`]: `),s(),!e.url||/[\0- \u007F]/.test(e.url)?(s=n.enter(`destinationLiteral`),l+=c.move(`<`),l+=c.move(n.safe(e.url,{before:l,after:`>`,...c.current()})),l+=c.move(`>`)):(s=n.enter(`destinationRaw`),l+=c.move(n.safe(e.url,{before:l,after:e.title?` `:` +`,...c.current()}))),s(),e.title&&(s=n.enter(`title${a}`),l+=c.move(` `+i),l+=c.move(n.safe(e.title,{before:l,after:i,...c.current()})),l+=c.move(i),s()),o(),l}function pu(e){let t=e.options.emphasis||`*`;if(t!==`*`&&t!==`_`)throw Error("Cannot serialize emphasis with `"+t+"` for `options.emphasis`, expected `*`, or `_`");return t}function mu(e){return`&#x`+e.toString(16).toUpperCase()+`;`}function hu(e,t,n){let r=Bi(e),i=Bi(t);return r===void 0?i===void 0?n===`_`?{inside:!0,outside:!0}:{inside:!1,outside:!1}:i===1?{inside:!0,outside:!0}:{inside:!1,outside:!0}:r===1?i===void 0?{inside:!1,outside:!1}:i===1?{inside:!0,outside:!0}:{inside:!1,outside:!1}:i===void 0?{inside:!1,outside:!1}:i===1?{inside:!0,outside:!1}:{inside:!1,outside:!1}}gu.peek=_u;function gu(e,t,n,r){let i=pu(n),a=n.enter(`emphasis`),o=n.createTracker(r),s=o.move(i),c=o.move(n.containerPhrasing(e,{after:i,before:s,...o.current()})),l=c.charCodeAt(0),u=hu(r.before.charCodeAt(r.before.length-1),l,i);u.inside&&(c=mu(l)+c.slice(1));let d=c.charCodeAt(c.length-1),f=hu(r.after.charCodeAt(0),d,i);f.inside&&(c=c.slice(0,-1)+mu(d));let p=o.move(i);return a(),n.attentionEncodeSurroundingInfo={after:f.outside,before:u.outside},s+c+p}function _u(e,t,n){return n.options.emphasis||`*`}function vu(e,t){let n=!1;return cc(e,function(e){if(`value`in e&&/\r?\n|\r/.test(e.value)||e.type===`break`)return n=!0,!1}),!!((!e.depth||e.depth<3)&&li(e)&&(t.options.setext||n))}function yu(e,t,n,r){let i=Math.max(Math.min(6,e.depth||1),1),a=n.createTracker(r);if(vu(e,n)){let t=n.enter(`headingSetext`),r=n.enter(`phrasing`),o=n.containerPhrasing(e,{...a.current(),before:` +`,after:` +`});return r(),t(),o+` +`+(i===1?`=`:`-`).repeat(o.length-(Math.max(o.lastIndexOf(`\r`),o.lastIndexOf(` +`))+1))}let o=`#`.repeat(i),s=n.enter(`headingAtx`),c=n.enter(`phrasing`);a.move(o+` `);let l=n.containerPhrasing(e,{before:`# `,after:` +`,...a.current()});return/^[\t ]/.test(l)&&(l=mu(l.charCodeAt(0))+l.slice(1)),l=l?o+` `+l:o,n.options.closeAtx&&(l+=` `+o),c(),s(),l}bu.peek=xu;function bu(e){return e.value||``}function xu(){return`<`}Su.peek=Cu;function Su(e,t,n,r){let i=du(n),a=i===`"`?`Quote`:`Apostrophe`,o=n.enter(`image`),s=n.enter(`label`),c=n.createTracker(r),l=c.move(`![`);return l+=c.move(n.safe(e.alt,{before:l,after:`]`,...c.current()})),l+=c.move(`](`),s(),!e.url&&e.title||/[\0- \u007F]/.test(e.url)?(s=n.enter(`destinationLiteral`),l+=c.move(`<`),l+=c.move(n.safe(e.url,{before:l,after:`>`,...c.current()})),l+=c.move(`>`)):(s=n.enter(`destinationRaw`),l+=c.move(n.safe(e.url,{before:l,after:e.title?` `:`)`,...c.current()}))),s(),e.title&&(s=n.enter(`title${a}`),l+=c.move(` `+i),l+=c.move(n.safe(e.title,{before:l,after:i,...c.current()})),l+=c.move(i),s()),l+=c.move(`)`),o(),l}function Cu(){return`!`}wu.peek=Tu;function wu(e,t,n,r){let i=e.referenceType,a=n.enter(`imageReference`),o=n.enter(`label`),s=n.createTracker(r),c=s.move(`![`),l=n.safe(e.alt,{before:c,after:`]`,...s.current()});c+=s.move(l+`][`),o();let u=n.stack;n.stack=[],o=n.enter(`reference`);let d=n.safe(n.associationId(e),{before:c,after:`]`,...s.current()});return o(),n.stack=u,a(),i===`full`||!l||l!==d?c+=s.move(d+`]`):i===`shortcut`?c=c.slice(0,-1):c+=s.move(`]`),c}function Tu(){return`!`}Eu.peek=Du;function Eu(e,t,n){let r=e.value||``,i="`",a=-1;for(;RegExp("(^|[^`])"+i+"([^`]|$)").test(r);)i+="`";for(/[^ \r\n]/.test(r)&&(/^[ \r\n]/.test(r)&&/[ \r\n]$/.test(r)||/^`|`$/.test(r))&&(r=` `+r+` `);++a\u007F]/.test(e.url))}ku.peek=Au;function ku(e,t,n,r){let i=du(n),a=i===`"`?`Quote`:`Apostrophe`,o=n.createTracker(r),s,c;if(Ou(e,n)){let t=n.stack;n.stack=[],s=n.enter(`autolink`);let r=o.move(`<`);return r+=o.move(n.containerPhrasing(e,{before:r,after:`>`,...o.current()})),r+=o.move(`>`),s(),n.stack=t,r}s=n.enter(`link`),c=n.enter(`label`);let l=o.move(`[`);return l+=o.move(n.containerPhrasing(e,{before:l,after:`](`,...o.current()})),l+=o.move(`](`),c(),!e.url&&e.title||/[\0- \u007F]/.test(e.url)?(c=n.enter(`destinationLiteral`),l+=o.move(`<`),l+=o.move(n.safe(e.url,{before:l,after:`>`,...o.current()})),l+=o.move(`>`)):(c=n.enter(`destinationRaw`),l+=o.move(n.safe(e.url,{before:l,after:e.title?` `:`)`,...o.current()}))),c(),e.title&&(c=n.enter(`title${a}`),l+=o.move(` `+i),l+=o.move(n.safe(e.title,{before:l,after:i,...o.current()})),l+=o.move(i),c()),l+=o.move(`)`),s(),l}function Au(e,t,n){return Ou(e,n)?`<`:`[`}ju.peek=Mu;function ju(e,t,n,r){let i=e.referenceType,a=n.enter(`linkReference`),o=n.enter(`label`),s=n.createTracker(r),c=s.move(`[`),l=n.containerPhrasing(e,{before:c,after:`]`,...s.current()});c+=s.move(l+`][`),o();let u=n.stack;n.stack=[],o=n.enter(`reference`);let d=n.safe(n.associationId(e),{before:c,after:`]`,...s.current()});return o(),n.stack=u,a(),i===`full`||!l||l!==d?c+=s.move(d+`]`):i===`shortcut`?c=c.slice(0,-1):c+=s.move(`]`),c}function Mu(){return`[`}function Nu(e){let t=e.options.bullet||`*`;if(t!==`*`&&t!==`+`&&t!==`-`)throw Error("Cannot serialize items with `"+t+"` for `options.bullet`, expected `*`, `+`, or `-`");return t}function Pu(e){let t=Nu(e),n=e.options.bulletOther;if(!n)return t===`*`?`-`:`*`;if(n!==`*`&&n!==`+`&&n!==`-`)throw Error("Cannot serialize items with `"+n+"` for `options.bulletOther`, expected `*`, `+`, or `-`");if(n===t)throw Error("Expected `bullet` (`"+t+"`) and `bulletOther` (`"+n+"`) to be different");return n}function Fu(e){let t=e.options.bulletOrdered||`.`;if(t!==`.`&&t!==`)`)throw Error("Cannot serialize items with `"+t+"` for `options.bulletOrdered`, expected `.` or `)`");return t}function Iu(e){let t=e.options.rule||`*`;if(t!==`*`&&t!==`-`&&t!==`_`)throw Error("Cannot serialize rules with `"+t+"` for `options.rule`, expected `*`, `-`, or `_`");return t}function Lu(e,t,n,r){let i=n.enter(`list`),a=n.bulletCurrent,o=e.ordered?Fu(n):Nu(n),s=e.ordered?o===`.`?`)`:`.`:Pu(n),c=t&&n.bulletLastUsed?o===n.bulletLastUsed:!1;if(!e.ordered){let t=e.children?e.children[0]:void 0;if((o===`*`||o===`-`)&&t&&(!t.children||!t.children[0])&&n.stack[n.stack.length-1]===`list`&&n.stack[n.stack.length-2]===`listItem`&&n.stack[n.stack.length-3]===`list`&&n.stack[n.stack.length-4]===`listItem`&&n.indexStack[n.indexStack.length-1]===0&&n.indexStack[n.indexStack.length-2]===0&&n.indexStack[n.indexStack.length-3]===0&&(c=!0),Iu(n)===o&&t){let t=-1;for(;++t-1?t.start:1)+(n.options.incrementListMarker===!1?0:t.children.indexOf(e))+a);let o=a.length+1;(i===`tab`||i===`mixed`&&(t&&t.type===`list`&&t.spread||e.spread))&&(o=Math.ceil(o/4)*4);let s=n.createTracker(r);s.move(a+` `.repeat(o-a.length)),s.shift(o);let c=n.enter(`listItem`),l=n.indentLines(n.containerFlow(e,s.current()),u);return c(),l;function u(e,t,n){return t?(n?``:` `.repeat(o))+e:(n?a:a+` `.repeat(o-a.length))+e}}function Bu(e,t,n,r){let i=n.enter(`paragraph`),a=n.enter(`phrasing`),o=n.containerPhrasing(e,r);return a(),i(),o}var Vu=Zs([`break`,`delete`,`emphasis`,`footnote`,`footnoteReference`,`image`,`imageReference`,`inlineCode`,`inlineMath`,`link`,`linkReference`,`mdxJsxTextElement`,`mdxTextExpression`,`strong`,`text`,`textDirective`]);function Hu(e,t,n,r){return(e.children.some(function(e){return Vu(e)})?n.containerPhrasing:n.containerFlow).call(n,e,r)}function Uu(e){let t=e.options.strong||`*`;if(t!==`*`&&t!==`_`)throw Error("Cannot serialize strong with `"+t+"` for `options.strong`, expected `*`, or `_`");return t}Wu.peek=Gu;function Wu(e,t,n,r){let i=Uu(n),a=n.enter(`strong`),o=n.createTracker(r),s=o.move(i+i),c=o.move(n.containerPhrasing(e,{after:i,before:s,...o.current()})),l=c.charCodeAt(0),u=hu(r.before.charCodeAt(r.before.length-1),l,i);u.inside&&(c=mu(l)+c.slice(1));let d=c.charCodeAt(c.length-1),f=hu(r.after.charCodeAt(0),d,i);f.inside&&(c=c.slice(0,-1)+mu(d));let p=o.move(i+i);return a(),n.attentionEncodeSurroundingInfo={after:f.outside,before:u.outside},s+c+p}function Gu(e,t,n){return n.options.strong||`*`}function Ku(e,t,n,r){return n.safe(e.value,r)}function qu(e){let t=e.options.ruleRepetition||3;if(t<3)throw Error("Cannot serialize rules with repetition `"+t+"` for `options.ruleRepetition`, expected `3` or more");return t}function Ju(e,t,n){let r=(Iu(n)+(n.options.ruleSpaces?` `:``)).repeat(qu(n));return n.options.ruleSpaces?r.slice(0,-1):r}var Yu={blockquote:tu,break:au,code:lu,definition:fu,emphasis:gu,hardBreak:au,heading:yu,html:bu,image:Su,imageReference:wu,inlineCode:Eu,link:ku,linkReference:ju,list:Lu,listItem:zu,paragraph:Bu,root:Hu,strong:Wu,text:Ku,thematicBreak:Ju};function Xu(){return{enter:{table:Zu,tableData:td,tableHeader:td,tableRow:$u},exit:{codeText:nd,table:Qu,tableData:ed,tableHeader:ed,tableRow:ed}}}function Zu(e){let t=e._align;this.enter({type:`table`,align:t.map(function(e){return e===`none`?null:e}),children:[]},e),this.data.inTable=!0}function Qu(e){this.exit(e),this.data.inTable=void 0}function $u(e){this.enter({type:`tableRow`,children:[]},e)}function ed(e){this.exit(e)}function td(e){this.enter({type:`tableCell`,children:[]},e)}function nd(e){let t=this.resume();this.data.inTable&&(t=t.replace(/\\([\\|])/g,rd));let n=this.stack[this.stack.length-1];n.type,n.value=t,this.exit(e)}function rd(e,t){return t===`|`?t:e}function id(e){let t=e||{},n=t.tableCellPadding,r=t.tablePipeAlign,i=t.stringLength,a=n?` `:`|`;return{unsafe:[{character:`\r`,inConstruct:`tableCell`},{character:` +`,inConstruct:`tableCell`},{atBreak:!0,character:`|`,after:`[ :-]`},{character:`|`,inConstruct:`tableCell`},{atBreak:!0,character:`:`,after:`-`},{atBreak:!0,character:`-`,after:`[:|-]`}],handlers:{inlineCode:f,table:o,tableCell:c,tableRow:s}};function o(e,t,n,r){return l(u(e,n,r),e.align)}function s(e,t,n,r){let i=l([d(e,n,r)]);return i.slice(0,i.indexOf(` +`))}function c(e,t,n,r){let i=n.enter(`tableCell`),o=n.enter(`phrasing`),s=n.containerPhrasing(e,{...r,before:a,after:a});return o(),i(),s}function l(e,t){return Ql(e,{align:t,alignDelimiters:r,padding:n,stringLength:i})}function u(e,t,n){let r=e.children,i=-1,a=[],o=t.enter(`table`);for(;++i0&&!n&&(e[e.length-1][1]._gfmAutolinkLiteralWalkedInto=!0),n}var Id={tokenize:Wd,partial:!0};function Ld(){return{document:{91:{name:`gfmFootnoteDefinition`,tokenize:Vd,continuation:{tokenize:Hd},exit:Ud}},text:{91:{name:`gfmFootnoteCall`,tokenize:Bd},93:{name:`gfmPotentialFootnoteCall`,add:`after`,tokenize:Rd,resolveTo:zd}}}}function Rd(e,t,n){let r=this,i=r.events.length,a=r.parser.gfmFootnotes||(r.parser.gfmFootnotes=[]),o;for(;i--;){let e=r.events[i][1];if(e.type===`labelImage`){o=e;break}if(e.type===`gfmFootnoteCall`||e.type===`labelLink`||e.type===`label`||e.type===`image`||e.type===`link`)break}return s;function s(i){if(!o||!o._balanced)return n(i);let s=Si(r.sliceSerialize({start:o.end,end:r.now()}));return s.codePointAt(0)!==94||!a.includes(s.slice(1))?n(i):(e.enter(`gfmFootnoteCallLabelMarker`),e.consume(i),e.exit(`gfmFootnoteCallLabelMarker`),t(i))}}function zd(e,t){let n=e.length;for(;n--;)if(e[n][1].type===`labelImage`&&e[n][0]===`enter`){e[n][1];break}e[n+1][1].type=`data`,e[n+3][1].type=`gfmFootnoteCallLabelMarker`;let r={type:`gfmFootnoteCall`,start:Object.assign({},e[n+3][1].start),end:Object.assign({},e[e.length-1][1].end)},i={type:`gfmFootnoteCallMarker`,start:Object.assign({},e[n+3][1].end),end:Object.assign({},e[n+3][1].end)};i.end.column++,i.end.offset++,i.end._bufferIndex++;let a={type:`gfmFootnoteCallString`,start:Object.assign({},i.end),end:Object.assign({},e[e.length-1][1].start)},o={type:`chunkString`,contentType:`string`,start:Object.assign({},a.start),end:Object.assign({},a.end)},s=[e[n+1],e[n+2],[`enter`,r,t],e[n+3],e[n+4],[`enter`,i,t],[`exit`,i,t],[`enter`,a,t],[`enter`,o,t],[`exit`,o,t],[`exit`,a,t],e[e.length-2],e[e.length-1],[`exit`,r,t]];return e.splice(n,e.length-n+1,...s),e}function Bd(e,t,n){let r=this,i=r.parser.gfmFootnotes||(r.parser.gfmFootnotes=[]),a=0,o;return s;function s(t){return e.enter(`gfmFootnoteCall`),e.enter(`gfmFootnoteCallLabelMarker`),e.consume(t),e.exit(`gfmFootnoteCallLabelMarker`),c}function c(t){return t===94?(e.enter(`gfmFootnoteCallMarker`),e.consume(t),e.exit(`gfmFootnoteCallMarker`),e.enter(`gfmFootnoteCallString`),e.enter(`chunkString`).contentType=`string`,l):n(t)}function l(s){if(a>999||s===93&&!o||s===null||s===91||U(s))return n(s);if(s===93){e.exit(`chunkString`);let a=e.exit(`gfmFootnoteCallString`);return i.includes(Si(r.sliceSerialize(a)))?(e.enter(`gfmFootnoteCallLabelMarker`),e.consume(s),e.exit(`gfmFootnoteCallLabelMarker`),e.exit(`gfmFootnoteCall`),t):n(s)}return U(s)||(o=!0),a++,e.consume(s),s===92?u:l}function u(t){return t===91||t===92||t===93?(e.consume(t),a++,l):l(t)}}function Vd(e,t,n){let r=this,i=r.parser.gfmFootnotes||(r.parser.gfmFootnotes=[]),a,o=0,s;return c;function c(t){return e.enter(`gfmFootnoteDefinition`)._container=!0,e.enter(`gfmFootnoteDefinitionLabel`),e.enter(`gfmFootnoteDefinitionLabelMarker`),e.consume(t),e.exit(`gfmFootnoteDefinitionLabelMarker`),l}function l(t){return t===94?(e.enter(`gfmFootnoteDefinitionMarker`),e.consume(t),e.exit(`gfmFootnoteDefinitionMarker`),e.enter(`gfmFootnoteDefinitionLabelString`),e.enter(`chunkString`).contentType=`string`,u):n(t)}function u(t){if(o>999||t===93&&!s||t===null||t===91||U(t))return n(t);if(t===93){e.exit(`chunkString`);let n=e.exit(`gfmFootnoteDefinitionLabelString`);return a=Si(r.sliceSerialize(n)),e.enter(`gfmFootnoteDefinitionLabelMarker`),e.consume(t),e.exit(`gfmFootnoteDefinitionLabelMarker`),e.exit(`gfmFootnoteDefinitionLabel`),f}return U(t)||(s=!0),o++,e.consume(t),t===92?d:u}function d(t){return t===91||t===92||t===93?(e.consume(t),o++,u):u(t)}function f(t){return t===58?(e.enter(`definitionMarker`),e.consume(t),e.exit(`definitionMarker`),i.includes(a)||i.push(a),G(e,p,`gfmFootnoteDefinitionWhitespace`)):n(t)}function p(e){return t(e)}}function Hd(e,t,n){return e.check(Ki,t,e.attempt(Id,t,n))}function Ud(e){e.exit(`gfmFootnoteDefinition`)}function Wd(e,t,n){let r=this;return G(e,i,`gfmFootnoteDefinitionIndent`,5);function i(e){let i=r.events[r.events.length-1];return i&&i[1].type===`gfmFootnoteDefinitionIndent`&&i[2].sliceSerialize(i[1],!0).length===4?t(e):n(e)}}function Gd(e){let t=(e||{}).singleTilde,n={name:`strikethrough`,tokenize:i,resolveAll:r};return t??=!0,{text:{126:n},insideSpan:{null:[n]},attentionMarkers:{null:[126]}};function r(e,t){let n=-1;for(;++n1?r(a):(e.consume(a),o++,c);if(o<2&&!t)return r(a);let l=e.exit(`strikethroughSequenceTemporary`),u=Bi(a);return l._open=!u||u===2&&!!s,l._close=!s||s===2&&!!u,n(a)}}}var Kd=class{constructor(){this.map=[],this.index=new Map}add(e,t,n){qd(this,e,t,n)}consume(e){if(this.map.sort(function(e,t){return e[0]-t[0]}),this.map.length===0)return;let t=this.map.length,n=[];for(;t>0;)--t,n.push(e.slice(this.map[t][0]+this.map[t][1]),this.map[t][2]),e.length=this.map[t][0];n.push(e.slice()),e.length=0;let r=n.pop();for(;r;){for(let t of r)e.push(t);r=n.pop()}this.map.length=0,this.index.clear()}};function qd(e,t,n,r){if(n===0&&r.length===0)return;let i=e.index.get(t);if(i){i[1]+=n,i[2].push(...r);return}let a=[t,n,r];e.map.push(a),e.index.set(t,a)}function Jd(e,t){let n=!1,r=[];for(;t-1;){let{type:e}=r.events[t][1];if(e===`lineEnding`||e===`linePrefix`)t--;else break}let i=t>-1?r.events[t][1].type:null,a=i===`tableHead`||i===`tableRow`?S:c;return a===S&&r.parser.lazy[r.now().line]?n(e):a(e)}function c(t){return e.enter(`tableHead`),e.enter(`tableRow`),l(t)}function l(e){return e===124?u(e):(o=!0,a+=1,u(e))}function u(t){return t===null?n(t):H(t)?a>1?(a=0,r.interrupt=!0,e.exit(`tableRow`),e.enter(`lineEnding`),e.consume(t),e.exit(`lineEnding`),p):n(t):W(t)?G(e,u,`whitespace`)(t):(a+=1,o&&(o=!1,i+=1),t===124?(e.enter(`tableCellDivider`),e.consume(t),e.exit(`tableCellDivider`),o=!0,u):(e.enter(`data`),d(t)))}function d(t){return t===null||t===124||U(t)?(e.exit(`data`),u(t)):(e.consume(t),t===92?f:d)}function f(t){return t===92||t===124?(e.consume(t),d):d(t)}function p(t){return r.interrupt=!1,r.parser.lazy[r.now().line]?n(t):(e.enter(`tableDelimiterRow`),o=!1,W(t)?G(e,m,`linePrefix`,r.parser.constructs.disable.null.includes(`codeIndented`)?void 0:4)(t):m(t))}function m(t){return t===45||t===58?g(t):t===124?(o=!0,e.enter(`tableCellDivider`),e.consume(t),e.exit(`tableCellDivider`),h):x(t)}function h(t){return W(t)?G(e,g,`whitespace`)(t):g(t)}function g(t){return t===58?(a+=1,o=!0,e.enter(`tableDelimiterMarker`),e.consume(t),e.exit(`tableDelimiterMarker`),_):t===45?(a+=1,_(t)):t===null||H(t)?b(t):x(t)}function _(t){return t===45?(e.enter(`tableDelimiterFiller`),v(t)):x(t)}function v(t){return t===45?(e.consume(t),v):t===58?(o=!0,e.exit(`tableDelimiterFiller`),e.enter(`tableDelimiterMarker`),e.consume(t),e.exit(`tableDelimiterMarker`),y):(e.exit(`tableDelimiterFiller`),y(t))}function y(t){return W(t)?G(e,b,`whitespace`)(t):b(t)}function b(n){return n===124?m(n):n===null||H(n)?!o||i!==a?x(n):(e.exit(`tableDelimiterRow`),e.exit(`tableHead`),t(n)):x(n)}function x(e){return n(e)}function S(t){return e.enter(`tableRow`),C(t)}function C(n){return n===124?(e.enter(`tableCellDivider`),e.consume(n),e.exit(`tableCellDivider`),C):n===null||H(n)?(e.exit(`tableRow`),t(n)):W(n)?G(e,C,`whitespace`)(n):(e.enter(`data`),w(n))}function w(t){return t===null||t===124||U(t)?(e.exit(`data`),C(t)):(e.consume(t),t===92?T:w)}function T(t){return t===92||t===124?(e.consume(t),w):w(t)}}function Zd(e,t){let n=-1,r=!0,i=0,a=[0,0,0,0],o=[0,0,0,0],s=!1,c=0,l,u,d,f=new Kd;for(;++nn[2]+1){let t=n[2]+1,r=n[3]-n[2]-1;e.add(t,r,[])}}e.add(n[3]+1,0,[[`exit`,o,t]])}return i!==void 0&&(a.end=Object.assign({},ef(t.events,i)),e.add(i,0,[[`exit`,a,t]]),a=void 0),a}function $d(e,t,n,r,i){let a=[],o=ef(t.events,n);i&&(i.end=Object.assign({},o),a.push([`exit`,i,t])),r.end=Object.assign({},o),a.push([`exit`,r,t]),e.add(n+1,0,a)}function ef(e,t){let n=e[t],r=n[0]===`enter`?`start`:`end`;return n[1][r]}var tf={name:`tasklistCheck`,tokenize:rf};function nf(){return{text:{91:tf}}}function rf(e,t,n){let r=this;return i;function i(t){return r.previous!==null||!r._gfmTasklistFirstContentOfListItem?n(t):(e.enter(`taskListCheck`),e.enter(`taskListCheckMarker`),e.consume(t),e.exit(`taskListCheckMarker`),a)}function a(t){return U(t)?(e.enter(`taskListCheckValueUnchecked`),e.consume(t),e.exit(`taskListCheckValueUnchecked`),o):t===88||t===120?(e.enter(`taskListCheckValueChecked`),e.consume(t),e.exit(`taskListCheckValueChecked`),o):n(t)}function o(t){return t===93?(e.enter(`taskListCheckMarker`),e.consume(t),e.exit(`taskListCheckMarker`),e.exit(`taskListCheck`),s):n(t)}function s(r){return H(r)?t(r):W(r)?e.check({tokenize:af},t,n)(r):n(r)}}function af(e,t,n){return G(e,r,`whitespace`);function r(e){return e===null?n(e):t(e)}}function of(e){return vi([xd(),Ld(),Gd(e),Yd(),nf()])}var sf={};function cf(e){let t=this,n=e||sf,r=t.data(),i=r.micromarkExtensions||=[],a=r.fromMarkdownExtensions||=[],o=r.toMarkdownExtensions||=[];i.push(of(n)),a.push(ud()),o.push(dd(n))}function lf(e,t){let n=e.trim().replace(/^\.?\//,``);if(!n||t.length===0)return null;if(t.includes(n))return n;let r=t.filter(e=>e.endsWith(`/${n}`));return r.length===1?r[0]:null}var uf=e=>e.replace(/[.*+?^${}()|[\]\\/-]/g,`\\$&`);function df(e,t){if(!e||t.length===0)return e;let n=new Set(t);for(let e of t){let r=e.slice(e.lastIndexOf(`/`)+1);r.includes(`.`)&&lf(r,t)===e&&n.add(r)}let r=[...n].sort((e,t)=>t.length-e.length).map(uf),i=RegExp(`(?]*>)/).map((e,t)=>t%2==1?e:e.replace(i,"`$1`")).join(``)}function ff(e){let t=typeof e.children==`string`?e.children:``;return!String(e.className??``).includes(`language-`)&&!t.includes(` +`)}function pf(e){let t=[],n=[],r=null,i=()=>{let e=n.join(` +`).trim();if(n=[],!e)return;let r=e.trimStart(),i=r.startsWith("```")||r.startsWith(`~~~`)||r.startsWith(`|`)||r.startsWith(`<`),a=t[t.length-1];if(a&&!a.bare&&/^#{1,6}\s/.test(a.text)&&!a.text.includes(` +`)&&!i){a.text=`${a.text}\n\n${e}`;return}t.push({text:e,bare:i})};for(let t of e.split(` +`)){let e=/^\s*(```|~~~)/.exec(t);if(r){n.push(t),e&&e[1]===r&&(r=null);continue}if(e){n.length&&i(),r=e[1],n.push(t);continue}if(t.trim()===``){i();continue}n.push(t)}return i(),t}function mf({text:e,files:t=[],onOpenFile:n}){let r=e=>n&&e&&t.length>0?lf(e,t):null,i=e=>n?.(e),a=n&&t.length>0?df(e,t):e;return(0,L.jsx)(`div`,{className:`md text-[15px] leading-[1.5] break-words`,children:(0,L.jsx)(il,{remarkPlugins:[cf],components:{a:({href:e,children:t,...n})=>{let a=e&&!/^[a-z]+:/i.test(e)?r(O(e)):null;return a?(0,L.jsx)(`button`,{type:`button`,className:`md-file`,onClick:()=>i(a),children:t}):(0,L.jsx)(`a`,{href:e,...n,target:`_blank`,rel:`noreferrer noopener`,children:t})},code:({children:e,...t})=>{let n=ff({children:e,...t})&&typeof e==`string`?r(e):null;return n?(0,L.jsx)(`button`,{type:`button`,className:`md-file`,onClick:()=>i(n),title:n,children:e}):(0,L.jsx)(`code`,{...t,children:e})}},children:a})})}function hf({path:e,onClose:t}){let n=s(),i=(0,I.useRef)(null);if(On(i,!!e),(0,I.useEffect)(()=>{if(!e)return;let n=e=>e.key===`Escape`&&t();return window.addEventListener(`keydown`,n),()=>window.removeEventListener(`keydown`,n)},[e,t]),!e)return null;let a=e.split(`/`).pop()??e,o=r(a);return(0,L.jsxs)(`div`,{ref:i,role:`dialog`,"aria-modal":`true`,"aria-label":a,className:`fixed inset-0 z-[60] flex flex-col bg-bg`,children:[(0,L.jsxs)(`header`,{className:`safe-top shrink-0 flex items-center gap-2 border-b border-border bg-surface/90 px-3 py-2 backdrop-blur`,children:[(0,L.jsx)(`button`,{type:`button`,onClick:t,"aria-label":n(`Close`),className:`p-2 rounded-full text-muted hover:bg-surface-2`,children:(0,L.jsx)(Fe,{size:20})}),(0,L.jsxs)(`div`,{className:`flex-1 min-w-0`,children:[(0,L.jsx)(`div`,{className:`font-semibold text-[15px] truncate`,children:a}),(0,L.jsx)(`div`,{className:`text-[12px] text-muted truncate`,children:e})]}),o!==`html`&&(0,L.jsx)(`a`,{href:h(e),target:`_blank`,rel:`noreferrer noopener`,"aria-label":n(`Open in a new tab`),className:`p-2 rounded-full text-muted hover:bg-surface-2`,children:(0,L.jsx)(Ae,{size:19})}),(0,L.jsx)(`a`,{href:h(e,!0),"aria-label":n(`Download`),className:`p-2 rounded-full text-muted hover:bg-surface-2`,children:(0,L.jsx)(ft,{size:19})})]}),(0,L.jsx)(`div`,{className:`min-h-0 flex-1 overflow-auto`,children:(0,L.jsx)(gf,{path:e,kind:o})})]})}function gf({path:e,kind:t}){let n=s();return t===`image`?(0,L.jsx)(`div`,{className:`flex h-full items-center justify-center p-3`,children:(0,L.jsx)(`img`,{src:h(e),alt:e,className:`max-h-full max-w-full rounded-2xl object-contain`})}):t===`pdf`?(0,L.jsx)(`iframe`,{title:e,src:h(e),className:`h-full w-full bg-white`}):t===`html`?(0,L.jsx)(vf,{path:e}):t===`event`?(0,L.jsx)(yf,{path:e}):t===`text`||t===`code`||t===`data`?(0,L.jsx)(Sf,{path:e,kind:t}):(0,L.jsxs)(`div`,{className:`p-8 text-center text-muted text-[14px]`,children:[n(`No preview for this file type.`),` `,(0,L.jsx)(`a`,{href:h(e,!0),className:`text-accent font-medium`,children:n(`Download it`)})]})}function _f(e){let[t,n]=(0,I.useState)(null),[r,i]=(0,I.useState)(null);return(0,I.useEffect)(()=>{let t=!0;return n(null),i(null),M.fileText(e).then(e=>t&&n(e)).catch(e=>t&&i(e.message)),()=>{t=!1}},[e]),{text:t,error:r}}function vf({path:e}){let{text:t,error:n}=_f(e);return n?(0,L.jsx)(Tf,{error:n}):t===null?(0,L.jsx)(wf,{}):(0,L.jsx)(`iframe`,{title:e,srcDoc:t,sandbox:`allow-scripts allow-popups allow-forms allow-modals`,referrerPolicy:`no-referrer`,className:`h-full w-full bg-white`})}function yf({path:e}){let t=s(),{text:n,error:r}=_f(e);if(r)return(0,L.jsx)(Tf,{error:r});if(n===null)return(0,L.jsx)(wf,{});let i=bf(n);return(0,L.jsxs)(`div`,{className:`mx-auto max-w-[560px] px-5 py-6 space-y-4`,children:[i.length===0&&(0,L.jsx)(`div`,{className:`text-center text-muted text-[14px]`,children:t(`No event in this file.`)}),i.map((e,n)=>(0,L.jsxs)(`div`,{className:`rounded-3xl border border-border/70 bg-surface shadow-sm p-5`,children:[(0,L.jsxs)(`div`,{className:`flex items-start gap-3`,children:[(0,L.jsx)(`div`,{className:`rounded-2xl bg-accent/12 text-accent p-2.5`,children:(0,L.jsx)(tt,{size:22})}),(0,L.jsxs)(`div`,{className:`min-w-0 flex-1`,children:[(0,L.jsx)(`div`,{className:`text-[18px] font-semibold leading-snug`,children:e.summary||t(`Untitled event`)}),(0,L.jsx)(`div`,{className:`mt-1 text-[14px] text-muted`,children:xf(e)}),e.location&&(0,L.jsxs)(`div`,{className:`mt-1 flex items-center gap-1 text-[14px] text-muted`,children:[(0,L.jsx)(Dt,{size:14}),` `,e.location]})]})]}),e.description&&(0,L.jsx)(`div`,{className:`mt-4 whitespace-pre-wrap text-[14px] leading-relaxed`,children:e.description})]},n)),(0,L.jsxs)(`a`,{href:h(e,!0),download:!0,className:`flex items-center justify-center gap-2 rounded-2xl bg-accent text-accent-fg px-4 py-3 text-[15px] font-medium`,children:[(0,L.jsx)(nt,{size:18}),` `,t(`Add to calendar`)]}),(0,L.jsx)(`p`,{className:`text-center text-[12.5px] text-muted`,children:t(`Opens in your calendar app, which asks before it saves anything.`)})]})}function bf(e){let t=e.replace(/\r\n/g,` +`).replace(/\n[ \t]/g,``).split(` +`),n=[],r=null,i=e=>e.replace(/\\n/gi,` +`).replace(/\\([,;\\])/g,`$1`),a=(e,t)=>{if(/VALUE=DATE(?![-])/i.test(t)||/^\d{8}$/.test(e)){let t=/^(\d{4})(\d{2})(\d{2})/.exec(e);return{at:t?new Date(+t[1],t[2]-1,+t[3]):null,allDay:!0}}let n=/^(\d{4})(\d{2})(\d{2})T(\d{2})(\d{2})(\d{2})?(Z?)$/.exec(e);if(!n)return{at:null,allDay:!1};let r=[+n[1],n[2]-1,+n[3],+n[4],+n[5],+(n[6]??0)];return{at:n[7]?new Date(Date.UTC(...r)):new Date(...r),allDay:!1}};for(let e of t)if(e===`BEGIN:VEVENT`)r={summary:``,location:``,description:``,start:null,end:null,allDay:!1};else if(e===`END:VEVENT`&&r)n.push(r),r=null;else if(r){let t=e.indexOf(`:`);if(t<0)continue;let[n,...o]=e.slice(0,t).split(`;`),s=e.slice(t+1),c=o.join(`;`);if(n===`SUMMARY`)r.summary=i(s);else if(n===`LOCATION`)r.location=i(s);else if(n===`DESCRIPTION`)r.description=i(s);else if(n===`DTSTART`){let e=a(s,c);r.start=e.at,r.allDay=e.allDay}else n===`DTEND`&&(r.end=a(s,c).at)}return n}function xf(e){if(!e.start)return``;let t=m(),n=e=>e.toLocaleDateString(t,{weekday:`short`,year:`numeric`,month:`short`,day:`numeric`}),r=e=>e.toLocaleTimeString(t,{hour:`numeric`,minute:`2-digit`});if(e.allDay){let t=e.end?new Date(e.end.getTime()-864e5):e.start;return t>e.start?`${n(e.start)} – ${n(t)}`:`${n(e.start)} · ${_(`all day`)}`}return e.end?e.start.toDateString()===e.end.toDateString()?`${n(e.start)} ${r(e.start)}–${r(e.end)}`:`${n(e.start)} ${r(e.start)} – ${n(e.end)} ${r(e.end)}`:`${n(e.start)} ${r(e.start)}`}function Sf({path:e,kind:t}){let{text:n,error:r}=_f(e);return r?(0,L.jsx)(Tf,{error:r}):n===null?(0,L.jsx)(wf,{}):t===`text`&&/\.md$/i.test(e)?(0,L.jsx)(`div`,{className:`mx-auto max-w-[720px] px-5 py-4`,children:(0,L.jsx)(mf,{text:n})}):t===`data`&&/\.csv$/i.test(e)?(0,L.jsx)(Cf,{text:n}):(0,L.jsx)(`pre`,{className:`whitespace-pre-wrap break-words px-4 py-3 font-mono text-[12.5px] leading-relaxed`,children:n})}function Cf({text:e}){let t=s(),n=e.split(/\r?\n/).filter(e=>e.trim()).slice(0,500).map(e=>e.split(`,`));if(!n.length)return(0,L.jsx)(`div`,{className:`p-6 text-muted text-center`,children:t(`Empty file.`)});let[r,...i]=n;return(0,L.jsx)(`div`,{className:`overflow-auto p-3`,children:(0,L.jsxs)(`table`,{className:`min-w-full text-[13px] border-separate border-spacing-0`,children:[(0,L.jsx)(`thead`,{children:(0,L.jsx)(`tr`,{children:r.map((e,t)=>(0,L.jsx)(`th`,{className:`sticky top-0 bg-surface-2 text-left font-semibold px-3 py-2 border-b border-border whitespace-nowrap`,children:e},t))})}),(0,L.jsx)(`tbody`,{children:i.map((e,t)=>(0,L.jsx)(`tr`,{className:`odd:bg-surface`,children:e.map((e,t)=>(0,L.jsx)(`td`,{className:`px-3 py-1.5 border-b border-border/60 whitespace-nowrap`,children:e},t))},t))})]})})}function wf(){return(0,L.jsx)(`div`,{className:`flex h-full items-center justify-center text-muted`,children:(0,L.jsx)(A,{className:`animate-spin`,size:22})})}function Tf({error:e}){let t=s();return(0,L.jsx)(`div`,{className:`p-8 text-center text-rose-600 dark:text-rose-300 text-[14px]`,children:t(`Could not load the file: {error}`,{error:e})})}var Ef=`OpenAI's terms cover using a ChatGPT plan inside OpenAI's own Codex; other apps have had this access cut off before (OpenCode, January 2026). If it stops working, an API key does.`,Df=2e3,Of=6e5;function kf({compact:e,onChanged:t}){let n=s(),{toast:r}=E(),[a,o]=(0,I.useState)(null),[c,l]=(0,I.useState)(`unknown`),[u,d]=(0,I.useState)(null),[f,p]=(0,I.useState)(null),[m,h]=(0,I.useState)(!0),[g,_]=(0,I.useState)(``),[v,y]=(0,I.useState)(null),b=(0,I.useRef)(0),x=(0,I.useCallback)(async()=>{try{let e=await M.chatgptStatus();return o(e),l(`yes`),e}catch(e){return/not found/i.test(e.message)?l(`no`):y(e.message),null}},[]);(0,I.useEffect)(()=>{x().then(e=>{e?.pending&&e.url&&(b.current=Date.now(),h(e.port_bound!==!1),p(e.url))})},[x]),(0,I.useEffect)(()=>{if(!f)return;let e=setInterval(()=>{x().then(e=>{e?.signed_in?(p(null),de(),r(n(`Signed in with {label}.`,{label:e.label||`ChatGPT`})),t?.()):e&&e.pending===!1&&e.error?(p(null),y(n(e.error))):Date.now()-b.current>Of&&(p(null),y(n(`The sign-in did not finish in ten minutes. Try again.`)))})},Df);return()=>clearInterval(e)},[f,x,t,r,n]);let S=async()=>{d(`login`),y(null);try{let e=await M.chatgptLogin();b.current=Date.now(),h(e.port_bound!==!1),_(``),p(e.url),window.open(e.url,`_blank`,`noopener`)}catch(e){/not found/i.test(e.message)?l(`no`):y(e.message)}finally{d(null)}},C=async()=>{let e=g.trim();if(e){d(`paste`),y(null);try{await M.chatgptCallback(e),_(``)}catch(e){let t=e.message;/state/i.test(t)?y(n(`That address belongs to another sign-in attempt. Open the page again and paste the address it ends on.`)):/no sign-in|409/i.test(t)?(p(null),y(n(`The sign-in did not finish in ten minutes. Try again.`))):y(t)}finally{d(null)}}},w=async()=>{d(`use`),y(null);try{await M.setLLM({provider:`chatgpt`,model:a?.models?.[0]??``,base_url:``,api_key:``}),de(),r(n(`ChatGPT answers the chat now.`)),t?.()}catch(e){y(e.message)}finally{d(null)}},T=async()=>{d(`logout`),y(null);try{await M.chatgptLogout(),de(),await x(),t?.()}catch(e){y(e.message)}finally{d(null)}},D=n(`Covers chat and the hands. Pictures and clips are not part of it; those need a provider with image or video models.`);return(0,L.jsxs)(`div`,{className:i(`space-y-2`,!e&&`rounded-2xl bg-surface-2/60 p-3`),children:[!e&&(0,L.jsxs)(`div`,{className:`flex items-center gap-2 text-[13px] font-medium`,children:[(0,L.jsx)(Mt,{size:15,className:`text-accent`}),` `,n(`Sign in with ChatGPT`)]}),c===`no`?(0,L.jsxs)(`p`,{className:`text-[12.5px] text-muted`,children:[n(`This nanoMuse has no sign-in route yet. In a terminal on this computer, run`),` `,(0,L.jsx)(`code`,{className:`rounded bg-surface-2 px-1 py-0.5 text-[12px]`,children:`nanomuse chatgpt login`}),` `,n(`and reload this page.`)]}):a?.signed_in?(0,L.jsxs)(`div`,{className:`space-y-2`,children:[(0,L.jsxs)(`p`,{className:`text-[12.5px]`,children:[(0,L.jsx)(`span`,{className:`font-medium`,children:n(`Signed in with {label}.`,{label:a.label||`ChatGPT`})}),` `,(0,L.jsx)(`span`,{className:`text-muted`,children:D})]}),(0,L.jsxs)(`div`,{className:`flex flex-wrap gap-2`,children:[(0,L.jsxs)(`button`,{type:`button`,disabled:u!==null,onClick:()=>void w(),className:i(Ne,`inline-flex items-center gap-1.5 py-2`),children:[u===`use`?(0,L.jsx)(A,{size:14,className:`animate-spin`}):(0,L.jsx)(Mt,{size:14}),` `,n(`Use it for the chat`)]}),(0,L.jsxs)(`button`,{type:`button`,disabled:u!==null,onClick:()=>void T(),className:i(je,`inline-flex items-center gap-1.5`),children:[u===`logout`?(0,L.jsx)(A,{size:14,className:`animate-spin`}):(0,L.jsx)(Tt,{size:14}),` `,n(`Sign out of ChatGPT`)]})]})]}):f?(0,L.jsxs)(`div`,{className:`space-y-2`,children:[(0,L.jsxs)(`p`,{className:`flex items-start gap-2 text-[12.5px] text-muted`,children:[(0,L.jsx)(A,{size:14,className:`mt-0.5 shrink-0 animate-spin`}),(0,L.jsx)(`span`,{children:n(m?`A page from OpenAI opened in a new tab. Sign in there; this card follows on its own.`:`A page from OpenAI opened in a new tab. Sign in there; when the browser ends on an address that will not load, paste that address below.`)})]}),(0,L.jsxs)(`div`,{className:`flex flex-wrap gap-2`,children:[(0,L.jsxs)(`a`,{href:f,target:`_blank`,rel:`noopener noreferrer`,className:i(je,`inline-flex items-center gap-1.5`),children:[(0,L.jsx)(Ae,{size:14}),` `,n(`Open the page again`)]}),(0,L.jsx)(`button`,{type:`button`,onClick:()=>p(null),className:je,children:n(`Cancel`)})]}),(0,L.jsxs)(`form`,{className:`flex flex-wrap items-center gap-2`,onSubmit:e=>{e.preventDefault(),C()},children:[(0,L.jsx)(`input`,{type:`url`,value:g,onChange:e=>_(e.target.value),placeholder:`http://localhost:1455/auth/callback?code=…`,"aria-label":n(`The address the browser ended on`),className:`min-w-0 flex-1 rounded-lg border border-border bg-surface px-2 py-1.5 text-[12.5px]`}),(0,L.jsxs)(`button`,{type:`submit`,disabled:u!==null||!g.trim(),className:i(je,`inline-flex items-center gap-1.5`),children:[u===`paste`?(0,L.jsx)(A,{size:14,className:`animate-spin`}):null,` `,n(`Use this address`)]})]}),!m&&(0,L.jsx)(`p`,{className:`text-[11.5px] text-muted`,children:n(`This nanoMuse runs where the browser cannot reach port 1455, so it cannot pick the sign-in up by itself.`)})]}):(0,L.jsxs)(`div`,{className:`space-y-2`,children:[(0,L.jsx)(`p`,{className:`text-[12.5px] text-muted`,children:D}),(0,L.jsxs)(`button`,{type:`button`,disabled:u!==null||c===`unknown`,onClick:()=>void S(),className:i(Ne,`inline-flex items-center gap-1.5 py-2`),children:[u===`login`?(0,L.jsx)(A,{size:14,className:`animate-spin`}):(0,L.jsx)(wt,{size:14}),` `,n(`Sign in with ChatGPT`)]})]}),(0,L.jsx)(`p`,{className:`text-[11.5px] leading-snug text-muted`,children:n(Ef)}),v&&(0,L.jsx)(`p`,{className:`text-[12px] text-rose-600 dark:text-rose-300`,children:v})]})}var Af=``,jf=`nm.connections.preset`;function Mf(e,t=ae().preset){try{sessionStorage.setItem(jf,t)}catch{}e(`connections`)}function Nf(){try{let e=sessionStorage.getItem(jf);return e&&sessionStorage.removeItem(jf),e}catch{return null}}function Pf({info:e,exhausted:t,compact:n}){let r=s(),{toast:a,setTab:o,state:l}=E(),u=l.hub?.account,d=ae(u),f=le(u),p=c(),m=e.invite_bonus_cny??5,h=e.own_key_docs||e.guidance?.docs||Af,g=e.invite_url||``,[_,v]=(0,I.useState)(!1),[y,b]=(0,I.useState)(!1),x=(e.guidance?.providers??De(f)).filter(e=>e.id!==d.id).map(e=>({id:e.id,name:pe(e,p),keyUrl:e.key_url,covers:`covers`in e?e.covers:e.capabilities})),S=Ee().map(e=>e.name),C=async e=>{try{await navigator.clipboard.writeText(e),a(r(`Copied`))}catch{a(e)}},w=async()=>{let e=r(`Try nanoMuse with me, a fully open-source personal agent, free to use. Sign up with my link: {link}`,{link:g}),t=navigator;if(t.share)try{await t.share({text:e});return}catch{}await C(e)},T=Ce(),[D,O]=me(`exhausted`,t),k=ve(xe(r,`exhausted`)),ee=t?r(`The free allowance is used up.`):r(`Nearly used up: ¥{left} of ¥{grant} left.`,{left:(e.left??0).toFixed(2),grant:(e.grant??0).toFixed(0)});return(0,L.jsxs)(`div`,{className:i(`space-y-2.5`,!n&&`pt-1`),children:[(0,L.jsxs)(`div`,{children:[(0,L.jsx)(`div`,{className:i(`font-semibold`,n?`text-[13.5px]`:`text-[15px]`),children:ee}),(0,L.jsx)(`div`,{className:`mt-0.5 text-[12.5px] text-muted`,children:r(`Three ways on; your sign-in and your devices keep working whichever you pick.`)})]}),(0,L.jsxs)(Ff,{icon:(0,L.jsx)(P,{size:16}),tone:`bg-accent/12 text-accent`,title:r(`Use your own model key`),children:[(0,L.jsx)(`p`,{className:`text-[12.5px] text-muted`,children:_e(r,u)}),(0,L.jsxs)(`div`,{className:`flex flex-wrap gap-2`,children:[(0,L.jsxs)(`button`,{type:`button`,onClick:()=>Mf(o,d.preset),className:i(Ne,`inline-flex items-center gap-1.5 py-2`),children:[(0,L.jsx)(P,{size:14}),` `,r(`Set it up`)]}),(0,L.jsxs)(`a`,{href:d.keyUrl,target:`_blank`,rel:`noopener noreferrer`,className:i(je,`inline-flex items-center gap-1.5`),children:[(0,L.jsx)(Ae,{size:14}),` `,r(`Get a key from {vendor}`,{vendor:d.label})]}),h?(0,L.jsxs)(`a`,{href:h,target:`_blank`,rel:`noopener noreferrer`,className:i(je,`inline-flex items-center gap-1.5`),children:[(0,L.jsx)(Ae,{size:14}),` `,r(`Step-by-step guide`)]}):null]}),x.length>0&&(0,L.jsxs)(`div`,{children:[(0,L.jsxs)(`button`,{type:`button`,onClick:()=>v(!_),className:`inline-flex items-center gap-1 text-[12px] text-muted`,children:[_?(0,L.jsx)(Le,{size:13}):(0,L.jsx)(Me,{size:13}),` `,r(`Other providers and what each key covers`)]}),_&&(0,L.jsx)(`ul`,{className:`mt-1.5 space-y-1 text-[12.5px]`,children:x.map(e=>(0,L.jsxs)(`li`,{className:`flex flex-wrap items-baseline justify-between gap-x-3`,children:[(0,L.jsxs)(`span`,{children:[(0,L.jsx)(`span`,{className:`font-medium`,children:e.name}),` `,(0,L.jsxs)(`span`,{className:`text-muted`,children:[`· `,ye(r,e.covers)]})]}),(0,L.jsxs)(`span`,{className:`flex gap-2`,children:[(0,L.jsx)(`button`,{type:`button`,onClick:()=>Mf(o,Oe(e.id)),className:`text-accent`,children:r(`Set it up`)}),(0,L.jsxs)(`a`,{href:e.keyUrl,target:`_blank`,rel:`noopener noreferrer`,className:`inline-flex items-center gap-0.5 text-accent`,children:[r(`Get a key`),` `,(0,L.jsx)(Ae,{size:11})]})]})]},e.id))})]})]}),(0,L.jsxs)(Ff,{icon:(0,L.jsx)(wt,{size:16}),tone:`bg-emerald-500/12 text-emerald-600 dark:text-emerald-300`,title:r(`Sign in with a plan you already pay for`),children:[(0,L.jsx)(`p`,{className:`text-[12.5px] text-muted`,children:r(`{plans}: the plan's models answer here, no key to make. ChatGPT works on every device, the others on the phones. A ChatGPT sign-in covers chat and the hands; pictures and clips still want a key.`,{plans:S.join(r(`, `))})}),y?(0,L.jsx)(kf,{compact:!0,onChanged:()=>b(!1)}):(0,L.jsxs)(`button`,{type:`button`,onClick:()=>b(!0),className:i(je,`inline-flex items-center gap-1.5`),children:[(0,L.jsx)(wt,{size:14}),` `,r(`Sign in with ChatGPT`)]})]}),(0,L.jsx)(Ff,{icon:(0,L.jsx)(hn,{size:16}),tone:`bg-violet-500/12 text-violet-600 dark:text-violet-300`,title:r(`Invite a friend: +¥{bonus} for you and +¥{bonus} for them, for each new person who signs up with your link.`,{bonus:m.toFixed(0)}),children:g?(0,L.jsxs)(`div`,{className:`flex flex-wrap gap-2`,children:[(0,L.jsxs)(`button`,{type:`button`,onClick:()=>void w(),className:i(je,`inline-flex items-center gap-1.5`),children:[(0,L.jsx)(Xt,{size:14}),` `,r(`Share the link`)]}),(0,L.jsxs)(`button`,{type:`button`,onClick:()=>void C(g),className:i(je,`inline-flex items-center gap-1.5`),children:[(0,L.jsx)(ut,{size:14}),` `,r(`Copy the link`)]})]}):(0,L.jsxs)(`button`,{type:`button`,onClick:()=>o(`account`),className:i(je,`inline-flex items-center gap-1.5`),children:[(0,L.jsx)(Xt,{size:14}),` `,r(`Your invite link is under Account`)]})}),t&&D&&(0,L.jsxs)(Ff,{icon:(0,L.jsx)(ge,{size:16}),tone:`bg-amber-400/15 text-amber-600 dark:text-amber-300`,title:k,children:[(0,L.jsxs)(`button`,{type:`button`,onClick:()=>fe(T.repo_url),className:i(`flex items-center justify-center gap-1.5 rounded-2xl border border-border px-4 py-2.5 text-[14px] font-medium text-muted disabled:opacity-40`,`inline-flex items-center gap-1.5`),children:[(0,L.jsx)(ge,{size:14}),` `,r(`Star on GitHub`)]}),(0,L.jsx)(`button`,{type:`button`,onClick:()=>{he(),O(!1)},className:i(`flex items-center justify-center gap-1.5 rounded-2xl border border-border px-4 py-2.5 text-[14px] font-medium text-muted disabled:opacity-40`,`inline-flex items-center gap-1.5`),children:r(`I already starred`)})]})]})}function Ff({icon:e,tone:t,title:n,children:r}){return(0,L.jsxs)(`div`,{className:`flex gap-3 rounded-2xl bg-surface-2/60 p-3`,children:[(0,L.jsx)(`span`,{className:i(`flex h-8 w-8 shrink-0 items-center justify-center rounded-xl`,t),children:e}),(0,L.jsxs)(`div`,{className:`min-w-0 flex-1 space-y-2`,children:[(0,L.jsx)(`div`,{className:`text-[13px] font-medium leading-snug`,children:n}),r]})]})}var If=`nm.cloud.warned_grant`;function Lf(){let e=s(),{state:t,setTab:n}=E(),[r,i]=(0,I.useState)(null),a=(0,I.useRef)(0),o=t.hub?.account,c=!!o?.signed_in&&!!o.is_model,l=t.finishedAt;if((0,I.useEffect)(()=>{if(!c||!l||r||Date.now()-a.current<6e4)return;a.current=Date.now();let e=!1;return M.cloudMe().then(t=>{if(e)return;let n=t.spend,r=n.grant??n.allowance_cny??0,a=n.left??null;if(n.unlimited||!n.warn||a===null||a<=0)return;let o=null;try{o=localStorage.getItem(If)}catch{}o!==String(r)&&i({left:a,grant:r,invite_url:t.invite?.url,invite_bonus_cny:n.invite_bonus_cny,invitee_bonus_cny:n.invitee_bonus_cny,own_key_docs:n.own_key_docs,guidance:n.guidance})}).catch(()=>{}),()=>{e=!0}},[c,l,r]),!r)return null;let u=()=>{try{localStorage.setItem(If,String(r.grant??0))}catch{}i(null)};return(0,L.jsxs)(`div`,{className:`rise mx-3 mb-1.5 flex items-start gap-2 rounded-2xl bg-amber-500/12 px-3 py-2 text-[12.5px] leading-snug text-amber-800 dark:text-amber-200`,children:[(0,L.jsx)(nn,{size:14,className:`mt-0.5 shrink-0`}),(0,L.jsxs)(`div`,{className:`min-w-0 flex-1`,children:[e(`Nearly used up: ¥{left} of ¥{grant} left.`,{left:(r.left??0).toFixed(2),grant:(r.grant??0).toFixed(0)}),` `,e(`Invite a friend (+¥{invite} for each of you) or bring your own key; your sign-in keeps working either way.`,{invite:(r.invite_bonus_cny??5).toFixed(0)}),` `,(0,L.jsx)(`button`,{type:`button`,onClick:()=>{u(),n(`account`)},className:`font-semibold underline decoration-dotted underline-offset-2`,children:e(`See the ways`)})]}),(0,L.jsx)(`button`,{type:`button`,onClick:u,"aria-label":e(`Dismiss`),className:`shrink-0 rounded-full p-0.5 opacity-70 hover:opacity-100`,children:(0,L.jsx)(Fe,{size:14})})]})}var Rf=`nm.cloud.first_sign_in`,zf=`nm:first-sign-in`;function Bf(){try{sessionStorage.setItem(Rf,`1`)}catch{}window.dispatchEvent(new Event(zf))}function Vf(){try{sessionStorage.removeItem(Rf)}catch{}window.dispatchEvent(new Event(zf))}function Hf(){try{return sessionStorage.getItem(Rf)===`1`}catch{return!1}}function Uf(){let[e,t]=(0,I.useState)(Hf);return(0,I.useEffect)(()=>{let e=()=>t(Hf());return window.addEventListener(zf,e),()=>window.removeEventListener(zf,e)},[]),e}function Wf(){let e=s(),{toast:t,refreshHub:n,setTab:r,state:a}=E(),o=ae(a.hub?.account),[c,l]=(0,I.useState)(`password`),[u,d]=(0,I.useState)(``),[f,p]=(0,I.useState)(``),[m,h]=(0,I.useState)(!1),[g,_]=(0,I.useState)(null),v=async()=>{Vf(),await n().catch(()=>void 0)},y=async()=>{if(!(u.length<8||u!==f)){h(!0),_(null);try{await M.cloudPassword(u),t(e(`Password set.`)),d(``),p(``),l(`source`)}catch(t){_(e(t.message))}finally{h(!1)}}},b=async()=>{await v(),Mf(r,o.preset)},x=(0,I.useRef)(null);On(x,!0);let S=f.length>0&&f!==u;return(0,L.jsx)(`div`,{className:`fixed inset-0 z-50 flex items-end justify-center bg-black/40 backdrop-blur-[2px] sm:items-center`,role:`dialog`,"aria-modal":`true`,children:(0,L.jsxs)(`div`,{ref:x,className:`safe-bottom w-full max-w-[520px] rounded-t-[28px] bg-bg p-6 shadow-2xl sm:rounded-[28px]`,children:[(0,L.jsxs)(`div`,{className:`mb-4 flex gap-1`,children:[(0,L.jsx)(`span`,{className:i(`h-1.5 w-5 rounded-full bg-accent`)}),(0,L.jsx)(`span`,{className:i(`h-1.5 rounded-full transition-all`,c===`source`?`w-5 bg-accent`:`w-1.5 bg-border`)})]}),c===`password`?(0,L.jsxs)(`form`,{className:`space-y-4`,onSubmit:e=>{e.preventDefault(),y()},children:[(0,L.jsxs)(`div`,{className:`flex items-start gap-3`,children:[(0,L.jsx)(`span`,{className:`flex h-11 w-11 shrink-0 items-center justify-center rounded-2xl bg-accent/12 text-accent`,children:(0,L.jsx)(P,{size:20})}),(0,L.jsxs)(`div`,{children:[(0,L.jsx)(`h2`,{className:`text-[20px] font-bold tracking-tight`,children:e(`Set a password`)}),(0,L.jsx)(`p`,{className:`mt-1 text-[13.5px] leading-relaxed text-muted`,children:e(`Your account is in. With a password, your phone and your other computers sign in at once, without waiting for a code. Optional; you can set one later under Account.`)})]})]}),(0,L.jsxs)(`div`,{className:`space-y-2`,children:[(0,L.jsx)(`input`,{type:`password`,value:u,onChange:e=>d(e.target.value),autoComplete:`new-password`,autoFocus:!0,placeholder:e(`At least 8 characters`),className:Ie}),(0,L.jsx)(`input`,{type:`password`,value:f,onChange:e=>p(e.target.value),autoComplete:`new-password`,placeholder:e(`Once more`),className:i(Ie,S&&`border-rose-400`)}),S&&(0,L.jsx)(`p`,{className:`text-[12px] text-rose-600 dark:text-rose-300`,children:e(`The two do not match.`)})]}),g&&(0,L.jsx)(`div`,{className:`rounded-2xl bg-rose-500/12 px-3 py-2 text-[12.5px] text-rose-700 dark:text-rose-300`,children:g}),(0,L.jsxs)(`div`,{className:`flex gap-2`,children:[(0,L.jsx)(`button`,{type:`button`,disabled:m,onClick:()=>l(`source`),className:je,children:e(`Skip`)}),(0,L.jsxs)(`button`,{type:`submit`,disabled:m||u.length<8||u!==f,className:i(Ne,`flex-1 py-3`),children:[m?(0,L.jsx)(A,{size:15,className:`animate-spin`}):null,` `,e(`Set the password`),` `,(0,L.jsx)(qe,{size:16})]})]})]}):(0,L.jsxs)(`div`,{className:`space-y-4`,children:[(0,L.jsxs)(`div`,{className:`flex items-start gap-3`,children:[(0,L.jsx)(`span`,{className:`flex h-11 w-11 shrink-0 items-center justify-center rounded-2xl bg-accent/12 text-accent`,children:(0,L.jsx)(ot,{size:20})}),(0,L.jsxs)(`div`,{children:[(0,L.jsx)(`h2`,{className:`text-[20px] font-bold tracking-tight`,children:e(`Which model answers?`)}),(0,L.jsx)(`p`,{className:`mt-1 text-[13.5px] leading-relaxed text-muted`,children:e(`Your account already brings one. You can add your own API key as well and switch at any time.`)})]})]}),(0,L.jsxs)(`ul`,{className:`space-y-2 text-[13px] leading-snug`,children:[(0,L.jsxs)(`li`,{className:`flex items-start gap-2.5 rounded-2xl bg-surface-2 px-3 py-2.5`,children:[(0,L.jsx)(ot,{size:16,className:`mt-0.5 shrink-0 text-accent`}),(0,L.jsxs)(`span`,{children:[(0,L.jsx)(`span`,{className:`font-medium`,children:e(`Use the nanoMuse Cloud model`)}),(0,L.jsx)(`span`,{className:`block text-muted`,children:e(`DeepSeek for the chat and Qwen for the hands, with a free allowance per account paid by the developer. Nothing to configure.`)})]})]}),(0,L.jsxs)(`li`,{className:`flex items-start gap-2.5 rounded-2xl bg-surface-2 px-3 py-2.5`,children:[(0,L.jsx)(P,{size:16,className:`mt-0.5 shrink-0 text-accent`}),(0,L.jsxs)(`span`,{children:[(0,L.jsx)(`span`,{className:`font-medium`,children:e(`I have my own API key`)}),(0,L.jsx)(`span`,{className:`block text-muted`,children:o.preset===`qwen`?e(`Alibaba Cloud Bailian first (one key covers chat, the hands, pictures and clips), then DeepSeek, Kimi, Zhipu, OpenAI, OpenRouter and any OpenAI-compatible endpoint. The key stays on this device.`):e(`OpenRouter first (one account, one key, pay as you go), then OpenAI, Anthropic, Gemini, DeepSeek and any OpenAI-compatible endpoint. The key stays on this device.`)})]})]}),(0,L.jsxs)(`li`,{className:`flex items-start gap-2.5 rounded-2xl bg-surface-2 px-3 py-2.5`,children:[(0,L.jsx)(wt,{size:16,className:`mt-0.5 shrink-0 text-accent`}),(0,L.jsxs)(`span`,{children:[(0,L.jsx)(`span`,{className:`font-medium`,children:e(`Sign in with a plan you already pay for`)}),(0,L.jsx)(`span`,{className:`block text-muted`,children:e(`A ChatGPT plan signs in from Connections and answers the chat and the hands. Pictures and clips still want a key.`)})]})]})]}),(0,L.jsxs)(`div`,{className:`flex gap-2`,children:[(0,L.jsx)(`button`,{type:`button`,disabled:m,onClick:()=>void b(),className:je,children:e(`I have my own API key`)}),(0,L.jsxs)(`button`,{type:`button`,disabled:m,onClick:()=>void v(),className:i(Ne,`flex-1 py-3`),children:[e(`Use the nanoMuse Cloud model`),` `,(0,L.jsx)(qe,{size:16})]})]})]})]})})}var Gf=`nanomuse_devtools`;function Kf(){try{return localStorage.getItem(Gf)===`1`}catch{return!1}}var qf=Kf(),Jf=new Set;function Yf(){return qf}function Xf(e){qf=e;try{localStorage.setItem(Gf,e?`1`:`0`)}catch{}Jf.forEach(e=>e())}function Zf(e){return Jf.add(e),()=>Jf.delete(e)}function Qf(){return(0,I.useSyncExternalStore)(Zf,Yf,Yf)}function $f(e,t,n){if(!n.signedIn||n.chatOnCloud||n.deviceChat)return;let r=e[t];if(r?.type===`notice`&&r.level===`error`&&r.code&&r.code!==`allowance`&&!r.model_used)for(let n=t-1;n>=0;n--){let t=e[n];if(t?.type===`user`){let e=(t.files??[]).map(e=>e.path);return t.text||e.length>0?{text:t.text,files:e}:void 0}}}var ep=[`idle`,`working`,`waiting`,`happy`,`error`];function tp({event:e,name:t=`nanoMuse`}){let n=s(),{toast:r}=E(),[a,o]=(0,I.useState)(null),c=e.cost??{},l=e.candidates??[null,null,null,null],u=e.moods??{},d=e.clips??{},f=async(e,t)=>{o(e);try{await t()}catch(e){r(e.message)}finally{o(null)}},p=e.stage===`estimate`||e.stage===`drawing`||e.stage===`choose`||e.stage===`posing`||e.stage===`animating`,m=c.clips?n(`{n} pictures and {c} clips`,{n:c.pictures??8,c:c.clips}):n(`{n} pictures`,{n:c.pictures??8}),g=(()=>{if(c.cloud===!1)return n(`{what}, made with your own key at your provider's prices.`,{what:m});if(c.error)return n(`The cost could not be checked: {error}`,{error:c.error});if(typeof c.cny!=`number`)return n(`Checking the cost…`);if(c.unlimited)return n(`About ¥{cny} for {what}; your account has no limit.`,{cny:c.cny.toFixed(2),what:m});let e=typeof c.left_cny==`number`?c.left_cny.toFixed(2):`?`;return c.affordable===!1?n(`About ¥{cny} for {what}, more than the ¥{left} left in your allowance.`,{cny:c.cny.toFixed(2),what:m,left:e}):n(`About ¥{cny} for {what}; ¥{left} left in your allowance.`,{cny:c.cny.toFixed(2),what:m,left:e})})();return(0,L.jsx)(`div`,{className:`rise flex justify-start pr-8`,children:(0,L.jsxs)(`div`,{className:i(`w-full max-w-[360px] overflow-hidden rounded-3xl rounded-tl-lg border bg-surface shadow-sm`,p?`border-accent/50`:`border-border/70`),children:[(0,L.jsxs)(`div`,{className:`flex items-start gap-3 px-4 pt-3.5 pb-2`,children:[(0,L.jsx)(`div`,{className:i(`mt-0.5 rounded-full p-2`,p?`bg-accent/12 text-accent`:`bg-surface-2 text-fg/80`),children:(0,L.jsx)(nn,{size:18})}),(0,L.jsxs)(`div`,{className:`min-w-0 flex-1`,children:[(0,L.jsxs)(`div`,{className:`text-[12.5px] font-medium text-muted`,children:[e.stage===`estimate`&&n(`A new look for {name}`,{name:t}),e.stage===`drawing`&&n(`Drawing four to choose from…`),e.stage===`choose`&&n(`Pick one: tap it, or say which`),e.stage===`posing`&&n(`Drawing the poses…`),e.stage===`animating`&&n(`The new look is on; making the clips…`),e.stage===`done`&&n(`The new look is on`),e.stage===`cancelled`&&n(`Not this time`),e.stage===`failed`&&n(`That did not work`)]}),(0,L.jsx)(`div`,{className:`mt-0.5 text-[14px] leading-snug`,children:e.description}),e.reference&&(0,L.jsxs)(`div`,{className:`mt-1.5 flex items-center gap-2 text-[12px] text-muted`,children:[(0,L.jsx)(`img`,{src:h(e.reference),alt:``,draggable:!1,className:`h-9 w-9 rounded-lg object-cover`}),n(`drawn from the picture you attached`)]})]})]}),e.stage===`estimate`&&(0,L.jsxs)(`div`,{className:`px-4 pb-3.5 space-y-2.5`,children:[(0,L.jsx)(`p`,{className:`text-[12.5px] text-muted`,children:g}),(0,L.jsxs)(`div`,{className:`flex gap-2`,children:[(0,L.jsxs)(`button`,{type:`button`,disabled:a!==null||c.cloud!==!1&&typeof c.cny!=`number`&&!c.error,onClick:()=>f(`start`,()=>M.avatarStart(e.session)),className:i(`flex items-center justify-center gap-1.5 rounded-2xl bg-accent text-accent-fg px-4 py-2.5 text-[14px] font-medium disabled:opacity-40`,`inline-flex items-center gap-1.5 py-2`),children:[a===`start`?(0,L.jsx)(A,{size:14,className:`animate-spin`}):(0,L.jsx)(nn,{size:14}),` `,n(`Draw`)]}),(0,L.jsxs)(`button`,{type:`button`,disabled:a!==null,onClick:()=>f(`cancel`,()=>M.avatarCancel(e.session)),className:i(`flex items-center justify-center gap-1.5 rounded-2xl border border-border px-4 py-2.5 text-[14px] font-medium text-muted disabled:opacity-40`,`inline-flex items-center gap-1.5`),children:[(0,L.jsx)(Fe,{size:14}),` `,n(`Not now`)]})]})]}),(e.stage===`drawing`||e.stage===`choose`)&&(0,L.jsxs)(`div`,{className:`px-4 pb-3.5 space-y-2.5`,children:[(0,L.jsx)(`div`,{className:`grid grid-cols-2 gap-2`,children:l.map((t,r)=>(0,L.jsxs)(`button`,{type:`button`,disabled:!t||e.stage!==`choose`||a!==null,onClick:()=>f(`pick${r}`,()=>M.avatarChoose(e.session,r)),"aria-label":n(`Candidate {n}`,{n:r+1}),className:i(`relative aspect-square overflow-hidden rounded-2xl bg-[#f1efeb] transition`,t&&e.stage===`choose`?`hover:ring-2 hover:ring-accent`:``),children:[t?(0,L.jsx)(`img`,{src:h(t),alt:``,draggable:!1,className:`h-full w-full object-cover`}):(0,L.jsx)(`span`,{className:`absolute inset-0 flex items-center justify-center text-muted`,children:e.stage===`drawing`?(0,L.jsx)(A,{size:20,className:`animate-spin`}):(0,L.jsx)(Fe,{size:18,className:`opacity-50`})}),a===`pick${r}`&&(0,L.jsx)(`span`,{className:`absolute inset-0 flex items-center justify-center bg-bg/60`,children:(0,L.jsx)(A,{size:20,className:`animate-spin`})}),(0,L.jsx)(`span`,{className:`absolute left-1.5 top-1.5 rounded-full bg-bg/80 px-1.5 text-[10.5px] font-semibold text-fg/80`,children:r+1})]},r))}),e.errors&&e.errors.length>0&&(0,L.jsx)(`p`,{className:`text-[12px] text-rose-600 dark:text-rose-300`,children:n(e.errors[0])}),e.stage===`choose`&&(0,L.jsxs)(`div`,{className:`flex gap-2`,children:[(0,L.jsxs)(`button`,{type:`button`,disabled:a!==null,onClick:()=>f(`redraw`,()=>M.avatarStart(e.session)),className:i(`flex items-center justify-center gap-1.5 rounded-2xl border border-border px-4 py-2.5 text-[14px] font-medium text-muted disabled:opacity-40`,`inline-flex items-center gap-1.5`),children:[a===`redraw`?(0,L.jsx)(A,{size:14,className:`animate-spin`}):(0,L.jsx)(Re,{size:14}),` `,n(`Redraw`)]}),(0,L.jsxs)(`button`,{type:`button`,disabled:a!==null,onClick:()=>f(`cancel`,()=>M.avatarCancel(e.session)),className:i(`flex items-center justify-center gap-1.5 rounded-2xl border border-border px-4 py-2.5 text-[14px] font-medium text-muted disabled:opacity-40`,`inline-flex items-center gap-1.5`),children:[(0,L.jsx)(Fe,{size:14}),` `,n(`Not now`)]})]})]}),(e.stage===`posing`||e.stage===`animating`||e.stage===`done`)&&(0,L.jsxs)(`div`,{className:`px-4 pb-3.5 space-y-2`,children:[(0,L.jsx)(`div`,{className:`flex gap-1.5`,children:ep.map(t=>(0,L.jsxs)(`div`,{className:`relative aspect-square flex-1 overflow-hidden rounded-xl bg-[#f1efeb]`,children:[d[t]?(0,L.jsx)(`video`,{src:h(d[t]),poster:u[t]?h(u[t]):void 0,autoPlay:!0,loop:!0,muted:!0,playsInline:!0,disablePictureInPicture:!0,className:`h-full w-full object-cover`},d[t]):u[t]?(0,L.jsx)(`img`,{src:h(u[t]),alt:``,draggable:!1,className:`h-full w-full object-cover`}):(0,L.jsx)(`span`,{className:`absolute inset-0 flex items-center justify-center text-muted`,children:(0,L.jsx)(A,{size:14,className:`animate-spin`})}),e.stage===`animating`&&u[t]&&!d[t]&&t!==`error`&&(0,L.jsx)(`span`,{className:`absolute bottom-1 right-1 rounded-full bg-white/80 p-0.5 text-muted`,children:(0,L.jsx)(A,{size:10,className:`animate-spin`})})]},t))}),e.stage===`done`?(0,L.jsxs)(`p`,{className:`flex items-center gap-1.5 text-[12.5px] text-muted`,children:[(0,L.jsx)(ke,{size:14,className:`text-emerald-600`}),` `,n(`Idle, working, waiting, happy, sorry: the face follows what {name} is doing.`,{name:t})]}):e.stage===`animating`?(0,L.jsx)(`p`,{className:`text-[12.5px] text-muted`,children:n(`The face is already on; four short clips are being made from the poses, a few minutes.`)}):(0,L.jsx)(`p`,{className:`text-[12.5px] text-muted`,children:n(`Four more pictures from the one you picked; this takes a minute or two.`)}),e.errors&&e.errors.length>0&&e.stage===`done`&&(0,L.jsxs)(`p`,{className:`text-[12px] text-muted`,children:[e.errors.some(e=>!e.includes(` clip:`))&&n(`Some poses could not be drawn and show the idle picture instead.`),` `,e.errors.some(e=>e.includes(` clip:`))&&n(`Some clips could not be made; those moods stay still.`)]})]}),(e.stage===`failed`||e.stage===`cancelled`)&&e.message&&(0,L.jsx)(`p`,{className:`px-4 pb-3.5 text-[12.5px] text-muted`,children:n(e.message)})]})})}function np(){let e=rp();if(!e||typeof e.keepRunning!=`function`)return null;try{return JSON.parse(e.keepRunning())}catch{return null}}function rp(){return window.NanoMuseAndroid??null}function ip(){let e=rp();return!!e&&typeof e.takeOverBrowser==`function`&&(typeof e.hasBrowser!=`function`||e.hasBrowser())}function ap(){let e=rp();if(!e||typeof e.accessibilityState!=`function`)return null;let t=e.accessibilityState();return t===`on`||t===`off`||t===`unsupported`?t:null}function op(e,t=15){switch(e){case`web_search`:return(0,L.jsx)(qt,{size:t});case`web_fetch`:case`browser`:return(0,L.jsx)(gt,{size:t});case`files`:return(0,L.jsx)(mt,{size:t});case`shell`:return(0,L.jsx)(dn,{size:t});case`python_execute`:return(0,L.jsx)(ct,{size:t});case`read_emails`:case`send_email`:return(0,L.jsx)(Et,{size:t});case`goals`:return(0,L.jsx)(un,{size:t});case`remember`:case`recall`:case`forget`:return(0,L.jsx)(Qe,{size:t});case`ask_user`:return(0,L.jsx)(kt,{size:t});case`devices`:return(0,L.jsx)(It,{size:t});case`device_shell`:return(0,L.jsx)(dn,{size:t});case`device_files`:case`device_get`:case`device_put`:return(0,L.jsx)(mt,{size:t});case`device_open`:return(0,L.jsx)(Ae,{size:t});case`device_screen`:return(0,L.jsx)(Lt,{size:t});case`device_notify`:return(0,L.jsx)(Xe,{size:t});case`delegate`:return(0,L.jsx)(Jt,{size:t});case`computer_screen`:return(0,L.jsx)(Lt,{size:t});case`computer_act`:return(0,L.jsx)(zt,{size:t});case`computer_task`:case`computer_app`:return(0,L.jsx)(vt,{size:t});case`phone_screen`:case`phone_act`:case`phone_task`:return(0,L.jsx)(tn,{size:t});default:return(0,L.jsx)(Ze,{size:t})}}function sp({device:e,className:t}){let n=s();return(0,L.jsxs)(`span`,{className:i(`inline-flex max-w-full items-center gap-1 rounded-full bg-accent/12 px-2 py-0.5 text-[11px] font-medium text-accent`,t),children:[(0,L.jsx)(It,{size:11,className:`shrink-0`}),` `,(0,L.jsx)(`span`,{className:`truncate`,children:n(`on {device}`,{device:e})})]})}var cp={safe:`bg-emerald-500/15 text-emerald-700 dark:text-emerald-300`,moderate:`bg-amber-500/15 text-amber-700 dark:text-amber-300`,sensitive:`bg-rose-500/15 text-rose-700 dark:text-rose-300`};function lp({risk:e}){return(0,L.jsx)(`span`,{className:i(`px-2 py-0.5 rounded-full text-[11px] font-semibold uppercase tracking-wide`,cp[e]),children:_(e)})}function up({args:e}){let t=Object.entries(e??{}).filter(([,e])=>e!=null&&e!==``);return t.length?(0,L.jsx)(`dl`,{className:`mt-2 grid grid-cols-[auto_1fr] gap-x-3 gap-y-1 text-[13px]`,children:t.map(([e,t])=>(0,L.jsxs)(`div`,{className:`contents`,children:[(0,L.jsx)(`dt`,{className:`text-muted`,children:e}),(0,L.jsx)(`dd`,{className:`break-words whitespace-pre-wrap font-mono text-[12.5px] leading-snug`,children:String(t)})]},e))}):null}function dp({event:e}){let[t,n]=(0,I.useState)(!1),r=e.status===`running`?(0,L.jsx)(A,{size:14,className:`animate-spin text-accent`}):e.status===`ok`?(0,L.jsx)(ke,{size:14,className:`text-emerald-500`}):e.status===`blocked`?(0,L.jsx)(Ye,{size:14,className:`text-rose-500`}):(0,L.jsx)(Fe,{size:14,className:`text-rose-500`});return(0,L.jsx)(`div`,{className:`rise flex justify-start pr-8`,children:(0,L.jsxs)(`button`,{type:`button`,onClick:()=>n(e=>!e),className:`max-w-full text-left rounded-2xl bg-surface-2/80 border border-border/60 px-3 py-1.5 text-[13px] text-muted hover:text-fg transition`,children:[(0,L.jsxs)(`span`,{className:`flex items-center gap-2`,children:[(0,L.jsx)(`span`,{className:`text-muted`,children:op(e.tool)}),(0,L.jsx)(`span`,{className:`truncate flex-1`,children:e.title||e.summary||e.tool}),e.device&&(0,L.jsx)(sp,{device:e.device}),r,e.output?t?(0,L.jsx)(Me,{size:13}):(0,L.jsx)(rt,{size:13}):null]}),t&&(0,L.jsxs)(`div`,{className:`mt-2 text-fg`,children:[(0,L.jsx)(up,{args:e.args}),e.output&&(0,L.jsx)(`pre`,{className:`mt-2 max-h-52 overflow-auto whitespace-pre-wrap break-words rounded-xl bg-bg p-2 text-[12px] leading-snug`,children:e.output})]})]})})}function fp(e,t,n){if(!t)return e.replace(/_/g,` `);switch(e){case`shell`:return _(`{what} commands`,{what:t.split(`,`).join(`, `)});case`send_email`:return _(`email to {who}`,{who:t.split(`,`).join(`, `)});case`remote_control`:return _(`the device {name}`,{name:typeof n?.device==`string`&&n.device?n.device:t});case`computer_app`:return _(`the hands in {app}`,{app:typeof n?.name==`string`&&n.name?n.name:t});default:return t}}function pp(e,t,n,r){switch(e){case`once`:return _(`Once`);case`conversation`:return _(`For this conversation`);case`session`:return _(`Until restart`);case`24h`:return _(`For 24 hours`);case`always`:return _(`Always for {subject}`,{subject:fp(t,n,r)});default:return e}}function mp({event:e,name:t=`nanoMuse`,onDecide:n}){let[r,a]=(0,I.useState)(!1),[o,c]=(0,I.useState)(!1),[l,d]=(0,I.useState)(!1),[f,p]=(0,I.useState)(!1),m=(e,t)=>{f||(p(!0),Promise.resolve(n(e,t)).finally(()=>p(!1)))},h=(0,I.useRef)(null),g=(0,I.useRef)(null),_=s(),y=e.status===`pending`,b=e.risk===`sensitive`,x=(e.grant_options??[`once`]).filter(e=>e!==`once`),S=e.egress_target||([`web_fetch`,`browser`,`web_search`].includes(e.tool)?e.target:null),C=e.tool===`send_email`?e.target:null,w=Object.values(e.args??{}).some(e=>e!=null&&e!==``);return(0,I.useEffect)(()=>{let e=g.current;e&&!r&&d(e.scrollHeight>e.clientHeight+2)},[e.args,r]),(0,I.useEffect)(()=>{(r||o)&&h.current?.scrollIntoView({block:`end`,behavior:`smooth`})},[r,o]),(0,L.jsx)(`div`,{className:`rise flex justify-start`,ref:h,children:(0,L.jsxs)(`div`,{className:i(`w-full max-w-[600px] overflow-hidden rounded-[22px] bg-surface shadow-[0_2px_12px_rgba(0,0,0,0.12)] dark:border dark:border-border dark:shadow-none`,y&&b&&`border border-rose-400/60 dark:border-rose-400/60`),children:[(0,L.jsxs)(`div`,{className:`flex items-start gap-3 px-4 pt-4 pb-2`,children:[(0,L.jsx)(`div`,{className:i(`flex h-10 w-10 shrink-0 items-center justify-center rounded-full`,b?`bg-rose-500/12 text-rose-500`:`bg-surface-2 text-fg`),children:b?(0,L.jsx)(Zt,{size:22}):op(e.tool,22)}),(0,L.jsxs)(`div`,{className:`min-w-0 flex-1`,children:[(0,L.jsxs)(`div`,{className:`flex flex-wrap items-center gap-1.5 text-[12.5px] font-medium text-muted`,children:[(0,L.jsx)(`span`,{children:e.remote?_(`{name} on {device} wants to`,{name:t,device:e.remote.name}):_(`{name} wants to`,{name:t})}),e.remote&&(0,L.jsx)(sp,{device:e.remote.name})]}),(0,L.jsx)(`div`,{className:`mt-0.5 break-words text-[17px] font-semibold leading-[22px]`,children:e.summary}),S?(0,L.jsxs)(`div`,{className:`mt-1 flex items-center gap-1 text-[13px] text-muted`,children:[(0,L.jsx)(gt,{size:12}),` `,(0,L.jsx)(`span`,{className:`truncate`,children:_(`at {host}`,{host:S})})]}):C?(0,L.jsxs)(`div`,{className:`mt-1 flex items-center gap-1 text-[13px] text-muted`,children:[(0,L.jsx)(Et,{size:12}),` `,(0,L.jsx)(`span`,{className:`truncate`,children:_(`to {recipient}`,{recipient:C})})]}):null,e.purpose&&(0,L.jsx)(`div`,{className:`mt-1.5 break-words text-[13px] leading-snug text-muted line-clamp-2`,children:e.purpose}),b&&(0,L.jsx)(`div`,{className:`mt-1.5`,children:(0,L.jsx)(lp,{risk:e.risk})})]})]}),e.warnings?.length>0&&(0,L.jsx)(`div`,{className:`space-y-1 px-4 pb-2`,children:e.warnings.map(e=>(0,L.jsxs)(`div`,{className:`flex items-start gap-1.5 text-[12.5px] text-rose-600 dark:text-rose-300`,children:[(0,L.jsx)(pn,{size:13,className:`mt-0.5 shrink-0`}),` `,(0,L.jsx)(`span`,{children:_(e)})]},e))}),(w||e.reasons?.length>0)&&(0,L.jsx)(`div`,{className:`px-4 pb-2`,children:(0,L.jsxs)(`div`,{className:`rounded-xl bg-surface-2 px-3 py-2.5`,children:[(0,L.jsx)(`div`,{className:`text-[11px] font-medium text-muted`,children:_(`Exactly what will run`)}),(0,L.jsxs)(`div`,{ref:g,className:i(`-mt-1`,!r&&`max-h-40 overflow-hidden`),children:[(0,L.jsx)(up,{args:e.args}),e.reasons?.length>0&&(0,L.jsx)(`div`,{className:`mt-1.5 text-[12px] text-muted`,children:_(`Why it asks: {reasons}`,{reasons:e.reasons.map(v).join(` · `)})})]}),(l||r)&&(0,L.jsxs)(`button`,{type:`button`,className:`mt-1 flex items-center gap-1 text-[12.5px] text-accent`,onClick:()=>a(e=>!e),children:[r?(0,L.jsx)(Me,{size:13}):(0,L.jsx)(rt,{size:13}),` `,_(r?`Fewer options`:`Show all`)]})]})}),y?(0,L.jsxs)(`div`,{className:`flex flex-col gap-2 px-4 pb-4 pt-2`,children:[(0,L.jsx)(`button`,{type:`button`,onClick:()=>m(!0,`once`),disabled:f,className:`h-[46px] w-full rounded-full bg-accent text-[15px] font-semibold text-accent-fg transition active:scale-[0.98] disabled:opacity-60`,children:_(`Allow once`)}),x.filter(e=>o||e===`conversation`||e===`always`).map(t=>(0,L.jsx)(`button`,{type:`button`,onClick:()=>m(!0,t),disabled:f,className:`h-11 w-full truncate rounded-full bg-surface-2 px-4 text-[15px] font-medium transition active:scale-[0.98] disabled:opacity-60`,children:pp(t,e.tool,e.target,e.args)},t)),(0,L.jsx)(`button`,{type:`button`,onClick:()=>m(!1,`once`),disabled:f,className:`h-11 w-full rounded-full bg-surface-2 text-[15px] font-medium transition active:scale-[0.98] disabled:opacity-60`,children:_(`Deny`)}),x.length===0?(0,L.jsx)(`div`,{className:`text-center text-[12px] text-muted`,children:_(`This kind of action is approved one at a time.`)}):!o&&x.some(e=>e!==`conversation`&&e!==`always`)&&(0,L.jsx)(`button`,{type:`button`,className:`self-center text-[12.5px] text-muted`,onClick:()=>c(!0),children:_(`Allow {subject} for longer…`,{subject:fp(e.tool,e.target,e.args)})})]}):(0,L.jsxs)(`div`,{className:i(`flex items-center gap-1.5 border-t border-border px-4 py-2.5 text-[13px] font-medium`,e.status===`approved`?`text-emerald-600 dark:text-emerald-300`:`text-muted`),children:[e.status===`approved`?(0,L.jsx)(ke,{size:15}):(0,L.jsx)(Fe,{size:15}),e.status===`approved`?`${_(`Approved`)}${e.scope&&e.scope!==`once`?` · ${pp(e.scope,e.tool,e.target).toLowerCase()}`:``}`:e.status===`denied`?_(`Denied`):_(`Expired without an answer`),(0,L.jsx)(`span`,{className:`ml-auto font-normal`,children:u(e.updated_ts??e.ts)})]})]})})}function hp({event:e,name:t}){let n=s();return(0,L.jsx)(`div`,{className:`rise flex justify-start pr-8`,children:(0,L.jsxs)(`div`,{className:`max-w-full rounded-[20px] rounded-bl-md border border-accent/30 bg-surface px-4 py-3`,children:[(0,L.jsxs)(`div`,{className:`flex items-center gap-1.5 text-[12.5px] font-medium text-accent`,children:[(0,L.jsx)(kt,{size:14}),` `,n(`{name} asks`,{name:t})]}),(0,L.jsx)(`div`,{className:`mt-1 text-[15px] leading-snug whitespace-pre-wrap break-words`,children:e.text}),e.status===`pending`&&(0,L.jsx)(`div`,{className:`mt-1.5 text-[12.5px] text-muted`,children:n(`Reply below to continue.`)}),e.status===`answered`&&e.answer&&(0,L.jsxs)(`div`,{className:`mt-2 text-[13px] text-muted border-t border-border pt-2`,children:[n(`You:`),` `,(0,L.jsx)(`span`,{className:`text-fg`,children:e.answer})]})]})})}function gp(e){return e.source===`reminder`||e.source===`memory`?t(e.text):_(e.text,e.vars)}function _p({event:e,onCloudRetry:t}){let n=s(),[r,a]=(0,I.useState)(!1),[o,c]=(0,I.useState)(!1),[l,u]=(0,I.useState)(null),d=e.detail&&e.detail!==e.text?e.detail:null;return e.code===`allowance`&&e.allowance?(0,L.jsxs)(`div`,{className:`rise flex flex-col items-center gap-2 px-6`,children:[(0,L.jsx)(`div`,{className:`max-w-full rounded-2xl bg-amber-500/12 px-3 py-1.5 text-center text-[12.5px] leading-snug text-amber-700 dark:text-amber-300`,children:n(e.text)}),(0,L.jsx)(`div`,{className:`w-full max-w-[520px]`,children:(0,L.jsx)(Pf,{info:e.allowance,exhausted:!0,compact:!0})})]}):(0,L.jsx)(`div`,{className:`rise flex justify-center px-6`,children:(0,L.jsxs)(`div`,{className:i(`max-w-full rounded-2xl px-3 py-1.5 text-center text-[12.5px] leading-snug`,e.level===`info`&&`bg-surface-2/70 text-muted`,e.level===`warn`&&`bg-amber-500/12 text-amber-700 dark:text-amber-300`,e.level===`error`&&`bg-rose-500/12 text-rose-700 dark:text-rose-300`),children:[gp(e),d&&(0,L.jsxs)(L.Fragment,{children:[` `,(0,L.jsx)(`button`,{type:`button`,onClick:()=>a(e=>!e),className:`underline decoration-dotted underline-offset-2 opacity-70 hover:opacity-100`,children:n(r?`Hide details`:`Details`)}),r&&(0,L.jsx)(`div`,{className:`mt-1.5 break-all text-left font-mono text-[11px] opacity-80`,children:d})]}),t&&(0,L.jsxs)(`div`,{className:`mt-1.5 flex flex-col items-center gap-1`,children:[(0,L.jsx)(`button`,{type:`button`,disabled:o,onClick:()=>{t&&(c(!0),u(null),t().catch(e=>u(n(e.message||`Could not send`))).finally(()=>c(!1)))},className:`rounded-full bg-accent/12 px-3 py-1 text-[12px] font-medium text-accent disabled:opacity-50`,children:n(`Use nanoMuse Cloud this time`)}),l&&(0,L.jsx)(`div`,{className:`text-[12px] text-rose-700 dark:text-rose-300`,children:l})]})]})})}function vp({event:e,onOpen:t}){let[r,i]=(0,I.useState)(!1),a=s(),o=e.status===`live`,c=e.url;try{c=new URL(e.url).host}catch{}return(0,L.jsx)(`div`,{className:`rise flex justify-start pr-8`,children:(0,L.jsxs)(`button`,{type:`button`,onClick:()=>t(e.id),"aria-label":a(`Browser: {title}`,{title:e.title||c}),className:`w-full max-w-[340px] overflow-hidden rounded-3xl rounded-tl-lg border border-border bg-surface shadow-sm hover:bg-surface-2 transition text-left`,children:[(0,L.jsxs)(`div`,{className:`relative aspect-[16/10] bg-surface-2`,children:[r?(0,L.jsxs)(`div`,{className:`absolute inset-0 flex flex-col items-center justify-center gap-1 text-muted`,children:[(0,L.jsx)(gt,{size:22}),(0,L.jsx)(`span`,{className:`text-[12px]`,children:a(`Frame no longer available`)})]}):(0,L.jsx)(`img`,{src:n(e.thread,e.frame),alt:e.title||c,onError:()=>i(!0),className:`absolute inset-0 h-full w-full object-cover object-top`},e.frame),(0,L.jsx)(`div`,{className:`absolute left-2.5 top-2.5 flex items-center gap-1.5 rounded-full bg-black/60 px-2 py-0.5 text-[10.5px] font-semibold text-white`,children:o?(0,L.jsxs)(L.Fragment,{children:[(0,L.jsx)(`span`,{className:`h-1.5 w-1.5 rounded-full bg-rose-400 animate-pulse`}),` `,a(`LIVE`)]}):(0,L.jsxs)(L.Fragment,{children:[(0,L.jsx)(gt,{size:11}),` `,a(`BROWSER`)]})})]}),(0,L.jsxs)(`div`,{className:`flex items-center gap-2 px-3.5 py-2.5`,children:[(0,L.jsxs)(`div`,{className:`min-w-0 flex-1`,children:[(0,L.jsx)(`div`,{className:`text-[13.5px] font-medium truncate`,children:e.title||c}),(0,L.jsxs)(`div`,{className:`text-[12px] text-muted truncate`,children:[e.by_user&&e.action.startsWith(`You`)?a(`You`)+e.action.slice(3):e.action,` · `,c]})]}),(0,L.jsx)(rt,{size:16,className:`text-muted shrink-0`})]})]})})}function yp({event:e,name:t=`nanoMuse`}){let n=s(),{state:r,toast:a}=E(),[o,c]=(0,I.useState)(!1),[l,d]=(0,I.useState)(!1),f=e.status===`live`,p=e.last,m=[e.app,e.title].filter(Boolean).join(` · `),h=r.holds.find(t=>t.thread===e.thread&&t.tool===`computer`),g=async()=>{c(!0);try{await M.stopHands()}catch{}finally{c(!1)}},_=async()=>{d(!0);try{await M.openHold(e.thread,`computer`)}catch(e){a(e.message)}finally{d(!1)}};return(0,L.jsx)(`div`,{className:`rise flex justify-start pr-8`,children:(0,L.jsxs)(`div`,{className:i(`w-full max-w-[360px] overflow-hidden rounded-3xl rounded-tl-lg border bg-surface shadow-sm`,f?`border-accent/50`:`border-border/70`),children:[(0,L.jsxs)(`div`,{className:`flex items-start gap-3 px-4 pt-3.5 pb-2`,children:[(0,L.jsx)(`div`,{className:i(`mt-0.5 rounded-full p-2`,f?`bg-accent/12 text-accent`:`bg-surface-2 text-fg/80`),children:(0,L.jsx)(vt,{size:18})}),(0,L.jsxs)(`div`,{className:`min-w-0 flex-1`,children:[(0,L.jsxs)(`div`,{className:`flex items-center gap-2 text-[12.5px] font-medium text-muted`,children:[(0,L.jsx)(`span`,{children:f?n(`{name} is using this computer`,{name:t}):e.status===`stopped`?n(`Hands stopped`):n(`Hands done`)}),f&&(0,L.jsxs)(`span`,{className:`flex items-center gap-1 rounded-full bg-accent/12 px-2 py-0.5 text-[10.5px] font-semibold text-accent`,children:[(0,L.jsx)(`span`,{className:`h-1.5 w-1.5 animate-pulse rounded-full bg-accent`}),` `,n(`LIVE`)]})]}),e.text&&(0,L.jsx)(`div`,{className:`mt-0.5 break-words text-[15px] font-semibold leading-snug`,children:e.text}),p?.action&&(0,L.jsxs)(`div`,{className:`mt-1.5 flex items-center gap-1.5 text-[13px] text-fg/90`,children:[(0,L.jsx)(zt,{size:13,className:`shrink-0 text-muted`}),(0,L.jsx)(`span`,{className:`truncate`,children:wp(p,n)})]}),m&&(0,L.jsx)(`div`,{className:`mt-1 truncate text-[12px] text-muted`,children:m}),e.notice&&(0,L.jsx)(`div`,{className:`mt-1.5 rounded-2xl bg-amber-500/12 px-3 py-1.5 text-[12.5px] text-amber-700 dark:text-amber-300`,children:e.notice}),f&&h&&(0,L.jsx)(bp,{hold:h})]})]}),(0,L.jsxs)(`div`,{className:`flex items-center gap-2 border-t border-border/70 px-4 py-2 text-[12px] text-muted`,children:[(0,L.jsx)(`span`,{children:n(`{n} steps`,{n:e.steps})}),(0,L.jsx)(`span`,{className:`ml-auto`,children:u(e.updated_ts??e.ts)}),f&&!h&&(0,L.jsxs)(`button`,{type:`button`,onClick:()=>void _(),disabled:l,className:`ml-1 inline-flex items-center gap-1.5 rounded-full bg-accent/12 px-3 py-1 text-[12.5px] font-semibold text-accent transition active:scale-95 disabled:opacity-60`,children:[(0,L.jsx)(vt,{size:11}),` `,n(`Take over`)]}),f&&(0,L.jsxs)(`button`,{type:`button`,onClick:()=>void g(),disabled:o,className:`ml-1 inline-flex items-center gap-1.5 rounded-full bg-fg px-3 py-1 text-[12.5px] font-semibold text-bg transition active:scale-95 disabled:opacity-60`,children:[(0,L.jsx)(sn,{size:10,fill:`currentColor`}),` `,n(`Stop`)]})]})]})})}function bp({hold:e,compact:t}){let n=s(),[r,a]=(0,I.useState)(!1),o=async()=>{a(!0);try{await M.doneHold(e.id)}catch{}finally{a(!1)}};return(0,L.jsxs)(`div`,{className:i(`flex items-center gap-2 rounded-2xl bg-amber-500/12 px-3 text-amber-800 dark:text-amber-200`,t?`py-1.5 text-[12.5px]`:`mt-1.5 py-2 text-[13px]`),children:[(0,L.jsx)(vt,{size:14,className:`shrink-0`}),(0,L.jsx)(`span`,{className:`min-w-0 flex-1 leading-snug`,children:Sp(e,n)}),(0,L.jsx)(`button`,{type:`button`,onClick:()=>void o(),disabled:r,className:`shrink-0 rounded-full bg-fg px-3 py-1 text-[12.5px] font-semibold text-bg transition active:scale-95 disabled:opacity-60`,children:r?(0,L.jsx)(A,{size:13,className:`animate-spin`}):n(`Done`)})]})}function xp(e,t){return t(e===`browser`?`the browser`:e===`phone`?`the phone`:`this computer`)}function Sp(e,t){return e.by===`agent`?e.reason?t(`Your turn: {reason}`,{reason:e.reason}):t(`Your turn`):t(`You took over {thing}`,{thing:xp(e.tool,t)})}function Cp({event:e,name:t=`nanoMuse`}){let n=s(),[r,a]=(0,I.useState)(!1),o=e.status===`on`,c=xp(e.tool,n),l=async()=>{a(!0);try{await M.doneHold(e.id)}catch{}finally{a(!1)}},d=e.timed_out?n(`{name} waited ten minutes and went on without you.`,{name:t}):e.stale?n(`Ended when the runtime restarted.`):e.by===`agent`?n(`You did it; {name} carried on.`,{name:t}):n(`Handed back; {name} carried on.`,{name:t});return(0,L.jsx)(`div`,{className:`rise flex justify-start pr-8`,children:(0,L.jsxs)(`div`,{className:i(`w-full max-w-[360px] overflow-hidden rounded-3xl rounded-tl-lg border bg-surface shadow-sm`,o?`border-amber-500/50`:`border-border/70 opacity-70`),children:[(0,L.jsxs)(`div`,{className:`flex items-start gap-3 px-4 pt-3.5 pb-3`,children:[(0,L.jsx)(`div`,{className:i(`mt-0.5 rounded-full p-2`,o?`bg-amber-500/15 text-amber-700 dark:text-amber-300`:`bg-surface-2 text-fg/70`),children:(0,L.jsx)(vt,{size:18})}),(0,L.jsxs)(`div`,{className:`min-w-0 flex-1`,children:[(0,L.jsx)(`div`,{className:`text-[12.5px] font-medium text-muted`,children:e.tool===`browser`?n(`The browser`):e.tool===`phone`?n(`The phone`):n(`This computer`)}),(0,L.jsx)(`div`,{className:`mt-0.5 break-words text-[15px] font-semibold leading-snug`,children:e.by===`agent`?n(`Your turn`):n(`You took over {thing}`,{thing:c})}),e.by===`agent`&&e.reason&&(0,L.jsx)(`div`,{className:`mt-1 break-words text-[13.5px] leading-snug text-fg/90`,children:e.reason}),(0,L.jsx)(`div`,{className:`mt-1.5 text-[12.5px] leading-snug text-muted`,children:o?e.by===`agent`?n(`Do this part yourself, then press Done. {name} looks again and carries on from there.`,{name:t}):n(`{name} waits. Press Done when you are finished and it looks again.`,{name:t}):d})]})]}),(0,L.jsxs)(`div`,{className:`flex items-center gap-2 border-t border-border/70 px-4 py-2 text-[12px] text-muted`,children:[(0,L.jsx)(`span`,{children:u(e.ts)}),o&&(0,L.jsxs)(`button`,{type:`button`,onClick:()=>void l(),disabled:r,className:`ml-auto inline-flex items-center gap-1.5 rounded-full bg-fg px-3.5 py-1 text-[12.5px] font-semibold text-bg transition active:scale-95 disabled:opacity-60`,children:[r?(0,L.jsx)(A,{size:13,className:`animate-spin`}):(0,L.jsx)(ke,{size:12}),` `,n(`Done`)]})]})]})})}function wp(e,t){let n=e.label?`“${e.label}”`:``;switch(e.action){case`click`:return n?t(`Clicked {label}`,{label:n}):t(`Clicked`);case`double_click`:return n?t(`Double-clicked {label}`,{label:n}):t(`Double-clicked`);case`right_click`:case`middle_click`:return n?t(`Right-clicked {label}`,{label:n}):t(`Right-clicked`);case`move`:return n?t(`Pointed at {label}`,{label:n}):t(`Moved the mouse`);case`type`:return t(`Typed {n} characters`,{n:(e.text??``).length});case`key`:return t(`Pressed {keys}`,{keys:(e.keys??[]).join(`+`)});case`scroll`:return t(`Scrolled`);case`drag`:return t(`Dragged`);case`open_app`:return n?t(`Opened {label}`,{label:n}):t(`Opened an application`);case`wait`:return t(`Waited`);default:return e.action??``}}function Tp({event:e,onOpen:t}){let n=s(),a=r(e.name),o=n(a===`html`?`Page`:a===`image`?`Image`:a===`data`?`Data`:a===`code`?`Code`:a===`event`?`Event`:`Document`),c=e.action===`update`?`${o} · ${n(`updated`)}`:o,l=a===`html`||a===`image`;return(0,L.jsx)(`div`,{className:`rise flex justify-start pr-8`,children:(0,L.jsxs)(`button`,{type:`button`,onClick:()=>t(e.path),className:i(`max-w-full overflow-hidden rounded-[20px] border border-border bg-surface text-left shadow-[0_4px_20px_-12px_rgba(0,0,0,0.2)] transition hover:bg-surface-2`,l?`w-[300px]`:``),children:[l&&(0,L.jsx)(Ep,{path:e.path,kind:a}),(0,L.jsxs)(`div`,{className:`flex items-center gap-3 px-4 py-3`,children:[!l&&(0,L.jsx)(`div`,{className:`rounded-2xl bg-accent/12 p-2.5 text-accent`,children:a===`code`?(0,L.jsx)(ct,{size:20}):a===`event`?(0,L.jsx)(tt,{size:20}):(0,L.jsx)(mt,{size:20})}),(0,L.jsxs)(`div`,{className:`min-w-0 flex-1`,children:[(0,L.jsx)(`div`,{className:`text-[11px] font-semibold uppercase tracking-wide text-muted`,children:c}),(0,L.jsx)(`div`,{className:`truncate text-[14.5px] font-medium`,children:e.name}),(0,L.jsx)(`div`,{className:`truncate text-[12px] text-muted`,children:e.path})]}),(0,L.jsx)(rt,{size:16,className:`ml-1 shrink-0 text-muted`})]})]})})}function Ep({path:e,kind:t}){return t===`image`?(0,L.jsx)(`img`,{src:h(e),alt:``,loading:`lazy`,className:`h-40 w-full object-cover`}):(0,L.jsx)(`div`,{className:`pointer-events-none relative h-40 w-full overflow-hidden bg-white`,children:(0,L.jsx)(`iframe`,{title:e,src:h(e),sandbox:``,tabIndex:-1,loading:`lazy`,scrolling:`no`,className:`absolute left-0 top-0 h-[480px] w-[900px] origin-top-left scale-[0.3333] border-0`})})}function Dp({open:e,onClose:t,title:n,children:r,footer:i}){let a=s(),o=(0,I.useRef)(null),c=(0,I.useId)();return On(o,e),(0,I.useEffect)(()=>{if(!e)return;let n=e=>e.key===`Escape`&&t();return window.addEventListener(`keydown`,n),()=>window.removeEventListener(`keydown`,n)},[e,t]),e?(0,L.jsxs)(`div`,{className:`fixed inset-0 z-50 flex items-end sm:items-center sm:justify-center`,children:[(0,L.jsx)(`div`,{className:`absolute inset-0 bg-black/45 backdrop-blur-[2px]`,onClick:t}),(0,L.jsxs)(`div`,{ref:o,role:`dialog`,"aria-modal":`true`,"aria-labelledby":n?c:void 0,className:`sheet-in relative w-full sm:max-w-lg max-h-[92dvh] flex flex-col bg-surface rounded-t-3xl sm:rounded-3xl shadow-2xl border border-border`,children:[(0,L.jsxs)(`div`,{className:`flex items-center gap-3 px-5 pt-4 pb-2`,children:[(0,L.jsx)(`div`,{className:`sm:hidden absolute left-1/2 -translate-x-1/2 top-2 h-1 w-10 rounded-full bg-border`}),(0,L.jsx)(`div`,{id:c,className:`flex-1 font-semibold text-[17px] mt-1`,children:n}),(0,L.jsx)(`button`,{type:`button`,onClick:t,"aria-label":a(`Close`),className:`p-2 -mr-2 rounded-full text-muted hover:bg-surface-2`,children:(0,L.jsx)(Fe,{size:20})})]}),(0,L.jsx)(`div`,{className:`flex-1 overflow-y-auto px-5 pb-4`,children:r}),i&&(0,L.jsx)(`div`,{className:`px-5 pt-2 pb-4 safe-bottom border-t border-border`,children:i})]})]}):null}var Op=1e3;function kp({thread:e,eventId:t,onClose:r}){let{state:a,toast:o}=E(),c=s(),l=(a.events[e]??[]).find(e=>e.id===t),u=a.holds.find(t=>t.thread===e&&t.tool===`browser`),[d,f]=(0,I.useState)(null),[p,m]=(0,I.useState)(null),[h,g]=(0,I.useState)(``),[_,v]=(0,I.useState)(``),[y,b]=(0,I.useState)(!1),x=(0,I.useRef)(null),S=d?d===`on`:!!u;(0,I.useEffect)(()=>b(!1),[l?.frame]),(0,I.useEffect)(()=>f(null),[u?.id,u?.status]);let C=l?.backend===`device`&&ip();(0,I.useEffect)(()=>{if(!C)return;let t=t=>{let n=t.detail;n?.thread&&n.thread!==e||M.browserControl(e,{action:`handed_back`}).catch(e=>o(e.message))};return window.addEventListener(`nanomuse:browser-handed-back`,t),()=>window.removeEventListener(`nanomuse:browser-handed-back`,t)},[C,e,o]);let w=(0,I.useCallback)(async t=>{m(t.action);try{await M.browserControl(e,t)}catch(e){o(e.message)}finally{m(null)}},[e,o]),T=()=>{if(C){rp()?.takeOverBrowser?.(e),M.browserControl(e,{action:`take_over`}).catch(()=>void 0);return}f(`on`),w({action:`take_over`})},D=()=>{f(`off`),w({action:`handed_back`})};(0,I.useEffect)(()=>{if(!S||C||!l||l.status!==`live`)return;let t=window.setInterval(()=>{document.hidden||M.browserControl(e,{action:`look`}).catch(()=>void 0)},Op);return()=>window.clearInterval(t)},[S,C,e,l]);let O=e=>{if(!S||p)return;let t=e.currentTarget.getBoundingClientRect(),n=(e.clientX-t.left)/t.width,r=(e.clientY-t.top)/t.height;w({action:`click`,x:Math.min(Math.max(n,0),1),y:Math.min(Math.max(r,0),1)})},k=e=>{!S||p||Math.abs(e.deltaY)<8||w({action:`scroll`,dy:Math.max(-2e3,Math.min(2e3,Math.round(e.deltaY*2)))})};if(!l)return null;let ee=l.url;try{ee=new URL(l.url).host}catch{}let te=l.status===`live`,j=a.profile?.name??`nanoMuse`,ne=u?c(`{name} is waiting for you`,{name:j}):a.status.state!==`idle`&&a.status.thread===e?c(`{name} is working`,{name:j}):l.action;return(0,L.jsxs)(Dp,{open:!0,onClose:r,title:(0,L.jsxs)(`div`,{className:`flex items-center gap-2 min-w-0`,children:[(0,L.jsx)(gt,{size:17,className:`text-accent shrink-0`}),(0,L.jsx)(`span`,{className:`truncate`,children:l.title||ee}),te&&(0,L.jsxs)(`span`,{className:`ml-1 flex items-center gap-1 rounded-full bg-rose-500/12 px-2 py-0.5 text-[10.5px] font-semibold text-rose-500`,children:[(0,L.jsx)(`span`,{className:`h-1.5 w-1.5 rounded-full bg-rose-500 animate-pulse`}),` `,c(`LIVE`)]})]}),footer:S?(0,L.jsxs)(`div`,{className:`space-y-2`,children:[(0,L.jsxs)(`form`,{className:`flex items-center gap-2`,onSubmit:e=>{e.preventDefault(),h&&w({action:`type`,text:h}).then(()=>g(``))},children:[(0,L.jsx)(`input`,{value:h,onChange:e=>g(e.target.value),placeholder:c(`Type into the focused field…`),"aria-label":c(`Type into the focused field…`),className:`flex-1 rounded-2xl bg-surface-2 px-3.5 py-2.5 text-[14px] outline-none`,autoComplete:`off`,autoCapitalize:`off`}),(0,L.jsx)(`button`,{type:`submit`,disabled:!h||!!p,"aria-label":c(`Type`),className:`rounded-full bg-accent p-2.5 text-white disabled:opacity-40`,children:p===`type`?(0,L.jsx)(A,{size:16,className:`animate-spin`}):(0,L.jsx)(qe,{size:16})}),(0,L.jsx)(`button`,{type:`button`,onClick:()=>void w({action:`key`,key:`Enter`}),disabled:!!p,"aria-label":c(`Press Enter`),className:`rounded-full bg-surface-2 p-2.5 text-fg disabled:opacity-40`,children:(0,L.jsx)(dt,{size:16})})]}),(0,L.jsxs)(`form`,{className:`flex items-center gap-2`,onSubmit:e=>{e.preventDefault(),_&&w({action:`navigate`,url:_}).then(()=>v(``))},children:[(0,L.jsx)(`button`,{type:`button`,onClick:()=>void w({action:`back`}),disabled:!!p,"aria-label":c(`Back`),className:`rounded-full bg-surface-2 p-2 text-fg disabled:opacity-40`,children:(0,L.jsx)(Ke,{size:15})}),(0,L.jsx)(`input`,{value:_,onChange:e=>v(e.target.value),placeholder:c(`Open a URL…`),"aria-label":c(`Open a URL…`),inputMode:`url`,autoCapitalize:`off`,className:`flex-1 min-w-0 rounded-2xl bg-surface-2 px-3.5 py-2 text-[13px] outline-none`}),(0,L.jsx)(`button`,{type:`submit`,disabled:!_||!!p,className:`rounded-2xl bg-surface-2 px-3 py-2 text-[13px] font-medium disabled:opacity-40`,children:c(`Go`)}),(0,L.jsx)(`button`,{type:`button`,onClick:()=>void w({action:`scroll`,dy:-600}),disabled:!!p,"aria-label":c(`Scroll up`),className:`rounded-full bg-surface-2 p-2 text-fg disabled:opacity-40`,children:(0,L.jsx)(Je,{size:15})}),(0,L.jsx)(`button`,{type:`button`,onClick:()=>void w({action:`scroll`,dy:600}),disabled:!!p,"aria-label":c(`Scroll down`),className:`rounded-full bg-surface-2 p-2 text-fg disabled:opacity-40`,children:(0,L.jsx)(Ge,{size:15})})]}),(0,L.jsxs)(`div`,{className:`flex items-center justify-between gap-2`,children:[(0,L.jsx)(`span`,{className:`min-w-0 truncate text-[12px] text-muted`,children:c(`Tap the page to click. If the browser was closed, open a URL first.`)}),(0,L.jsxs)(`button`,{type:`button`,onClick:D,disabled:p===`handed_back`,className:`flex shrink-0 items-center gap-1.5 whitespace-nowrap rounded-full bg-fg px-3.5 py-1.5 text-[13px] font-semibold text-bg disabled:opacity-60`,children:[p===`handed_back`?(0,L.jsx)(A,{size:14,className:`animate-spin`}):(0,L.jsx)(ke,{size:14}),` `,c(`Done`)]})]})]}):(0,L.jsxs)(`div`,{className:`flex items-center justify-between gap-2`,children:[(0,L.jsxs)(`div`,{className:`min-w-0 text-[12.5px] text-muted truncate`,children:[ne,` · `,ee]}),(0,L.jsxs)(`div`,{className:`flex items-center gap-2 shrink-0`,children:[(0,L.jsx)(`button`,{type:`button`,onClick:()=>void w({action:`look`}),disabled:!!p,"aria-label":c(`Refresh`),className:`rounded-full bg-surface-2 p-2 text-muted disabled:opacity-40`,children:p===`look`?(0,L.jsx)(A,{size:15,className:`animate-spin`}):(0,L.jsx)(Re,{size:15})}),(0,L.jsxs)(`button`,{type:`button`,onClick:T,disabled:d===`on`,className:`flex items-center gap-1.5 rounded-full bg-accent px-3.5 py-2 text-[13px] font-semibold text-white disabled:opacity-60`,children:[(0,L.jsx)(vt,{size:14}),` `,c(`Take over`)]})]})]}),children:[u&&u.by===`agent`&&(0,L.jsx)(`div`,{className:`mb-2`,children:(0,L.jsx)(bp,{hold:u,compact:!0})}),(0,L.jsxs)(`div`,{className:i(`relative overflow-hidden rounded-2xl border border-border bg-surface-2`,S&&`ring-2 ring-accent`),children:[y?(0,L.jsxs)(`div`,{className:`flex aspect-[16/10] flex-col items-center justify-center gap-1 text-muted`,children:[(0,L.jsx)(gt,{size:24}),(0,L.jsx)(`span`,{className:`text-[12.5px]`,children:c(`This frame is no longer available.`)}),(0,L.jsx)(`button`,{type:`button`,onClick:()=>void w({action:`look`}),className:`text-accent text-[13px] font-medium`,children:c(`Look again`)})]}):(0,L.jsx)(`img`,{ref:x,src:n(e,l.frame),alt:l.title||ee,onError:()=>b(!0),onClick:O,onWheel:k,draggable:!1,className:i(`block w-full select-none`,S?`cursor-crosshair`:``)},l.frame),p&&p!==`look`&&(0,L.jsx)(`div`,{className:`absolute inset-0 flex items-center justify-center bg-black/20`,children:(0,L.jsx)(A,{size:26,className:`animate-spin text-white`})})]}),(0,L.jsxs)(`div`,{className:`mt-2 flex items-center justify-between text-[12px] text-muted`,children:[(0,L.jsx)(`span`,{className:`truncate`,children:l.url}),(0,L.jsx)(`span`,{className:`shrink-0 ml-2`,children:l.frames===1?c(`1 frame`):c(`{n} frames`,{n:l.frames})})]}),S&&(0,L.jsxs)(`div`,{className:`mt-3 rounded-2xl bg-accent/8 px-3.5 py-2.5 text-[13px] leading-snug`,children:[(0,L.jsx)(`div`,{className:`font-medium`,children:u&&u.by===`agent`?Sp(u,c):c(`You have the page. Press Done when you are finished.`)}),(0,L.jsx)(`div`,{className:`mt-1 text-muted`,children:c(`{name} waits meanwhile, then looks at the page as you left it and carries on. Passwords you type here go to the website, never to the model.`,{name:j})})]})]})}function Ap(){if(typeof window>`u`)return null;let e=window;return e.SpeechRecognition??e.webkitSpeechRecognition??null}function jp(){return Ap()!==null}function Mp(e,t){let[n,r]=(0,I.useState)(!1),i=(0,I.useRef)(null),a=(0,I.useRef)(``),o=s(),c=(0,I.useCallback)(()=>{i.current?.stop()},[]),l=(0,I.useCallback)(()=>{let n=Ap();if(!n)return;let s=new n;s.lang=navigator.language||`en-US`,s.continuous=!0,s.interimResults=!0,a.current=``,s.onresult=t=>{let n=``;for(let e=t.resultIndex;e{let n=e.error||``;n!==`aborted`&&n!==`no-speech`&&t?.(n===`not-allowed`||n===`service-not-allowed`?o(`The microphone is not allowed. Allow it in the browser and try again.`):o(`Voice input stopped ({code}).`,{code:n}))},s.onend=()=>{i.current=null,r(!1)},i.current=s;try{s.start(),r(!0)}catch{i.current=null,r(!1)}},[e,t,o]),u=(0,I.useCallback)(()=>{i.current?c():l()},[l,c]);return(0,I.useEffect)(()=>()=>i.current?.abort(),[]),{supported:jp(),listening:n,toggle:u,stop:c}}function Np({listening:e,onClick:t,className:n}){let r=s();return(0,L.jsx)(`button`,{type:`button`,onClick:t,"aria-label":r(e?`Stop voice input`:`Voice input`),"aria-pressed":e,className:i(`flex h-9 w-9 shrink-0 items-center justify-center rounded-full transition active:scale-95`,e?`bg-accent/15 text-accent animate-pulse`:`text-fg/70 hover:bg-surface-2`,n),children:e?(0,L.jsx)(Pt,{size:19}):(0,L.jsx)(Ft,{size:19})})}function Pp({lines:e}){return(0,L.jsx)(`div`,{className:`flex items-end gap-2 pr-10`,children:(0,L.jsx)(`div`,{className:`min-w-0 max-w-full`,children:e.map((e,t)=>(0,L.jsx)(`div`,{className:`my-1 max-w-[340px] rounded-[20px] bg-surface-2 px-3.5 py-2.5 text-[14.5px] leading-snug whitespace-pre-wrap break-words wide:max-w-[600px]`,children:e},t))})})}function Fp({chips:e,chosen:t,busy:n,onPick:r,onElse:a}){let o=s();return e.length===0&&!t?null:(0,L.jsxs)(`section`,{className:`rise mx-1 my-2 rounded-[22px] border border-border/70 bg-surface p-3.5`,children:[(0,L.jsxs)(`div`,{className:`flex items-center gap-2 text-[13px] font-medium text-fg`,children:[(0,L.jsx)(nn,{size:14,className:`text-accent`}),` `,o(`Pick a name for me, or type one`)]}),(0,L.jsxs)(`div`,{className:`mt-2.5 flex flex-wrap gap-2`,children:[e.map(e=>{let a=t===e;return(0,L.jsxs)(`button`,{type:`button`,disabled:n||!!t,onClick:()=>r(e),className:i(`inline-flex items-center gap-1.5 rounded-full px-3.5 py-1.5 text-[13.5px] font-medium transition-colors disabled:opacity-60`,a?`bg-accent text-accent-fg`:`bg-surface-2 hover:bg-border/60`),children:[a&&(0,L.jsx)(ke,{size:13,strokeWidth:3}),e]},e)}),!t&&(0,L.jsx)(`button`,{type:`button`,disabled:n,onClick:a,className:`rounded-full border border-border px-3.5 py-1.5 text-[13.5px] text-muted hover:bg-surface-2 disabled:opacity-60`,children:o(`Something else`)})]})]})}var Ip=[{id:`pink`,background:`#F9D9E3`,accent:`#B5476A`,mood:`idle`},{id:`blue`,background:`#D6E6FA`,accent:`#2F5FA8`,mood:`working`},{id:`yellow`,background:`#FBEFC7`,accent:`#9A6B12`,mood:`waiting`},{id:`purple`,background:`#E4DDF7`,accent:`#5D44A6`,mood:`happy`},{id:`green`,background:`#D9F0DF`,accent:`#2E7D4F`,mood:`error`}],Lp=`github.com/zeeshanhaque21/nanoMuse`,Rp=540,zp=720;function Bp(e,t){return!e||w(e.avatar)?j(t):e.avatar?re(e.avatar,t):null}function Vp(e){return new Promise(t=>{let n=new Image;n.crossOrigin=`anonymous`,n.onload=()=>t(n),n.onerror=()=>t(null),n.src=e})}function Hp(e,t,n){let r=t.includes(` `)?t.split(` `):Array.from(t),i=t.includes(` `)?` `:``,a=[],o=``;for(let t of r){let r=o?o+i+t:t;e.measureText(r).width>n&&o?(a.push(o),o=t):o=r}return o&&a.push(o),a}function Up(e,t,n,r,i,a){e.beginPath(),e.moveTo(t+a,n),e.arcTo(t+r,n,t+r,n+i,a),e.arcTo(t+r,n+i,t,n+i,a),e.arcTo(t,n+i,t,n,a),e.arcTo(t,n,t+r,n,a),e.closePath()}async function Wp(e,t,n,r,i,a=2){let o=document.createElement(`canvas`);o.width=Rp*a,o.height=zp*a;let s=o.getContext(`2d`);if(!s)return o;s.scale(a,a),s.fillStyle=e.background,Up(s,0,0,Rp,zp,36),s.fill(),s.font=`600 22px system-ui, -apple-system, 'Segoe UI', sans-serif`;let c=Hp(s,r,400),l=Math.max(...c.map(e=>s.measureText(e).width))+48,u=c.length*30+36,d=(Rp-l)/2;s.fillStyle=`#ffffff`,Up(s,d,56,l,u,24),s.fill(),s.beginPath(),s.moveTo(Rp/2-14,56+u-1),s.lineTo(Rp/2,56+u+18),s.lineTo(284,56+u-1),s.closePath(),s.fill(),s.fillStyle=e.accent,s.textAlign=`center`,s.textBaseline=`top`,c.forEach((e,t)=>s.fillText(e,Rp/2,74+t*30+3));let f=56+u+54;s.fillStyle=`#ffffff`,s.beginPath(),s.arc(Rp/2,f+150,158,0,Math.PI*2),s.fill();let p=Bp(t,e.mood),m=p?await Vp(p):null;return s.save(),s.beginPath(),s.arc(Rp/2,f+150,150,0,Math.PI*2),s.clip(),m?(s.fillStyle=`#f1efeb`,s.fillRect(120,f,300,300),s.drawImage(m,120,f,300,300)):(s.fillStyle=t?.color??`#0064d4`,s.fillRect(120,f,300,300),s.font=`150px system-ui, 'Apple Color Emoji', 'Segoe UI Emoji', sans-serif`,s.textAlign=`center`,s.textBaseline=`middle`,s.fillStyle=`#ffffff`,s.fillText(t?.emoji??`✨`,Rp/2,f+150+6)),s.restore(),s.fillStyle=e.accent,s.textAlign=`center`,s.textBaseline=`top`,s.font=`700 30px system-ui, -apple-system, 'Segoe UI', sans-serif`,s.fillText(n,Rp/2,f+300+34),s.font=`500 15px system-ui, -apple-system, 'Segoe UI', sans-serif`,s.globalAlpha=.8,Hp(s,i,460).forEach((e,t)=>s.fillText(e,Rp/2,644+t*22)),s.globalAlpha=1,o}function Gp(e){return new Promise(t=>e.toBlob(t,`image/png`))}function Kp({open:e,onClose:t}){let{state:n,toast:r}=E(),a=s(),o=n.profile,c=o?.name??`nanoMuse`,[l,u]=(0,I.useState)(0),[d,f]=(0,I.useState)([]),[p,m]=(0,I.useState)(!1),h=(0,I.useRef)(!0),g=a(`Hi, I'm {name}, a personal AI agent. Meet nanoMuse: open source, runs on your phone.`,{name:c}),_=a(`Your personal AI agent, open source · {repo}`,{repo:Lp});(0,I.useEffect)(()=>{if(h.current=!0,e)return u(0),(async()=>{let e=[];for(let t of Ip){let n=await Wp(t,o,c,g,_,1);e.push(n.toDataURL(`image/png`))}h.current&&f(e)})(),()=>{h.current=!1}},[e,o?.avatar,o?.emoji,o?.color,c]);let v=async()=>{m(!0);try{let e=await Gp(await Wp(Ip[l]??Ip[0],o,c,g,_,2));if(!e)throw Error(a(`The card could not be drawn.`));let n=new File([e],`${c}-nanomuse.png`,{type:`image/png`}),i=`${g}\nhttps://${Lp}`,s=navigator;if(typeof s.share==`function`&&(!s.canShare||s.canShare({files:[n]})))try{await s.share({files:[n],text:i,title:c}),t();return}catch(e){if(e.name===`AbortError`)return}let u=document.createElement(`a`);u.href=URL.createObjectURL(e),u.download=n.name,u.click(),window.setTimeout(()=>URL.revokeObjectURL(u.href),2e3),r(a(`Saved the card as a picture.`))}catch(e){r(e.message)}finally{m(!1)}};return(0,L.jsxs)(Dp,{open:e,onClose:t,title:a(`Share my avatar`),children:[(0,L.jsx)(`p`,{className:`mb-3 text-[13px] text-muted`,children:a(`Pick a card. It goes out through the system share sheet, or saves as a picture where there is none.`)}),(0,L.jsx)(`div`,{className:`grid grid-cols-3 gap-2.5 sm:grid-cols-5`,children:Ip.map((e,t)=>(0,L.jsx)(`button`,{type:`button`,"aria-label":e.id,"aria-pressed":l===t,onClick:()=>u(t),className:i(`overflow-hidden rounded-2xl border-2 transition`,l===t?`border-accent`:`border-transparent`),style:{background:e.background,aspectRatio:`${Rp} / ${zp}`},children:d[t]?(0,L.jsx)(`img`,{src:d[t],alt:``,className:`h-full w-full object-cover`}):(0,L.jsx)(A,{size:18,className:`mx-auto my-8 animate-spin text-muted`})},e.id))}),d[l]&&(0,L.jsx)(`img`,{src:d[l],alt:``,className:`mx-auto mt-4 w-[260px] rounded-[20px] shadow-md`}),(0,L.jsxs)(`div`,{className:`mt-4 flex justify-end gap-2`,children:[(0,L.jsx)(`button`,{type:`button`,onClick:t,className:je,children:a(`Later`)}),(0,L.jsxs)(`button`,{type:`button`,disabled:p||!d.length,onClick:()=>void v(),className:Ne,children:[p?(0,L.jsx)(A,{size:15,className:`animate-spin`}):typeof navigator.share==`function`?(0,L.jsx)(Xt,{size:15}):(0,L.jsx)(ft,{size:15}),` `,typeof navigator.share==`function`?a(`Share`):a(`Save picture`)]})]})]})}function qp({message:e,onRetry:t}){let n=s();return(0,L.jsxs)(`div`,{className:`flex flex-col items-center gap-3 px-8 py-10 text-center`,children:[(0,L.jsx)(`p`,{className:`text-[14px] text-rose-600 dark:text-rose-300`,children:n(e)||n(`Could not load.`)}),(0,L.jsxs)(`button`,{type:`button`,onClick:t,className:`flex h-10 items-center gap-1.5 rounded-full bg-surface px-4 text-[13.5px] font-medium shadow-[0_1px_4px_rgba(0,0,0,0.14)] dark:border dark:border-border dark:shadow-none`,children:[(0,L.jsx)(Re,{size:14}),` `,n(`Try again`)]})]})}var Jp=[{id:`health`,label:`Health`,icon:e=>(0,L.jsx)(yt,{...e}),tone:`bg-rose-500/12 text-rose-600 dark:text-rose-300`},{id:`finance`,label:`Finance`,icon:e=>(0,L.jsx)(Wt,{...e}),tone:`bg-emerald-500/12 text-emerald-600 dark:text-emerald-300`},{id:`career`,label:`Career`,icon:e=>(0,L.jsx)($e,{...e}),tone:`bg-sky-500/12 text-sky-600 dark:text-sky-300`},{id:`learning`,label:`Learning`,icon:e=>(0,L.jsx)(_t,{...e}),tone:`bg-violet-500/12 text-violet-600 dark:text-violet-300`},{id:`relationships`,label:`Relationships`,icon:e=>(0,L.jsx)(se,{...e}),tone:`bg-pink-500/12 text-pink-600 dark:text-pink-300`},{id:`family`,label:`Family`,icon:e=>(0,L.jsx)(hn,{...e}),tone:`bg-amber-500/12 text-amber-600 dark:text-amber-300`},{id:`home`,label:`Home`,icon:e=>(0,L.jsx)(bt,{...e}),tone:`bg-orange-500/12 text-orange-600 dark:text-orange-300`},{id:`travel`,label:`Travel`,icon:e=>(0,L.jsx)(lt,{...e}),tone:`bg-cyan-500/12 text-cyan-600 dark:text-cyan-300`},{id:`creative`,label:`Creative`,icon:e=>(0,L.jsx)(Vt,{...e}),tone:`bg-fuchsia-500/12 text-fuchsia-600 dark:text-fuchsia-300`},{id:`other`,label:`Other`,icon:e=>(0,L.jsx)(ln,{...e}),tone:`bg-surface-2 text-muted`}];function Yp(e){return Jp.find(t=>t.id===e)??null}var Xp=[{id:``,label:`No reminders`},{id:`daily`,label:`Every day`},{id:`weekdays`,label:`Weekdays`},{id:`weekly`,label:`Once a week`},{id:`monthly`,label:`Once a month`}],Zp=[`mon`,`tue`,`wed`,`thu`,`fri`,`sat`,`sun`];function Qp(e){let t=/^(daily|weekdays|weekly|monthly)(?:\s+(\S+?))?(?:\s+(\d{1,2}:\d{2}))?$/.exec(e.trim());if(!t)return{cadence:``,anchor:``,time:`09:00`};let n=t[2]??``,r=t[3]??`09:00`;return n&&/^\d{1,2}:\d{2}$/.test(n)&&(r=n,n=``),{cadence:t[1],anchor:n,time:r.padStart(5,`0`)}}function $p(e,t,n){return e?[e,t,n].filter(Boolean).join(` `):``}function em(e){let t=Zp.indexOf(e);return t<0?e:new Date(2024,0,1+t).toLocaleDateString(m(),{weekday:`long`})}function tm(e){let{cadence:t,anchor:n,time:r}=Qp(e);switch(t){case`daily`:return _(`Daily at {time}`,{time:r});case`weekdays`:return _(`Weekdays at {time}`,{time:r});case`weekly`:return n&&Zp.includes(n)?_(`{day}s at {time}`,{day:em(n),time:r}):_(`Weekly at {time}`,{time:r});case`monthly`:return _(`Monthly on the {day} at {time}`,{day:nm(Number(n||1)),time:r});default:return``}}function nm(e){if(c()!==`en`)return String(e);let t=[`th`,`st`,`nd`,`rd`],n=e%100;return`${e}${t[(n-20)%10]??t[n]??t[0]}`}function rm(e,t){if(!e)return``;let n=new Date(`${e}T00:00:00`),r=n.toLocaleDateString(m(),{month:`short`,day:`numeric`,year:n.getFullYear()===new Date().getFullYear()?void 0:`numeric`});if(t)return _(`Was due {date}`,{date:r});let i=Math.ceil((n.getTime()-Date.now())/864e5);return i<=0?_(`Due today`):i===1?_(`Due tomorrow`):i<=14?_(`Due in {n} days`,{n:i}):_(`By {date}`,{date:r})}function im({open:e,onClose:t}){let{state:n,setTab:r,draft:a,toast:o}=E(),[c,l]=(0,I.useState)(0),[u,d]=(0,I.useState)(!1),[f,p]=(0,I.useState)(!1),[m,h]=(0,I.useState)(!1),g=n.profile?.name??`nanoMuse`,_=n.pendingApprovals.length,v=s();(0,I.useEffect)(()=>{e&&(l(+(_>0)),d(!1),p(!1))},[e]);let y=(e,n)=>{t(),n&&history.replaceState(null,``,`${window.location.pathname}${window.location.search}#${n}`),r(e)},b=n.status.state===`working`,x=_>0?_>1?v(`{n} approvals waiting for you`,{n:_}):v(`1 approval waiting for you`):b?n.status.detail||v(`On it`):n.status.state===`waiting`?v(`Waiting for you`):v(`online`),S=async()=>{h(!0);try{(await M.stopThread(n.status.thread||`main`)).ok||o(v(`Nothing to stop`))}catch(e){o(e.message)}finally{h(!1)}},C=[{icon:(0,L.jsx)(it,{size:22}),label:v(`Activity`)},{icon:(0,L.jsx)(Qt,{size:22}),label:v(`Approvals`),badge:_},{icon:(0,L.jsx)(at,{size:22}),label:v(`Daily`)},{icon:(0,L.jsx)(ht,{size:22}),label:v(`Soul & memory`)}];return(0,L.jsxs)(Dp,{open:e,onClose:t,children:[(0,L.jsxs)(`div`,{className:`relative flex flex-col items-center px-1 pb-3 text-center`,children:[(0,L.jsx)(`button`,{type:`button`,"aria-label":v(`Share avatar`),title:v(`Share avatar`),onClick:()=>p(!0),className:`absolute right-0 top-0 flex h-9 w-9 items-center justify-center rounded-full bg-surface-2/70 text-fg hover:bg-surface-2`,children:(0,L.jsx)(Xt,{size:16})}),(0,L.jsxs)(`div`,{className:`relative`,children:[(0,L.jsx)(D,{profile:n.profile,status:n.status,size:72}),(0,L.jsx)(`button`,{type:`button`,"aria-label":v(`Edit`),"aria-expanded":u,onClick:()=>d(e=>!e),className:`absolute -bottom-0.5 -right-0.5 flex h-6 w-6 items-center justify-center rounded-full bg-surface text-fg shadow-[0_1px_4px_rgba(0,0,0,0.18)] hover:bg-surface-2 dark:border dark:border-border`,children:(0,L.jsx)(Ht,{size:13})}),u&&(0,L.jsxs)(`div`,{className:`absolute left-1/2 top-full z-20 mt-2 w-56 -translate-x-1/2 overflow-hidden rounded-2xl border border-border/70 bg-surface py-1 text-left text-[14px] shadow-lg`,children:[(0,L.jsx)(`button`,{type:`button`,onClick:()=>{a(v(`Change your avatar to `)),t(),r(`chat`)},className:`block w-full px-4 py-2.5 text-left hover:bg-surface-2`,children:v(`Change avatar`)}),(0,L.jsx)(`button`,{type:`button`,onClick:()=>y(`you`,`who`),className:`block w-full px-4 py-2.5 text-left hover:bg-surface-2`,children:v(`Edit name`)}),(0,L.jsx)(`button`,{type:`button`,onClick:()=>y(`avatar`),className:`block w-full px-4 py-2.5 text-left text-muted hover:bg-surface-2`,children:v(`Avatar studio…`)})]})]}),(0,L.jsx)(`div`,{className:`mt-2.5 text-[21px] font-semibold leading-[26px]`,children:g}),(0,L.jsxs)(`div`,{className:i(`mt-0.5 flex items-center gap-1.5 text-[14px]`,b||_>0?`text-fg`:`text-muted`),children:[b&&(0,L.jsx)(A,{size:13,className:`animate-spin text-accent`}),(0,L.jsx)(`span`,{className:`line-clamp-2`,children:x})]}),(b||n.status.state===`waiting`)&&(0,L.jsxs)(`button`,{type:`button`,onClick:()=>void S(),disabled:m,className:`mt-2.5 inline-flex items-center gap-1.5 rounded-full bg-fg px-4 py-1.5 text-[13.5px] font-semibold text-bg transition active:scale-95 disabled:opacity-60`,children:[(0,L.jsx)(sn,{size:12,fill:`currentColor`}),` `,v(`Stop`)]})]}),(0,L.jsx)(`div`,{role:`tablist`,className:`mb-5 flex rounded-2xl bg-surface-2/60 p-1`,children:C.map((e,t)=>(0,L.jsxs)(`button`,{type:`button`,role:`tab`,"aria-selected":c===t,"aria-label":e.label,title:e.label,onClick:()=>l(t),className:i(`relative flex h-11 flex-1 items-center justify-center rounded-[13px] text-fg transition`,c===t&&`bg-surface shadow-sm`),children:[e.icon,e.badge?(0,L.jsx)(`span`,{className:`absolute right-1.5 top-1 flex h-[17px] min-w-[17px] items-center justify-center rounded-full bg-rose-500 px-1 text-[10px] font-bold text-white`,children:e.badge}):null]},e.label))}),c===0&&(0,L.jsx)(vm,{open:e}),c===1&&(0,L.jsxs)(L.Fragment,{children:[_>0&&(0,L.jsx)(sm,{onDone:()=>void 0}),(0,L.jsx)(ym,{open:e})]}),c===2&&(0,L.jsx)(cm,{onSettings:()=>y(`you`,`proactivity`)}),c===3&&(0,L.jsx)(am,{name:g,onEdit:()=>y(`you`,`who`),onMemory:()=>y(`memory`)}),(0,L.jsx)(Kp,{open:f,onClose:()=>p(!1)})]})}function am({name:e,onEdit:t,onMemory:n}){let{state:r}=E(),i=s(),a=r.profile?.tagline?.trim()??``;return(0,L.jsxs)(`div`,{className:`pb-2`,children:[(0,L.jsx)(`div`,{className:`px-1 text-[15px]`,children:e}),(0,L.jsxs)(`button`,{type:`button`,onClick:t,className:`mt-2 flex h-[50px] w-full items-center justify-center gap-2 rounded-2xl bg-surface-2/70 text-[15px] font-medium hover:bg-surface-2`,children:[(0,L.jsx)(Ht,{size:18}),` `,i(`Edit`)]}),(0,L.jsxs)(`div`,{className:`mt-4 grid grid-cols-2 gap-3`,children:[(0,L.jsx)(om,{title:`SOUL`,caption:i(`Handle with care`),foot:a,colors:`from-[#7d6bc7] to-[#574494]`,onClick:t}),(0,L.jsx)(om,{title:i(`Memory`),caption:i(`Handle with care`),foot:r.settings?.memory_enabled===!1?i(`Off`):``,colors:`from-[#b0413e] to-[#7a1f1f]`,onClick:n})]})]})}function om({title:e,caption:t,foot:n,colors:r,onClick:a}){return(0,L.jsxs)(`button`,{type:`button`,onClick:a,className:i(`flex h-[130px] flex-col items-start rounded-[18px] bg-gradient-to-b p-3.5 text-left text-white transition active:scale-[0.98]`,r),children:[(0,L.jsx)(`span`,{className:`text-[17px] font-semibold`,children:e}),(0,L.jsx)(`span`,{className:`mt-0.5 text-[11px] text-white/85`,children:t}),(0,L.jsx)(`span`,{className:`mt-auto text-[12px] text-white/90`,children:n})]})}function sm({onDone:e}){let{state:t,decide:n,openThread:r,toast:i}=E(),a=t.profile?.name??`nanoMuse`,o=s(),c=[...t.pendingApprovals].sort((e,t)=>e.ts.localeCompare(t.ts)),l=e=>{let n=t.threads.find(t=>t.id===e);return n?n.id===`main`?o(n.title):n.title:e};return(0,I.useEffect)(()=>{if(c.length===0){let t=window.setTimeout(e,600);return()=>window.clearTimeout(t)}},[c.length,e]),c.length===0?(0,L.jsxs)(`div`,{className:`py-10 text-center text-muted text-[14px]`,children:[(0,L.jsx)(ke,{size:26,className:`mx-auto mb-2 text-emerald-500`}),o(`Nothing is waiting for you.`)]}):(0,L.jsxs)(`div`,{className:`space-y-4 pb-2`,children:[(0,L.jsx)(`p`,{className:`text-[12.5px] text-muted`,children:o(`Actions {name} wants to take but cannot without you. Each one shows what will run and why; a permission you grant is bound to that exact tool and target.`,{name:a})}),c.map(e=>(0,L.jsxs)(`div`,{children:[(0,L.jsxs)(`button`,{type:`button`,onClick:()=>r(e.thread),className:`mb-1 px-1 text-[12px] font-semibold uppercase tracking-wide text-muted hover:text-accent`,children:[l(e.thread),` · `,u(e.ts)]}),(0,L.jsx)(`div`,{className:`rounded-[22px] border border-border/70`,children:(0,L.jsx)(mp,{event:e,onDecide:(t,r)=>n(e.id,t,r).catch(e=>i(e.message))})})]},e.id))]})}function cm({onSettings:t}){let{state:n,refreshSettings:r,toast:a}=E(),[o,c]=(0,I.useState)(null),[l,d]=(0,I.useState)(null),[f,p]=(0,I.useState)(null),m=n.profile?.name??`nanoMuse`,h=s(),g=()=>M.upcoming().then(e=>{c(e),d(null)}).catch(e=>o===null?d(e.message):a(e.message));(0,I.useEffect)(()=>{g()},[n.goalsVersion,n.remindersVersion,n.profile?.proactive,n.profile?.goal_interval_minutes]);let _=async()=>{try{await M.updateSettings({profile:{proactive:!n.profile?.proactive}}),await r()}catch(e){a(e.message)}},v=async e=>{p(e);try{await M.advanceGoal(e),a(h(`{name} is working on it in the main chat`,{name:m}))}catch(e){a(e.message)}finally{p(null)}};return o?(0,L.jsxs)(`div`,{className:`space-y-4 pb-2`,children:[(0,L.jsxs)(`div`,{className:`rounded-2xl border border-border p-3.5`,children:[(0,L.jsxs)(`div`,{className:`flex items-center justify-between gap-3`,children:[(0,L.jsxs)(`div`,{children:[(0,L.jsx)(`div`,{className:`font-medium`,children:h(`Background work`)}),(0,L.jsx)(`div`,{className:`text-[12.5px] text-muted`,children:o.proactive?`${h(o.proactivity[0].toUpperCase()+o.proactivity.slice(1))} · ${h(`every {n} min {name} picks one active goal and works on its next step.`,{n:o.effective_interval_minutes,name:m})}${o.quiet_until?` ${h(`Quiet hours until {time}.`,{time:u(o.quiet_until)})}`:o.next_pass_at?` ${h(`Next around {time}.`,{time:u(o.next_pass_at)})}`:``}`:h(`Off. {name} only works when you ask.`,{name:m})})]}),(0,L.jsx)(`button`,{type:`button`,role:`switch`,"aria-checked":o.proactive,onClick:()=>void _(),className:i(`relative h-7 w-12 shrink-0 rounded-full transition`,o.proactive?`bg-accent`:`bg-border`),children:(0,L.jsx)(`span`,{className:i(`absolute top-0.5 h-6 w-6 rounded-full bg-white shadow transition`,o.proactive?`left-[26px]`:`left-0.5`)})})]}),(0,L.jsx)(`button`,{type:`button`,onClick:t,className:`mt-2 text-[12.5px] text-accent font-medium`,children:h(`Level, interval and quiet hours in Settings`)})]}),(0,L.jsxs)(`div`,{children:[(0,L.jsx)(`div`,{className:`text-[12px] uppercase tracking-wide text-muted font-semibold mb-1.5`,children:h(`In line`)}),o.queue.length===0?(0,L.jsx)(`div`,{className:`text-[13px] text-muted`,children:h(`No active goal has a next step. Add one in Goals and {name} will pick it up.`,{name:m})}):(0,L.jsx)(`ul`,{className:`space-y-1.5`,children:o.queue.map((e,t)=>(0,L.jsxs)(`li`,{className:`flex items-center gap-2.5 rounded-2xl bg-surface-2/60 px-3 py-2`,children:[(0,L.jsx)(`span`,{className:`w-5 text-center text-[12px] font-semibold text-muted`,children:t+1}),(0,L.jsxs)(`div`,{className:`min-w-0 flex-1`,children:[(0,L.jsx)(`div`,{className:`text-[13.5px] font-medium truncate`,children:e.title}),(0,L.jsxs)(`div`,{className:`text-[11.5px] text-muted truncate`,children:[e.next_step??h(`No next step`),` · `,h(`{done}/{total} done`,{done:e.progress.done,total:e.progress.total})]})]}),(0,L.jsx)(`button`,{type:`button`,onClick:()=>void v(e.goal_id),disabled:f!==null||o.busy,"aria-label":h(`Work on {title} now`,{title:e.title}),className:`rounded-full bg-accent/12 p-2 text-accent disabled:opacity-50`,children:f===e.goal_id?(0,L.jsx)(A,{size:15,className:`animate-spin`}):(0,L.jsx)(Gt,{size:15})})]},e.goal_id))})]}),o.check_ins.length>0&&(0,L.jsxs)(`div`,{children:[(0,L.jsx)(`div`,{className:`text-[12px] uppercase tracking-wide text-muted font-semibold mb-1.5`,children:h(`Check-ins`)}),(0,L.jsx)(`ul`,{className:`space-y-1.5`,children:o.check_ins.map(t=>(0,L.jsxs)(`li`,{className:`flex items-center gap-2.5 rounded-2xl bg-surface-2/60 px-3 py-2`,children:[(0,L.jsx)(Xe,{size:15,className:`text-muted shrink-0`}),(0,L.jsxs)(`div`,{className:`min-w-0 flex-1`,children:[(0,L.jsx)(`div`,{className:`text-[13.5px] font-medium truncate`,children:t.title}),(0,L.jsxs)(`div`,{className:`text-[11.5px] text-muted truncate`,children:[e(t.at),` · `,u(t.at),` · `,tm(t.cadence).toLowerCase()]})]})]},t.goal_id))}),(0,L.jsx)(`div`,{className:`mt-1.5 text-[12px] text-muted`,children:h(`Goal nudges you asked for; they arrive whatever the proactivity level, but wait out quiet hours.`)})]}),(0,L.jsx)(lm,{items:o.reminders,name:m,onChange:()=>void g()}),(0,L.jsx)(pm,{data:o.triggers,name:m,onChange:()=>void g()})]}):l?(0,L.jsx)(qp,{message:l,onRetry:()=>void g()}):(0,L.jsx)(`div`,{className:`py-10 flex justify-center text-muted`,children:(0,L.jsx)(A,{className:`animate-spin`,size:20})})}function lm({items:t,name:n,onChange:r}){let{toast:i}=E(),a=s(),[o,c]=(0,I.useState)(null),[l,d]=(0,I.useState)(!1),f=t.filter(e=>e.status===`active`),p=t.filter(e=>e.status!==`active`),m=async e=>{c(e.id);try{await M.cancelReminder(e.id),r()}catch(e){i(e.message)}finally{c(null)}},h=async e=>{c(e.id);try{await M.fireReminder(e.id),i(e.kind===`task`?a(`{name} is on it`,{name:n}):a(`{name} will say it now`,{name:n})),r()}catch(e){i(e.message)}finally{c(null)}};return(0,L.jsxs)(`div`,{children:[(0,L.jsxs)(`div`,{className:`flex items-center justify-between mb-1.5`,children:[(0,L.jsx)(`div`,{className:`text-[12px] uppercase tracking-wide text-muted font-semibold`,children:a(`Reminders & routines`)}),!l&&(0,L.jsx)(`button`,{type:`button`,onClick:()=>d(!0),className:`text-[12.5px] text-accent font-medium`,children:a(`+ Add`)})]}),l&&(0,L.jsx)(um,{onDone:()=>{d(!1),r()},onCancel:()=>d(!1)}),f.length===0&&!l?(0,L.jsx)(`div`,{className:`text-[13px] text-muted`,children:a(`Nothing scheduled. Tell {name} “remind me at six to call mum” or “every weekday morning, summarise my unread email”.`,{name:n})}):(0,L.jsx)(`ul`,{className:`space-y-1.5`,children:f.map(t=>(0,L.jsxs)(`li`,{className:`flex items-center gap-2.5 rounded-2xl bg-surface-2/60 px-3 py-2`,children:[t.kind===`task`?(0,L.jsx)(F,{size:15,className:`text-muted shrink-0`}):(0,L.jsx)(We,{size:15,className:`text-muted shrink-0`}),(0,L.jsxs)(`div`,{className:`min-w-0 flex-1`,children:[(0,L.jsx)(`div`,{className:`text-[13.5px] font-medium truncate`,children:t.text}),(0,L.jsxs)(`div`,{className:`text-[11.5px] text-muted truncate`,children:[t.next_at?`${e(t.next_at)} · ${u(t.next_at)}`:a(`Not scheduled`),t.repeat&&` · ${tm(t.repeat).toLowerCase()}`,t.kind===`task`&&` · ${a(`does the work`)}`]})]}),(0,L.jsx)(`button`,{type:`button`,onClick:()=>void h(t),disabled:o!==null,"aria-label":t.kind===`task`?a(`Do “{text}” now`,{text:t.text}):a(`Remind me now: {text}`,{text:t.text}),className:`rounded-full bg-accent/12 p-2 text-accent disabled:opacity-50`,children:o===t.id?(0,L.jsx)(A,{size:15,className:`animate-spin`}):(0,L.jsx)(Gt,{size:15})}),(0,L.jsx)(`button`,{type:`button`,onClick:()=>void m(t),disabled:o!==null,"aria-label":a(`Cancel: {text}`,{text:t.text}),className:`rounded-full p-2 text-muted hover:text-fg disabled:opacity-50`,children:(0,L.jsx)(Fe,{size:15})})]},t.id))}),p.length>0&&(0,L.jsxs)(`details`,{className:`mt-2`,children:[(0,L.jsx)(`summary`,{className:`text-[12px] text-muted cursor-pointer select-none`,children:a(`{n} finished recently`,{n:p.length})}),(0,L.jsx)(`ul`,{className:`mt-1.5 space-y-1`,children:p.map(t=>(0,L.jsxs)(`li`,{className:`flex items-center gap-2 px-3 text-[12.5px] text-muted`,children:[(0,L.jsx)(`span`,{className:`min-w-0 flex-1 truncate line-through decoration-border`,children:t.text}),(0,L.jsx)(`span`,{className:`shrink-0`,children:t.status===`done`?t.last_fired_at?e(t.last_fired_at):a(`done`):a(`cancelled`)})]},t.id))})]}),(0,L.jsx)(`div`,{className:`mt-1.5 text-[12px] text-muted`,children:a(`A time you named is kept whatever the level or the quiet hours. Reminders just say it; routines do the work and report.`)})]})}function um({onDone:e,onCancel:t}){let{toast:n}=E(),r=s(),[a,o]=(0,I.useState)(``),[c,l]=(0,I.useState)(`remind`),[u,d]=(0,I.useState)(`once`),[f,p]=(0,I.useState)(()=>gm()),[h,g]=(0,I.useState)(`daily`),[_,v]=(0,I.useState)(`09:00`),[y,b]=(0,I.useState)(`mon`),[x,S]=(0,I.useState)(`1`),[C,w]=(0,I.useState)(!1),T=h===`weekly`?`weekly ${y} ${_}`:h===`monthly`?`monthly ${x} ${_}`:`${h} ${_}`,D=async()=>{if(a.trim()){w(!0);try{await M.createReminder(u===`once`?{text:a.trim(),kind:c,at:f.replace(`T`,` `)}:{text:a.trim(),kind:c,repeat:T}),e()}catch(e){n(e.message)}finally{w(!1)}}},O=`h-9 rounded-xl bg-surface border border-border px-3 text-[13px] outline-none focus:border-accent`;return(0,L.jsxs)(`div`,{className:`mb-2 rounded-2xl border border-border p-3 space-y-2`,children:[(0,L.jsx)(`input`,{autoFocus:!0,value:a,onChange:e=>o(e.target.value),placeholder:r(c===`task`?`What should be done…`:`What to remind you of…`),className:i(O,`w-full h-10 text-[14px]`)}),(0,L.jsxs)(`div`,{className:`flex gap-1.5 text-[12.5px]`,children:[(0,L.jsx)(hm,{options:[[`remind`,r(`Remind me`)],[`task`,r(`Do it for me`)]],value:c,onChange:e=>l(e)}),(0,L.jsx)(hm,{options:[[`once`,r(`Once`)],[`repeat`,r(`Repeat`)]],value:u,onChange:e=>d(e)})]}),u===`once`?(0,L.jsx)(`input`,{type:`datetime-local`,value:f,onChange:e=>p(e.target.value),className:i(O,`w-full`)}):(0,L.jsxs)(`div`,{className:`flex flex-wrap gap-1.5`,children:[(0,L.jsxs)(`select`,{value:h,onChange:e=>g(e.target.value),className:O,children:[(0,L.jsx)(`option`,{value:`daily`,children:r(`Every day`)}),(0,L.jsx)(`option`,{value:`weekdays`,children:r(`Weekdays`)}),(0,L.jsx)(`option`,{value:`weekly`,children:r(`Weekly`)}),(0,L.jsx)(`option`,{value:`monthly`,children:r(`Monthly`)})]}),h===`weekly`&&(0,L.jsx)(`select`,{value:y,onChange:e=>b(e.target.value),className:O,children:[`mon`,`tue`,`wed`,`thu`,`fri`,`sat`,`sun`].map((e,t)=>(0,L.jsx)(`option`,{value:e,children:new Date(2024,0,1+t).toLocaleDateString(m(),{weekday:`long`})},e))}),h===`monthly`&&(0,L.jsx)(`select`,{value:x,onChange:e=>S(e.target.value),className:O,children:Array.from({length:28},(e,t)=>String(t+1)).map(e=>(0,L.jsx)(`option`,{value:e,children:r(`Day {d}`,{d:e})},e))}),(0,L.jsx)(`input`,{type:`time`,value:_,onChange:e=>v(e.target.value),className:O})]}),(0,L.jsxs)(`div`,{className:`flex justify-end gap-2 pt-0.5`,children:[(0,L.jsx)(`button`,{type:`button`,onClick:t,className:`rounded-full px-3 py-1.5 text-[13px] text-muted`,children:r(`Cancel`)}),(0,L.jsx)(`button`,{type:`button`,onClick:()=>void D(),disabled:C||!a.trim(),className:`rounded-full bg-accent px-3.5 py-1.5 text-[13px] font-medium text-accent-fg disabled:opacity-50`,children:r(C?`Saving…`:u===`once`?`Set reminder`:`Set routine`)})]})]})}var dm={mail:Et,event:et,hook:_n};function fm(e,t){if(e.kind===`mail`)return e.match?t(`mail matching “{match}”`,{match:e.match}):t(`any new mail`);if(e.kind===`event`){let n=e.match?t(`events matching “{match}”`,{match:e.match}):t(`any event`);return t(`{n} min before {what}`,{n:e.lead_minutes,what:n})}return e.match?t(`webhook “{match}”`,{match:e.match}):t(`webhook`)}function pm({data:t,name:n,onChange:r}){let{toast:a}=E(),o=s(),[c,l]=(0,I.useState)(null),[u,d]=(0,I.useState)(!1),f=t.items.filter(e=>e.status===`active`),p=f.some(e=>e.kind===`mail`),m=async e=>{l(e.id);try{await M.cancelTrigger(e.id),r()}catch(e){a(e.message)}finally{l(null)}},h=async e=>{l(e.id);try{await M.fireTrigger(e.id),a(o(`{name} is on it`,{name:n})),r()}catch(e){a(e.message)}finally{l(null)}},g=async e=>{if(e.url)try{await navigator.clipboard.writeText(e.url),a(o(`Webhook URL copied`))}catch{a(e.url)}};return(0,L.jsxs)(`div`,{children:[(0,L.jsxs)(`div`,{className:`flex items-center justify-between mb-1.5`,children:[(0,L.jsx)(`div`,{className:`text-[12px] uppercase tracking-wide text-muted font-semibold`,children:o(`When something happens`)}),!u&&(0,L.jsx)(`button`,{type:`button`,onClick:()=>d(!0),className:`text-[12.5px] text-accent font-medium`,children:o(`+ Add`)})]}),u&&(0,L.jsx)(mm,{available:t.available,onDone:()=>{d(!1),r()},onCancel:()=>d(!1)}),f.length===0&&!u?(0,L.jsx)(`div`,{className:`text-[13px] text-muted`,children:o(`Nothing yet. Tell {name} “when the landlord writes back, summarise it and draft a reply” or “half an hour before any review, brief me”.`,{name:n})}):(0,L.jsx)(`ul`,{className:`space-y-1.5`,children:f.map(t=>{let n=dm[t.kind];return(0,L.jsxs)(`li`,{className:`flex items-start gap-2.5 rounded-2xl bg-surface-2/60 px-3 py-2`,children:[(0,L.jsx)(n,{size:15,className:`text-muted shrink-0 mt-[3px]`}),(0,L.jsxs)(`div`,{className:`min-w-0 flex-1`,children:[(0,L.jsx)(`div`,{className:`text-[13.5px] font-medium`,children:fm(t,o)}),(0,L.jsx)(`div`,{className:`text-[12px] leading-snug text-fg/80 line-clamp-2`,children:t.text}),(0,L.jsxs)(`div`,{className:`text-[11.5px] text-muted flex flex-wrap items-center gap-x-1.5`,children:[t.fired>0?(0,L.jsxs)(`span`,{children:[o(`fired {n}×`,{n:t.fired}),t.last_fired_at&&` · ${e(t.last_fired_at)}`]}):(0,L.jsx)(`span`,{children:o(`not fired yet`)}),t.kind===`hook`&&t.url&&(0,L.jsxs)(`button`,{type:`button`,onClick:()=>void g(t),className:`inline-flex items-center gap-1 text-accent font-medium`,children:[(0,L.jsx)(ut,{size:11}),` `,o(`Copy URL`)]})]})]}),(0,L.jsx)(`button`,{type:`button`,onClick:()=>void h(t),disabled:c!==null,"aria-label":o(`Run now: {text}`,{text:t.text}),className:`rounded-full bg-accent/12 p-2 text-accent disabled:opacity-50`,children:c===t.id?(0,L.jsx)(A,{size:15,className:`animate-spin`}):(0,L.jsx)(Gt,{size:15})}),(0,L.jsx)(`button`,{type:`button`,onClick:()=>void m(t),disabled:c!==null,"aria-label":o(`Cancel: {text}`,{text:t.text}),className:`rounded-full p-2 text-muted hover:text-fg disabled:opacity-50`,children:(0,L.jsx)(Fe,{size:15})})]},t.id)})}),p&&(0,L.jsx)(`div`,{className:i(`mt-1.5 text-[12px]`,t.mail_error?`text-rose-500`:`text-muted`),children:t.mail_error?o(`The inbox could not be read: {error}`,{error:t.mail_error}):t.mail_checked_at?o(`Inbox checked {when}; {name} looks every {n} min.`,{when:e(t.mail_checked_at),name:n,n:t.mail_poll_minutes}):o(`{name} will look at the inbox shortly, then every {n} min.`,{name:n,n:t.mail_poll_minutes})}),(0,L.jsx)(`div`,{className:`mt-1.5 text-[12px] text-muted`,children:o(`Each time it happens {name} does the work in the chat it was set from and reports in the Feed. A mail or a request is treated as data, never as instructions.`,{name:n})})]})}function mm({available:e,onDone:t,onCancel:n}){let{toast:r}=E(),a=s(),o=[`mail`,`event`,`hook`].find(t=>e[t])??`hook`,[c,l]=(0,I.useState)(o),[u,d]=(0,I.useState)(``),[f,p]=(0,I.useState)(`30`),[m,h]=(0,I.useState)(``),[g,_]=(0,I.useState)(!1),[v,y]=(0,I.useState)(null),b=async()=>{if(m.trim()){_(!0);try{let e=await M.createTrigger({kind:c,text:m.trim(),match:u.trim(),lead_minutes:Number(f)||30});e.kind===`hook`&&e.url?y(e):t()}catch(e){r(e.message)}finally{_(!1)}}},x=`h-9 rounded-xl bg-surface border border-border px-3 text-[13px] outline-none focus:border-accent`;if(v)return(0,L.jsxs)(`div`,{className:`mb-2 rounded-2xl border border-border p-3 space-y-2`,children:[(0,L.jsx)(`div`,{className:`text-[13.5px] font-medium`,children:a(`Webhook ready`)}),(0,L.jsx)(`div`,{className:`text-[12.5px] text-muted`,children:a(`POST anything to this URL and the work starts. The key is in the URL; share it only with the program that will call it.`)}),(0,L.jsx)(`code`,{className:`block break-all rounded-xl bg-surface-2 px-3 py-2 text-[12px]`,children:v.url}),(0,L.jsxs)(`div`,{className:`flex justify-end gap-2 pt-0.5`,children:[(0,L.jsx)(`button`,{type:`button`,onClick:()=>void navigator.clipboard.writeText(v.url??``).then(()=>r(a(`Webhook URL copied`)),()=>r(v.url??``)),className:`rounded-full px-3 py-1.5 text-[13px] text-accent font-medium`,children:a(`Copy`)}),(0,L.jsx)(`button`,{type:`button`,onClick:t,className:`rounded-full bg-accent px-3.5 py-1.5 text-[13px] font-medium text-accent-fg`,children:a(`Done`)})]})]});let S=[[`mail`,a(`New mail`)],[`event`,a(`Before an event`)],[`hook`,a(`Webhook`)]];return(0,L.jsxs)(`div`,{className:`mb-2 rounded-2xl border border-border p-3 space-y-2`,children:[(0,L.jsx)(hm,{options:S,value:c,onChange:e=>l(e)}),!e[c]&&(0,L.jsx)(`div`,{className:`text-[12.5px] text-rose-500`,children:a(c===`mail`?`Connect a mailbox under Connections first.`:`Add a calendar under Connections first.`)}),(0,L.jsxs)(`div`,{className:`flex gap-1.5`,children:[(0,L.jsx)(`input`,{value:u,onChange:e=>d(e.target.value),placeholder:a(c===`mail`?`Words in the sender or subject (empty: any mail)`:c===`event`?`Words in the title or place (empty: any event)`:`A name for this hook`),className:i(x,`min-w-0 flex-1`)}),c===`event`&&(0,L.jsxs)(`label`,{className:`flex items-center gap-1 text-[12.5px] text-muted`,children:[(0,L.jsx)(`input`,{type:`number`,min:0,max:1440,value:f,onChange:e=>p(e.target.value),className:i(x,`w-[64px] px-2`),"aria-label":a(`Minutes before`)}),a(`min before`)]})]}),(0,L.jsx)(`input`,{value:m,onChange:e=>h(e.target.value),placeholder:a(`What should be done each time…`),className:i(x,`w-full h-10 text-[14px]`)}),(0,L.jsx)(`div`,{className:`text-[12px] text-muted`,children:a(`When {condition}`,{condition:fm({kind:c,match:u.trim(),lead_minutes:Number(f)||30},a)})}),(0,L.jsxs)(`div`,{className:`flex justify-end gap-2 pt-0.5`,children:[(0,L.jsx)(`button`,{type:`button`,onClick:n,className:`rounded-full px-3 py-1.5 text-[13px] text-muted`,children:a(`Cancel`)}),(0,L.jsx)(`button`,{type:`button`,onClick:()=>void b(),disabled:g||!m.trim()||!e[c],className:`rounded-full bg-accent px-3.5 py-1.5 text-[13px] font-medium text-accent-fg disabled:opacity-50`,children:a(g?`Saving…`:`Set trigger`)})]})]})}function hm({options:e,value:t,onChange:n}){return(0,L.jsx)(`div`,{className:`flex rounded-full bg-surface-2 p-0.5`,children:e.map(([e,r])=>(0,L.jsx)(`button`,{type:`button`,onClick:()=>n(e),className:i(`rounded-full px-2.5 py-1 transition`,t===e?`bg-surface shadow-sm font-medium`:`text-muted`),children:r},e))})}function gm(){let e=new Date(Date.now()+36e5);e.setMinutes(0,0,0);let t=e=>String(e).padStart(2,`0`);return`${e.getFullYear()}-${t(e.getMonth()+1)}-${t(e.getDate())}T${t(e.getHours())}:${t(e.getMinutes())}`}function _m(e){let[t,n]=(0,I.useState)(null),[r,i]=(0,I.useState)(null),a=async()=>{try{n(await M.activity(150)),i(null)}catch(e){i(e.message||`Could not load.`)}};return(0,I.useEffect)(()=>{if(!e)return;a();let t=window.setInterval(()=>void a(),4e3);return()=>window.clearInterval(t)},[e]),[t,a,r]}function vm({open:e}){let[t,n,r]=_m(e),{state:i}=E(),a=s(),o=i.profile?.name??`nanoMuse`,c=(t?.audit??[]).filter(e=>e.event===`tool_call`).reverse(),l=c.filter(e=>e.channel===`gui`).length;return(0,L.jsxs)(`div`,{className:`pb-2`,children:[(0,L.jsx)(`p`,{className:`text-[12.5px] text-muted mb-2`,children:a(`Every tool call goes through the Sentinel and is written to the audit log, including the ones it refused.`)}),l>0&&(0,L.jsx)(`p`,{className:`text-[12.5px] text-muted mb-2`,children:a(`On the phone's screen: {gui} of {total} steps ({pct}%). The screen is the last resort; a skill, a fetch or the browser comes first.`,{gui:String(l),total:String(c.length),pct:String(Math.round(l/c.length*100))})}),!t&&r&&(0,L.jsx)(qp,{message:r,onRetry:()=>void n()}),!t&&!r&&(0,L.jsx)(`div`,{className:`py-10 flex justify-center text-muted`,children:(0,L.jsx)(A,{className:`animate-spin`,size:20})}),t&&c.length===0&&(0,L.jsx)(`div`,{className:`py-8 text-center text-muted text-[14px]`,children:a(`Nothing yet today. What you ask for and what {name} does about it shows up here.`,{name:o})}),(0,L.jsx)(`ul`,{className:`space-y-1.5`,children:c.map((e,t)=>(0,L.jsx)(wm,{entry:e},`${e.ts}-${t}`))})]})}function ym({open:e}){let{state:t,toast:n}=E(),r=s(),[i,a]=_m(e),o=async()=>{if(window.confirm(r(`Forget every permission you granted? {name} will ask again next time.`,{name:t.profile?.name??`nanoMuse`})))try{await M.resetApprovals(),await a(),n(r(`Permissions reset`))}catch(e){n(e.message)}},c=async e=>{try{await M.revokeGrant(e.key),await a(),n(r(`Revoked: {subject}`,{subject:fp(e.tool,e.target)}))}catch(e){n(e.message)}},l=t.settings?.sentinel.mode;return(0,L.jsxs)(`div`,{className:`space-y-4 pb-2`,children:[(0,L.jsxs)(`div`,{className:`rounded-2xl border border-border p-3.5`,children:[(0,L.jsxs)(`div`,{className:`flex items-center gap-2 font-medium`,children:[(0,L.jsx)(Qt,{size:18,className:`text-accent`}),` `,r(`Sentinel mode:`),` `,(0,L.jsx)(`span`,{className:`capitalize`,children:l===`ask`?r(`balanced`):l===`strict`?r(`cautious`):l===`auto`?r(`hands-off`):l})]}),(0,L.jsxs)(`p`,{className:`mt-1 text-[12.5px] text-muted`,children:[l===`ask`&&r(`Safe and moderate actions run freely; anything sensitive (email, shell, purchases) waits for you.`),l===`strict`&&r(`Moderate and sensitive actions both wait for your approval.`),l===`auto`&&r(`Everything is approved automatically except explicit deny rules. Use with care.`)]}),i?.tainted&&(0,L.jsxs)(`p`,{className:`mt-2 text-[12.5px] text-amber-600 dark:text-amber-300 flex items-center gap-1.5`,children:[(0,L.jsx)($t,{size:14}),` `,r(`Private data was read this session: network calls to new destinations need approval.`)]})]}),(0,L.jsx)(Sm,{grants:i?.grants??[],onRevoke:c}),(0,L.jsx)(Cm,{title:r(`Always ask (from config)`),tools:t.settings?.sentinel.always_ask_tools??[],muted:!0}),(i?.grants.length??0)>0&&(0,L.jsx)(`button`,{type:`button`,onClick:()=>void o(),className:`w-full rounded-2xl border border-border py-2.5 text-[14px] font-medium`,children:r(`Reset all granted permissions`)})]})}function bm(e,t){switch(e.scope){case`conversation`:return t(`for this conversation`);case`session`:return t(`until restart`);case`24h`:return e.expires_at?t(`until {time}`,{time:u(e.expires_at)}):t(`for 24 hours`);case`always`:return t(`always`);default:return e.scope}}var xm=[`sensitive`,`moderate`,`low`,`safe`];function Sm({grants:e,onRevoke:t}){let n=s(),{state:r}=E(),i=e=>r.settings?.tools.find(t=>t.name===e)?.risk??`moderate`,a=xm.map(t=>({risk:t,rows:e.filter(e=>i(e.tool)===t)})).filter(e=>e.rows.length>0);return(0,L.jsx)(`div`,{className:`space-y-3`,children:e.length===0?(0,L.jsxs)(`div`,{children:[(0,L.jsx)(`div`,{className:`text-[12px] uppercase tracking-wide text-muted font-semibold mb-1.5`,children:n(`Permissions you granted`)}),(0,L.jsx)(`div`,{className:`text-[13px] text-muted`,children:n(`No standing approvals. When you answer “always allow” to a risky step, it is listed here and can be revoked; approvals you give once are not kept.`)})]}):a.map((e,r)=>(0,L.jsxs)(`div`,{children:[(0,L.jsxs)(`div`,{className:`text-[12px] uppercase tracking-wide text-muted font-semibold mb-1.5`,children:[r===0?`${n(`Permissions you granted`)} · `:``,n(e.risk)]}),(0,L.jsx)(`ul`,{className:`space-y-1.5`,children:e.rows.map(e=>(0,L.jsxs)(`li`,{className:`flex items-center gap-2.5 rounded-2xl bg-surface-2/60 px-3 py-2`,children:[(0,L.jsx)(`span`,{className:`text-accent`,children:op(e.tool,15)}),(0,L.jsxs)(`div`,{className:`min-w-0 flex-1`,children:[(0,L.jsx)(`div`,{className:`text-[13.5px] font-medium truncate`,children:fp(e.tool,e.target)}),(0,L.jsxs)(`div`,{className:`text-[11.5px] text-muted`,children:[e.tool,` · `,bm(e,n),` · `,n(`granted {time}`,{time:u(e.granted_at)})]})]}),(0,L.jsx)(`button`,{type:`button`,"aria-label":n(`Revoke {what}`,{what:pp(e.scope,e.tool,e.target)}),onClick:()=>t(e),className:`rounded-full p-1.5 text-muted hover:bg-surface active:scale-95`,children:(0,L.jsx)(Fe,{size:15})})]},e.key))})]},e.risk))})}function Cm({title:e,tools:t,muted:n}){let r=s();return(0,L.jsxs)(`div`,{children:[(0,L.jsx)(`div`,{className:`text-[12px] uppercase tracking-wide text-muted font-semibold mb-1.5`,children:e}),t.length===0?(0,L.jsx)(`div`,{className:`text-[13px] text-muted`,children:r(`None`)}):(0,L.jsx)(`div`,{className:`flex flex-wrap gap-1.5`,children:t.map(e=>(0,L.jsxs)(`span`,{className:i(`rounded-full px-2.5 py-1 text-[12.5px] flex items-center gap-1`,n?`bg-surface-2 text-muted`:`bg-accent/12 text-accent`),children:[op(e,12),` `,e]},e))})]})}function wm({entry:e}){let t=s(),n=e.decision===`deny`,r=e.ok===!1&&!n;return(0,L.jsxs)(`li`,{className:`flex items-start gap-2.5 rounded-2xl bg-surface-2/60 px-3 py-2`,children:[(0,L.jsx)(`div`,{className:i(`mt-0.5`,n?`text-rose-500`:r?`text-amber-500`:`text-muted`),children:n||r?(0,L.jsx)(Ye,{size:15}):(0,L.jsx)(ke,{size:15})}),(0,L.jsxs)(`div`,{className:`min-w-0 flex-1`,children:[(0,L.jsxs)(`div`,{className:`flex items-center gap-2 text-[13.5px]`,children:[(0,L.jsx)(`span`,{className:`text-muted`,children:op(e.tool??``,13)}),(0,L.jsx)(`span`,{className:`font-medium truncate`,children:e.summary||e.tool})]}),(0,L.jsxs)(`div`,{className:`mt-0.5 flex flex-wrap items-center gap-x-2 gap-y-0.5 text-[11.5px] text-muted`,children:[(0,L.jsx)(`span`,{children:u(e.ts)}),e.risk&&(0,L.jsx)(lp,{risk:e.risk}),e.approved===!0&&(0,L.jsxs)(`span`,{className:`text-emerald-600 dark:text-emerald-300`,children:[t(`approved by you`),e.approval_scope&&e.approval_scope!==`once`?` (${e.approval_scope})`:``]}),e.approved==null&&e.approval_scope&&e.approval_scope!==`once`&&(0,L.jsx)(`span`,{className:`text-emerald-600 dark:text-emerald-300`,children:t(`covered by your {scope} permission`,{scope:e.approval_scope})}),n&&(0,L.jsx)(`span`,{className:`text-rose-500`,children:t(`blocked`)}),r&&(0,L.jsx)(`span`,{className:`text-amber-600`,children:t(`failed`)}),typeof e.duration_ms==`number`&&(0,L.jsxs)(`span`,{children:[(e.duration_ms/1e3).toFixed(1),`s`]})]}),n&&e.reasons&&e.reasons.length>0&&(0,L.jsx)(`div`,{className:`mt-0.5 text-[12px] text-muted`,children:e.reasons.map(v).join(` · `)})]})]})}function Tm({title:e,actions:t=[],trailing:n,children:r}){let{state:i,setDrawer:a}=E(),o=s(),[c,l]=(0,I.useState)(!1),u=i.profile?.name||`nanoMuse`,d=i.pendingApprovals.length,f=d>0?d>1?o(`{n} approvals waiting for you`,{n:d}):o(`1 approval waiting for you`):i.status.state===`working`?i.status.detail||o(`On it`):i.status.state===`waiting`?o(`Waiting for you`):null;return(0,L.jsxs)(L.Fragment,{children:[(0,L.jsx)(ne,{profile:i.profile,status:i.status,name:u,statusLine:f,statusTone:f?`accent`:`muted`,spinning:i.status.state===`working`&&d===0,badge:d,onAvatar:()=>l(!0),leading:(0,L.jsx)(te,{onClick:()=>a(!0),label:o(`Chats`),className:`wide:invisible`,children:(0,L.jsx)(Ot,{size:22})}),trailing:n??(0,L.jsx)(Em,{actions:t})}),(e||r)&&(0,L.jsxs)(`div`,{className:`flex shrink-0 items-center gap-3 pr-5`,children:[(0,L.jsx)(k,{className:`flex-1`,children:e}),r]}),(0,L.jsx)(im,{open:c,onClose:()=>l(!1)})]})}function Em({actions:e=[]}){let{setTab:t}=E(),n=s(),[r,i]=(0,I.useState)(!1),a=(0,I.useRef)(null);(0,I.useEffect)(()=>{if(!r)return;let e=e=>{a.current?.contains(e.target)||i(!1)},t=e=>{e.key===`Escape`&&i(!1)};return window.addEventListener(`pointerdown`,e),window.addEventListener(`keydown`,t),()=>{window.removeEventListener(`pointerdown`,e),window.removeEventListener(`keydown`,t)}},[r]);let o=e=>{i(!1),t(e)},c=[...e.map(e=>({label:e.label,onClick:()=>{i(!1),e.onClick()}})),{label:n(`Memory`),onClick:()=>o(`memory`)},{label:n(`Settings`),onClick:()=>o(`you`)}];return(0,L.jsxs)(`div`,{ref:a,className:`relative`,children:[(0,L.jsx)(te,{onClick:()=>i(e=>!e),label:n(`More`),expanded:r,children:(0,L.jsx)(pt,{size:22})}),r&&(0,L.jsx)(`ul`,{role:`menu`,className:`absolute right-0 top-12 z-30 min-w-[180px] overflow-hidden rounded-2xl border border-border bg-surface py-1 shadow-xl`,children:c.map(e=>(0,L.jsx)(`li`,{children:(0,L.jsx)(`button`,{type:`button`,role:`menuitem`,onClick:e.onClick,className:`w-full px-4 py-2.5 text-left text-[14.5px] hover:bg-surface-2`,children:e.label})},e.label))})]})}var Dm=`nanomuse-naming`;function Om(e){return e.replace(/[.*+?^${}()|[\]\\]/g,`\\$&`)}function km(e,t,n=!1){let r="```"+t,i=e;if(i.includes(r)){let e=RegExp("```"+Om(t)+"[ \\t]*\\r?\\n[\\s\\S]*?```",`g`);i=i.replace(e,``);let n=i.lastIndexOf(r);n>=0&&(i=i.slice(0,n))}if(n){let e=i.lastIndexOf("```");e>=0&&r.startsWith(i.slice(e))&&(i=i.slice(0,e))}return i===e?e:i.replace(/\s+$/,``)}function Am(e,t=!1){return km(e,Dm,t)}function jm(e){return e.filter(e=>!e.this&&e.kind!==`web`&&e.name.trim()!==``)}function Mm(e){let t=/^@([^\s,:;,:;]*)$/.exec(e);return t?t[1]:null}function Nm(e,t,n=6){let r=Mm(e);if(r===null)return[];let i=r.toLowerCase();return jm(t).filter(e=>e.name.toLowerCase().startsWith(i)).sort((e,t)=>Number(t.online)-Number(e.online)||e.name.localeCompare(t.name)).slice(0,n)}function Pm(e,t){let n=e.trimStart();if(!n.startsWith(`@`))return null;let r=n.slice(1),i=r.toLowerCase(),a=jm(t),o=a.filter(e=>{let t=e.name.trim().toLowerCase();if(!i.startsWith(t))return!1;let n=r.charAt(t.length);return n===``||/[\s,:;,:;]/.test(n)}).sort((e,t)=>t.name.length-e.name.length);if(o[0])return o[0];let s=/^[^\s,:;,:;]+/.exec(r)?.[0]?.toLowerCase()??``;if(!s)return null;let c=a.filter(e=>e.name.trim().toLowerCase().startsWith(s));if(c.length===1)return c[0];let l=c.filter(e=>e.online);return l.length===1?l[0]:null}var Fm=`nm.show_steps`;function Im(){try{return localStorage.getItem(Fm)!==`0`}catch{return!0}}var Lm=Im(),Rm=new Set;function zm(){return Lm}function Bm(e){Lm=e;try{localStorage.setItem(Fm,e?`1`:`0`)}catch{}Rm.forEach(e=>e())}function Vm(e){return Rm.add(e),()=>Rm.delete(e)}function Hm(){return(0,I.useSyncExternalStore)(Vm,zm,zm)}function Um(){let{state:e,send:t,sendViaCloud:n,decide:r,loadEvents:i,openFile:a,toast:o,setDrawer:c,setTab:l}=E(),u=s(),{profile:d,status:f,activeThread:p,threads:m}=e,h=e.events[p],g=(0,I.useMemo)(()=>h??[],[h]),_=h!==void 0,v=e.streams[p],b=m.find(e=>e.id===p),[x,S]=(0,I.useState)(!1),[C,w]=(0,I.useState)(null),T=d?.name??`nanoMuse`,D=b?.device?e.hub?.devices.find(e=>e.id===b.device)?.online??null:null,O=th(e.working[p]),k=(0,I.useRef)(null),ee=(0,I.useRef)(null),A=(0,I.useRef)(!0),[j,re]=(0,I.useState)(!1),[ie,N]=(0,I.useState)(!1),ae=(0,I.useRef)(null),[oe,se]=(0,I.useState)(0);(0,I.useLayoutEffect)(()=>{let e=ae.current;if(!e||(se(e.offsetHeight),typeof ResizeObserver>`u`))return;let t=new ResizeObserver(()=>se(e.offsetHeight));return t.observe(e),()=>t.disconnect()},[]);let ce=e.firstrun,le=!!ce&&ce.phase!==`none`&&ce.session_id===p,ue=le&&ce.running,de=y()===`zh-CN`?`zh`:`en`,[fe,pe]=(0,I.useState)(null);(0,I.useEffect)(()=>{if(!le||fe?.lang===de)return;let e=!0;return M.firstrun(de).then(t=>e&&t.intro&&pe({lang:de,lines:t.intro})).catch(()=>void 0),()=>{e=!1}},[le,de,fe?.lang]);let me=e=>{M.firstrunPick(e).then(()=>t(p,e)).catch(e=>o(e.message||u(`Could not send`)))},he=()=>window.dispatchEvent(new Event(`nanomuse:quick-chat`)),[ge,_e]=(0,I.useState)(null),ve=e.settings?.onboarded===!0,ye=(0,I.useRef)(!1),xe=(0,I.useRef)(!1);(0,I.useEffect)(()=>{if(b?.busy){ye.current||(xe.current=ue),ye.current=!0;return}ye.current&&(ye.current=!1,ve&&!xe.current&&!ue&&sh(g)&&_e(Se()))},[b?.busy,g,ve,ue]);let[Ce,Te]=(0,I.useState)(null);(0,I.useEffect)(()=>{let{days:e,fresh:t}=be();t&&Te(e)},[]);let Ee=(0,I.useCallback)(()=>{let e=k.current;e&&(e.scrollTop=e.scrollHeight,re(!1),N(!1))},[]),De=(0,I.useCallback)(()=>{let e=k.current;if(!e)return;let t=e.scrollHeight-e.scrollTop-e.clientHeight;A.current=t<120,re(t>400),N(t>8)},[]),Oe=(0,I.useRef)(null);(0,I.useLayoutEffect)(()=>{Oe.current!==p&&(Oe.current=p,A.current=!0),A.current&&Ee()},[g,v?.text,p,Ee]),(0,I.useEffect)(()=>{let e=k.current,t=ee.current;if(!e||!t||typeof ResizeObserver>`u`)return;let n=new ResizeObserver(()=>{A.current?Ee():De()});return n.observe(e),n.observe(t),()=>n.disconnect()},[Ee,De]);let ke=()=>{let e=k.current;e&&e.scrollTo({top:e.scrollHeight,behavior:`smooth`})},Ae=e.pendingApprovals.length,je=e.pendingApprovals.filter(e=>e.thread===p).length,Ne=(0,I.useMemo)(()=>{let e=!f.thread||f.thread===p;if(je>0&&!(e&&f.state===`working`))return je>1?u(`{n} approvals waiting for you`,{n:je}):u(`1 approval waiting for you`);if(!e)return b?.busy?u(`On it`):void 0;if(f.state===`idle`&&!b?.busy)return;if(f.detail)return f.detail;if(f.state===`waiting`)return u(`Waiting for you`);let t=oh(g);return t?u(`On it: {request}`,{request:t}):u(`On it`)},[f,b,p,je,g,u]),Pe=g.filter(e=>e.type===`approval`&&e.status===`pending`).length,Fe=Hm(),Ie=(0,I.useMemo)(()=>Fe?g:g.filter(e=>e.type!==`tool`),[g,Fe]),Le={signedIn:!!e.hub?.account.signed_in,chatOnCloud:!!e.settings?.llm.cloud,deviceChat:!!b?.device},Re=e=>{let t=$f(Ie,e,Le);return t?()=>n(p,t.text,t.files):void 0},ze=(0,I.useMemo)(()=>Array.from(new Set(g.flatMap(e=>e.type===`artifact`?[e.path]:[]))),[g]);return(0,L.jsxs)(`div`,{className:`relative flex h-full flex-col`,children:[(0,L.jsx)(`div`,{ref:ae,className:`pointer-events-none absolute inset-x-0 top-0 z-10`,children:(0,L.jsx)(ne,{scrim:!0,profile:d,status:f,name:T,statusLine:Ne,statusTone:f.state===`idle`&&!b?.busy?`muted`:`accent`,spinning:(f.state===`working`&&f.thread===p||!!b?.busy)&&je===0,badge:Ae,onAvatar:()=>S(!0),leading:(0,L.jsx)(te,{onClick:()=>c(!0),label:u(`Chats`),dot:m.length>1&&p!==`main`,className:`wide:invisible`,children:(0,L.jsx)(Ot,{size:22})}),trailing:(0,L.jsx)(Em,{actions:[{label:u(`Coding agents`),onClick:()=>l(`coding`)}]}),under:b&&b.id!==`main`?b.device?(0,L.jsxs)(`span`,{className:`flex max-w-full items-center gap-1 rounded-full bg-accent/12 px-2.5 py-0.5 text-[11.5px] font-medium text-accent`,children:[D===!1?(0,L.jsx)(`span`,{className:`h-1.5 w-1.5 rounded-full bg-border`}):(0,L.jsx)(`span`,{className:`h-1.5 w-1.5 rounded-full bg-emerald-500`}),(0,L.jsx)(`span`,{className:`truncate`,children:u(`on {device}`,{device:b.device_name||b.device})})]}):b.remote_from?(0,L.jsxs)(`span`,{className:`flex max-w-full items-center gap-1 rounded-full bg-surface-2 px-2.5 py-0.5 text-[11.5px] font-medium text-fg/80`,children:[(0,L.jsx)(It,{size:11}),` `,(0,L.jsx)(`span`,{className:`truncate`,children:u(`from {device}`,{device:b.remote_from.name})})]}):(0,L.jsx)(`span`,{className:`truncate rounded-full bg-surface-2 px-2.5 py-0.5 text-[11.5px] font-medium text-fg/80`,children:b.title}):void 0})}),(0,L.jsx)(`div`,{"aria-hidden":!0,className:`list-fade-top pointer-events-none absolute inset-x-0 top-0 z-[5] h-20`,style:{opacity:+!!ie}}),(0,L.jsxs)(`div`,{ref:k,onScroll:De,className:`relative flex-1 overflow-y-auto px-3 pb-3`,children:[(0,L.jsxs)(`div`,{ref:ee,className:`space-y-2.5`,children:[(0,L.jsx)(`div`,{"aria-hidden":!0,style:{height:oe}}),e.hasMore[p]&&g.length>0&&(0,L.jsx)(`div`,{className:`flex justify-center`,children:(0,L.jsx)(`button`,{type:`button`,className:`text-[12.5px] text-accent px-3 py-1 rounded-full bg-surface-2`,onClick:()=>void i(p,g[0]?.id),children:u(`Load earlier messages`)})}),le&&_&&!e.hasMore[p]&&fe&&(0,L.jsx)(Pp,{lines:fe.lines}),_&&g.length===0&&!v&&!le&&(0,L.jsx)(rh,{name:T,device:b?.device?b.device_name||b.device:void 0,onSend:e=>t(p,e).catch(e=>o(e.message||u(`Could not send`)))}),Ie.map((e,t)=>(0,L.jsx)(Wm,{event:e,prev:Ie[t-1],name:T,onDecide:(t,n)=>r(e.id,t,n).catch(e=>o(e.message||u(`Could not send decision`))),onOpenFile:a,onOpenBrowser:w,files:ze,onCloudRetry:Re(t)},e.id)),v&&v.text&&(0,L.jsx)(Qm,{text:v.text,streaming:!0,files:ze,onOpenFile:a}),(b?.busy||f.state!==`idle`)&&!v?.text&&f.state!==`waiting`&&(0,L.jsx)(eh,{label:b?.queued?u(`{n} queued`,{n:b.queued}):void 0}),le&&ce.phase===`ask_agent_name`&&!b?.busy&&(0,L.jsx)(Fp,{chips:ce.chips,chosen:ce.chosen,onPick:me,onElse:he}),O&&!b?.busy&&(0,L.jsx)(nh,{who:O}),!b?.busy&&f.state===`idle`&&ge!==null&&(0,L.jsx)(we,{moment:`tasks`,n:ge,className:`mx-1 my-2`}),!b?.busy&&f.state===`idle`&&Ce!==null&&(0,L.jsx)(we,{moment:`days_used`,n:Ce,className:`mx-1 my-2`})]}),j&&(0,L.jsxs)(`button`,{type:`button`,onClick:ke,className:`sticky bottom-2 left-1/2 -translate-x-1/2 rounded-full bg-ink text-ink-fg shadow px-3 py-1.5 text-[12.5px] font-medium flex items-center gap-1`,children:[(0,L.jsx)(Me,{size:14}),` `,u(`Latest`),Pe?` · ${u(`{n} approval`,{n:Pe})}`:``]})]}),(0,L.jsx)(Lf,{}),(0,L.jsx)(ih,{name:T,busy:!!b?.busy&&Pe===0,waiting:g.some(e=>e.type===`question`&&e.status===`pending`),onSend:(e,n)=>t(p,e,n).catch(e=>{throw o(e.message||u(`Could not send`)),e})}),(0,L.jsx)(im,{open:x,onClose:()=>S(!1)}),C&&(0,L.jsx)(kp,{thread:p,eventId:C,onClose:()=>w(null)})]})}function Wm({event:e,prev:t,name:n,onDecide:r,onOpenFile:i,onOpenBrowser:a,files:o,onCloudRetry:s}){let c=Km(t,e)?(0,L.jsx)(qm,{ts:e.ts}):null,l=(()=>{switch(e.type){case`user`:return(0,L.jsx)(Jm,{event:e,onOpenFile:i});case`assistant`:return e.quiet?(0,L.jsx)($m,{text:e.text,about:e.about,ts:e.ts}):(0,L.jsx)(Qm,{text:e.text,reasoning:e.reasoning,continued:t?.type===`assistant`,files:o,onOpenFile:i,spoken:e.via===`call`,modelUsed:e.model_used});case`tool`:return(0,L.jsx)(dp,{event:e});case`approval`:return(0,L.jsx)(mp,{event:e,name:n,onDecide:r});case`question`:return(0,L.jsx)(hp,{event:e,name:n});case`notice`:return(0,L.jsx)(_p,{event:e,onCloudRetry:s});case`artifact`:return(0,L.jsx)(Tp,{event:e,onOpen:i});case`browser`:return(0,L.jsx)(vp,{event:e,onOpen:a});case`hands`:return(0,L.jsx)(yp,{event:e,name:n});case`hold`:return(0,L.jsx)(Cp,{event:e,name:n});case`avatar`:return(0,L.jsx)(tp,{event:e,name:n});default:return null}})();return l?(0,L.jsxs)(L.Fragment,{children:[c,l]}):null}var Gm=6e5;function Km(e,t){return t.ts?!e?.ts||new Date(t.ts).getTime()-new Date(e.ts).getTime()>=Gm:!1}function qm({ts:e}){let t=l(e);return t?(0,L.jsx)(`div`,{className:`pt-2 pb-0.5 text-center text-[11.5px] font-medium text-muted`,children:t}):null}function Jm({event:e,onOpenFile:t}){let n=s(),r=e.files??[],a=r.filter(e=>e.kind===`image`),o=r.filter(e=>e.kind!==`image`);return(0,L.jsxs)(`div`,{className:`rise flex flex-col items-end pl-12`,children:[e.via===`call`?(0,L.jsxs)(`span`,{className:`mb-1 flex items-center gap-1 text-[11.5px] font-medium text-muted`,children:[(0,L.jsx)(Ut,{size:11}),` `,n(`said on a call`)]}):e.via?(0,L.jsx)(`span`,{className:`mb-1 text-[11.5px] font-medium text-muted`,children:n(`asked from {device}`,{device:e.via})}):e.to_device_name||e.to_device?(0,L.jsxs)(`span`,{className:`mb-1 flex items-center gap-1 text-[11.5px] font-medium text-accent`,children:[(0,L.jsx)(It,{size:11}),` `,n(`to {device}`,{device:e.to_device_name||e.to_device||``})]}):(e.via_device_name||e.via_device)&&(0,L.jsx)(`span`,{className:`mb-1 text-[11.5px] font-medium text-muted`,children:n(`From {device}`,{device:e.via_device_name||e.via_device||``})}),a.length>0&&(0,L.jsx)(`div`,{className:`mb-1 flex max-w-full flex-wrap justify-end gap-1.5`,children:a.map(e=>(0,L.jsx)(`button`,{type:`button`,onClick:()=>t(e.path),"aria-label":e.name,className:i(`overflow-hidden rounded-2xl border border-border/60 bg-surface-2 shadow-sm active:scale-[0.98] transition`,a.length===1?`max-h-64 max-w-[240px]`:`h-28 w-28`),children:(0,L.jsx)(`img`,{src:h(e.path),alt:e.name,loading:`lazy`,className:i(`object-cover`,a.length===1?`max-h-64 w-auto max-w-full`:`h-full w-full`)})},e.path))}),o.map(e=>(0,L.jsxs)(`button`,{type:`button`,onClick:()=>t(e.path),className:`mb-1 flex max-w-full items-center gap-2.5 rounded-2xl border border-border bg-surface px-3 py-2 text-left shadow-sm hover:bg-surface-2 active:scale-[0.98] transition`,children:[(0,L.jsx)(`span`,{className:`rounded-xl bg-accent/12 p-2 text-accent`,children:e.kind===`data`?(0,L.jsx)(cn,{size:17}):(0,L.jsx)(mt,{size:17})}),(0,L.jsxs)(`span`,{className:`min-w-0`,children:[(0,L.jsx)(`span`,{className:`block truncate text-[14px] font-medium`,children:e.name}),(0,L.jsx)(`span`,{className:`block text-[11.5px] text-muted`,children:Ym(e.size)})]})]},e.path)),e.text&&(0,L.jsx)(`div`,{className:`bubble-user max-w-full rounded-[20px] bg-bubble-user px-4 py-2.5 text-bubble-user-fg`,children:(0,L.jsx)(`div`,{className:`md text-[15px] leading-[1.45] whitespace-pre-wrap break-words`,children:e.text})})]})}function Ym(e){return e<1024?`${e} B`:e<1048576?`${Math.round(e/1024)} KB`:`${(e/1048576).toFixed(1)} MB`}function Xm(e){let t=e.toLowerCase().split(`.`).pop()??``;return[`csv`,`tsv`,`json`,`xlsx`,`xls`].includes(t)?`data`:`other`}var Zm=`image/*,.pdf,.txt,.md,.csv,.tsv,.json,.log,.html,.xml,.yaml,.yml,.toml,.ics,.vcf,.xlsx,.xls,.docx`;function Qm({text:e,reasoning:t,streaming:n,continued:r,files:a,onOpenFile:o,spoken:c,modelUsed:l}){let[u,d]=(0,I.useState)(!1),f=s(),p=(0,I.useMemo)(()=>pf(Am(e,!!n)),[e,n]);return p.length===0&&!n&&!t?null:(0,L.jsx)(`div`,{className:i(`rise flex items-end gap-2 pr-10`,r&&`-mt-1`),children:(0,L.jsxs)(`div`,{className:`min-w-0 max-w-full`,children:[t&&(0,L.jsx)(`button`,{type:`button`,className:`mb-1 ml-1 text-[12px] text-muted`,onClick:()=>d(e=>!e),children:f(u?`Hide thinking`:`Show thinking`)}),t&&u&&(0,L.jsx)(`div`,{className:`mb-1.5 rounded-2xl bg-surface-2/70 px-3 py-2 text-[13px] text-muted whitespace-pre-wrap break-words`,children:t}),p.map((e,t)=>e.bare?(0,L.jsx)(`div`,{className:`my-1 max-w-full`,children:(0,L.jsx)(mf,{text:e.text,files:a,onOpenFile:o})},t):(0,L.jsxs)(`div`,{className:i(`my-1 max-w-[340px] rounded-[20px] bg-bubble-agent px-3.5 py-2.5 wide:max-w-[600px]`,c&&`border border-accent/15`),children:[c&&t===0&&(0,L.jsxs)(`div`,{className:`mb-0.5 flex items-center gap-1 text-[11px] font-medium text-accent/80`,children:[(0,L.jsx)(Ut,{size:10}),` `,f(`said on a call`)]}),(0,L.jsx)(mf,{text:e.text,files:a,onOpenFile:o}),n&&t===p.length-1&&(0,L.jsx)(`span`,{className:`inline-block w-1.5 h-4 ml-0.5 align-middle bg-accent/70 animate-pulse rounded-sm`})]},t)),p.length===0&&n&&(0,L.jsx)(`div`,{className:`my-1 rounded-[20px] bg-bubble-agent px-3.5 py-2.5`,children:(0,L.jsx)(`span`,{className:`inline-block w-1.5 h-4 align-middle bg-accent/70 animate-pulse rounded-sm`})}),l&&!n&&(0,L.jsx)(`div`,{className:`ml-1 text-[11px] text-muted`,children:f(`Answered by nanoMuse Cloud this time ({model})`,{model:l})})]})})}function $m({text:e,about:n,ts:r}){let[i,a]=(0,I.useState)(!1),o=s(),c=n?t(n.replace(/^Working on your goal: /,``)):o(`background check`);return(0,L.jsx)(`div`,{className:`rise flex justify-center px-6`,children:(0,L.jsxs)(`button`,{type:`button`,onClick:()=>a(e=>!e),className:`max-w-full rounded-2xl px-3 py-1.5 text-[12px] text-muted text-center leading-snug`,children:[(0,L.jsxs)(`span`,{className:`inline-flex items-center gap-1.5`,children:[(0,L.jsx)(Rt,{size:12}),` `,o(`Checked on {label}: nothing new`,{label:c}),r?` · ${u(r)}`:``]}),i&&(0,L.jsx)(`span`,{className:`block mt-1 text-left whitespace-pre-wrap text-[12.5px]`,children:e})]})})}function eh({label:e}){return(0,L.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,L.jsxs)(`div`,{className:`rounded-[20px] rounded-bl-md bg-bubble-agent px-3.5 py-2.5 flex items-center gap-1`,children:[(0,L.jsx)(`span`,{className:`typing-dot h-2 w-2 rounded-full bg-muted`}),(0,L.jsx)(`span`,{className:`typing-dot h-2 w-2 rounded-full bg-muted`}),(0,L.jsx)(`span`,{className:`typing-dot h-2 w-2 rounded-full bg-muted`})]}),e&&(0,L.jsx)(`span`,{className:`text-[12px] text-muted`,children:e})]})}function th(e){let t=e?e.at*1e3+ie:0,[n,r]=(0,I.useState)(0);return(0,I.useEffect)(()=>{if(!t)return;let e=t-Date.now();if(e<=0){r(t);return}let n=window.setTimeout(()=>r(t),e+50);return()=>window.clearTimeout(n)},[t]),!e||n===t?null:e}function nh({who:e}){let t=s();return(0,L.jsxs)(`div`,{className:`flex items-center gap-1.5 px-1 text-[12px] text-muted`,children:[(0,L.jsx)(A,{size:12,className:`animate-spin`}),(0,L.jsx)(`span`,{children:t(`{device} is working…`,{device:e.device_name||e.device})})]})}function rh({name:e,device:t,onSend:n}){let r=s(),i=t?[r(`What is on your screen right now?`),r(`Which folder are you in, and what is in it?`),r(`Check for updates and tell me what needs a restart`)]:[r(`What can you do for me?`),r(`Plan my week: ask me what's on my plate`),r(`Research and compare two options for me`),r(`Set up a long-term goal and track it`)];return(0,L.jsxs)(`div`,{className:`flex flex-col items-center text-center px-6 pt-10 pb-6 gap-3`,children:[(0,L.jsx)(`div`,{className:`text-[20px] font-semibold`,children:t?r(`This chat goes to {device}.`,{device:t}):r(`Hi, I'm {name}.`,{name:e})}),(0,L.jsx)(`p`,{className:`text-muted text-[14.5px] leading-snug max-w-sm`,children:t?r(`Whatever you ask here, the {name} on {device} does where it is: its shell, its files, its screen. Every step shows up here, and anything that needs an approval asks you here.`,{name:e,device:t}):r(`I don't just answer; I get things done: research, plans, files, code, email, long-running goals. Everything I do shows up here, and anything hard to undo waits for your approval.`)}),(0,L.jsx)(`div`,{className:`mt-2 flex flex-wrap justify-center gap-2`,children:i.map(e=>(0,L.jsx)(`button`,{type:`button`,onClick:()=>n(e),className:`rounded-full bg-surface-2 px-3.5 py-1.5 text-[13.5px] hover:bg-border/60`,children:e},e))})]})}function ih({name:e,busy:t,waiting:n,onSend:r}){let{state:a,draft:o,draftFiles:c,toast:l}=E(),[u,d]=(0,I.useState)(``),[f,p]=(0,I.useState)(!1),m=(0,I.useRef)(``),g=Mp((0,I.useCallback)((e,t)=>{let n=m.current,r=n&&!/\s$/.test(n)?` `:``;d(n+r+e+t)},[]),(0,I.useCallback)(e=>l(e),[l])),_=()=>{g.listening||(m.current=u),g.toggle()},[v,y]=(0,I.useState)([]),[b,x]=(0,I.useState)([]);(0,I.useEffect)(()=>{if(!a.draftFiles)return;let e=a.draftFiles.map(e=>({key:`shared-${e.path}`,file:new File([],e.name),preview:e.kind===`image`?h(e.path):null,info:e,error:null}));x(t=>[...t.filter(t=>!e.some(e=>e.key===t.key)),...e].slice(0,10)),c(null)},[a.draftFiles]);let S=(0,I.useRef)(null),C=(0,I.useRef)(null),w=s();(0,I.useEffect)(()=>()=>b.forEach(e=>e.preview?.startsWith(`blob:`)&&URL.revokeObjectURL(e.preview)),[b]),(0,I.useEffect)(()=>{let e=()=>S.current?.focus();return window.addEventListener(`nanomuse:quick-chat`,e),()=>window.removeEventListener(`nanomuse:quick-chat`,e)},[]);let T=e=>{let t=Array.from(e).slice(0,Math.max(0,10-b.length));if(t.length===0)return;let n=t.map(e=>({key:`${e.name}-${e.size}-${e.lastModified}-${Math.random().toString(36).slice(2,7)}`,file:e,preview:e.type.startsWith(`image/`)?URL.createObjectURL(e):null,info:null,error:null}));x(e=>[...e,...n]);for(let e of n)M.upload(e.file).then(t=>x(n=>n.map(n=>n.key===e.key?{...n,info:t}:n))).catch(t=>{let n=t.message?N(t.message):w(`Upload failed`);x(t=>t.map(t=>t.key===e.key?{...t,error:n}:t)),l(n)})},D=e=>x(t=>t.filter(t=>t.key!==e)),O=b.some(e=>!e.info&&!e.error),k=b.flatMap(e=>e.info?[e.info.path]:[]);(0,I.useEffect)(()=>{let e=S.current;e&&(e.style.height=`0px`,e.style.height=`${Math.min(e.scrollHeight,160)}px`)},[u]),(0,I.useEffect)(()=>{if(a.draft===null)return;d(a.draft),o(null);let e=S.current;e&&(e.focus(),e.setSelectionRange(e.value.length,e.value.length))},[a.draft]);let ee=a.settings?.skills?.enabled!==!1;(0,I.useEffect)(()=>{ee&&M.skills().then(e=>y(e.skills.filter(e=>e.enabled))).catch(()=>y([]))},[ee,a.skillsVersion]);let te=/^\/([a-z0-9-]*)$/i.exec(u),j=te?v.filter(e=>e.name.startsWith(te[1].toLowerCase())).slice(0,6):[],ne=e=>{d(`/${e.name} `),S.current?.focus()},re=a.hub?.devices??[],ie=Nm(u,re),ae=ie.length===0?Pm(u,re):null,oe=e=>{d(`@${e.name} `),S.current?.focus()},se=e=>{e?.preventDefault();let t=u.trim();if(!t&&k.length===0||O||f)return;g.listening&&g.stop();let n=b;p(!0),d(``),x([]),S.current?.focus(),r(t,k).catch(()=>{d(e=>e||t),x(e=>e.length?e:n)}).finally(()=>p(!1))};return(0,L.jsxs)(`form`,{onSubmit:se,className:`shrink-0 bg-bg px-3 pt-1.5 pb-1`,children:[t&&!n&&(0,L.jsx)(`div`,{className:`px-2 pb-1 text-[12px] text-muted`,children:w(`{name} is working; anything you send now is picked up right away.`,{name:e})}),j.length>0&&(0,L.jsx)(`ul`,{className:`mb-2 max-h-72 overflow-y-auto rounded-3xl border border-border/70 bg-surface shadow-lg divide-y divide-border/70`,role:`listbox`,"aria-label":w(`Skills`),children:j.map(e=>(0,L.jsx)(`li`,{children:(0,L.jsxs)(`button`,{type:`button`,onClick:()=>ne(e),className:`flex w-full items-center gap-3 px-4 py-2.5 text-left hover:bg-surface-2/70 active:bg-surface-2`,children:[(0,L.jsx)(gn,{size:16,className:`shrink-0 text-accent`}),(0,L.jsxs)(`span`,{className:`min-w-0 flex-1`,children:[(0,L.jsxs)(`span`,{className:`block text-[14px] font-medium`,children:[`/`,e.name]}),(0,L.jsx)(`span`,{className:`block truncate text-[12.5px] text-muted`,children:e.description})]})]})},e.name))}),ie.length>0&&(0,L.jsx)(`ul`,{className:`mb-2 max-h-72 overflow-y-auto rounded-3xl border border-border/70 bg-surface shadow-lg divide-y divide-border/70`,role:`listbox`,"aria-label":w(`Devices`),children:ie.map(e=>(0,L.jsx)(`li`,{children:(0,L.jsxs)(`button`,{type:`button`,onClick:()=>oe(e),className:`flex w-full items-center gap-3 px-4 py-2.5 text-left hover:bg-surface-2/70 active:bg-surface-2`,children:[(0,L.jsx)(`span`,{className:`shrink-0 text-accent`,children:e.kind===`computer`?(0,L.jsx)(Lt,{size:16}):(0,L.jsx)(tn,{size:16})}),(0,L.jsxs)(`span`,{className:`min-w-0 flex-1`,children:[(0,L.jsxs)(`span`,{className:`block text-[14px] font-medium`,children:[`@`,e.name]}),(0,L.jsx)(`span`,{className:`block truncate text-[12.5px] text-muted`,children:e.online?w(`Runs this there and reports back`):w(`Offline`)})]})]})},e.id))}),ae&&(0,L.jsxs)(`div`,{className:`flex items-center gap-1.5 px-2 pb-1 text-[12px] text-muted`,children:[(0,L.jsx)(It,{size:12}),` `,w(`This goes to {device}.`,{device:ae.name})]}),b.length>0&&(0,L.jsx)(`div`,{className:`mb-1 flex gap-2.5 overflow-x-auto px-1 pt-2.5 pb-1 pr-3`,role:`list`,"aria-label":w(`Attachments`),children:b.map(e=>(0,L.jsxs)(`div`,{role:`listitem`,className:i(`relative shrink-0 rounded-2xl border bg-surface-2`,e.error?`border-danger/60`:`border-border/70`),children:[e.preview?(0,L.jsx)(`img`,{src:e.preview,alt:e.file.name,className:`h-16 w-16 rounded-2xl object-cover`}):(0,L.jsxs)(`div`,{className:`flex h-16 w-40 items-center gap-2 px-2.5`,children:[(0,L.jsx)(`span`,{className:`rounded-xl bg-accent/12 p-1.5 text-accent`,children:Xm(e.file.name)===`data`?(0,L.jsx)(cn,{size:16}):(0,L.jsx)(mt,{size:16})}),(0,L.jsxs)(`span`,{className:`min-w-0`,children:[(0,L.jsx)(`span`,{className:`block truncate text-[12.5px] font-medium`,children:e.file.name}),(0,L.jsx)(`span`,{className:`block text-[11px] text-muted`,children:e.error?w(`Upload failed`):Ym(e.info?.size??e.file.size)})]})]}),!e.info&&!e.error&&(0,L.jsx)(`div`,{className:`absolute inset-0 flex items-center justify-center rounded-2xl bg-bg/50`,children:(0,L.jsx)(A,{size:18,className:`animate-spin text-accent`})}),(0,L.jsx)(`button`,{type:`button`,onClick:()=>D(e.key),"aria-label":w(`Remove`),className:`absolute -right-1.5 -top-1.5 flex h-6 w-6 items-center justify-center rounded-full border border-border bg-surface text-muted shadow-sm`,children:(0,L.jsx)(Fe,{size:13})})]},e.key))}),(0,L.jsxs)(`div`,{className:`flex items-end gap-2 rounded-[26px] border border-border bg-surface px-1.5 py-1.5 shadow-[0_2px_12px_-6px_rgba(0,0,0,0.12)] focus-within:border-fg/20`,children:[(0,L.jsx)(`input`,{ref:C,type:`file`,multiple:!0,accept:Zm,className:`hidden`,onChange:e=>{e.target.files&&T(e.target.files),e.target.value=``}}),(0,L.jsx)(`button`,{type:`button`,onClick:()=>C.current?.click(),"aria-label":w(`Attach a file`),className:`flex h-9 w-9 shrink-0 items-center justify-center rounded-full text-fg/70 transition hover:bg-surface-2 active:scale-95`,children:(0,L.jsx)(Kt,{size:22})}),(0,L.jsx)(`textarea`,{ref:S,value:u,onChange:e=>d(e.target.value),onPaste:e=>{let t=Array.from(e.clipboardData?.files??[]);t.length>0&&(e.preventDefault(),T(t))},onKeyDown:e=>{if(e.key===`Tab`&&j.length>0&&j[0]){e.preventDefault(),ne(j[0]);return}if(e.key===`Tab`&&ie.length>0&&ie[0]){e.preventDefault(),oe(ie[0]);return}e.key===`Enter`&&!e.shiftKey&&!e.nativeEvent.isComposing&&(e.preventDefault(),se())},rows:1,placeholder:n?w(`Answer {name}…`,{name:e}):b.length>0?w(`Say what to do with it…`):w(`Message`),"aria-label":w(`Message`),className:`flex-1 resize-none bg-transparent px-1 py-2 text-[15px] leading-[1.4] outline-none placeholder:text-muted`}),g.supported&&(0,L.jsx)(Np,{listening:g.listening,onClick:_}),(0,L.jsx)(`button`,{type:`submit`,disabled:!u.trim()&&k.length===0||O,"aria-label":w(`Send`),className:i(`flex h-9 w-9 shrink-0 items-center justify-center rounded-full transition active:scale-95`,u.trim()||k.length>0?`bg-ink text-ink-fg`:`bg-surface-2 text-muted`,`disabled:opacity-60`),children:(0,L.jsx)(Je,{size:19,strokeWidth:2.5})})]})]})}function ah({threads:e,active:t,onPick:n,onCleared:r,compact:a=!1,grouped:o=!1}){let{state:c,toast:l,dispatch:d}=E(),f=s(),[p,m]=(0,I.useState)(``),[h,g]=(0,I.useState)(!1),_=(0,I.useRef)(null),v=(c.hub?.devices??[]).filter(e=>!e.this&&e.kind!==`web`&&e.online),y=e=>c.hub?.devices.find(t=>t.id===e)?.kind??`phone`,b=async e=>{try{let t=await M.askDevice(e.id);d({type:`ws`,msg:{kind:`thread`,thread:t.thread}}),n(t.thread.id)}catch(e){l(e.message)}},x=async()=>{g(!0);try{let e=await M.createThread(p.trim()||f(`Side chat`));d({type:`ws`,msg:{kind:`thread`,thread:e}}),m(``),n(e.id)}catch(e){l(e.message)}finally{g(!1)}},S=async e=>{if(window.confirm(f(`Delete this side chat and its history?`)))try{await M.deleteThread(e),d({type:`ws`,msg:{kind:`thread_deleted`,thread:e}})}catch(e){l(e.message)}},C=async e=>{if(window.confirm(f(`Clear this conversation? Memory and goals are kept.`)))try{await M.clearThread(e),d({type:`ws`,msg:{kind:`thread_cleared`,thread:e}}),r?.()}catch(e){l(e.message)}},w=e=>(0,L.jsxs)(`li`,{className:i(`group flex items-center gap-2 px-3`,a?`py-2 rounded-xl hover:bg-surface-2/60`:`py-2.5`,e.id===t&&`bg-surface-2/60`),children:[(0,L.jsxs)(`button`,{type:`button`,onClick:()=>n(e.id),className:`flex-1 text-left min-w-0`,children:[(0,L.jsxs)(`div`,{className:i(`font-medium truncate flex items-center gap-2`,a?`text-[13.5px]`:`text-[15px]`),children:[e.device?(0,L.jsx)(`span`,{className:`text-accent`,children:y(e.device)===`computer`?(0,L.jsx)(Lt,{size:14}):(0,L.jsx)(tn,{size:14})}):e.remote_from?(0,L.jsx)(It,{size:14,className:`text-muted`}):null,(0,L.jsx)(`span`,{className:`truncate`,children:e.id===`main`?f(e.title):e.title}),e.busy&&(0,L.jsx)(`span`,{className:`h-1.5 w-1.5 shrink-0 rounded-full bg-amber-400 animate-pulse`})]}),(0,L.jsxs)(`div`,{className:i(`text-muted`,a?`text-[11.5px]`:`text-[12px]`),children:[f(`{n} events`,{n:e.events}),e.queued?` · ${f(`{n} queued`,{n:e.queued})}`:``,` · `,u(e.updated_at)]})]}),(0,L.jsx)(`button`,{type:`button`,"aria-label":f(`Clear`),onClick:()=>void C(e.id),className:i(`p-2 text-muted hover:text-fg`,a&&`opacity-0 group-hover:opacity-100 focus:opacity-100`),children:(0,L.jsx)(Fe,{size:16})}),e.id!==`main`&&(0,L.jsx)(`button`,{type:`button`,"aria-label":f(`Delete`),onClick:()=>void S(e.id),className:i(`p-2 text-muted hover:text-rose-500`,a&&`opacity-0 group-hover:opacity-100 focus:opacity-100`),children:(0,L.jsx)(fn,{size:16})})]},e.id),T=i(`divide-y divide-border overflow-hidden`,a?`rounded-xl`:`rounded-2xl border border-border`),D=`px-3 pb-1 pt-3 text-[11.5px] font-semibold uppercase tracking-wide text-muted`;return(0,L.jsxs)(`div`,{children:[o?(0,L.jsxs)(L.Fragment,{children:[(0,L.jsx)(`div`,{className:D,children:f(`Main chat`)}),(0,L.jsx)(`ul`,{className:T,children:e.filter(e=>e.id===`main`).map(w)}),(0,L.jsxs)(`div`,{className:i(D,`flex items-center justify-between pr-1`),children:[(0,L.jsx)(`span`,{children:f(`Side chats`)}),(0,L.jsx)(`button`,{type:`button`,"aria-label":f(`New side chat`),onClick:()=>_.current?.focus(),className:`flex h-6 w-6 items-center justify-center rounded-full text-muted hover:bg-surface-2 hover:text-fg`,children:(0,L.jsx)(Kt,{size:15})})]}),(0,L.jsx)(`ul`,{className:T,children:e.filter(e=>e.id!==`main`).map(w)}),e.every(e=>e.id===`main`)&&(0,L.jsx)(`p`,{className:`px-3 py-2 text-[12px] text-muted`,children:f(`A side chat keeps one topic apart from the rest.`)})]}):(0,L.jsx)(`ul`,{className:T,children:e.map(w)}),v.length>0&&(0,L.jsxs)(`div`,{className:`mt-4`,children:[(0,L.jsx)(`div`,{className:`mb-1.5 text-[12px] font-medium text-muted`,children:f(`Ask one of your devices`)}),(0,L.jsx)(`div`,{className:`flex flex-wrap gap-2`,children:v.map(e=>(0,L.jsxs)(`button`,{type:`button`,onClick:()=>void b(e),className:`flex items-center gap-1.5 rounded-full border border-border bg-surface px-3 py-1.5 text-[13px] font-medium hover:bg-surface-2`,children:[e.kind===`phone`?(0,L.jsx)(tn,{size:14,className:`text-accent`}):(0,L.jsx)(Lt,{size:14,className:`text-accent`}),e.name]},e.id))})]}),(0,L.jsxs)(`div`,{className:i(`flex gap-2`,a?`mt-3`:`mt-4`),children:[(0,L.jsx)(`input`,{ref:_,value:p,onChange:e=>m(e.target.value),onKeyDown:e=>{e.key===`Enter`&&!h&&x()},placeholder:f(a?`New side chat`:`New side chat, e.g. “Trip to Kyoto”`),className:i(`min-w-0 flex-1 bg-surface-2 outline-none focus:ring-2 focus:ring-accent/40`,a?`rounded-xl px-3 py-2 text-[13px]`:`rounded-2xl px-3.5 py-2.5 text-[14px]`)}),(0,L.jsxs)(`button`,{type:`button`,disabled:h,onClick:()=>void x(),"aria-label":f(`New`),className:i(`flex items-center gap-1.5 bg-accent text-accent-fg font-medium disabled:opacity-50`,a?`rounded-xl px-2.5`:`rounded-2xl px-3.5 py-2.5`),children:[(0,L.jsx)(jt,{size:18}),` `,!a&&f(`New`)]})]})]})}function oh(e){let t=[...e].reverse().find(e=>e.type===`user`),n=(((t?.type===`user`?t.text:``)||``).split(/\r?\n/).map(e=>e.trim()).find(e=>e.length>0)??``).replace(/\s+/g,` `);if(n.length<=36)return n;let r=n.slice(0,36),i=r.lastIndexOf(` `);return(i>16?r.slice(0,i):r).trimEnd()+`…`}function sh(e){let t=!1;for(let n=e.length-1;n>=0;n--){let r=e[n];if(r.type===`assistant`){if(!r.text||r.quiet)return!1;t=!0;continue}if(r.type===`user`)return t&&!r.via;if(r.type===`notice`)return!1}return!1}function ch(e){let t=Sn(),n=t?`Desktop app (${t.platform}, shell ${t.version})`:`Web app (${navigator.userAgent})`;return`https://github.com/zeeshanhaque21/nanoMuse/issues/new?${new URLSearchParams({template:`bug_report.yml`,version:e||``,os:n}).toString()}`}function lh(){let{state:e,setTab:t,openThread:n}=E(),r=s(),[a,o]=(0,I.useState)(!1),[c,l]=(0,I.useState)(!1),[u,d]=(0,I.useState)(``),f=(0,I.useRef)(null),p=Qf(),{profile:m,status:h}=e,g=m?.name??`nanoMuse`,_=e.pendingApprovals.length,v=e.goals.filter(e=>e.proposal&&e.status!==`cancelled`).length,y=e.pendingApprovals.filter(t=>t.ts>e.feedSeenAt).length,b=(e.hub?.devices??[]).filter(e=>!e.this&&e.kind!==`web`&&e.online).length,x=_>0?_>1?r(`{n} approvals waiting for you`,{n:_}):r(`1 approval waiting for you`):h.state===`idle`?r(`Idle`):h.detail||(h.state===`waiting`?r(`Waiting for you`):r(`Working…`));(0,I.useEffect)(()=>{if(!c)return;let e=e=>{f.current?.contains(e.target)||l(!1)},t=e=>{e.key===`Escape`&&l(!1)};return document.addEventListener(`mousedown`,e),document.addEventListener(`keydown`,t),()=>{document.removeEventListener(`mousedown`,e),document.removeEventListener(`keydown`,t)}},[c]);let S=[{id:`chat`,label:`Chat`,icon:(0,L.jsx)(At,{size:21}),badge:_},{id:`feed`,label:`Feed`,icon:(0,L.jsx)(Bt,{size:21}),badge:y},{id:`ideas`,label:`Ideas`,icon:(0,L.jsx)(Ct,{size:21})},{id:`goals`,label:`Goals`,icon:(0,L.jsx)(rn,{size:21}),badge:v},{id:`library`,label:`Library`,icon:(0,L.jsx)(St,{size:21})},{id:`devices`,label:`Devices`,icon:(0,L.jsx)(It,{size:21}),dot:b>0},...p?[{id:`coding`,label:`Coding`,icon:(0,L.jsx)(on,{size:21})}]:[]],C=u.trim().toLowerCase(),w=C?e.threads.filter(e=>e.id===`main`||(e.id===`main`?r(e.title):e.title).toLowerCase().includes(C)||(e.device_name??``).toLowerCase().includes(C)):e.threads,T=e=>i(`relative flex w-[60px] flex-col items-center gap-[3px] rounded-xl py-1.5 text-[10.5px] font-medium leading-none transition`,e?`bg-surface-2 text-fg`:`text-fg/65 hover:bg-surface-2/60 hover:text-fg`);return(0,L.jsxs)(`div`,{className:`flex h-full shrink-0`,children:[(0,L.jsxs)(`aside`,{className:`relative flex h-full w-[76px] shrink-0 flex-col items-center border-r border-border bg-surface/70`,children:[(0,L.jsx)(`div`,{className:`titlebar-room`}),(0,L.jsxs)(`button`,{type:`button`,onClick:()=>o(!0),className:`relative mt-3 rounded-full transition hover:scale-[1.04]`,"aria-label":r(`Activity`),title:`${g} · ${x}`,children:[(0,L.jsx)(D,{profile:m,status:h,size:44}),_>0&&(0,L.jsx)(`span`,{className:`pointer-events-none absolute -right-1 -top-1 flex h-[18px] min-w-[18px] items-center justify-center rounded-full border-2 border-surface bg-rose-500 px-1 text-[10.5px] font-bold text-white`,children:_})]}),(0,L.jsx)(`span`,{className:`mt-1.5 max-w-[68px] truncate px-1 text-[11px] font-semibold leading-tight`,children:g}),(0,L.jsx)(`nav`,{className:`mt-3 flex w-full flex-1 flex-col items-center gap-0.5 overflow-y-auto overflow-x-hidden px-2`,children:S.map(n=>{let a=e.tab===n.id;return(0,L.jsxs)(`button`,{type:`button`,onClick:()=>t(n.id),"aria-current":a?`page`:void 0,className:T(a),children:[(0,L.jsx)(`span`,{className:i(a?`text-accent`:`text-fg/60`),children:n.icon}),(0,L.jsx)(`span`,{className:`max-w-full truncate`,children:r(n.label)}),n.badge?(0,L.jsx)(`span`,{className:`absolute right-1.5 top-1 flex h-[17px] min-w-[17px] items-center justify-center rounded-full bg-rose-500 px-1 text-[10px] font-bold text-white`,children:n.badge}):n.dot?(0,L.jsxs)(L.Fragment,{children:[(0,L.jsx)(`span`,{"aria-hidden":`true`,className:`absolute right-3 top-2 h-2 w-2 rounded-full border-2 border-surface bg-emerald-500`}),(0,L.jsx)(`span`,{className:`sr-only`,children:r(`{n} online`,{n:b})})]}):null]},n.id)})}),(0,L.jsxs)(`div`,{className:`flex w-full flex-col items-center gap-0.5 px-2 pb-3 pt-2`,children:[(0,L.jsxs)(`button`,{type:`button`,onClick:()=>t(`account`),"aria-current":e.tab===`account`?`page`:void 0,className:T(e.tab===`account`),title:e.hub?.account.signed_in?e.hub.account.hint:r(`Account`),children:[(0,L.jsx)(mn,{size:21,className:e.tab===`account`?`text-accent`:`text-fg/60`}),(0,L.jsx)(`span`,{className:`max-w-full truncate`,children:r(`Account`)})]}),(0,L.jsxs)(`button`,{type:`button`,onClick:()=>t(`you`),"aria-current":e.tab===`you`?`page`:void 0,className:T(e.tab===`you`),children:[(0,L.jsx)(en,{size:21,className:e.tab===`you`?`text-accent`:`text-fg/60`}),(0,L.jsx)(`span`,{className:`max-w-full truncate`,children:r(`Settings`)})]}),(0,L.jsxs)(`div`,{ref:f,className:`relative w-full`,children:[(0,L.jsxs)(`button`,{type:`button`,onClick:()=>l(e=>!e),"aria-expanded":c,"aria-haspopup":`menu`,className:i(T(c),`mx-auto`),children:[(0,L.jsx)(Ot,{size:21,className:`text-fg/60`}),(0,L.jsx)(`span`,{children:r(`More`)})]}),c&&(0,L.jsxs)(`div`,{role:`menu`,className:`absolute bottom-0 left-[68px] z-30 w-[232px] rounded-2xl border border-border bg-surface p-1.5 shadow-[0_12px_40px_-12px_rgba(0,0,0,0.3)]`,children:[(0,L.jsxs)(`a`,{role:`menuitem`,href:ch(e.version),target:`_blank`,rel:`noreferrer`,onClick:()=>l(!1),className:`flex items-center gap-2.5 rounded-xl px-2.5 py-2 text-[13px] font-medium hover:bg-surface-2`,children:[(0,L.jsx)(ce,{size:16,className:`text-fg/60`}),` `,r(`Report a bug`)]}),(0,L.jsxs)(`button`,{type:`button`,role:`menuitem`,onClick:()=>{l(!1),t(`you`),window.location.hash=`developer`},className:`flex w-full items-center gap-2.5 rounded-xl px-2.5 py-2 text-left text-[13px] font-medium hover:bg-surface-2`,children:[(0,L.jsx)(yn,{size:16,className:`text-fg/60`}),(0,L.jsx)(`span`,{className:`flex-1`,children:r(`Developer tools`)}),(0,L.jsx)(`span`,{className:`text-[11.5px] font-normal text-muted`,children:r(p?`On`:`Off`)})]}),e.version&&(0,L.jsxs)(`div`,{className:`px-2.5 pb-1 pt-1.5 text-[11.5px] text-muted`,children:[`nanoMuse `,e.version]})]})]})]}),(0,L.jsx)(im,{open:a,onClose:()=>o(!1)})]}),e.tab===`chat`&&(0,L.jsxs)(`section`,{className:`flex h-full w-[248px] shrink-0 flex-col border-r border-border bg-surface/40`,"aria-label":r(`Chats`),children:[(0,L.jsx)(`div`,{className:`titlebar-room`}),(0,L.jsxs)(`div`,{className:`px-3 pb-2 pt-4`,children:[(0,L.jsx)(`h2`,{className:`px-1 text-[15px] font-semibold tracking-tight`,children:r(`Chats`)}),(0,L.jsxs)(`label`,{className:`mt-2 flex items-center gap-2 rounded-xl bg-surface-2 px-2.5 py-1.5 text-muted focus-within:ring-2 focus-within:ring-accent/40`,children:[(0,L.jsx)(qt,{size:14,className:`shrink-0`}),(0,L.jsx)(`input`,{value:u,onChange:e=>d(e.target.value),placeholder:r(`Search`),"aria-label":r(`Search chats`),className:`min-w-0 flex-1 bg-transparent text-[13px] text-fg outline-none placeholder:text-muted`}),u&&(0,L.jsx)(`button`,{type:`button`,onClick:()=>d(``),"aria-label":r(`Clear`),className:`shrink-0 hover:text-fg`,children:(0,L.jsx)(Fe,{size:14})})]})]}),(0,L.jsx)(`div`,{className:`min-h-0 flex-1 overflow-y-auto px-2 pb-3`,children:(0,L.jsx)(ah,{threads:w,active:e.activeThread,onPick:e=>n(e),compact:!0,grouped:!0})})]})]})}function uh(){let{state:e,send:t,openThread:n,openFile:r,markFeedSeen:i,setTab:a,toast:o}=E(),[c,l]=(0,I.useState)(null),[u,p]=(0,I.useState)(null),[h,g]=(0,I.useState)(null),[_,v]=(0,I.useState)(null),b=e.profile?.name??`nanoMuse`,x=s(),S=y();(0,I.useEffect)(()=>{let e=!0;return M.feed(80).then(t=>e&&l(t)).catch(e=>o(e.message)),M.upcoming().then(t=>e&&g(t)).catch(()=>void 0),M.feedPosts().then(t=>e&&p(t)).catch(()=>void 0),()=>{e=!1}},[e.feedVersion,e.remindersVersion]),(0,I.useEffect)(()=>{let e=!0;return M.calendar().then(t=>e&&v(t)).catch(()=>void 0),()=>{e=!1}},[e.calendarVersion,e.connectionsVersion]),(0,I.useEffect)(()=>{c&&c.length&&c[0].ts>e.feedSeenAt&&i(c[0].ts)},[c,e.feedSeenAt,i]);let C=(0,I.useMemo)(()=>Oh(c??[]),[c,S]),[w,T]=(0,I.useState)(!1),[D,O]=(0,I.useState)(null),[k,ee]=(0,I.useState)(()=>d(dh)===`1`),[j,ne]=(0,I.useState)(!1),re=()=>{f(dh,`1`),ee(!0)},ie=async()=>{ne(!0);try{let e=await M.refreshFeedPosts();p(e),e.error&&o(x(`Could not write posts: {error}`,{error:e.error}))}catch(e){o(e.message)}finally{ne(!1)}},N=e=>{t(`main`,e.prompt||`${x(`About this post from my feed:`)}\n\n**${e.title}**\n\n${e.body.slice(0,1200)}`).catch(e=>o(e.message||x(`Could not send`))),n(`main`)},ae=(0,I.useMemo)(()=>ph(u?.posts??[]),[u]),oe=u!==null&&u.posts.length===0;return(0,L.jsxs)(`div`,{className:`flex h-full flex-col`,children:[(0,L.jsx)(Tm,{title:``,trailing:(0,L.jsx)(te,{onClick:()=>T(!0),label:x(`Feed settings`),children:(0,L.jsx)(en,{size:22})})}),(0,L.jsxs)(`div`,{className:`flex-1 overflow-y-auto px-3.5 pb-7`,children:[ae.length===0&&(0,L.jsxs)(L.Fragment,{children:[(0,L.jsx)(hh,{text:mh(fh(),new Date)}),!k&&(0,L.jsx)(bh,{instructions:u?.instructions??``,onEdit:()=>T(!0),onAck:re}),oe&&(0,L.jsxs)(L.Fragment,{children:[(0,L.jsx)(xh,{emoji:`🖼️`,title:x(`Nothing in the feed yet`),body:x(`As we get to know each other, new posts will show up here. Every day at {time} I read what I remember about you (your memory files, the last week of diary, your goals) and write a few short posts.`,{time:u?.time??`08:00`})}),(0,L.jsx)(xh,{emoji:`📝`,title:x(`Steer it with one sentence`),body:x(`Tap the sliders at the top right to tell me what you want more of, switch the daily routine off, or have me write the first day now.`)}),e.settings&&!e.settings.llm_ready&&(0,L.jsx)(gh,{children:(0,L.jsxs)(`button`,{type:`button`,onClick:()=>a(`you`),className:`flex w-full items-center gap-2 p-4 text-left text-[14px] text-muted`,children:[(0,L.jsx)(xt,{size:16,className:`shrink-0 text-accent`}),` `,x(`Add a model first; the feed is written by your agent.`)]})}),(0,L.jsx)(gh,{children:(0,L.jsx)(`div`,{className:`p-4`,children:j?(0,L.jsxs)(`div`,{className:`flex items-center justify-center gap-2.5 text-[15px]`,children:[(0,L.jsx)(A,{size:18,className:`animate-spin text-accent`}),` `,x(`Writing…`)]}):(0,L.jsx)(`button`,{type:`button`,onClick:()=>void ie(),className:`h-[46px] w-full rounded-full bg-accent text-[15px] font-semibold text-accent-fg`,children:x(`Write it now`)})})})]})]}),ae.map(([e,t],n)=>(0,L.jsxs)(`section`,{children:[(0,L.jsx)(hh,{text:mh(e,new Date(t[0].ts))}),n===0&&!k&&(0,L.jsx)(bh,{instructions:u?.instructions??``,onEdit:()=>T(!0),onAck:re}),n===0&&j&&(0,L.jsx)(gh,{children:(0,L.jsxs)(`div`,{className:`flex items-center gap-2.5 p-4 text-[15px]`,children:[(0,L.jsx)(A,{size:18,className:`animate-spin text-accent`}),` `,x(`Writing…`)]})}),t.map(e=>(0,L.jsx)(yh,{post:e,onDiscuss:()=>N(e),onInfo:()=>O(e)},e.id))]},e)),(0,L.jsxs)(`div`,{className:`space-y-4 px-0.5 pt-3`,children:[h&&(0,L.jsx)(wh,{data:h,name:b,onSettings:()=>a(`you`),onGoals:()=>a(`goals`)}),_?.configured&&(0,L.jsx)(Th,{data:_,onAsk:()=>n(`main`)}),c&&c.length===0&&(!u||u.posts.length===0)&&(0,L.jsxs)(`div`,{className:`py-10 text-center text-muted text-[14px] px-6`,children:[(0,L.jsx)(Rt,{size:28,className:`mx-auto mb-2 opacity-60`}),x(`Nothing yet. Once {name} works on a goal in the background or needs your approval, it shows up here.`,{name:b})]}),c&&c.length>0&&(0,L.jsx)(`div`,{className:`px-1 pt-1 text-[12px] font-semibold uppercase tracking-wide text-muted`,children:x(`While you were away`)}),C.map(([t,i])=>(0,L.jsxs)(`section`,{children:[(0,L.jsx)(`div`,{className:`px-1 mb-1.5 text-[12px] uppercase tracking-wide text-muted font-semibold`,children:t}),(0,L.jsx)(`ul`,{className:`space-y-2`,children:i.map(t=>(0,L.jsx)(`li`,{children:(0,L.jsx)(Dh,{item:t,unseen:t.ts>e.feedSeenAt,onOpen:()=>{t.kind===`artifact`&&t.path?r(t.path):n(t.thread)}})},t.id))})]},t))]})]}),(0,L.jsx)(Ch,{open:w,onClose:()=>T(!1),data:u,writing:j,onChange:p,onWriteNow:()=>void ie()}),(0,L.jsx)(Dp,{open:D!==null,onClose:()=>O(null),title:D?.title,children:D&&(0,L.jsxs)(`div`,{className:`space-y-3 px-1 pb-2`,children:[(0,L.jsx)(Sh,{label:x(`Post type`),value:vh(D.area)}),(0,L.jsx)(Sh,{label:x(`Written`),value:new Date(D.ts).toLocaleString(m(),{dateStyle:`medium`,timeStyle:`short`})}),(0,L.jsx)(`button`,{type:`button`,onClick:async()=>{let e=D.id;O(null);try{await M.deleteFeedPost(e),p(t=>t&&{...t,posts:t.posts.filter(t=>t.id!==e)})}catch(e){o(e.message)}},className:`w-full rounded-full bg-surface-2 py-2.5 text-[15px] font-medium text-rose-500`,children:x(`Delete this post`)})]})})]})}var dh=`nanomuse.feed.introAck`;function fh(){let e=new Date;return`${e.getFullYear()}-${String(e.getMonth()+1).padStart(2,`0`)}-${String(e.getDate()).padStart(2,`0`)}`}function ph(e){let t=new Map;for(let n of e){let e=new Date(n.ts),r=`${e.getFullYear()}-${String(e.getMonth()+1).padStart(2,`0`)}-${String(e.getDate()).padStart(2,`0`)}`,i=t.get(r);i?i.push(n):t.set(r,[n])}return[...t.entries()]}function mh(e,t){let n=fh(),r=new Date;r.setDate(r.getDate()-1);let i=`${r.getFullYear()}-${String(r.getMonth()+1).padStart(2,`0`)}-${String(r.getDate()).padStart(2,`0`)}`,a=t.toLocaleDateString(m(),{weekday:`long`});if(e===n){let e=new Date().getHours(),t=_(e<12?`morning`:e<18?`afternoon`:`evening`);return _(`{weekday} {part}`,{weekday:a,part:t})}return e===i?_(`Yesterday`):`${a} · ${t.toLocaleDateString(m(),{month:`short`,day:`numeric`})}`}function hh({text:e}){return(0,L.jsx)(`h2`,{className:`px-1.5 pt-3.5 pb-2 text-[22px] font-bold leading-7`,children:e})}function gh({children:e,className:t}){return(0,L.jsx)(`div`,{className:i(`my-1.5 overflow-hidden rounded-[18px] bg-surface dark:border dark:border-border`,t),children:e})}var _h={planning:`🗓️`,research:`🔍`,goals:`🎯`,money:`💰`,health:`🌿`,home:`🏠`,learning:`📚`,people:`👥`,files:`📄`,fun:`🎈`};function vh(e){switch(e){case`planning`:return _(`Planning`);case`research`:return _(`Research`);case`goals`:return _(`Goals`);case`money`:return _(`Money`);case`health`:return _(`Health`);case`home`:return _(`Home`);case`learning`:return _(`Learning`);case`people`:return _(`People`);case`files`:return _(`Files`);case`fun`:return _(`Fun`);default:return _(`Note`)}}function yh({post:e,onDiscuss:t,onInfo:n}){let r=s();return(0,L.jsx)(gh,{children:(0,L.jsxs)(`article`,{className:`pl-3.5 pr-2.5 pt-3.5 pb-1.5`,children:[(0,L.jsxs)(`div`,{className:`flex items-start gap-3`,children:[(0,L.jsx)(`div`,{className:`flex h-11 w-11 shrink-0 items-center justify-center rounded-xl bg-surface-2 text-[22px] leading-none`,children:_h[e.area]??`📝`}),(0,L.jsxs)(`div`,{className:`min-w-0 flex-1`,children:[(0,L.jsx)(`h3`,{className:`text-[16px] font-semibold leading-[22px]`,children:e.title}),(0,L.jsx)(`div`,{className:`md mt-1 text-[15px] leading-[22px] text-fg/85`,children:(0,L.jsx)(mf,{text:e.body})})]})]}),(0,L.jsxs)(`div`,{className:`mt-1.5 flex items-center`,children:[(0,L.jsxs)(`button`,{type:`button`,onClick:t,className:`flex items-center gap-1.5 rounded-full px-2 py-2 text-[14px] hover:bg-surface-2`,children:[(0,L.jsx)(At,{size:22,strokeWidth:1.8}),` `,r(`Discuss`)]}),(0,L.jsx)(`button`,{type:`button`,onClick:n,"aria-label":r(`About this post`),className:`ml-auto rounded-full p-2 hover:bg-surface-2`,children:(0,L.jsx)(xt,{size:22,strokeWidth:1.8})})]})]})})}function bh({instructions:e,onEdit:t,onAck:n}){let r=s();return(0,L.jsxs)(gh,{children:[(0,L.jsxs)(`div`,{className:`px-4 py-3.5`,children:[(0,L.jsx)(`div`,{className:`text-[17px] font-semibold`,children:r(`About the feed`)}),(0,L.jsx)(`p`,{className:`mt-1 text-[13px] leading-[18px] text-muted`,children:r(`Short posts your agent writes for you from what it remembers: your memory files, the last week of diary, your goals. The sentence below steers every post from now on; edit it any time.`)})]}),(0,L.jsxs)(`div`,{className:`border-t border-border/70 px-4 py-3.5`,children:[(0,L.jsx)(`p`,{className:`text-[15px] leading-[22px]`,children:e||r(`Build me a feed about what I care about. Keep it short and direct, easy to skim, no clickbait.`)}),(0,L.jsxs)(`div`,{className:`mt-3.5 flex justify-end gap-2.5`,children:[(0,L.jsx)(`button`,{type:`button`,onClick:t,className:`rounded-full bg-surface-2 px-6 py-2.5 text-[15px] font-medium`,children:r(`Edit`)}),(0,L.jsx)(`button`,{type:`button`,onClick:n,className:`rounded-full bg-accent px-6 py-2.5 text-[15px] font-semibold text-accent-fg`,children:r(`Got it`)})]})]})]})}function xh({emoji:e,title:t,body:n}){return(0,L.jsx)(gh,{children:(0,L.jsxs)(`div`,{className:`flex items-start gap-3 p-3.5`,children:[(0,L.jsx)(`div`,{className:`flex h-11 w-11 shrink-0 items-center justify-center rounded-xl bg-surface-2 text-[22px] leading-none`,children:e}),(0,L.jsxs)(`div`,{className:`min-w-0 flex-1`,children:[(0,L.jsx)(`div`,{className:`text-[16px] font-semibold leading-[22px]`,children:t}),(0,L.jsx)(`p`,{className:`mt-1 text-[15px] leading-[22px] text-fg/85`,children:n})]})]})})}function Sh({label:e,value:t}){return(0,L.jsxs)(`div`,{className:`flex items-start gap-3 text-[14.5px]`,children:[(0,L.jsx)(`span`,{className:`w-14 shrink-0 text-muted`,children:e}),(0,L.jsx)(`span`,{className:`min-w-0 flex-1 break-words`,children:t})]})}function Ch({open:e,onClose:t,data:n,writing:r,onChange:i,onWriteNow:a}){let{toast:o,state:c}=E(),l=s(),[u,d]=(0,I.useState)(``),[f,p]=(0,I.useState)(!1);(0,I.useEffect)(()=>{e&&d(n?.instructions??``)},[e,n]);let m=async()=>{p(!0);try{i(await M.setFeedInstructions({instructions:u})),t()}catch(e){o(e.message)}finally{p(!1)}},h=async e=>{try{i(await M.setFeedInstructions(e))}catch(e){o(e.message)}},g=c.settings?.llm_ready!==!1;return(0,L.jsx)(Dp,{open:e,onClose:t,title:l(`Feed`),children:(0,L.jsxs)(`div`,{className:`space-y-3 px-1 pb-2`,children:[(0,L.jsx)(`p`,{className:`text-[13px] leading-[18px] text-muted`,children:l(`Your feed is driven by the instruction below. Any edit you make here applies to every post from now on.`)}),(0,L.jsx)(`textarea`,{value:u,onChange:e=>d(e.target.value),rows:4,maxLength:2e3,placeholder:l(`Build me a feed about what I care about. Keep it short and direct, easy to skim, no clickbait.`),className:`w-full resize-none rounded-2xl bg-surface-2 px-3.5 py-2.5 text-[15px] leading-snug outline-none focus:ring-2 focus:ring-accent/40`}),(0,L.jsxs)(`div`,{className:`space-y-2 rounded-2xl bg-surface-2 px-3.5 py-2.5`,children:[(0,L.jsx)(Pe,{label:l(`Write it every day`),hint:n?.daily===!1?void 0:l(`Daily at {time}`,{time:n?.time??`08:00`}),checked:n?.daily!==!1,onChange:e=>void h({daily:e}),disabled:!n}),n?.daily!==!1&&(0,L.jsxs)(`label`,{className:`flex items-center justify-between gap-3 text-[13px] text-muted`,children:[(0,L.jsx)(`span`,{children:l(`Time of day`)}),(0,L.jsx)(`input`,{type:`time`,value:n?.time??`08:00`,onChange:e=>e.target.value&&void h({time:e.target.value}),className:`rounded-lg bg-surface px-2 py-1 text-[13px] text-fg outline-none focus:ring-2 focus:ring-accent/40`})]}),!g&&(0,L.jsx)(`div`,{className:`text-[12.5px] text-muted`,children:l(`Add a model first; the feed is written by your agent.`)})]}),(0,L.jsxs)(`button`,{type:`button`,onClick:a,disabled:r||!n||!g,className:`flex w-full items-center justify-center gap-2 rounded-full bg-surface-2 py-2.5 text-[15px] font-medium disabled:opacity-60`,children:[r?(0,L.jsx)(A,{size:16,className:`animate-spin`}):(0,L.jsx)(nn,{size:16,className:`text-accent`}),l(r?`Writing…`:`Write it now`)]}),(0,L.jsx)(`button`,{type:`button`,onClick:()=>void m(),disabled:f,className:`h-[46px] w-full rounded-full bg-accent text-[15px] font-semibold text-accent-fg disabled:opacity-60`,children:l(`Save`)})]})})}function wh({data:t,name:n,onSettings:r,onGoals:i}){let a=s(),o=t.queue[0],c=t.reminders.filter(e=>e.status===`active`&&!!e.next_at),l=c[0],d=c.length;return(0,L.jsxs)(`div`,{className:`rounded-3xl border border-border/70 bg-surface shadow-sm px-4 py-3.5`,children:[(0,L.jsxs)(`div`,{className:`flex items-center gap-2 text-[12px] uppercase tracking-wide text-muted font-semibold`,children:[(0,L.jsx)(Xe,{size:13}),` `,a(`Next up`)]}),t.proactive?o?(0,L.jsxs)(`div`,{className:`mt-1.5 text-[14px] leading-snug`,children:[t.busy?a(`Working now`):t.quiet_until?a(`Quiet hours after {time}`,{time:u(t.quiet_until)}):t.next_pass_at?a(`Around {time}`,{time:u(t.next_pass_at)}):a(`Soon`),`: `,(0,L.jsx)(`span`,{className:`font-medium`,children:o.title}),o.next_step&&(0,L.jsxs)(`span`,{className:`text-muted`,children:[` · `,o.next_step]}),o.overdue&&(0,L.jsxs)(`span`,{className:`text-rose-500 font-medium`,children:[` · `,a(`overdue`)]}),t.queue.length>1&&(0,L.jsxs)(`span`,{className:`text-muted`,children:[` · `,a(`{n} more in line`,{n:t.queue.length-1})]})]}):(0,L.jsxs)(`div`,{className:`mt-1.5 text-[14px] leading-snug`,children:[a(`No goal has a next step to work on.`),` `,(0,L.jsx)(`button`,{type:`button`,onClick:i,className:`text-accent font-medium`,children:a(`Add one`)})]}):(0,L.jsxs)(`div`,{className:`mt-1.5 text-[14px] leading-snug`,children:[a(`Background work is off. {name} only acts when you ask.`,{name:n}),` `,(0,L.jsx)(`button`,{type:`button`,onClick:r,className:`text-accent font-medium`,children:a(`Turn it on`)})]}),t.check_ins[0]&&(0,L.jsxs)(`div`,{className:`mt-1.5 text-[12.5px] text-muted`,children:[a(`Check-in on`),` `,(0,L.jsx)(`span`,{className:`font-medium text-fg`,children:t.check_ins[0].title}),` `,e(t.check_ins[0].at),t.check_ins.length>1&&` · ${a(`{n} more`,{n:t.check_ins.length-1})}`]}),l&&(0,L.jsxs)(`div`,{className:`mt-1.5 text-[12.5px] text-muted`,children:[l.kind===`task`?a(`Routine`):a(`Reminder`),` `,(0,L.jsx)(`span`,{className:`font-medium text-fg`,children:l.text}),` `,e(l.next_at),d>1&&` · ${a(`{n} more`,{n:d-1})}`]})]})}function Th({data:e,onAsk:t}){let n=s(),r=t=>t.start.slice(0,10)<=e.today,a=e.events.filter(r),o=e.events.filter(e=>!r(e)),c=new Date,l=e=>!e.all_day&&new Date(e.end)e.error),d=a.every(l)&&o.length>0,f=d?o:a;return(0,L.jsxs)(`div`,{className:`rounded-3xl border border-border/70 bg-surface shadow-sm px-4 py-3.5`,children:[(0,L.jsxs)(`div`,{className:`flex items-center gap-2 text-[12px] uppercase tracking-wide text-muted font-semibold`,children:[(0,L.jsx)(tt,{size:13}),` `,n(d?`Tomorrow`:`Today`),f.length>0&&(0,L.jsx)(`span`,{className:`ml-auto normal-case tracking-normal font-normal`,children:n(`{n} scheduled`,{n:f.length})})]}),f.length===0?(0,L.jsx)(`div`,{className:`mt-1.5 text-[14px] leading-snug text-muted`,children:n(`Nothing on the calendar today.`)}):(0,L.jsx)(`ul`,{className:`mt-1.5 space-y-1`,children:f.map(e=>(0,L.jsxs)(`li`,{className:i(`flex items-baseline gap-2.5 text-[14px] leading-snug`,!d&&l(e)&&`opacity-50`),children:[(0,L.jsx)(`span`,{className:`w-[86px] shrink-0 tabular-nums text-[12.5px] text-muted`,children:e.all_day?n(`all day`):`${e.start.slice(11,16)}–${e.end.slice(11,16)}`}),(0,L.jsxs)(`span`,{className:`min-w-0 flex-1`,children:[(0,L.jsx)(`span`,{className:`font-medium`,children:e.summary}),e.location&&(0,L.jsxs)(`span`,{className:`text-muted text-[12.5px]`,children:[` `,(0,L.jsx)(Dt,{size:11,className:`inline -mt-0.5`}),` `,e.location]})]})]},`${e.uid}-${e.start}`))}),u.length>0&&(0,L.jsx)(`div`,{className:`mt-1.5 text-[12px] text-rose-500`,children:n(`{name} could not be read`,{name:u.map(e=>e.name).join(`, `)})}),(0,L.jsx)(`button`,{type:`button`,onClick:t,className:`mt-2 text-[12.5px] text-accent font-medium`,children:n(`Ask about your week`)})]})}function Eh(e){return e.replace(/```[\s\S]*?```/g,` `).replace(/^#{1,6}\s+/gm,``).replace(/(\*\*|__|`)/g,``).replace(/^\s*[-*+]\s+/gm,`• `).replace(/\[([^\]]+)\]\([^)]*\)/g,`$1`).trim()}function Dh({item:n,unseen:r,onOpen:a}){let o=s(),c=n.kind===`approval`?(0,L.jsx)(Zt,{size:18}):n.kind===`question`?(0,L.jsx)(kt,{size:18}):n.kind===`artifact`?(0,L.jsx)(mt,{size:18}):n.quiet?(0,L.jsx)(Rt,{size:18}):n.title.startsWith(`New mail: `)?(0,L.jsx)(Et,{size:18}):n.title.startsWith(`Coming up: `)?(0,L.jsx)(et,{size:18}):n.title.startsWith(`Webhook: `)?(0,L.jsx)(_n,{size:18}):(0,L.jsx)(nn,{size:18}),l=n.kind===`approval`?`bg-amber-500/12 text-amber-600 dark:text-amber-300`:n.kind===`question`?`bg-accent/12 text-accent`:`bg-surface-2 text-muted`;return n.quiet?(0,L.jsxs)(`button`,{type:`button`,onClick:a,className:`w-full text-left px-2 py-1.5 flex items-center gap-2 text-[12.5px] text-muted`,children:[(0,L.jsx)(Rt,{size:13,className:`shrink-0`}),(0,L.jsxs)(`span`,{className:`truncate`,children:[o(`{label}: nothing new`,{label:t(n.title.replace(/^Working on your goal: /,``))}),n.text?`: ${n.text}`:``]}),(0,L.jsx)(`span`,{className:`ml-auto shrink-0`,children:e(n.ts)})]}):(0,L.jsx)(`button`,{type:`button`,onClick:a,className:i(`w-full text-left rounded-3xl border bg-surface shadow-sm px-4 py-3 active:scale-[0.99] transition`,r?`border-accent/40`:`border-border/70`),children:(0,L.jsxs)(`div`,{className:`flex items-start gap-3`,children:[(0,L.jsx)(`div`,{className:i(`rounded-2xl p-2 mt-0.5`,l),children:c}),(0,L.jsxs)(`div`,{className:`flex-1 min-w-0`,children:[(0,L.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,L.jsx)(`div`,{className:`font-semibold text-[14.5px] leading-snug truncate`,children:t(n.title)}),r&&(0,L.jsx)(`span`,{className:`h-2 w-2 rounded-full bg-accent shrink-0`})]}),n.text&&(0,L.jsx)(`div`,{className:`mt-0.5 text-[13.5px] text-muted leading-snug line-clamp-3 whitespace-pre-wrap`,children:Eh(n.text)}),(0,L.jsxs)(`div`,{className:`mt-1.5 flex items-center gap-2 text-[12px] text-muted`,children:[(0,L.jsx)(`span`,{children:e(n.ts)}),(0,L.jsx)(`span`,{children:`·`}),(0,L.jsx)(`span`,{className:`truncate`,children:n.thread===`main`?o(n.thread_title):n.thread_title}),(0,L.jsxs)(`span`,{className:`ml-auto flex items-center gap-1 text-accent font-medium`,children:[n.kind===`artifact`?o(`Open`):n.kind===`approval`||n.kind===`question`?o(`Answer`):o(`Open chat`),(0,L.jsx)(qe,{size:13})]})]})]})]})})}function Oh(e){let t=new Date,n=new Date(t);n.setDate(t.getDate()-1);let r=e=>{let r=new Date(e);return r.toDateString()===t.toDateString()?_(`Today`):r.toDateString()===n.toDateString()?_(`Yesterday`):r.toLocaleDateString(m(),{weekday:`long`,month:`short`,day:`numeric`})},i=new Map;for(let t of e){let e=r(t.ts);i.set(e,[...i.get(e)??[],t])}return[...i.entries()]}function kh({children:e,className:t}){return(0,L.jsx)(`div`,{className:i(`mx-4 overflow-hidden rounded-2xl bg-surface dark:border dark:border-border`,t),children:e})}function Ah({inset:e=52}){return(0,L.jsx)(`div`,{className:i(`border-t border-border/60`,e===52?`ml-[52px]`:`ml-4`)})}function jh({icon:e,label:t,value:n,onClick:r,external:a=!1,trailing:o,chevron:s=!0}){let c=(0,L.jsxs)(L.Fragment,{children:[e&&(0,L.jsx)(`span`,{className:`shrink-0 text-fg`,children:e}),(0,L.jsx)(`span`,{className:i(`min-w-0 truncate text-[16px] leading-[21px]`,n?`max-w-[60%] shrink-0`:`flex-1`),children:t}),n&&(0,L.jsx)(`span`,{className:`min-w-0 flex-1 truncate pl-3 text-right text-[14px] leading-[18px] text-muted`,children:n}),o??(s?a?(0,L.jsx)(Ae,{size:16,className:`shrink-0 text-muted/70`}):(0,L.jsx)(rt,{size:18,className:`shrink-0 text-muted/70`}):null)]}),l=`flex min-h-[54px] w-full items-center gap-3.5 px-4 py-2 text-left`;return r?(0,L.jsx)(`button`,{type:`button`,onClick:r,className:i(l,`hover:bg-surface-2/60`),children:c}):(0,L.jsx)(`div`,{className:l,children:c})}function Mh({icon:e,label:t,value:n,checked:r,disabled:a=!1,onChange:o}){return(0,L.jsxs)(`button`,{type:`button`,role:`switch`,"aria-checked":r,disabled:a,onClick:()=>o(!r),className:i(`flex min-h-[54px] w-full items-center gap-3.5 px-4 py-2 text-left`,a?`opacity-60`:`hover:bg-surface-2/60`),children:[e&&(0,L.jsx)(`span`,{className:`shrink-0 text-fg`,children:e}),(0,L.jsx)(`span`,{className:i(`min-w-0 truncate text-[16px] leading-[21px]`,n?`max-w-[60%] shrink-0`:`flex-1`),children:t}),n&&(0,L.jsx)(`span`,{className:`min-w-0 flex-1 truncate pl-3 text-right text-[14px] leading-[18px] text-muted`,children:n}),(0,L.jsx)(Nh,{checked:r})]})}function Nh({checked:e}){return(0,L.jsx)(`span`,{"aria-hidden":!0,className:i(`relative h-7 w-12 shrink-0 rounded-full transition`,e?`bg-accent`:`bg-surface-2 border border-border`),children:(0,L.jsx)(`span`,{className:i(`absolute top-0.5 h-6 w-6 rounded-full bg-white shadow transition`,e?`left-[22px]`:`left-0.5`)})})}function Ph({children:e,className:t}){return(0,L.jsx)(`p`,{className:i(`px-8 py-2 text-[13px] leading-[18px] text-muted`,t),children:e})}function Fh({children:e}){return(0,L.jsx)(`p`,{className:`px-8 pb-2 pt-[18px] text-[13px] leading-[18px] text-muted`,children:e})}function Ih({me:e,onChanged:t,flush:n=!1}){let r=s(),{state:a,toast:o}=E(),c=!!a.hub?.account.signed_in,[l,u]=(0,I.useState)(null),[d,f]=(0,I.useState)(!1),p=e??l,m=async()=>{if(c&&!e)try{u(await M.cloudMe())}catch{}};(0,I.useEffect)(()=>{m()},[c,e]);let h=p?.contribute??{on:!1,samples:0},g=h.samples??0,_=h.privacy_url||``,v=async n=>{f(!0);try{await M.cloudContribute(n),o(r(n?`On. Turn it off here at any time.`:`Off. Nothing more is kept.`)),e?t?.():await m()}catch(e){o(e.message)}finally{f(!1)}},y=async()=>{if(window.confirm(r(`The kept conversations are removed from the server. This cannot be undone.`))){f(!0);try{let n=await M.cloudDeleteSamples();o(r(`{n} turns deleted`,{n:String(n.deleted)})),e?t?.():await m()}catch(e){o(e.message)}finally{f(!1)}}};return(0,L.jsxs)(`div`,{className:i(n&&`-mx-4`),children:[(0,L.jsx)(Lh,{signedIn:c}),(0,L.jsx)(kh,{children:(0,L.jsx)(Mh,{label:r(`Help improve nanoMuse's AI models`),checked:c&&h.on,disabled:d||!c||!p,onChange:e=>void v(e)})}),(0,L.jsxs)(Ph,{children:[r(`While this is on, the text of your chats with the nanoMuse Cloud models (what you wrote, what it answered and the tools it chose to call) is kept on the relay to train the community's own open model. Not your memory or SOUL (the system prompt), not what tools returned, not pictures, and never next to who you are. Your own API key never passes through the relay.`),` `,c?h.default_on!==void 0&&(h.default_on?r(`New accounts start with it on.`):r(`New accounts start with it off.`)):r(`Sign in to nanoMuse Cloud to use it.`),` `,c&&g>0&&r(`{n} turns kept so far.`,{n:String(g)}),` `,_?(0,L.jsx)(`a`,{href:_,target:`_blank`,rel:`noopener noreferrer`,className:`text-accent underline-offset-2 hover:underline`,children:r(`Privacy policy`)}):null]}),c&&g>0&&(0,L.jsxs)(kh,{className:`mt-3`,children:[(0,L.jsx)(jh,{icon:d?(0,L.jsx)(A,{size:22,className:`animate-spin`}):(0,L.jsx)(fn,{size:22}),label:r(`Delete the kept conversations`),value:r(`{n} turns`,{n:String(g)}),onClick:()=>void y(),chevron:!1}),(0,L.jsx)(Ah,{inset:16}),(0,L.jsx)(Ph,{className:`px-4 pb-2.5 pt-2`,children:r(`Removes every turn kept from this account, whether the switch is on or off now. Turning the switch off keeps what was kept until you delete it here.`)})]})]})}function Lh({signedIn:e}){let t=s(),{toast:n}=E(),[r,i]=(0,I.useState)(null),[a,o]=(0,I.useState)(!1),c=r?.relay?.counts??{conversations:0,messages:0},l=e&&(c.conversations>0||c.messages>0),u=async()=>{try{i(await M.syncState())}catch{}};(0,I.useEffect)(()=>{u()},[e]);let d=async(e,t)=>{o(!0);try{i(await e()),n(t)}catch(e){n(e.message),await u()}finally{o(!1)}},f=e=>{(e||!l||window.confirm(t(`Off deletes the synced conversations from nanoMuse Cloud. The chats on each device stay.`)))&&d(()=>M.syncSetState(e),t(e?`On. Your devices show the same conversations from now on.`:`Off. Nothing is kept on nanoMuse Cloud any more.`))},p=()=>{window.confirm(t(`The synced conversations are removed from nanoMuse Cloud. The chats on each device stay. This cannot be undone.`))&&d(()=>M.syncDelete(),t(`Synced conversations deleted.`))},m=e=>{d(()=>M.syncSetSideChats(e),t(e?`On. This device's side chats go to the account; the other devices' are on their way.`:`Off. Side chats stay on this device from now on.`))},h=e&&!!r?.enabled;return(0,L.jsxs)(`div`,{className:`mb-6`,children:[(0,L.jsx)(kh,{children:(0,L.jsx)(Mh,{label:t(`Sync conversations between my devices`),checked:h,disabled:a||!e||!r,onChange:f})}),(0,L.jsxs)(Ph,{children:[t(`The text of your chats is kept on nanoMuse Cloud so every device shows the same conversations. Files and images stay on the device they were made on.`),` `,e?r?.paused?t(`Paused: sign in again to continue.`):l&&t(`{c} chats, {m} messages kept so far.`,{c:String(c.conversations),m:String(c.messages)}):t(`Sign in to nanoMuse Cloud to use it.`)]}),r&&`side_chats`in r&&(0,L.jsxs)(L.Fragment,{children:[(0,L.jsx)(kh,{className:`mt-3`,children:(0,L.jsx)(Mh,{label:t(`Also sync side chats`),checked:h&&!!r.side_chats,disabled:a||!h,onChange:m})}),(0,L.jsx)(Ph,{children:t(`Off: side chats stay on this device. On: this device's side chats go to the account and the other devices' side chats come here.`)})]}),l&&(0,L.jsxs)(kh,{className:`mt-3`,children:[(0,L.jsx)(jh,{icon:a?(0,L.jsx)(A,{size:22,className:`animate-spin`}):(0,L.jsx)(fn,{size:22}),label:t(`Delete synced conversations`),value:t(`{n} chats`,{n:String(c.conversations)}),onClick:p,chevron:!1}),(0,L.jsx)(Ah,{inset:16}),(0,L.jsx)(Ph,{className:`px-4 pb-2.5 pt-2`,children:t(`Removes what nanoMuse Cloud stores for this account; the chats on each device stay, and the switch stays on. Deleting a chat on one device deletes it on all of them.`)})]})]})}var Rh=`nm.invite`;function zh(){try{let e=new URLSearchParams(window.location.search).get(`invite`);if(e){let t=Bh(e);t&&localStorage.setItem(Rh,t)}return localStorage.getItem(Rh)??``}catch{return``}}function Bh(e){return e.toUpperCase().replace(/[^A-Z0-9]/g,``).slice(0,8)}function Vh(e){return/^\s*[+\d]/.test(e)?`tel`:`email`}function Hh({onSignedIn:e,useAsModel:t=!1,cta:n,autoFocus:r=!0}){let a=s(),o=(0,I.useId)(),c=Ce(),[l,u]=(0,I.useState)(`code`),[d,f]=(0,I.useState)(``),[p,m]=(0,I.useState)(``),[h,g]=(0,I.useState)(``),[_,v]=(0,I.useState)(!1),[y,b]=(0,I.useState)(null),[x,S]=(0,I.useState)(null),[C,w]=(0,I.useState)(``),[T,E]=(0,I.useState)(!1);(0,I.useEffect)(()=>{let e=zh();e&&(w(e),E(!0))},[]);let D=async()=>{if(t){b(`model`);try{await M.cloudUseAsModel()}catch{}}await e()},O=async()=>{let e=d.trim();if(e){b(`code`),S(null);try{await M.cloudCode(e),v(!0)}catch(e){S(a(e.message))}finally{b(null)}}},k=async()=>{let e=d.trim();if(!(!e||p.trim().length<4)){b(`verify`),S(null);try{(await M.cloudVerify(e,p.trim(),C.trim())).created&&Bf(),m(``),v(!1);try{localStorage.removeItem(Rh)}catch{}await D()}catch(e){S(a(e.message))}finally{b(null)}}},ee=async()=>{let e=d.trim();if(e&&h){b(`login`),S(null);try{await M.cloudLogin(e,h),g(``),await D()}catch(e){S(a(e.message))}finally{b(null)}}},te=()=>void(l===`password`?ee():_?k():O()),j=n??a(t?`Sign in and use its model`:`Sign in`);return(0,L.jsxs)(`form`,{className:`space-y-3`,onSubmit:e=>{e.preventDefault(),te()},children:[(0,L.jsxs)(`div`,{className:`grid grid-cols-2 gap-1 rounded-2xl bg-surface-2/70 p-1 text-[13px] font-medium`,children:[(0,L.jsx)(Uh,{active:l===`code`,onClick:()=>u(`code`),icon:(0,L.jsx)(Mt,{size:14}),label:a(`With a code`)}),(0,L.jsx)(Uh,{active:l===`password`,onClick:()=>u(`password`),icon:(0,L.jsx)(P,{size:14}),label:a(`With a password`)})]}),(0,L.jsxs)(`div`,{children:[(0,L.jsx)(`label`,{htmlFor:`${o}-id`,className:`text-[12px] text-muted`,children:ue()?a(`Mainland China phone number or e-mail`):a(`E-mail (or a mainland China phone number)`)}),(0,L.jsx)(`input`,{id:`${o}-id`,value:d,onChange:e=>{f(e.target.value),v(!1)},inputMode:Vh(d),autoComplete:`username`,autoFocus:r,placeholder:a(`138 0000 0000 or you@example.com`),className:i(Ie,`mt-1`)}),l===`code`&&!_&&(!ue()||oe(d))&&(0,L.jsx)(`p`,{className:`mt-1.5 text-[12px] text-muted`,children:a(`Text-message codes reach mainland-China numbers only. Use an e-mail address instead.`)})]}),l===`password`?(0,L.jsxs)(`div`,{children:[(0,L.jsx)(`label`,{htmlFor:`${o}-password`,className:`text-[12px] text-muted`,children:a(`Password`)}),(0,L.jsx)(`input`,{id:`${o}-password`,type:`password`,value:h,onChange:e=>g(e.target.value),autoComplete:`current-password`,className:i(Ie,`mt-1`)}),(0,L.jsx)(`p`,{className:`mt-1.5 text-[12px] text-muted`,children:a(`No password yet? Use a code first; set one under Account.`)})]}):(0,L.jsxs)(L.Fragment,{children:[_&&(0,L.jsxs)(`div`,{children:[(0,L.jsx)(`label`,{htmlFor:`${o}-code`,className:`text-[12px] text-muted`,children:a(`The code you received`)}),(0,L.jsx)(`input`,{id:`${o}-code`,value:p,onChange:e=>m(e.target.value.replace(/\D/g,``).slice(0,8)),inputMode:`numeric`,autoComplete:`one-time-code`,placeholder:`123456`,autoFocus:!0,className:i(`w-full rounded-2xl bg-surface-2 px-3.5 py-2.5 text-[14.5px] outline-none focus:ring-2 focus:ring-accent/40`,`mt-1 tracking-[0.3em]`)})]}),T?(0,L.jsxs)(`div`,{children:[(0,L.jsx)(`label`,{htmlFor:`${o}-invite`,className:`text-[12px] text-muted`,children:a(`Invite code (optional)`)}),(0,L.jsx)(`input`,{id:`${o}-invite`,value:C,onChange:e=>w(Bh(e.target.value)),autoComplete:`off`,placeholder:`ABCD2345`,className:i(Ie,`mt-1 tracking-[0.2em] uppercase`)}),(0,L.jsx)(`p`,{className:`mt-1.5 text-[12px] text-muted`,children:a(`A friend's code counts for a new account: you both get ¥{invite} more allowance.`,{invite:(c.invite_bonus_cny??5).toFixed(0)})})]}):(0,L.jsx)(`button`,{type:`button`,onClick:()=>E(!0),className:`text-[12px] text-muted underline-offset-2 hover:underline`,children:a(`Have an invite code?`)})]}),x&&(0,L.jsx)(`div`,{className:`rounded-2xl bg-rose-500/12 px-3 py-2 text-[12.5px] text-rose-700 dark:text-rose-300`,children:x}),(0,L.jsx)(`div`,{className:`flex gap-2`,children:l===`code`&&_?(0,L.jsxs)(L.Fragment,{children:[(0,L.jsx)(`button`,{type:`button`,disabled:y!==null,onClick:()=>void O(),className:je,children:a(`Send again`)}),(0,L.jsxs)(`button`,{type:`submit`,disabled:y!==null||p.trim().length<4,className:i(Ne,`flex-1 py-3`),children:[y?(0,L.jsx)(A,{size:15,className:`animate-spin`}):null,` `,j]})]}):l===`code`?(0,L.jsxs)(`button`,{type:`submit`,disabled:y!==null||!d.trim(),className:i(Ne,`flex-1 py-3`),children:[y===`code`?(0,L.jsx)(A,{size:15,className:`animate-spin`}):null,` `,a(`Send me a code`)]}):(0,L.jsxs)(`button`,{type:`submit`,disabled:y!==null||!d.trim()||!h,className:i(Ne,`flex-1 py-3`),children:[y?(0,L.jsx)(A,{size:15,className:`animate-spin`}):null,` `,j]})})]})}function Uh({active:e,onClick:t,icon:n,label:r}){return(0,L.jsxs)(`button`,{type:`button`,onClick:t,"aria-pressed":e,className:i(`flex items-center justify-center gap-1.5 rounded-xl px-2 py-2 transition`,e?`bg-surface text-fg shadow-sm`:`text-muted hover:text-fg`),children:[n,` `,r]})}function Wh(){let{state:e,refreshSettings:t,refreshHub:n,toast:r,skipSignIn:i}=E(),a=s(),o=e.profile?.name??`nanoMuse`,c=(0,L.jsxs)(`ul`,{className:`grid grid-cols-2 gap-2 text-[12.5px] wide:grid-cols-1 wide:gap-1.5 wide:text-[13.5px]`,children:[(0,L.jsx)(Gh,{icon:(0,L.jsx)(It,{size:15}),text:a(`Every device of yours, one nanoMuse`)}),(0,L.jsx)(Gh,{icon:(0,L.jsx)(st,{size:15}),text:a(`A model with a free allowance, or your own key`)}),(0,L.jsx)(Gh,{icon:(0,L.jsx)(vt,{size:15}),text:a(`It uses your phone and computers for you`)}),(0,L.jsx)(Gh,{icon:(0,L.jsx)(Qt,{size:15}),text:a(`Keys in your vault; nothing you say is kept on the relay`)})]});return(0,L.jsxs)(`div`,{className:`relative mx-auto flex h-[100dvh] w-full max-w-[760px] flex-col overflow-hidden bg-bg sm:border-x sm:border-border wide:max-w-none wide:border-0`,children:[(0,L.jsx)(`div`,{className:`pointer-events-none absolute inset-x-0 top-0 h-[46vh] bg-[radial-gradient(ellipse_at_top,rgba(0,100,212,0.14),transparent_65%)] dark:bg-[radial-gradient(ellipse_at_top,rgba(23,147,255,0.2),transparent_65%)] wide:inset-y-0 wide:h-auto wide:bg-[radial-gradient(ellipse_at_left,rgba(0,100,212,0.12),transparent_60%)] wide:dark:bg-[radial-gradient(ellipse_at_left,rgba(23,147,255,0.16),transparent_60%)]`}),(0,L.jsx)(`div`,{className:`titlebar-room relative`}),(0,L.jsx)(`div`,{className:`relative flex-1 overflow-y-auto px-6 pb-8 wide:flex wide:items-center wide:px-12`,children:(0,L.jsxs)(`div`,{className:`mx-auto w-full wide:grid wide:max-w-[980px] wide:grid-cols-[1.1fr_1fr] wide:items-center wide:gap-16`,children:[(0,L.jsxs)(`div`,{className:`safe-top flex flex-col items-center pt-14 text-center wide:items-start wide:pt-0 wide:text-left`,children:[(0,L.jsx)(xn,{size:88,className:`drop-shadow-[0_20px_40px_rgba(0,100,212,0.28)]`}),(0,L.jsx)(`h1`,{className:`mt-6 text-[28px] font-bold tracking-tight wide:text-[34px]`,children:a(`Sign in to {name}`,{name:o})}),(0,L.jsx)(`p`,{className:`mt-2 max-w-sm text-[14.5px] leading-relaxed text-muted wide:max-w-md wide:text-[15.5px]`,children:a(`One free account. It is what lets your phone and computers work as one and brings a model to start with.`)}),(0,L.jsx)(`div`,{className:`mt-7 hidden w-full wide:block`,children:c}),(0,L.jsx)(Te,{compact:!0,className:`mt-6 hidden w-full wide:block`})]}),(0,L.jsxs)(`div`,{children:[(0,L.jsx)(`div`,{className:`mt-8 rounded-[28px] border border-border/70 bg-surface p-5 shadow-sm wide:mt-0 wide:p-7`,children:(0,L.jsx)(Hh,{onSignedIn:async()=>{r(a(`Signed in to nanoMuse Cloud.`)),await Promise.all([t(),n()])}})}),(0,L.jsx)(`button`,{type:`button`,onClick:i,className:`mt-4 w-full rounded-2xl border border-border/70 px-4 py-2.5 text-[13.5px] text-fg/80 hover:bg-surface-2`,"data-testid":`sign-in-skip`,children:a(`Use your own API key instead`)}),(0,L.jsx)(`p`,{className:`mt-2 text-center text-[11.5px] leading-relaxed text-muted`,children:a(`You can sign in later under Connections, for sync and your devices.`)}),(0,L.jsx)(`div`,{className:`mt-6 wide:hidden`,children:c}),(0,L.jsx)(Te,{compact:!0,className:`mt-6 wide:hidden`}),(0,L.jsxs)(`p`,{className:`mt-4 text-center text-[11.5px] leading-relaxed text-muted wide:mt-5`,children:[a(`The relay keeps an account id, a masked identifier, usage counts and your agent's name and look; what else, and what is yours to switch off, is in the`),` `,a(`relay privacy policy (ask your relay operator)`),`.`]})]})]})})]})}function Gh({icon:e,text:t}){return(0,L.jsxs)(`li`,{className:`flex items-start gap-2 rounded-2xl bg-surface-2/60 px-3 py-2.5 text-fg/80 wide:bg-transparent wide:px-0 wide:py-1`,children:[(0,L.jsx)(`span`,{className:`mt-0.5 text-accent`,children:e}),(0,L.jsx)(`span`,{className:`leading-snug`,children:t})]})}function Kh(e,t,n){return!e||!e.account.required||e.account.signed_in||t?.llm_ready?!1:!n}var qh=`modulepreload`,Jh=function(e){return`/`+e},Yh={},Xh=function(e){return e.pathname.endsWith(`.css`)},Zh=function(e,t,n){let r=Promise.resolve();if(t&&t.length>0){let e,i=document.querySelector(`meta[property=csp-nonce]`),a=i?.nonce||i?.getAttribute(`nonce`);function o(e){return Promise.all(e.map(e=>Promise.resolve(e).then(e=>({status:`fulfilled`,value:e}),e=>({status:`rejected`,reason:e}))))}function s(e){return import.meta.resolve?new URL(import.meta.resolve(e)):new URL(e,import.meta.url)}r=o(t.map(t=>{t=Jh(t,n);let r=s(t);if(r.href in Yh)return;Yh[r.href]=!0;let i=Xh(r);if(e===void 0){e={all:new Set,styles:new Set};let t=document.getElementsByTagName(`link`);for(let n=t.length-1;n>=0;n--){let r=t[n];e.all.add(r.href),r.rel===`stylesheet`&&e.styles.add(r.href)}}if((i?e.styles:e.all).has(r.href))return;let o=document.createElement(`link`);if(o.rel=i?`stylesheet`:qh,i||(o.as=`script`),o.crossOrigin=``,o.href=r.href,a&&o.setAttribute(`nonce`,a),document.head.appendChild(o),i)return new Promise((e,t)=>{o.addEventListener(`load`,e),o.addEventListener(`error`,()=>t(Error(`Unable to preload CSS for ${r}`)))})}).filter(e=>e!==void 0))}function i(e){let t=new Event(`vite:preloadError`,{cancelable:!0});if(t.payload=e,window.dispatchEvent(t),!t.defaultPrevented)throw e}return r.then(t=>{for(let e of t||[])e.status===`rejected`&&i(e.reason);return e().catch(i)})},Qh=(0,I.lazy)(()=>Zh(()=>import(`./AccountScreen-Bws27b-C.js`).then(e=>({default:e.AccountScreen})),__vite__mapDeps([0,1,2,3,4,5,6,7,8]))),$h=(0,I.lazy)(()=>Zh(()=>import(`./AvatarStudioScreen-Dgqo0TEO.js`).then(e=>({default:e.AvatarStudioScreen})),__vite__mapDeps([9,1,2,3,4,10,8,11]))),eg=(0,I.lazy)(()=>Zh(()=>import(`./ChannelsScreen-D_7Ynsew.js`).then(e=>({default:e.ChannelsScreen})),__vite__mapDeps([12,1,3,4,10,8]))),tg=(0,I.lazy)(()=>Zh(()=>import(`./CodingScreen-BLVF-Er8.js`).then(e=>({default:e.CodingScreen})),__vite__mapDeps([13,1,4,10,8]))),ng=(0,I.lazy)(()=>Zh(()=>import(`./ConnectionsScreen-CuIVN07d.js`).then(e=>({default:e.ConnectionsScreen})),__vite__mapDeps([14,1,2,3,4,5,7,15,10,8,16]))),rg=(0,I.lazy)(()=>Zh(()=>import(`./DevicesScreen-BkPa89LS.js`).then(e=>({default:e.DevicesScreen})),__vite__mapDeps([17,1,3,4,10,8,16]))),ig=(0,I.lazy)(()=>Zh(()=>import(`./GoalsScreen-yUUdUKV2.js`).then(e=>({default:e.GoalsScreen})),__vite__mapDeps([18,1,2,3,4]))),ag=(0,I.lazy)(()=>Zh(()=>import(`./IdeasScreen-CmecfnoP.js`).then(e=>({default:e.IdeasScreen})),__vite__mapDeps([19,1,10]))),og=(0,I.lazy)(()=>Zh(()=>import(`./LibraryScreen-BoofKOos.js`).then(e=>({default:e.LibraryScreen})),__vite__mapDeps([20,1]))),sg=(0,I.lazy)(()=>Zh(()=>import(`./MemoryScreen-DHNxjNpq.js`).then(e=>({default:e.MemoryScreen})),__vite__mapDeps([21,1,8]))),cg=(0,I.lazy)(()=>Zh(()=>import(`./Onboarding-DBBDNzyW.js`).then(e=>({default:e.Onboarding})),__vite__mapDeps([22,1,2,3,4,23,11,14,5,7,15,10,8,16]))),lg=(0,I.lazy)(()=>Zh(()=>import(`./SettingsScreen-B84xmoRg.js`).then(e=>({default:e.SettingsScreen})),__vite__mapDeps([24,1,2,3,4,5,6,15,23,11,8]))),ug=(0,I.lazy)(()=>Zh(()=>import(`./SkillsScreen-DsMpJe1f.js`).then(e=>({default:e.SkillsScreen})),__vite__mapDeps([25,1,8])));function dg(){return(0,L.jsx)(`div`,{className:`flex h-full min-h-[40vh] items-center justify-center text-muted`,children:(0,L.jsx)(A,{className:`animate-spin`,size:20})})}var fg=e=>({size:26,strokeWidth:e?2:1.7,fill:e?`currentColor`:`none`,fillOpacity:e?.18:0}),pg=[{id:`chat`,label:`Chat`,icon:e=>(0,L.jsx)(At,{...fg(e)})},{id:`feed`,label:`Feed`,icon:e=>(0,L.jsx)(Bt,{...fg(e)})},{id:`ideas`,label:`Ideas`,icon:e=>(0,L.jsx)(Ct,{...fg(e)})},{id:`goals`,label:`Goals`,icon:e=>(0,L.jsx)(rn,{...fg(e)})},{id:`library`,label:`Library`,icon:e=>(0,L.jsx)(St,{...fg(e)})}];function mg(){let{state:e,setTab:t,openFile:n}=E(),r=Uf(),a=s();(0,I.useEffect)(()=>{let t=e.profile?.name?.trim();document.title=t&&t.toLowerCase()!==`nanomuse`?`${t} · nanoMuse`:`nanoMuse`},[e.profile?.name]),(0,I.useEffect)(()=>{let e=Sn()?.onQuickChat?.(()=>{t(`chat`),requestAnimationFrame(()=>window.dispatchEvent(new Event(`nanomuse:quick-chat`)))});return()=>{typeof e==`function`&&e()}},[t]),(0,I.useEffect)(()=>{let e=()=>{let e=window.location.hash.slice(1);(e&&pg.some(t=>t.id===e)||e===`devices`||e===`you`||e===`memory`||e===`connections`||e===`channels`||e===`skills`||e===`account`||e===`coding`||e===`avatar`)&&t(e)};return e(),window.addEventListener(`hashchange`,e),()=>window.removeEventListener(`hashchange`,e)},[t]);let o=r&&e.hub?.account.signed_in?(0,L.jsx)(Wf,{}):null,c=e.lite&&e.settings!==null&&!e.settings.onboarded;if((0,I.useEffect)(()=>{c&&M.onboarded(!0).catch(()=>void 0)},[c]),e.authError)return(0,L.jsx)(gg,{});if(!e.loaded)return(0,L.jsx)(hg,{error:e.error});if(Kh(e.hub,e.settings,e.signInSkipped))return(0,L.jsx)(Wh,{});if(!e.lite&&e.settings&&!e.settings.onboarded&&!e.onboardingDismissed&&!e.threads.some(e=>e.events>0))return(0,L.jsxs)(I.Suspense,{fallback:(0,L.jsx)(dg,{}),children:[(0,L.jsx)(cg,{}),o]});let l=e.pendingApprovals.length,u=e.goals.filter(e=>e.proposal&&e.status!==`cancelled`).length,d=e.pendingApprovals.filter(t=>t.ts>e.feedSeenAt).length;return(0,L.jsxs)(`div`,{className:i(`mx-auto flex h-[100dvh] max-w-[760px] flex-col bg-bg sm:border-x sm:border-border`,!e.lite&&`wide:max-w-none wide:flex-row wide:border-x-0`),children:[!e.lite&&(0,L.jsx)(`div`,{className:`hidden wide:block wide:h-full`,children:(0,L.jsx)(lh,{})}),(0,L.jsxs)(`div`,{className:`relative flex min-h-0 min-w-0 flex-1 flex-col`,children:[e.gone&&(0,L.jsxs)(`div`,{className:`flex items-center justify-center gap-2 bg-surface-2 text-muted text-[12.5px] py-1`,children:[(0,L.jsx)(vn,{size:14}),` `,a(e.lite?`This demo has ended.`:`This nanoMuse has stopped. Reload the page once it is running again.`)]}),!e.gone&&!e.connected&&e.loaded&&(0,L.jsxs)(`div`,{className:`flex items-center justify-center gap-2 bg-amber-500/15 text-amber-700 dark:text-amber-300 text-[12.5px] py-1`,children:[(0,L.jsx)(vn,{size:14}),` `,a(`Reconnecting to your nanoMuse…`)]}),!e.lite&&(0,L.jsx)(En,{}),(0,L.jsx)(`main`,{className:i(`tabbar-room mx-auto min-h-0 w-full flex-1 wide:max-w-[900px]`,!e.lite&&`wide:pb-0`),children:(0,L.jsxs)(I.Suspense,{fallback:(0,L.jsx)(dg,{}),children:[e.tab===`chat`&&(0,L.jsx)(Um,{}),e.tab===`feed`&&(0,L.jsx)(uh,{}),e.tab===`ideas`&&(0,L.jsx)(ag,{}),e.tab===`goals`&&(0,L.jsx)(ig,{}),e.tab===`library`&&(0,L.jsx)(og,{}),e.tab===`memory`&&(0,L.jsx)(sg,{}),e.tab===`skills`&&(0,L.jsx)(ug,{}),e.tab===`connections`&&(0,L.jsx)(ng,{}),e.tab===`channels`&&(0,L.jsx)(eg,{}),e.tab===`devices`&&(0,L.jsx)(rg,{}),e.tab===`you`&&(0,L.jsx)(lg,{}),e.tab===`account`&&(0,L.jsx)(Qh,{}),e.tab===`coding`&&(0,L.jsx)(tg,{}),e.tab===`avatar`&&(0,L.jsx)($h,{})]})}),(0,L.jsx)(`nav`,{className:i(`tabbar-float pointer-events-none absolute inset-x-0 z-20 flex justify-center px-3`,!e.lite&&`wide:hidden`),children:(0,L.jsx)(`ul`,{className:`pointer-events-auto flex w-full max-w-[420px] items-center gap-0.5 rounded-full bg-surface-2/55 px-3.5 py-1.5 ring-1 ring-border/50 backdrop-blur-2xl`,children:pg.map(n=>{let r=e.tab===n.id,o=n.id===`chat`?l:n.id===`feed`?d:n.id===`goals`?u:0;return(0,L.jsx)(`li`,{className:`min-w-0 flex-1`,children:(0,L.jsx)(`button`,{type:`button`,onClick:()=>t(n.id),"aria-label":a(n.label),"aria-current":r?`page`:void 0,className:i(`flex h-[46px] w-full items-center justify-center`,r?`text-ink-fg`:`text-muted hover:text-fg`),children:(0,L.jsxs)(`span`,{className:i(`relative flex h-[46px] w-full max-w-[60px] items-center justify-center rounded-full transition-colors duration-300`,r&&`bg-ink`),children:[n.icon(r),o>0&&(0,L.jsx)(`span`,{className:`absolute right-2.5 top-1 flex h-[17px] min-w-[17px] items-center justify-center rounded-full bg-rose-500 px-1 text-[10px] font-bold text-white`,children:o})]})})},n.id)})})})]}),(0,L.jsx)(kn,{}),(0,L.jsx)(hf,{path:e.viewer,onClose:()=>n(null)}),o,e.toast&&(0,L.jsx)(`div`,{className:`pointer-events-none fixed inset-x-0 bottom-[calc(6rem+env(safe-area-inset-bottom))] z-[70] flex justify-center px-4`,children:(0,L.jsx)(`div`,{role:`status`,className:`rise rounded-2xl bg-fg text-bg px-4 py-2 text-[13.5px] shadow-lg max-w-sm text-center`,children:e.toast})})]})}function hg({error:e}){let t=s();return(0,L.jsxs)(`div`,{className:`mx-auto flex h-[100dvh] max-w-sm flex-col items-center justify-center px-6 text-center`,children:[(0,L.jsx)(xn,{size:72}),e?(0,L.jsxs)(L.Fragment,{children:[(0,L.jsx)(`p`,{className:`mt-6 text-[15px] font-medium`,children:t(`Could not reach your nanoMuse.`)}),(0,L.jsx)(`p`,{className:`mt-1.5 text-[13px] text-muted`,children:t(e)}),(0,L.jsx)(`button`,{type:`button`,onClick:()=>window.location.reload(),className:`mt-5 rounded-full bg-fg px-5 py-2 text-[14px] font-medium text-bg`,children:t(`Try again`)})]}):(0,L.jsxs)(`p`,{className:`mt-6 flex items-center gap-2 text-[14px] text-muted`,children:[(0,L.jsx)(A,{className:`animate-spin`,size:16}),` `,t(`Connecting to your nanoMuse…`)]})]})}function gg(){let[e,t]=(0,I.useState)(``),n=s();return(0,L.jsxs)(`div`,{className:`mx-auto flex h-[100dvh] max-w-md flex-col items-center justify-center px-6 text-center`,children:[(0,L.jsx)(xn,{size:88}),(0,L.jsx)(`h1`,{className:`mt-4 text-[22px] font-bold`,children:n(`Connect to your nanoMuse`)}),(0,L.jsxs)(`p`,{className:`mt-2 text-[14px] text-muted`,children:[n(`This app talks to the nanoMuse server you run yourself. Scan the QR code printed by`),` `,(0,L.jsx)(`code`,{className:`rounded bg-surface-2 px-1`,children:`nanomuse serve`}),n(`, or paste the access token below.`)]}),(0,L.jsxs)(`form`,{className:`mt-5 w-full flex gap-2`,onSubmit:t=>{t.preventDefault(),e.trim()&&(g(e.trim()),window.location.reload())},children:[(0,L.jsx)(`input`,{value:e,onChange:e=>t(e.target.value),"aria-label":n(`Access token`),placeholder:n(`Access token`),className:`flex-1 rounded-2xl bg-surface-2 px-4 py-2.5 text-[15px] outline-none focus:ring-2 focus:ring-accent/40`}),(0,L.jsx)(`button`,{type:`submit`,className:`rounded-2xl bg-accent text-accent-fg px-4 font-medium`,children:n(`Connect`)})]})]})}a(),ee(),wn(),bn.createRoot(document.getElementById(`root`)).render((0,L.jsx)(I.StrictMode,{children:(0,L.jsx)(T,{children:(0,L.jsx)(mg,{})})}));export{Ht as $,Af as A,fn as B,Dp as C,Xe as Ct,Xf as D,np as E,Ke as Et,Mn as F,Qt as G,on as H,Sn as I,Jt as J,Zt as K,Cn as L,Nf as M,kf as N,Qf as O,mf as P,Ut as Q,yn as R,qp as S,Ze as St,rp as T,qe as Tt,nn as U,sn as V,tn as W,Kt as X,qt as Y,Gt as Z,rm as _,st as _t,Ah as a,At as at,Qp as b,tt as bt,Mh as c,wt as ct,Tm as d,vt as dt,Vt as et,Xp as f,gt as ft,tm as g,ct as gt,Yp as h,ut as ht,kh as i,Nt as it,Mf as j,Pf as k,Bm as l,P as lt,Zp as m,pt as mt,Ih as n,Lt as nt,jh as o,Et as ot,Jp as p,mt as pt,Xt as q,Ph as r,It as rt,Fh as s,Tt as st,Hh as t,Rt as tt,Hm as u,xt as ut,$p as v,at as vt,ap as w,Je as wt,em as x,Qe as xt,nm as y,rt as yt,gn as z}; \ No newline at end of file diff --git a/nanomuse/server/static/assets/index-tZx-TDX4.js b/nanomuse/server/static/assets/index-tZx-TDX4.js deleted file mode 100644 index ef1718bd2..000000000 --- a/nanomuse/server/static/assets/index-tZx-TDX4.js +++ /dev/null @@ -1,44 +0,0 @@ -const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["assets/AccountScreen-CfcZ3emY.js","assets/MuseHeader-BvAlmxiL.js","assets/StarNudge-Cr_QPa4y.js","assets/external-link-V2ISE5bW.js","assets/Form-C77NCy9F.js","assets/clapperboard-90G9CI1B.js","assets/database-zap-Bv9NPF9E.js","assets/image-Cn9LGhlN.js","assets/BackBar-DmScFXW_.js","assets/AvatarStudioScreen-DuBIZ1Gf.js","assets/refresh-cw-BMLOGb5p.js","assets/AvatarPicker-DUnXfRVQ.js","assets/ChannelsScreen-DGK7O7Nz.js","assets/CodingScreen-DAGGlv2e.js","assets/ConnectionsScreen-DIFZneZ_.js","assets/plug-u8jLJjTk.js","assets/CloudCard-CZ8tYr3g.js","assets/DevicesScreen-BLIuBnuO.js","assets/GoalsScreen-DgatXriG.js","assets/IdeasScreen-Bwp6l7Xs.js","assets/LibraryScreen-BclDd8-A.js","assets/MemoryScreen-6ZrrpUSE.js","assets/Onboarding-B0JPnst7.js","assets/IdentityForm-IeJQ0HCo.js","assets/SettingsScreen-CJQ-5PSy.js","assets/SkillsScreen-ZetN1PPI.js"])))=>i.map(i=>d[i]); -import{A as e,B as t,C as n,D as r,E as i,I as a,J as o,K as s,L as c,M as l,N as u,O as d,P as f,Q as p,R as m,S as h,T as g,U as _,V as v,W as y,X as b,Y as x,Z as S,b as C,c as w,d as T,f as E,i as D,j as O,n as k,p as ee,q as A,r as j,s as M,t as te,u as ne,x as N,y as re,z as P}from"./MuseHeader-BvAlmxiL.js";import{A as ie,C as ae,D as oe,E as se,M as ce,N as le,P as ue,S as de,a as fe,b as pe,c as me,h as he,i as ge,j as _e,l as ve,n as ye,o as be,p as xe,r as Se,s as Ce,t as we,u as Te,v as Ee,x as De,y as Oe}from"./StarNudge-Cr_QPa4y.js";import{n as ke,t as Ae}from"./external-link-V2ISE5bW.js";import{a as je,c as Me,i as Ne,n as Pe,o as Fe,r as Ie,s as Le}from"./Form-C77NCy9F.js";import{t as Re}from"./refresh-cw-BMLOGb5p.js";(function(){let e=document.createElement(`link`).relList;if(e&&e.supports&&e.supports(`modulepreload`))return;for(let e of document.querySelectorAll(`link[rel="modulepreload"]`))n(e);new MutationObserver(e=>{for(let t of e)if(t.type===`childList`)for(let e of t.addedNodes)e.tagName===`LINK`&&e.rel===`modulepreload`&&n(e)}).observe(document,{childList:!0,subtree:!0});function t(e){let t={};return e.integrity&&(t.integrity=e.integrity),e.referrerPolicy&&(t.referrerPolicy=e.referrerPolicy),t.credentials=e.crossOrigin===`use-credentials`?`include`:e.crossOrigin===`anonymous`?`omit`:`same-origin`,t}function n(e){if(e.ep)return;e.ep=!0;let n=t(e);fetch(e.href,n)}})();var ze=b((e=>{function t(e,t){var n=e.length;e.push(t);a:for(;0>>1,a=e[r];if(0>>1;ri(c,n))li(u,c)?(e[r]=u,e[l]=n,r=l):(e[r]=c,e[s]=n,r=s);else if(li(u,n))e[r]=u,e[l]=n,r=l;else break a}}return t}function i(e,t){var n=e.sortIndex-t.sortIndex;return n===0?e.id-t.id:n}if(typeof performance==`object`&&typeof performance.now==`function`){var a=performance;e.unstable_now=function(){return a.now()}}else{var o=Date,s=o.now();e.unstable_now=function(){return o.now()-s}}var c=[],l=[],u=1,d=null,f=3,p=!1,m=!1,h=!1,g=typeof setTimeout==`function`?setTimeout:null,_=typeof clearTimeout==`function`?clearTimeout:null,v=typeof setImmediate<`u`?setImmediate:null;typeof navigator<`u`&&navigator.scheduling!==void 0&&navigator.scheduling.isInputPending!==void 0&&navigator.scheduling.isInputPending.bind(navigator.scheduling);function y(e){for(var i=n(l);i!==null;){if(i.callback===null)r(l);else if(i.startTime<=e)r(l),i.sortIndex=i.expirationTime,t(c,i);else break;i=n(l)}}function b(e){if(h=!1,y(e),!m){if(n(c)!==null)m=!0,j(x);else{var t=n(l);t!==null&&M(b,t.startTime-e)}}}function x(t,i){m=!1,h&&(h=!1,_(w),w=-1),p=!0;var a=f;try{for(y(i),d=n(c);d!==null&&(!(d.expirationTime>i)||t&&!D());){var o=d.callback;if(typeof o==`function`){d.callback=null,f=d.priorityLevel;var s=o(d.expirationTime<=i);i=e.unstable_now(),typeof s==`function`?d.callback=s:d===n(c)&&r(c),y(i)}else r(c);d=n(c)}if(d!==null)var u=!0;else{var g=n(l);g!==null&&M(b,g.startTime-i),u=!1}return u}finally{d=null,f=a,p=!1}}var S=!1,C=null,w=-1,T=5,E=-1;function D(){return!(e.unstable_now()-Ee||125o?(r.sortIndex=a,t(l,r),n(c)===null&&r===n(l)&&(h?(_(w),w=-1):h=!0,M(b,a-o))):(r.sortIndex=s,t(c,r),m||p||(m=!0,j(x))),r},e.unstable_shouldYield=D,e.unstable_wrapCallback=function(e){var t=f;return function(){var n=f;f=t;try{return e.apply(this,arguments)}finally{f=n}}}})),Be=b(((e,t)=>{t.exports=ze()})),Ve=b((e=>{var t=x(),n=Be();function r(e){for(var t=`https://reactjs.org/docs/error-decoder.html?invariant=`+e,n=1;nt}return!1}function g(e,t,n,r,i,a,o){this.acceptsBooleans=t===2||t===3||t===4,this.attributeName=r,this.attributeNamespace=i,this.mustUseProperty=n,this.propertyName=e,this.type=t,this.sanitizeURL=a,this.removeEmptyString=o}var _={};`children dangerouslySetInnerHTML defaultValue defaultChecked innerHTML suppressContentEditableWarning suppressHydrationWarning style`.split(` `).forEach(function(e){_[e]=new g(e,0,!1,e,null,!1,!1)}),[[`acceptCharset`,`accept-charset`],[`className`,`class`],[`htmlFor`,`for`],[`httpEquiv`,`http-equiv`]].forEach(function(e){var t=e[0];_[t]=new g(t,1,!1,e[1],null,!1,!1)}),[`contentEditable`,`draggable`,`spellCheck`,`value`].forEach(function(e){_[e]=new g(e,2,!1,e.toLowerCase(),null,!1,!1)}),[`autoReverse`,`externalResourcesRequired`,`focusable`,`preserveAlpha`].forEach(function(e){_[e]=new g(e,2,!1,e,null,!1,!1)}),`allowFullScreen async autoFocus autoPlay controls default defer disabled disablePictureInPicture disableRemotePlayback formNoValidate hidden loop noModule noValidate open playsInline readOnly required reversed scoped seamless itemScope`.split(` `).forEach(function(e){_[e]=new g(e,3,!1,e.toLowerCase(),null,!1,!1)}),[`checked`,`multiple`,`muted`,`selected`].forEach(function(e){_[e]=new g(e,3,!0,e,null,!1,!1)}),[`capture`,`download`].forEach(function(e){_[e]=new g(e,4,!1,e,null,!1,!1)}),[`cols`,`rows`,`size`,`span`].forEach(function(e){_[e]=new g(e,6,!1,e,null,!1,!1)}),[`rowSpan`,`start`].forEach(function(e){_[e]=new g(e,5,!1,e.toLowerCase(),null,!1,!1)});var v=/[\-:]([a-z])/g;function y(e){return e[1].toUpperCase()}`accent-height alignment-baseline arabic-form baseline-shift cap-height clip-path clip-rule color-interpolation color-interpolation-filters color-profile color-rendering dominant-baseline enable-background fill-opacity fill-rule flood-color flood-opacity font-family font-size font-size-adjust font-stretch font-style font-variant font-weight glyph-name glyph-orientation-horizontal glyph-orientation-vertical horiz-adv-x horiz-origin-x image-rendering letter-spacing lighting-color marker-end marker-mid marker-start overline-position overline-thickness paint-order panose-1 pointer-events rendering-intent shape-rendering stop-color stop-opacity strikethrough-position strikethrough-thickness stroke-dasharray stroke-dashoffset stroke-linecap stroke-linejoin stroke-miterlimit stroke-opacity stroke-width text-anchor text-decoration text-rendering underline-position underline-thickness unicode-bidi unicode-range units-per-em v-alphabetic v-hanging v-ideographic v-mathematical vector-effect vert-adv-y vert-origin-x vert-origin-y word-spacing writing-mode xmlns:xlink x-height`.split(` `).forEach(function(e){var t=e.replace(v,y);_[t]=new g(t,1,!1,e,null,!1,!1)}),`xlink:actuate xlink:arcrole xlink:role xlink:show xlink:title xlink:type`.split(` `).forEach(function(e){var t=e.replace(v,y);_[t]=new g(t,1,!1,e,`http://www.w3.org/1999/xlink`,!1,!1)}),[`xml:base`,`xml:lang`,`xml:space`].forEach(function(e){var t=e.replace(v,y);_[t]=new g(t,1,!1,e,`http://www.w3.org/XML/1998/namespace`,!1,!1)}),[`tabIndex`,`crossOrigin`].forEach(function(e){_[e]=new g(e,1,!1,e.toLowerCase(),null,!1,!1)}),_.xlinkHref=new g(`xlinkHref`,1,!1,`xlink:href`,`http://www.w3.org/1999/xlink`,!0,!1),[`src`,`href`,`action`,`formAction`].forEach(function(e){_[e]=new g(e,1,!1,e.toLowerCase(),null,!0,!0)});function b(e,t,n,r){var i=_.hasOwnProperty(t)?_[t]:null;(i===null?r||!(2s||i[o]!==a[s]){var c=` -`+i[o].replace(` at new `,` at `);return e.displayName&&c.includes(``)&&(c=c.replace(``,e.displayName)),c}while(1<=o&&0<=s);break}}}finally{oe=!1,Error.prepareStackTrace=n}return(e=e?e.displayName||e.name:``)?ae(e):``}function ce(e){switch(e.tag){case 5:return ae(e.type);case 16:return ae(`Lazy`);case 13:return ae(`Suspense`);case 19:return ae(`SuspenseList`);case 0:case 2:case 15:return e=se(e.type,!1),e;case 11:return e=se(e.type.render,!1),e;case 1:return e=se(e.type,!0),e;default:return``}}function le(e){if(e==null)return null;if(typeof e==`function`)return e.displayName||e.name||null;if(typeof e==`string`)return e;switch(e){case T:return`Fragment`;case w:return`Portal`;case D:return`Profiler`;case E:return`StrictMode`;case A:return`Suspense`;case j:return`SuspenseList`}if(typeof e==`object`)switch(e.$$typeof){case k:return(e.displayName||`Context`)+`.Consumer`;case O:return(e._context.displayName||`Context`)+`.Provider`;case ee:var t=e.render;return e=e.displayName,e||=(e=t.displayName||t.name||``,e===``?`ForwardRef`:`ForwardRef(`+e+`)`),e;case M:return t=e.displayName||null,t===null?le(e.type)||`Memo`:t;case te:t=e._payload,e=e._init;try{return le(e(t))}catch{}}return null}function ue(e){var t=e.type;switch(e.tag){case 24:return`Cache`;case 9:return(t.displayName||`Context`)+`.Consumer`;case 10:return(t._context.displayName||`Context`)+`.Provider`;case 18:return`DehydratedFragment`;case 11:return e=t.render,e=e.displayName||e.name||``,t.displayName||(e===``?`ForwardRef`:`ForwardRef(`+e+`)`);case 7:return`Fragment`;case 5:return t;case 4:return`Portal`;case 3:return`Root`;case 6:return`Text`;case 16:return le(t);case 8:return t===E?`StrictMode`:`Mode`;case 22:return`Offscreen`;case 12:return`Profiler`;case 21:return`Scope`;case 13:return`Suspense`;case 19:return`SuspenseList`;case 25:return`TracingMarker`;case 1:case 0:case 17:case 2:case 14:case 15:if(typeof t==`function`)return t.displayName||t.name||null;if(typeof t==`string`)return t}return null}function de(e){switch(typeof e){case`boolean`:case`number`:case`string`:case`undefined`:return e;case`object`:return e;default:return``}}function fe(e){var t=e.type;return(e=e.nodeName)&&e.toLowerCase()===`input`&&(t===`checkbox`||t===`radio`)}function pe(e){var t=fe(e)?`checked`:`value`,n=Object.getOwnPropertyDescriptor(e.constructor.prototype,t),r=``+e[t];if(!e.hasOwnProperty(t)&&n!==void 0&&typeof n.get==`function`&&typeof n.set==`function`){var i=n.get,a=n.set;return Object.defineProperty(e,t,{configurable:!0,get:function(){return i.call(this)},set:function(e){r=``+e,a.call(this,e)}}),Object.defineProperty(e,t,{enumerable:n.enumerable}),{getValue:function(){return r},setValue:function(e){r=``+e},stopTracking:function(){e._valueTracker=null,delete e[t]}}}}function me(e){e._valueTracker||=pe(e)}function he(e){if(!e)return!1;var t=e._valueTracker;if(!t)return!0;var n=t.getValue(),r=``;return e&&(r=fe(e)?e.checked?`true`:`false`:e.value),e=r,e!==n&&(t.setValue(e),!0)}function ge(e){if(e||=typeof document<`u`?document:void 0,e===void 0)return null;try{return e.activeElement||e.body}catch{return e.body}}function _e(e,t){var n=t.checked;return P({},t,{defaultChecked:void 0,defaultValue:void 0,value:void 0,checked:n??e._wrapperState.initialChecked})}function ve(e,t){var n=t.defaultValue==null?``:t.defaultValue,r=t.checked==null?t.defaultChecked:t.checked;n=de(t.value==null?n:t.value),e._wrapperState={initialChecked:r,initialValue:n,controlled:t.type===`checkbox`||t.type===`radio`?t.checked!=null:t.value!=null}}function ye(e,t){t=t.checked,t!=null&&b(e,`checked`,t,!1)}function be(e,t){ye(e,t);var n=de(t.value),r=t.type;if(n!=null)r===`number`?(n===0&&e.value===``||e.value!=n)&&(e.value=``+n):e.value!==``+n&&(e.value=``+n);else if(r===`submit`||r===`reset`){e.removeAttribute(`value`);return}t.hasOwnProperty(`value`)?Se(e,t.type,n):t.hasOwnProperty(`defaultValue`)&&Se(e,t.type,de(t.defaultValue)),t.checked==null&&t.defaultChecked!=null&&(e.defaultChecked=!!t.defaultChecked)}function xe(e,t,n){if(t.hasOwnProperty(`value`)||t.hasOwnProperty(`defaultValue`)){var r=t.type;if(!(r!==`submit`&&r!==`reset`||t.value!==void 0&&t.value!==null))return;t=``+e._wrapperState.initialValue,n||t===e.value||(e.value=t),e.defaultValue=t}n=e.name,n!==``&&(e.name=``),e.defaultChecked=!!e._wrapperState.initialChecked,n!==``&&(e.name=n)}function Se(e,t,n){(t!==`number`||ge(e.ownerDocument)!==e)&&(n==null?e.defaultValue=``+e._wrapperState.initialValue:e.defaultValue!==``+n&&(e.defaultValue=``+n))}var Ce=Array.isArray;function we(e,t,n,r){if(e=e.options,t){t={};for(var i=0;i`+t.valueOf().toString()+``,t=je.firstChild;e.firstChild;)e.removeChild(e.firstChild);for(;t.firstChild;)e.appendChild(t.firstChild)}});function Ne(e,t){if(t){var n=e.firstChild;if(n&&n===e.lastChild&&n.nodeType===3){n.nodeValue=t;return}}e.textContent=t}var Pe={animationIterationCount:!0,aspectRatio:!0,borderImageOutset:!0,borderImageSlice:!0,borderImageWidth:!0,boxFlex:!0,boxFlexGroup:!0,boxOrdinalGroup:!0,columnCount:!0,columns:!0,flex:!0,flexGrow:!0,flexPositive:!0,flexShrink:!0,flexNegative:!0,flexOrder:!0,gridArea:!0,gridRow:!0,gridRowEnd:!0,gridRowSpan:!0,gridRowStart:!0,gridColumn:!0,gridColumnEnd:!0,gridColumnSpan:!0,gridColumnStart:!0,fontWeight:!0,lineClamp:!0,lineHeight:!0,opacity:!0,order:!0,orphans:!0,tabSize:!0,widows:!0,zIndex:!0,zoom:!0,fillOpacity:!0,floodOpacity:!0,stopOpacity:!0,strokeDasharray:!0,strokeDashoffset:!0,strokeMiterlimit:!0,strokeOpacity:!0,strokeWidth:!0},Fe=[`Webkit`,`ms`,`Moz`,`O`];Object.keys(Pe).forEach(function(e){Fe.forEach(function(t){t=t+e.charAt(0).toUpperCase()+e.substring(1),Pe[t]=Pe[e]})});function Ie(e,t,n){return t==null||typeof t==`boolean`||t===``?``:n||typeof t!=`number`||t===0||Pe.hasOwnProperty(e)&&Pe[e]?(``+t).trim():t+`px`}function Le(e,t){for(var n in e=e.style,t)if(t.hasOwnProperty(n)){var r=n.indexOf(`--`)===0,i=Ie(n,t[n],r);n===`float`&&(n=`cssFloat`),r?e.setProperty(n,i):e[n]=i}}var Re=P({menuitem:!0},{area:!0,base:!0,br:!0,col:!0,embed:!0,hr:!0,img:!0,input:!0,keygen:!0,link:!0,meta:!0,param:!0,source:!0,track:!0,wbr:!0});function ze(e,t){if(t){if(Re[e]&&(t.children!=null||t.dangerouslySetInnerHTML!=null))throw Error(r(137,e));if(t.dangerouslySetInnerHTML!=null){if(t.children!=null)throw Error(r(60));if(typeof t.dangerouslySetInnerHTML!=`object`||!(`__html`in t.dangerouslySetInnerHTML))throw Error(r(61))}if(t.style!=null&&typeof t.style!=`object`)throw Error(r(62))}}function Ve(e,t){if(e.indexOf(`-`)===-1)return typeof t.is==`string`;switch(e){case`annotation-xml`:case`color-profile`:case`font-face`:case`font-face-src`:case`font-face-uri`:case`font-face-format`:case`font-face-name`:case`missing-glyph`:return!1;default:return!0}}var He=null;function Ue(e){return e=e.target||e.srcElement||window,e.correspondingUseElement&&(e=e.correspondingUseElement),e.nodeType===3?e.parentNode:e}var We=null,Ge=null,Ke=null;function qe(e){if(e=Ii(e)){if(typeof We!=`function`)throw Error(r(280));var t=e.stateNode;t&&(t=Ri(t),We(e.stateNode,e.type,t))}}function Je(e){Ge?Ke?Ke.push(e):Ke=[e]:Ge=e}function Ye(){if(Ge){var e=Ge,t=Ke;if(Ke=Ge=null,qe(e),t)for(e=0;e>>=0,e===0?32:31-(jt(e)/Mt|0)|0}var Pt=64,Ft=4194304;function It(e){switch(e&-e){case 1:return 1;case 2:return 2;case 4:return 4;case 8:return 8;case 16:return 16;case 32:return 32;case 64:case 128:case 256:case 512:case 1024:case 2048:case 4096:case 8192:case 16384:case 32768:case 65536:case 131072:case 262144:case 524288:case 1048576:case 2097152:return e&4194240;case 4194304:case 8388608:case 16777216:case 33554432:case 67108864:return e&130023424;case 134217728:return 134217728;case 268435456:return 268435456;case 536870912:return 536870912;case 1073741824:return 1073741824;default:return e}}function Lt(e,t){var n=e.pendingLanes;if(n===0)return 0;var r=0,i=e.suspendedLanes,a=e.pingedLanes,o=n&268435455;if(o!==0){var s=o&~i;s===0?(a&=o,a!==0&&(r=It(a))):r=It(s)}else o=n&~i,o===0?a!==0&&(r=It(a)):r=It(o);if(r===0)return 0;if(t!==0&&t!==r&&(t&i)===0&&(i=r&-r,a=t&-t,i>=a||i===16&&a&4194240))return t;if(r&4&&(r|=n&16),t=e.entangledLanes,t!==0)for(e=e.entanglements,t&=r;0n;n++)t.push(e);return t}function Ut(e,t,n){e.pendingLanes|=t,t!==536870912&&(e.suspendedLanes=0,e.pingedLanes=0),e=e.eventTimes,t=31-At(t),e[t]=n}function Wt(e,t){var n=e.pendingLanes&~t;e.pendingLanes=t,e.suspendedLanes=0,e.pingedLanes=0,e.expiredLanes&=t,e.mutableReadLanes&=t,e.entangledLanes&=t,t=e.entanglements;var r=e.eventTimes;for(e=e.expirationTimes;0=er),rr=` `,ir=!1;function ar(e,t){switch(e){case`keyup`:return Qn.indexOf(t.keyCode)!==-1;case`keydown`:return t.keyCode!==229;case`keypress`:case`mousedown`:case`focusout`:return!0;default:return!1}}function or(e){return e=e.detail,typeof e==`object`&&`data`in e?e.data:null}var sr=!1;function cr(e,t){switch(e){case`compositionend`:return or(t);case`keypress`:return t.which===32?(ir=!0,rr):null;case`textInput`:return e=t.data,e===rr&&ir?null:e;default:return null}}function lr(e,t){if(sr)return e===`compositionend`||!$n&&ar(e,t)?(e=En(),Tn=wn=Cn=null,sr=!1,e):null;switch(e){case`paste`:return null;case`keypress`:if(!(t.ctrlKey||t.altKey||t.metaKey)||t.ctrlKey&&t.altKey){if(t.char&&1=t)return{node:n,offset:t-e};e=r}a:{for(;n;){if(n.nextSibling){n=n.nextSibling;break a}n=n.parentNode}n=void 0}n=jr(n)}}function Nr(e,t){return e&&t?e===t?!0:e&&e.nodeType===3?!1:t&&t.nodeType===3?Nr(e,t.parentNode):`contains`in e?e.contains(t):e.compareDocumentPosition?!!(e.compareDocumentPosition(t)&16):!1:!1}function Pr(){for(var e=window,t=ge();t instanceof e.HTMLIFrameElement;){try{var n=typeof t.contentWindow.location.href==`string`}catch{n=!1}if(n)e=t.contentWindow;else break;t=ge(e.document)}return t}function Fr(e){var t=e&&e.nodeName&&e.nodeName.toLowerCase();return t&&(t===`input`&&(e.type===`text`||e.type===`search`||e.type===`tel`||e.type===`url`||e.type===`password`)||t===`textarea`||e.contentEditable===`true`)}function Ir(e){var t=Pr(),n=e.focusedElem,r=e.selectionRange;if(t!==n&&n&&n.ownerDocument&&Nr(n.ownerDocument.documentElement,n)){if(r!==null&&Fr(n)){if(t=r.start,e=r.end,e===void 0&&(e=t),`selectionStart`in n)n.selectionStart=t,n.selectionEnd=Math.min(e,n.value.length);else if(e=(t=n.ownerDocument||document)&&t.defaultView||window,e.getSelection){e=e.getSelection();var i=n.textContent.length,a=Math.min(r.start,i);r=r.end===void 0?a:Math.min(r.end,i),!e.extend&&a>r&&(i=r,r=a,a=i),i=Mr(n,a);var o=Mr(n,r);i&&o&&(e.rangeCount!==1||e.anchorNode!==i.node||e.anchorOffset!==i.offset||e.focusNode!==o.node||e.focusOffset!==o.offset)&&(t=t.createRange(),t.setStart(i.node,i.offset),e.removeAllRanges(),a>r?(e.addRange(t),e.extend(o.node,o.offset)):(t.setEnd(o.node,o.offset),e.addRange(t)))}}for(t=[],e=n;e=e.parentNode;)e.nodeType===1&&t.push({element:e,left:e.scrollLeft,top:e.scrollTop});for(typeof n.focus==`function`&&n.focus(),n=0;n=document.documentMode,Rr=null,zr=null,Br=null,Vr=!1;function Hr(e,t,n){var r=n.window===n?n.document:n.nodeType===9?n:n.ownerDocument;Vr||Rr==null||Rr!==ge(r)||(r=Rr,`selectionStart`in r&&Fr(r)?r={start:r.selectionStart,end:r.selectionEnd}:(r=(r.ownerDocument&&r.ownerDocument.defaultView||window).getSelection(),r={anchorNode:r.anchorNode,anchorOffset:r.anchorOffset,focusNode:r.focusNode,focusOffset:r.focusOffset}),Br&&Ar(Br,r)||(Br=r,r=pi(zr,`onSelect`),0Bi||(e.current=zi[Bi],zi[Bi]=null,Bi--)}function J(e,t){Bi++,zi[Bi]=e.current,e.current=t}var Hi={},Ui=Vi(Hi),Wi=Vi(!1),Gi=Hi;function Ki(e,t){var n=e.type.contextTypes;if(!n)return Hi;var r=e.stateNode;if(r&&r.__reactInternalMemoizedUnmaskedChildContext===t)return r.__reactInternalMemoizedMaskedChildContext;var i={},a;for(a in n)i[a]=t[a];return r&&(e=e.stateNode,e.__reactInternalMemoizedUnmaskedChildContext=t,e.__reactInternalMemoizedMaskedChildContext=i),i}function qi(e){return e=e.childContextTypes,e!=null}function Ji(){q(Wi),q(Ui)}function Yi(e,t,n){if(Ui.current!==Hi)throw Error(r(168));J(Ui,t),J(Wi,n)}function Xi(e,t,n){var i=e.stateNode;if(t=t.childContextTypes,typeof i.getChildContext!=`function`)return n;for(var a in i=i.getChildContext(),i)if(!(a in t))throw Error(r(108,ue(e)||`Unknown`,a));return P({},n,i)}function Zi(e){return e=(e=e.stateNode)&&e.__reactInternalMemoizedMergedChildContext||Hi,Gi=Ui.current,J(Ui,e),J(Wi,Wi.current),!0}function Qi(e,t,n){var i=e.stateNode;if(!i)throw Error(r(169));n?(e=Xi(e,t,Gi),i.__reactInternalMemoizedMergedChildContext=e,q(Wi),q(Ui),J(Ui,e)):q(Wi),J(Wi,n)}var $i=null,ea=!1,ta=!1;function na(e){$i===null?$i=[e]:$i.push(e)}function ra(e){ea=!0,na(e)}function ia(){if(!ta&&$i!==null){ta=!0;var e=0,t=I;try{var n=$i;for(I=1;e>=o,i-=o,fa=1<<32-At(t)+i|n<h?(g=d,d=null):g=d.sibling;var _=p(r,d,s[h],c);if(_===null){d===null&&(d=g);break}e&&d&&_.alternate===null&&t(r,d),a=o(_,a,h),u===null?l=_:u.sibling=_,u=_,d=g}if(h===s.length)return n(r,d),Y&&ma(r,h),l;if(d===null){for(;hg?(_=h,h=null):_=h.sibling;var y=p(a,h,v.value,l);if(y===null){h===null&&(h=_);break}e&&h&&y.alternate===null&&t(a,h),s=o(y,s,g),d===null?u=y:d.sibling=y,d=y,h=_}if(v.done)return n(a,h),Y&&ma(a,g),u;if(h===null){for(;!v.done;g++,v=c.next())v=f(a,v.value,l),v!==null&&(s=o(v,s,g),d===null?u=v:d.sibling=v,d=v);return Y&&ma(a,g),u}for(h=i(a,h);!v.done;g++,v=c.next())v=m(h,a,g,v.value,l),v!==null&&(e&&v.alternate!==null&&h.delete(v.key===null?g:v.key),s=o(v,s,g),d===null?u=v:d.sibling=v,d=v);return e&&h.forEach(function(e){return t(a,e)}),Y&&ma(a,g),u}function _(e,r,i,o){if(typeof i==`object`&&i&&i.type===T&&i.key===null&&(i=i.props.children),typeof i==`object`&&i){switch(i.$$typeof){case C:a:{for(var c=i.key,l=r;l!==null;){if(l.key===c){if(c=i.type,c===T){if(l.tag===7){n(e,l.sibling),r=a(l,i.props.children),r.return=e,e=r;break a}}else if(l.elementType===c||typeof c==`object`&&c&&c.$$typeof===te&&Na(c)===l.type){n(e,l.sibling),r=a(l,i.props),r.ref=ja(e,l,i),r.return=e,e=r;break a}n(e,l);break}t(e,l),l=l.sibling}i.type===T?(r=Zl(i.props.children,e.mode,o,i.key),r.return=e,e=r):(o=Xl(i.type,i.key,i.props,null,e.mode,o),o.ref=ja(e,r,i),o.return=e,e=o)}return s(e);case w:a:{for(l=i.key;r!==null;){if(r.key===l){if(r.tag===4&&r.stateNode.containerInfo===i.containerInfo&&r.stateNode.implementation===i.implementation){n(e,r.sibling),r=a(r,i.children||[]),r.return=e,e=r;break a}n(e,r);break}t(e,r),r=r.sibling}r=eu(i,e.mode,o),r.return=e,e=r}return s(e);case te:return l=i._init,_(e,r,l(i._payload),o)}if(Ce(i))return h(e,r,i,o);if(re(i))return g(e,r,i,o);Ma(e,i)}return typeof i==`string`&&i!==``||typeof i==`number`?(i=``+i,r!==null&&r.tag===6?(n(e,r.sibling),r=a(r,i),r.return=e,e=r):(n(e,r),r=$l(i,e.mode,o),r.return=e,e=r),s(e)):n(e,r)}return _}var Fa=Pa(!0),Ia=Pa(!1),La=Vi(null),Ra=null,za=null,Ba=null;function Va(){Ba=za=Ra=null}function Ha(e){var t=La.current;q(La),e._currentValue=t}function Ua(e,t,n){for(;e!==null;){var r=e.alternate;if((e.childLanes&t)===t?r!==null&&(r.childLanes&t)!==t&&(r.childLanes|=t):(e.childLanes|=t,r!==null&&(r.childLanes|=t)),e===n)break;e=e.return}}function Wa(e,t){Ra=e,Ba=za=null,e=e.dependencies,e!==null&&e.firstContext!==null&&((e.lanes&t)!==0&&(Ms=!0),e.firstContext=null)}function Ga(e){var t=e._currentValue;if(Ba!==e){if(e={context:e,memoizedValue:t,next:null},za===null){if(Ra===null)throw Error(r(308));za=e,Ra.dependencies={lanes:0,firstContext:e}}else za=za.next=e}return t}var Ka=null;function qa(e){Ka===null?Ka=[e]:Ka.push(e)}function Ja(e,t,n,r){var i=t.interleaved;return i===null?(n.next=n,qa(t)):(n.next=i.next,i.next=n),t.interleaved=n,Ya(e,r)}function Ya(e,t){e.lanes|=t;var n=e.alternate;for(n!==null&&(n.lanes|=t),n=e,e=e.return;e!==null;)e.childLanes|=t,n=e.alternate,n!==null&&(n.childLanes|=t),n=e,e=e.return;return n.tag===3?n.stateNode:null}var Xa=!1;function Za(e){e.updateQueue={baseState:e.memoizedState,firstBaseUpdate:null,lastBaseUpdate:null,shared:{pending:null,interleaved:null,lanes:0},effects:null}}function Qa(e,t){e=e.updateQueue,t.updateQueue===e&&(t.updateQueue={baseState:e.baseState,firstBaseUpdate:e.firstBaseUpdate,lastBaseUpdate:e.lastBaseUpdate,shared:e.shared,effects:e.effects})}function $a(e,t){return{eventTime:e,lane:t,tag:0,payload:null,callback:null,next:null}}function eo(e,t,n){var r=e.updateQueue;if(r===null)return null;if(r=r.shared,$&2){var i=r.pending;return i===null?t.next=t:(t.next=i.next,i.next=t),r.pending=t,Ya(e,n)}return i=r.interleaved,i===null?(t.next=t,qa(r)):(t.next=i.next,i.next=t),r.interleaved=t,Ya(e,n)}function to(e,t,n){if(t=t.updateQueue,t!==null&&(t=t.shared,n&4194240)){var r=t.lanes;r&=e.pendingLanes,n|=r,t.lanes=n,Gt(e,n)}}function no(e,t){var n=e.updateQueue,r=e.alternate;if(r!==null&&(r=r.updateQueue,n===r)){var i=null,a=null;if(n=n.firstBaseUpdate,n!==null){do{var o={eventTime:n.eventTime,lane:n.lane,tag:n.tag,payload:n.payload,callback:n.callback,next:null};a===null?i=a=o:a=a.next=o,n=n.next}while(n!==null);a===null?i=a=t:a=a.next=t}else i=a=t;n={baseState:r.baseState,firstBaseUpdate:i,lastBaseUpdate:a,shared:r.shared,effects:r.effects},e.updateQueue=n;return}e=n.lastBaseUpdate,e===null?n.firstBaseUpdate=t:e.next=t,n.lastBaseUpdate=t}function ro(e,t,n,r){var i=e.updateQueue;Xa=!1;var a=i.firstBaseUpdate,o=i.lastBaseUpdate,s=i.shared.pending;if(s!==null){i.shared.pending=null;var c=s,l=c.next;c.next=null,o===null?a=l:o.next=l,o=c;var u=e.alternate;u!==null&&(u=u.updateQueue,s=u.lastBaseUpdate,s!==o&&(s===null?u.firstBaseUpdate=l:s.next=l,u.lastBaseUpdate=c))}if(a!==null){var d=i.baseState;o=0,u=l=c=null,s=a;do{var f=s.lane,p=s.eventTime;if((r&f)===f){u!==null&&(u=u.next={eventTime:p,lane:0,tag:s.tag,payload:s.payload,callback:s.callback,next:null});a:{var m=e,h=s;switch(f=t,p=n,h.tag){case 1:if(m=h.payload,typeof m==`function`){d=m.call(p,d,f);break a}d=m;break a;case 3:m.flags=m.flags&-65537|128;case 0:if(m=h.payload,f=typeof m==`function`?m.call(p,d,f):m,f==null)break a;d=P({},d,f);break a;case 2:Xa=!0}}s.callback!==null&&s.lane!==0&&(e.flags|=64,f=i.effects,f===null?i.effects=[s]:f.push(s))}else p={eventTime:p,lane:f,tag:s.tag,payload:s.payload,callback:s.callback,next:null},u===null?(l=u=p,c=d):u=u.next=p,o|=f;if(s=s.next,s===null){if(s=i.shared.pending,s===null)break;f=s,s=f.next,f.next=null,i.lastBaseUpdate=f,i.shared.pending=null}}while(1);if(u===null&&(c=d),i.baseState=c,i.firstBaseUpdate=l,i.lastBaseUpdate=u,t=i.shared.interleaved,t!==null){i=t;do o|=i.lane,i=i.next;while(i!==t)}else a===null&&(i.shared.lanes=0);Jc|=o,e.lanes=o,e.memoizedState=d}}function io(e,t,n){if(e=t.effects,t.effects=null,e!==null)for(t=0;tn?n:4,e(!0);var r=yo.transition;yo.transition={};try{e(!1),t()}finally{I=n,yo.transition=r}}function as(){return Mo().memoizedState}function os(e,t,n){var r=pl(e);if(n={lane:r,action:n,hasEagerState:!1,eagerState:null,next:null},cs(e))ls(t,n);else if(n=Ja(e,t,n,r),n!==null){var i=fl();ml(n,e,r,i),us(n,t,r)}}function ss(e,t,n){var r=pl(e),i={lane:r,action:n,hasEagerState:!1,eagerState:null,next:null};if(cs(e))ls(t,i);else{var a=e.alternate;if(e.lanes===0&&(a===null||a.lanes===0)&&(a=t.lastRenderedReducer,a!==null))try{var o=t.lastRenderedState,s=a(o,n);if(i.hasEagerState=!0,i.eagerState=s,kr(s,o)){var c=t.interleaved;c===null?(i.next=i,qa(t)):(i.next=c.next,c.next=i),t.interleaved=i;return}}catch{}n=Ja(e,t,i,r),n!==null&&(i=fl(),ml(n,e,r,i),us(n,t,r))}}function cs(e){var t=e.alternate;return e===Z||t!==null&&t===Z}function ls(e,t){wo=Co=!0;var n=e.pending;n===null?t.next=t:(t.next=n.next,n.next=t),e.pending=t}function us(e,t,n){if(n&4194240){var r=t.lanes;r&=e.pendingLanes,n|=r,t.lanes=n,Gt(e,n)}}var ds={readContext:Ga,useCallback:Do,useContext:Do,useEffect:Do,useImperativeHandle:Do,useInsertionEffect:Do,useLayoutEffect:Do,useMemo:Do,useReducer:Do,useRef:Do,useState:Do,useDebugValue:Do,useDeferredValue:Do,useTransition:Do,useMutableSource:Do,useSyncExternalStore:Do,useId:Do,unstable_isNewReconciler:!1},fs={readContext:Ga,useCallback:function(e,t){return jo().memoizedState=[e,t===void 0?null:t],e},useContext:Ga,useEffect:Jo,useImperativeHandle:function(e,t,n){return n=n==null?null:n.concat([e]),Ko(4194308,4,Qo.bind(null,t,e),n)},useLayoutEffect:function(e,t){return Ko(4194308,4,e,t)},useInsertionEffect:function(e,t){return Ko(4,2,e,t)},useMemo:function(e,t){var n=jo();return t=t===void 0?null:t,e=e(),n.memoizedState=[e,t],e},useReducer:function(e,t,n){var r=jo();return t=n===void 0?t:n(t),r.memoizedState=r.baseState=t,e={pending:null,interleaved:null,lanes:0,dispatch:null,lastRenderedReducer:e,lastRenderedState:t},r.queue=e,e=e.dispatch=os.bind(null,Z,e),[r.memoizedState,e]},useRef:function(e){var t=jo();return e={current:e},t.memoizedState=e},useState:Uo,useDebugValue:es,useDeferredValue:function(e){return jo().memoizedState=e},useTransition:function(){var e=Uo(!1),t=e[0];return e=is.bind(null,e[1]),jo().memoizedState=e,[t,e]},useMutableSource:function(){},useSyncExternalStore:function(e,t,n){var i=Z,a=jo();if(Y){if(n===void 0)throw Error(r(407));n=n()}else{if(n=t(),Vc===null)throw Error(r(349));bo&30||Ro(i,t,n)}a.memoizedState=n;var o={value:n,getSnapshot:t};return a.queue=o,Jo(Bo.bind(null,i,o,e),[e]),i.flags|=2048,Wo(9,zo.bind(null,i,o,n,t),void 0,null),n},useId:function(){var e=jo(),t=Vc.identifierPrefix;if(Y){var n=pa,r=fa;n=(r&~(1<<32-At(r)-1)).toString(32)+n,t=`:`+t+`R`+n,n=To++,0<\/script>`,e=e.removeChild(e.firstChild)):typeof i.is==`string`?e=c.createElement(n,{is:i.is}):(e=c.createElement(n),n===`select`&&(c=e,i.multiple?c.multiple=!0:i.size&&(c.size=i.size))):e=c.createElementNS(e,n),e[Ai]=t,e[ji]=i,nc(e,t,!1,!1),t.stateNode=e;a:{switch(c=Ve(n,i),n){case`dialog`:H(`cancel`,e),H(`close`,e),o=i;break;case`iframe`:case`object`:case`embed`:H(`load`,e),o=i;break;case`video`:case`audio`:for(o=0;oel&&(t.flags|=128,i=!0,ac(s,!1),t.lanes=4194304)}}else{if(!i){if(e=ho(c),e!==null){if(t.flags|=128,i=!0,n=e.updateQueue,n!==null&&(t.updateQueue=n,t.flags|=4),ac(s,!0),s.tail===null&&s.tailMode===`hidden`&&!c.alternate&&!Y)return oc(t),null}else 2*F()-s.renderingStartTime>el&&n!==1073741824&&(t.flags|=128,i=!0,ac(s,!1),t.lanes=4194304)}s.isBackwards?(c.sibling=t.child,t.child=c):(n=s.last,n===null?t.child=c:n.sibling=c,s.last=c)}return s.tail===null?(oc(t),null):(t=s.tail,s.rendering=t,s.tail=t.sibling,s.renderingStartTime=F(),t.sibling=null,n=X.current,J(X,i?n&1|2:n&1),t);case 22:case 23:return wl(),i=t.memoizedState!==null,e!==null&&e.memoizedState!==null!==i&&(t.flags|=8192),i&&t.mode&1?Wc&1073741824&&(oc(t),t.subtreeFlags&6&&(t.flags|=8192)):oc(t),null;case 24:return null;case 25:return null}throw Error(r(156,t.tag))}function cc(e,t){switch(_a(t),t.tag){case 1:return qi(t.type)&&Ji(),e=t.flags,e&65536?(t.flags=e&-65537|128,t):null;case 3:return fo(),q(Wi),q(Ui),_o(),e=t.flags,e&65536&&!(e&128)?(t.flags=e&-65537|128,t):null;case 5:return mo(t),null;case 13:if(q(X),e=t.memoizedState,e!==null&&e.dehydrated!==null){if(t.alternate===null)throw Error(r(340));Oa()}return e=t.flags,e&65536?(t.flags=e&-65537|128,t):null;case 19:return q(X),null;case 4:return fo(),null;case 10:return Ha(t.type._context),null;case 22:case 23:return wl(),null;case 24:return null;default:return null}}var lc=!1,uc=!1,dc=typeof WeakSet==`function`?WeakSet:Set,Q=null;function fc(e,t){var n=e.ref;if(n!==null){if(typeof n==`function`)try{n(null)}catch(n){Rl(e,t,n)}else n.current=null}}function pc(e,t,n){try{n()}catch(n){Rl(e,t,n)}}var mc=!1;function hc(e,t){if(xi=vn,e=Pr(),Fr(e)){if(`selectionStart`in e)var n={start:e.selectionStart,end:e.selectionEnd};else a:{n=(n=e.ownerDocument)&&n.defaultView||window;var i=n.getSelection&&n.getSelection();if(i&&i.rangeCount!==0){n=i.anchorNode;var a=i.anchorOffset,o=i.focusNode;i=i.focusOffset;try{n.nodeType,o.nodeType}catch{n=null;break a}var s=0,c=-1,l=-1,u=0,d=0,f=e,p=null;b:for(;;){for(var m;f!==n||a!==0&&f.nodeType!==3||(c=s+a),f!==o||i!==0&&f.nodeType!==3||(l=s+i),f.nodeType===3&&(s+=f.nodeValue.length),(m=f.firstChild)!==null;)p=f,f=m;for(;;){if(f===e)break b;if(p===n&&++u===a&&(c=s),p===o&&++d===i&&(l=s),(m=f.nextSibling)!==null)break;f=p,p=f.parentNode}f=m}n=c===-1||l===-1?null:{start:c,end:l}}else n=null}n||={start:0,end:0}}else n=null;for(Si={focusedElem:e,selectionRange:n},vn=!1,Q=t;Q!==null;)if(t=Q,e=t.child,t.subtreeFlags&1028&&e!==null)e.return=t,Q=e;else for(;Q!==null;){t=Q;try{var h=t.alternate;if(t.flags&1024)switch(t.tag){case 0:case 11:case 15:break;case 1:if(h!==null){var g=h.memoizedProps,_=h.memoizedState,v=t.stateNode;v.__reactInternalSnapshotBeforeUpdate=v.getSnapshotBeforeUpdate(t.elementType===t.type?g:hs(t.type,g),_)}break;case 3:var y=t.stateNode.containerInfo;y.nodeType===1?y.textContent=``:y.nodeType===9&&y.documentElement&&y.removeChild(y.documentElement);break;case 5:case 6:case 4:case 17:break;default:throw Error(r(163))}}catch(e){Rl(t,t.return,e)}if(e=t.sibling,e!==null){e.return=t.return,Q=e;break}Q=t.return}return h=mc,mc=!1,h}function gc(e,t,n){var r=t.updateQueue;if(r=r===null?null:r.lastEffect,r!==null){var i=r=r.next;do{if((i.tag&e)===e){var a=i.destroy;i.destroy=void 0,a!==void 0&&pc(t,n,a)}i=i.next}while(i!==r)}}function _c(e,t){if(t=t.updateQueue,t=t===null?null:t.lastEffect,t!==null){var n=t=t.next;do{if((n.tag&e)===e){var r=n.create;n.destroy=r()}n=n.next}while(n!==t)}}function vc(e){var t=e.ref;if(t!==null){var n=e.stateNode;switch(e.tag){case 5:e=n;break;default:e=n}typeof t==`function`?t(e):t.current=e}}function yc(e){var t=e.alternate;t!==null&&(e.alternate=null,yc(t)),e.child=null,e.deletions=null,e.sibling=null,e.tag===5&&(t=e.stateNode,t!==null&&(delete t[Ai],delete t[ji],delete t[Ni],delete t[K],delete t[Pi])),e.stateNode=null,e.return=null,e.dependencies=null,e.memoizedProps=null,e.memoizedState=null,e.pendingProps=null,e.stateNode=null,e.updateQueue=null}function bc(e){return e.tag===5||e.tag===3||e.tag===4}function xc(e){a:for(;;){for(;e.sibling===null;){if(e.return===null||bc(e.return))return null;e=e.return}for(e.sibling.return=e.return,e=e.sibling;e.tag!==5&&e.tag!==6&&e.tag!==18;){if(e.flags&2||e.child===null||e.tag===4)continue a;e.child.return=e,e=e.child}if(!(e.flags&2))return e.stateNode}}function Sc(e,t,n){var r=e.tag;if(r===5||r===6)e=e.stateNode,t?n.nodeType===8?n.parentNode.insertBefore(e,t):n.insertBefore(e,t):(n.nodeType===8?(t=n.parentNode,t.insertBefore(e,n)):(t=n,t.appendChild(e)),n=n._reactRootContainer,n!=null||t.onclick!==null||(t.onclick=bi));else if(r!==4&&(e=e.child,e!==null))for(Sc(e,t,n),e=e.sibling;e!==null;)Sc(e,t,n),e=e.sibling}function Cc(e,t,n){var r=e.tag;if(r===5||r===6)e=e.stateNode,t?n.insertBefore(e,t):n.appendChild(e);else if(r!==4&&(e=e.child,e!==null))for(Cc(e,t,n),e=e.sibling;e!==null;)Cc(e,t,n),e=e.sibling}var wc=null,Tc=!1;function Ec(e,t,n){for(n=n.child;n!==null;)Dc(e,t,n),n=n.sibling}function Dc(e,t,n){if(Ot&&typeof Ot.onCommitFiberUnmount==`function`)try{Ot.onCommitFiberUnmount(Dt,n)}catch{}switch(n.tag){case 5:uc||fc(n,t);case 6:var r=wc,i=Tc;wc=null,Ec(e,t,n),wc=r,Tc=i,wc!==null&&(Tc?(e=wc,n=n.stateNode,e.nodeType===8?e.parentNode.removeChild(n):e.removeChild(n)):wc.removeChild(n.stateNode));break;case 18:wc!==null&&(Tc?(e=wc,n=n.stateNode,e.nodeType===8?ki(e.parentNode,n):e.nodeType===1&&ki(e,n),gn(e)):ki(wc,n.stateNode));break;case 4:r=wc,i=Tc,wc=n.stateNode.containerInfo,Tc=!0,Ec(e,t,n),wc=r,Tc=i;break;case 0:case 11:case 14:case 15:if(!uc&&(r=n.updateQueue,r!==null&&(r=r.lastEffect,r!==null))){i=r=r.next;do{var a=i,o=a.destroy;a=a.tag,o!==void 0&&(a&2||a&4)&&pc(n,t,o),i=i.next}while(i!==r)}Ec(e,t,n);break;case 1:if(!uc&&(fc(n,t),r=n.stateNode,typeof r.componentWillUnmount==`function`))try{r.props=n.memoizedProps,r.state=n.memoizedState,r.componentWillUnmount()}catch(e){Rl(n,t,e)}Ec(e,t,n);break;case 21:Ec(e,t,n);break;case 22:n.mode&1?(uc=(r=uc)||n.memoizedState!==null,Ec(e,t,n),uc=r):Ec(e,t,n);break;default:Ec(e,t,n)}}function Oc(e){var t=e.updateQueue;if(t!==null){e.updateQueue=null;var n=e.stateNode;n===null&&(n=e.stateNode=new dc),t.forEach(function(t){var r=Hl.bind(null,e,t);n.has(t)||(n.add(t),t.then(r,r))})}}function kc(e,t){var n=t.deletions;if(n!==null)for(var i=0;ia&&(a=s),i&=~o}if(i=a,i=F()-i,i=(120>i?120:480>i?480:1080>i?1080:1920>i?1920:3e3>i?3e3:4320>i?4320:1960*Lc(i/1960))-i,10e?16:e,ol===null)var i=!1;else{if(e=ol,ol=null,sl=0,$&6)throw Error(r(331));var a=$;for($|=4,Q=e.current;Q!==null;){var o=Q,s=o.child;if(Q.flags&16){var c=o.deletions;if(c!==null){for(var l=0;lF()-$c?Tl(e,0):Xc|=n),hl(e,t)}function Bl(e,t){t===0&&(e.mode&1?(t=Ft,Ft<<=1,!(Ft&130023424)&&(Ft=4194304)):t=1);var n=fl();e=Ya(e,t),e!==null&&(Ut(e,t,n),hl(e,n))}function Vl(e){var t=e.memoizedState,n=0;t!==null&&(n=t.retryLane),Bl(e,n)}function Hl(e,t){var n=0;switch(e.tag){case 13:var i=e.stateNode,a=e.memoizedState;a!==null&&(n=a.retryLane);break;case 19:i=e.stateNode;break;default:throw Error(r(314))}i!==null&&i.delete(t),Bl(e,n)}var Ul=function(e,t,n){if(e!==null){if(e.memoizedProps!==t.pendingProps||Wi.current)Ms=!0;else{if((e.lanes&n)===0&&!(t.flags&128))return Ms=!1,tc(e,t,n);Ms=!!(e.flags&131072)}}else Ms=!1,Y&&t.flags&1048576&&ha(t,ca,t.index);switch(t.lanes=0,t.tag){case 2:var i=t.type;$s(e,t),e=t.pendingProps;var a=Ki(t,Ui.current);Wa(t,n),a=ko(null,t,i,e,a,n);var o=Ao();return t.flags|=1,typeof a==`object`&&a&&typeof a.render==`function`&&a.$$typeof===void 0?(t.tag=1,t.memoizedState=null,t.updateQueue=null,qi(i)?(o=!0,Zi(t)):o=!1,t.memoizedState=a.state!==null&&a.state!==void 0?a.state:null,Za(t),a.updater=_s,t.stateNode=a,a._reactInternals=t,xs(t,i,e,n),t=Vs(null,t,i,!0,o,n)):(t.tag=0,Y&&o&&ga(t),Ns(null,t,a,n),t=t.child),t;case 16:i=t.elementType;a:{switch($s(e,t),e=t.pendingProps,a=i._init,i=a(i._payload),t.type=i,a=t.tag=Jl(i),e=hs(i,e),a){case 0:t=zs(null,t,i,e,n);break a;case 1:t=Bs(null,t,i,e,n);break a;case 11:t=Ps(null,t,i,e,n);break a;case 14:t=Fs(null,t,i,hs(i.type,e),n);break a}throw Error(r(306,i,``))}return t;case 0:return i=t.type,a=t.pendingProps,a=t.elementType===i?a:hs(i,a),zs(e,t,i,a,n);case 1:return i=t.type,a=t.pendingProps,a=t.elementType===i?a:hs(i,a),Bs(e,t,i,a,n);case 3:a:{if(Hs(t),e===null)throw Error(r(387));i=t.pendingProps,o=t.memoizedState,a=o.element,Qa(e,t),ro(t,i,null,n);var s=t.memoizedState;if(i=s.element,o.isDehydrated){if(o={element:i,isDehydrated:!1,cache:s.cache,pendingSuspenseBoundaries:s.pendingSuspenseBoundaries,transitions:s.transitions},t.updateQueue.baseState=o,t.memoizedState=o,t.flags&256){a=Ss(Error(r(423)),t),t=Us(e,t,i,n,a);break a}if(i!==a){a=Ss(Error(r(424)),t),t=Us(e,t,i,n,a);break a}for(ya=U(t.stateNode.containerInfo.firstChild),va=t,Y=!0,ba=null,n=Ia(t,null,i,n),t.child=n;n;)n.flags=n.flags&-3|4096,n=n.sibling}else{if(Oa(),i===a){t=ec(e,t,n);break a}Ns(e,t,i,n)}t=t.child}return t;case 5:return po(t),e===null&&wa(t),i=t.type,a=t.pendingProps,o=e===null?null:e.memoizedProps,s=a.children,Ci(i,a)?s=null:o!==null&&Ci(i,o)&&(t.flags|=32),Rs(e,t),Ns(e,t,s,n),t.child;case 6:return e===null&&wa(t),null;case 13:return Ks(e,t,n);case 4:return uo(t,t.stateNode.containerInfo),i=t.pendingProps,e===null?t.child=Fa(t,null,i,n):Ns(e,t,i,n),t.child;case 11:return i=t.type,a=t.pendingProps,a=t.elementType===i?a:hs(i,a),Ps(e,t,i,a,n);case 7:return Ns(e,t,t.pendingProps,n),t.child;case 8:return Ns(e,t,t.pendingProps.children,n),t.child;case 12:return Ns(e,t,t.pendingProps.children,n),t.child;case 10:a:{if(i=t.type._context,a=t.pendingProps,o=t.memoizedProps,s=a.value,J(La,i._currentValue),i._currentValue=s,o!==null){if(kr(o.value,s)){if(o.children===a.children&&!Wi.current){t=ec(e,t,n);break a}}else for(o=t.child,o!==null&&(o.return=t);o!==null;){var c=o.dependencies;if(c!==null){s=o.child;for(var l=c.firstContext;l!==null;){if(l.context===i){if(o.tag===1){l=$a(-1,n&-n),l.tag=2;var u=o.updateQueue;if(u!==null){u=u.shared;var d=u.pending;d===null?l.next=l:(l.next=d.next,d.next=l),u.pending=l}}o.lanes|=n,l=o.alternate,l!==null&&(l.lanes|=n),Ua(o.return,n,t),c.lanes|=n;break}l=l.next}}else if(o.tag===10)s=o.type===t.type?null:o.child;else if(o.tag===18){if(s=o.return,s===null)throw Error(r(341));s.lanes|=n,c=s.alternate,c!==null&&(c.lanes|=n),Ua(s,n,t),s=o.sibling}else s=o.child;if(s!==null)s.return=o;else for(s=o;s!==null;){if(s===t){s=null;break}if(o=s.sibling,o!==null){o.return=s.return,s=o;break}s=s.return}o=s}}Ns(e,t,a.children,n),t=t.child}return t;case 9:return a=t.type,i=t.pendingProps.children,Wa(t,n),a=Ga(a),i=i(a),t.flags|=1,Ns(e,t,i,n),t.child;case 14:return i=t.type,a=hs(i,t.pendingProps),a=hs(i.type,a),Fs(e,t,i,a,n);case 15:return Is(e,t,t.type,t.pendingProps,n);case 17:return i=t.type,a=t.pendingProps,a=t.elementType===i?a:hs(i,a),$s(e,t),t.tag=1,qi(i)?(e=!0,Zi(t)):e=!1,Wa(t,n),ys(t,i,a),xs(t,i,a,n),Vs(null,t,i,!0,e,n);case 19:return Qs(e,t,n);case 22:return Ls(e,t,n)}throw Error(r(156,t.tag))};function Wl(e,t){return _t(e,t)}function Gl(e,t,n,r){this.tag=e,this.key=n,this.sibling=this.child=this.return=this.stateNode=this.type=this.elementType=null,this.index=0,this.ref=null,this.pendingProps=t,this.dependencies=this.memoizedState=this.updateQueue=this.memoizedProps=null,this.mode=r,this.subtreeFlags=this.flags=0,this.deletions=null,this.childLanes=this.lanes=0,this.alternate=null}function Kl(e,t,n,r){return new Gl(e,t,n,r)}function ql(e){return e=e.prototype,!(!e||!e.isReactComponent)}function Jl(e){if(typeof e==`function`)return+!!ql(e);if(e!=null){if(e=e.$$typeof,e===ee)return 11;if(e===M)return 14}return 2}function Yl(e,t){var n=e.alternate;return n===null?(n=Kl(e.tag,t,e.key,e.mode),n.elementType=e.elementType,n.type=e.type,n.stateNode=e.stateNode,n.alternate=e,e.alternate=n):(n.pendingProps=t,n.type=e.type,n.flags=0,n.subtreeFlags=0,n.deletions=null),n.flags=e.flags&14680064,n.childLanes=e.childLanes,n.lanes=e.lanes,n.child=e.child,n.memoizedProps=e.memoizedProps,n.memoizedState=e.memoizedState,n.updateQueue=e.updateQueue,t=e.dependencies,n.dependencies=t===null?null:{lanes:t.lanes,firstContext:t.firstContext},n.sibling=e.sibling,n.index=e.index,n.ref=e.ref,n}function Xl(e,t,n,i,a,o){var s=2;if(i=e,typeof e==`function`)ql(e)&&(s=1);else if(typeof e==`string`)s=5;else a:switch(e){case T:return Zl(n.children,a,o,t);case E:s=8,a|=8;break;case D:return e=Kl(12,n,t,a|2),e.elementType=D,e.lanes=o,e;case A:return e=Kl(13,n,t,a),e.elementType=A,e.lanes=o,e;case j:return e=Kl(19,n,t,a),e.elementType=j,e.lanes=o,e;case ne:return Ql(n,a,o,t);default:if(typeof e==`object`&&e)switch(e.$$typeof){case O:s=10;break a;case k:s=9;break a;case ee:s=11;break a;case M:s=14;break a;case te:s=16,i=null;break a}throw Error(r(130,e==null?e:typeof e,``))}return t=Kl(s,n,t,a),t.elementType=e,t.type=i,t.lanes=o,t}function Zl(e,t,n,r){return e=Kl(7,e,r,t),e.lanes=n,e}function Ql(e,t,n,r){return e=Kl(22,e,r,t),e.elementType=ne,e.lanes=n,e.stateNode={isHidden:!1},e}function $l(e,t,n){return e=Kl(6,e,null,t),e.lanes=n,e}function eu(e,t,n){return t=Kl(4,e.children===null?[]:e.children,e.key,t),t.lanes=n,t.stateNode={containerInfo:e.containerInfo,pendingChildren:null,implementation:e.implementation},t}function tu(e,t,n,r,i){this.tag=t,this.containerInfo=e,this.finishedWork=this.pingCache=this.current=this.pendingChildren=null,this.timeoutHandle=-1,this.callbackNode=this.pendingContext=this.context=null,this.callbackPriority=0,this.eventTimes=Ht(0),this.expirationTimes=Ht(-1),this.entangledLanes=this.finishedLanes=this.mutableReadLanes=this.expiredLanes=this.pingedLanes=this.suspendedLanes=this.pendingLanes=0,this.entanglements=Ht(0),this.identifierPrefix=r,this.onRecoverableError=i,this.mutableSourceEagerHydrationData=null}function nu(e,t,n,r,i,a,o,s,c){return e=new tu(e,t,n,s,c),t===1?(t=1,!0===a&&(t|=8)):t=0,a=Kl(3,null,null,t),e.current=a,a.stateNode=e,a.memoizedState={element:r,isDehydrated:n,cache:null,transitions:null,pendingSuspenseBoundaries:null},Za(a),e}function ru(e,t,n){var r=3{function n(){if(typeof __REACT_DEVTOOLS_GLOBAL_HOOK__<`u`&&typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE==`function`)try{__REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE(n)}catch(e){console.error(e)}}n(),t.exports=Ve()})),Ue=b((e=>{var t=He();e.createRoot=t.createRoot,e.hydrateRoot=t.hydrateRoot})),We=o(`alarm-clock`,[[`circle`,{cx:`12`,cy:`13`,r:`8`,key:`3y4lt7`}],[`path`,{d:`M12 9v4l2 2`,key:`1c63tq`}],[`path`,{d:`M5 3 2 6`,key:`18tl5t`}],[`path`,{d:`m22 6-3-3`,key:`1opdir`}],[`path`,{d:`M6.38 18.7 4 21`,key:`17xu3x`}],[`path`,{d:`M17.64 18.67 20 21`,key:`kv2oe2`}]]),Ge=o(`arrow-down`,[[`path`,{d:`M12 5v14`,key:`s699le`}],[`path`,{d:`m19 12-7 7-7-7`,key:`1idqje`}]]),Ke=o(`arrow-left`,[[`path`,{d:`m12 19-7-7 7-7`,key:`1l729n`}],[`path`,{d:`M19 12H5`,key:`x3x0zl`}]]),qe=o(`arrow-right`,[[`path`,{d:`M5 12h14`,key:`1ays0h`}],[`path`,{d:`m12 5 7 7-7 7`,key:`xquz4c`}]]),Je=o(`arrow-up`,[[`path`,{d:`m5 12 7-7 7 7`,key:`hav0vg`}],[`path`,{d:`M12 19V5`,key:`x0mq9r`}]]),Ye=o(`ban`,[[`circle`,{cx:`12`,cy:`12`,r:`10`,key:`1mglay`}],[`path`,{d:`M4.929 4.929 19.07 19.071`,key:`196cmz`}]]),Xe=o(`bell`,[[`path`,{d:`M10.268 21a2 2 0 0 0 3.464 0`,key:`vwvbt9`}],[`path`,{d:`M3.262 15.326A1 1 0 0 0 4 17h16a1 1 0 0 0 .74-1.673C19.41 13.956 18 12.499 18 8A6 6 0 0 0 6 8c0 4.499-1.411 5.956-2.738 7.326`,key:`11g9vi`}]]),Ze=o(`bot`,[[`path`,{d:`M12 8V4H8`,key:`hb8ula`}],[`rect`,{width:`16`,height:`12`,x:`4`,y:`8`,rx:`2`,key:`enze0r`}],[`path`,{d:`M2 14h2`,key:`vft8re`}],[`path`,{d:`M20 14h2`,key:`4cs60a`}],[`path`,{d:`M15 13v2`,key:`1xurst`}],[`path`,{d:`M9 13v2`,key:`rq6x2g`}]]),Qe=o(`brain`,[[`path`,{d:`M12 18V5`,key:`adv99a`}],[`path`,{d:`M15 13a4.17 4.17 0 0 1-3-4 4.17 4.17 0 0 1-3 4`,key:`1e3is1`}],[`path`,{d:`M17.598 6.5A3 3 0 1 0 12 5a3 3 0 1 0-5.598 1.5`,key:`1gqd8o`}],[`path`,{d:`M17.997 5.125a4 4 0 0 1 2.526 5.77`,key:`iwvgf7`}],[`path`,{d:`M18 18a4 4 0 0 0 2-7.464`,key:`efp6ie`}],[`path`,{d:`M19.967 17.483A4 4 0 1 1 12 18a4 4 0 1 1-7.967-.517`,key:`1gq6am`}],[`path`,{d:`M6 18a4 4 0 0 1-2-7.464`,key:`k1g0md`}],[`path`,{d:`M6.003 5.125a4 4 0 0 0-2.526 5.77`,key:`q97ue3`}]]),$e=o(`briefcase`,[[`path`,{d:`M16 20V4a2 2 0 0 0-2-2h-4a2 2 0 0 0-2 2v16`,key:`jecpp`}],[`rect`,{width:`20`,height:`14`,x:`2`,y:`6`,rx:`2`,key:`i6l2r4`}]]),et=o(`calendar-clock`,[[`path`,{d:`M16 14v2.2l1.6 1`,key:`fo4ql5`}],[`path`,{d:`M16 2v4`,key:`4m81vk`}],[`path`,{d:`M21 7.5V6a2 2 0 0 0-2-2H5a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h3.5`,key:`1osxxc`}],[`path`,{d:`M3 10h5`,key:`r794hk`}],[`path`,{d:`M8 2v4`,key:`1cmpym`}],[`circle`,{cx:`16`,cy:`16`,r:`6`,key:`qoo3c4`}]]),tt=o(`calendar-days`,[[`path`,{d:`M8 2v4`,key:`1cmpym`}],[`path`,{d:`M16 2v4`,key:`4m81vk`}],[`rect`,{width:`18`,height:`18`,x:`3`,y:`4`,rx:`2`,key:`1hopcy`}],[`path`,{d:`M3 10h18`,key:`8toen8`}],[`path`,{d:`M8 14h.01`,key:`6423bh`}],[`path`,{d:`M12 14h.01`,key:`1etili`}],[`path`,{d:`M16 14h.01`,key:`1gbofw`}],[`path`,{d:`M8 18h.01`,key:`lrp35t`}],[`path`,{d:`M12 18h.01`,key:`mhygvu`}],[`path`,{d:`M16 18h.01`,key:`kzsmim`}]]),nt=o(`calendar-plus`,[[`path`,{d:`M16 19h6`,key:`xwg31i`}],[`path`,{d:`M16 2v4`,key:`4m81vk`}],[`path`,{d:`M19 16v6`,key:`tddt3s`}],[`path`,{d:`M21 12.598V6a2 2 0 0 0-2-2H5a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h8.5`,key:`1glfrc`}],[`path`,{d:`M3 10h18`,key:`8toen8`}],[`path`,{d:`M8 2v4`,key:`1cmpym`}]]),rt=o(`chevron-right`,[[`path`,{d:`m9 18 6-6-6-6`,key:`mthhwq`}]]),it=o(`clipboard-list`,[[`rect`,{width:`8`,height:`4`,x:`8`,y:`2`,rx:`1`,ry:`1`,key:`tgr4d6`}],[`path`,{d:`M16 4h2a2 2 0 0 1 2 2v14a2 2 0 0 1-2 2H6a2 2 0 0 1-2-2V6a2 2 0 0 1 2-2h2`,key:`116196`}],[`path`,{d:`M12 11h4`,key:`1jrz19`}],[`path`,{d:`M12 16h4`,key:`n85exb`}],[`path`,{d:`M8 11h.01`,key:`1dfujw`}],[`path`,{d:`M8 16h.01`,key:`18s6g9`}]]),at=o(`clock`,[[`circle`,{cx:`12`,cy:`12`,r:`10`,key:`1mglay`}],[`path`,{d:`M12 6v6l4 2`,key:`mmk7yg`}]]),ot=o(`cloud-cog`,[[`path`,{d:`m10.852 19.772-.383.924`,key:`r7sl7d`}],[`path`,{d:`m13.148 14.228.383-.923`,key:`1d5zpm`}],[`path`,{d:`M13.148 19.772a3 3 0 1 0-2.296-5.544l-.383-.923`,key:`1ydik7`}],[`path`,{d:`m13.53 20.696-.382-.924a3 3 0 1 1-2.296-5.544`,key:`1m1vsf`}],[`path`,{d:`m14.772 15.852.923-.383`,key:`660p6e`}],[`path`,{d:`m14.772 18.148.923.383`,key:`hrcpis`}],[`path`,{d:`M4.2 15.1a7 7 0 1 1 9.93-9.858A7 7 0 0 1 15.71 8h1.79a4.5 4.5 0 0 1 2.5 8.2`,key:`j2q98n`}],[`path`,{d:`m9.228 15.852-.923-.383`,key:`1p9ong`}],[`path`,{d:`m9.228 18.148-.923.383`,key:`6558rz`}]]),st=o(`cloud`,[[`path`,{d:`M17.5 19H9a7 7 0 1 1 6.71-9h1.79a4.5 4.5 0 1 1 0 9Z`,key:`p7xjir`}]]),ct=o(`code-xml`,[[`path`,{d:`m18 16 4-4-4-4`,key:`1inbqp`}],[`path`,{d:`m6 8-4 4 4 4`,key:`15zrgr`}],[`path`,{d:`m14.5 4-5 16`,key:`e7oirm`}]]),lt=o(`compass`,[[`circle`,{cx:`12`,cy:`12`,r:`10`,key:`1mglay`}],[`path`,{d:`m16.24 7.76-1.804 5.411a2 2 0 0 1-1.265 1.265L7.76 16.24l1.804-5.411a2 2 0 0 1 1.265-1.265z`,key:`9ktpf1`}]]),ut=o(`copy`,[[`rect`,{width:`14`,height:`14`,x:`8`,y:`8`,rx:`2`,ry:`2`,key:`17jyea`}],[`path`,{d:`M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2`,key:`zix9uf`}]]),dt=o(`corner-down-left`,[[`path`,{d:`M20 4v7a4 4 0 0 1-4 4H4`,key:`6o5b7l`}],[`path`,{d:`m9 10-5 5 5 5`,key:`1kshq7`}]]),ft=o(`download`,[[`path`,{d:`M12 15V3`,key:`m9g1x1`}],[`path`,{d:`M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4`,key:`ih7n3h`}],[`path`,{d:`m7 10 5 5 5-5`,key:`brsn70`}]]),pt=o(`ellipsis`,[[`circle`,{cx:`12`,cy:`12`,r:`1`,key:`41hilf`}],[`circle`,{cx:`19`,cy:`12`,r:`1`,key:`1wjl8i`}],[`circle`,{cx:`5`,cy:`12`,r:`1`,key:`1pcz8c`}]]),mt=o(`file-text`,[[`path`,{d:`M6 22a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h8a2.4 2.4 0 0 1 1.704.706l3.588 3.588A2.4 2.4 0 0 1 20 8v12a2 2 0 0 1-2 2z`,key:`1oefj6`}],[`path`,{d:`M14 2v5a1 1 0 0 0 1 1h5`,key:`wfsgrz`}],[`path`,{d:`M10 9H8`,key:`b1mrlr`}],[`path`,{d:`M16 13H8`,key:`t4e002`}],[`path`,{d:`M16 17H8`,key:`z1uh3a`}]]),ht=o(`fingerprint-pattern`,[[`path`,{d:`M12 10a2 2 0 0 0-2 2c0 1.02-.1 2.51-.26 4`,key:`1nerag`}],[`path`,{d:`M14 13.12c0 2.38 0 6.38-1 8.88`,key:`o46ks0`}],[`path`,{d:`M17.29 21.02c.12-.6.43-2.3.5-3.02`,key:`ptglia`}],[`path`,{d:`M2 12a10 10 0 0 1 18-6`,key:`ydlgp0`}],[`path`,{d:`M2 16h.01`,key:`1gqxmh`}],[`path`,{d:`M21.8 16c.2-2 .131-5.354 0-6`,key:`drycrb`}],[`path`,{d:`M5 19.5C5.5 18 6 15 6 12a6 6 0 0 1 .34-2`,key:`1tidbn`}],[`path`,{d:`M8.65 22c.21-.66.45-1.32.57-2`,key:`13wd9y`}],[`path`,{d:`M9 6.8a6 6 0 0 1 9 5.2v2`,key:`1fr1j5`}]]),gt=o(`globe`,[[`circle`,{cx:`12`,cy:`12`,r:`10`,key:`1mglay`}],[`path`,{d:`M12 2a14.5 14.5 0 0 0 0 20 14.5 14.5 0 0 0 0-20`,key:`13o1zl`}],[`path`,{d:`M2 12h20`,key:`9i4pu4`}]]),_t=o(`graduation-cap`,[[`path`,{d:`M21.42 10.922a1 1 0 0 0-.019-1.838L12.83 5.18a2 2 0 0 0-1.66 0L2.6 9.08a1 1 0 0 0 0 1.832l8.57 3.908a2 2 0 0 0 1.66 0z`,key:`j76jl0`}],[`path`,{d:`M22 10v6`,key:`1lu8f3`}],[`path`,{d:`M6 12.5V16a6 3 0 0 0 12 0v-3.5`,key:`1r8lef`}]]),vt=o(`hand`,[[`path`,{d:`M18 11V6a2 2 0 0 0-2-2a2 2 0 0 0-2 2`,key:`1fvzgz`}],[`path`,{d:`M14 10V4a2 2 0 0 0-2-2a2 2 0 0 0-2 2v2`,key:`1kc0my`}],[`path`,{d:`M10 10.5V6a2 2 0 0 0-2-2a2 2 0 0 0-2 2v8`,key:`10h0bg`}],[`path`,{d:`M18 8a2 2 0 1 1 4 0v6a8 8 0 0 1-8 8h-2c-2.8 0-4.5-.86-5.99-2.34l-3.6-3.6a2 2 0 0 1 2.83-2.82L7 15`,key:`1s1gnw`}]]),yt=o(`heart`,[[`path`,{d:`M2 9.5a5.5 5.5 0 0 1 9.591-3.676.56.56 0 0 0 .818 0A5.49 5.49 0 0 1 22 9.5c0 2.29-1.5 4-3 5.5l-5.492 5.313a2 2 0 0 1-3 .019L5 15c-1.5-1.5-3-3.2-3-5.5`,key:`mvr1a0`}]]),bt=o(`house`,[[`path`,{d:`M15 21v-8a1 1 0 0 0-1-1h-4a1 1 0 0 0-1 1v8`,key:`5wwlr5`}],[`path`,{d:`M3 10a2 2 0 0 1 .709-1.528l7-6a2 2 0 0 1 2.582 0l7 6A2 2 0 0 1 21 10v9a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z`,key:`r6nss1`}]]),F=o(`info`,[[`circle`,{cx:`12`,cy:`12`,r:`10`,key:`1mglay`}],[`path`,{d:`M12 16v-4`,key:`1dtifu`}],[`path`,{d:`M12 8h.01`,key:`e9boi3`}]]),xt=o(`key-round`,[[`path`,{d:`M2.586 17.414A2 2 0 0 0 2 18.828V21a1 1 0 0 0 1 1h3a1 1 0 0 0 1-1v-1a1 1 0 0 1 1-1h1a1 1 0 0 0 1-1v-1a1 1 0 0 1 1-1h.172a2 2 0 0 0 1.414-.586l.814-.814a6.5 6.5 0 1 0-4-4z`,key:`1s6t7t`}],[`circle`,{cx:`16.5`,cy:`7.5`,r:`.5`,fill:`currentColor`,key:`w0ekpg`}]]),St=o(`layout-grid`,[[`rect`,{width:`7`,height:`7`,x:`3`,y:`3`,rx:`1`,key:`1g98yp`}],[`rect`,{width:`7`,height:`7`,x:`14`,y:`3`,rx:`1`,key:`6d4xhi`}],[`rect`,{width:`7`,height:`7`,x:`14`,y:`14`,rx:`1`,key:`nxv5o0`}],[`rect`,{width:`7`,height:`7`,x:`3`,y:`14`,rx:`1`,key:`1bb6yr`}]]),Ct=o(`lightbulb`,[[`path`,{d:`M15 14c.2-1 .7-1.7 1.5-2.5 1-.9 1.5-2.2 1.5-3.5A6 6 0 0 0 6 8c0 1 .2 2.2 1.5 3.5.7.7 1.3 1.5 1.5 2.5`,key:`1gvzjb`}],[`path`,{d:`M9 18h6`,key:`x1upvd`}],[`path`,{d:`M10 22h4`,key:`ceow96`}]]),wt=o(`log-in`,[[`path`,{d:`m10 17 5-5-5-5`,key:`1bsop3`}],[`path`,{d:`M15 12H3`,key:`6jk70r`}],[`path`,{d:`M15 3h4a2 2 0 0 1 2 2v14a2 2 0 0 1-2 2h-4`,key:`u53s6r`}]]),Tt=o(`log-out`,[[`path`,{d:`m16 17 5-5-5-5`,key:`1bji2h`}],[`path`,{d:`M21 12H9`,key:`dn1m92`}],[`path`,{d:`M9 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h4`,key:`1uf3rs`}]]),Et=o(`mail`,[[`path`,{d:`m22 7-8.991 5.727a2 2 0 0 1-2.009 0L2 7`,key:`132q7q`}],[`rect`,{x:`2`,y:`4`,width:`20`,height:`16`,rx:`2`,key:`izxlao`}]]),Dt=o(`map-pin`,[[`path`,{d:`M20 10c0 4.993-5.539 10.193-7.399 11.799a1 1 0 0 1-1.202 0C9.539 20.193 4 14.993 4 10a8 8 0 0 1 16 0`,key:`1r0f0z`}],[`circle`,{cx:`12`,cy:`10`,r:`3`,key:`ilqhr7`}]]),Ot=o(`menu`,[[`path`,{d:`M4 5h16`,key:`1tepv9`}],[`path`,{d:`M4 12h16`,key:`1lakjw`}],[`path`,{d:`M4 19h16`,key:`1djgab`}]]),kt=o(`message-circle-question-mark`,[[`path`,{d:`M2.992 16.342a2 2 0 0 1 .094 1.167l-1.065 3.29a1 1 0 0 0 1.236 1.168l3.413-.998a2 2 0 0 1 1.099.092 10 10 0 1 0-4.777-4.719`,key:`1sd12s`}],[`path`,{d:`M9.09 9a3 3 0 0 1 5.83 1c0 2-3 3-3 3`,key:`1u773s`}],[`path`,{d:`M12 17h.01`,key:`p32p05`}]]),At=o(`message-circle`,[[`path`,{d:`M2.992 16.342a2 2 0 0 1 .094 1.167l-1.065 3.29a1 1 0 0 0 1.236 1.168l3.413-.998a2 2 0 0 1 1.099.092 10 10 0 1 0-4.777-4.719`,key:`1sd12s`}]]),jt=o(`message-square-plus`,[[`path`,{d:`M22 17a2 2 0 0 1-2 2H6.828a2 2 0 0 0-1.414.586l-2.202 2.202A.71.71 0 0 1 2 21.286V5a2 2 0 0 1 2-2h16a2 2 0 0 1 2 2z`,key:`18887p`}],[`path`,{d:`M12 8v6`,key:`1ib9pf`}],[`path`,{d:`M9 11h6`,key:`1fldmi`}]]),Mt=o(`message-square-text`,[[`path`,{d:`M22 17a2 2 0 0 1-2 2H6.828a2 2 0 0 0-1.414.586l-2.202 2.202A.71.71 0 0 1 2 21.286V5a2 2 0 0 1 2-2h16a2 2 0 0 1 2 2z`,key:`18887p`}],[`path`,{d:`M7 11h10`,key:`1twpyw`}],[`path`,{d:`M7 15h6`,key:`d9of3u`}],[`path`,{d:`M7 7h8`,key:`af5zfr`}]]),Nt=o(`message-square`,[[`path`,{d:`M22 17a2 2 0 0 1-2 2H6.828a2 2 0 0 0-1.414.586l-2.202 2.202A.71.71 0 0 1 2 21.286V5a2 2 0 0 1 2-2h16a2 2 0 0 1 2 2z`,key:`18887p`}]]),Pt=o(`mic-off`,[[`path`,{d:`M12 19v3`,key:`npa21l`}],[`path`,{d:`M15 9.34V5a3 3 0 0 0-5.68-1.33`,key:`1gzdoj`}],[`path`,{d:`M16.95 16.95A7 7 0 0 1 5 12v-2`,key:`cqa7eg`}],[`path`,{d:`M18.89 13.23A7 7 0 0 0 19 12v-2`,key:`16hl24`}],[`path`,{d:`m2 2 20 20`,key:`1ooewy`}],[`path`,{d:`M9 9v3a3 3 0 0 0 5.12 2.12`,key:`r2i35w`}]]),Ft=o(`mic`,[[`path`,{d:`M12 19v3`,key:`npa21l`}],[`path`,{d:`M19 10v2a7 7 0 0 1-14 0v-2`,key:`1vc78b`}],[`rect`,{x:`9`,y:`2`,width:`6`,height:`13`,rx:`3`,key:`s6n7sd`}]]),It=o(`monitor-smartphone`,[[`path`,{d:`M18 8V6a2 2 0 0 0-2-2H4a2 2 0 0 0-2 2v7a2 2 0 0 0 2 2h8`,key:`10dyio`}],[`path`,{d:`M10 19v-3.96 3.15`,key:`1irgej`}],[`path`,{d:`M7 19h5`,key:`qswx4l`}],[`rect`,{width:`6`,height:`10`,x:`16`,y:`12`,rx:`2`,key:`1egngj`}]]),Lt=o(`monitor`,[[`rect`,{width:`20`,height:`14`,x:`2`,y:`3`,rx:`2`,key:`48i651`}],[`line`,{x1:`8`,x2:`16`,y1:`21`,y2:`21`,key:`1svkeh`}],[`line`,{x1:`12`,x2:`12`,y1:`17`,y2:`21`,key:`vw1qmm`}]]),Rt=o(`moon`,[[`path`,{d:`M20.985 12.486a9 9 0 1 1-9.473-9.472c.405-.022.617.46.402.803a6 6 0 0 0 8.268 8.268c.344-.215.825-.004.803.401`,key:`kfwtm`}]]),zt=o(`mouse-pointer-click`,[[`path`,{d:`M14 4.1 12 6`,key:`ita8i4`}],[`path`,{d:`m5.1 8-2.9-.8`,key:`1go3kf`}],[`path`,{d:`m6 12-1.9 2`,key:`mnht97`}],[`path`,{d:`M7.2 2.2 8 5.1`,key:`1cfko1`}],[`path`,{d:`M9.037 9.69a.498.498 0 0 1 .653-.653l11 4.5a.5.5 0 0 1-.074.949l-4.349 1.041a1 1 0 0 0-.74.739l-1.04 4.35a.5.5 0 0 1-.95.074z`,key:`s0h3yz`}]]),Bt=o(`newspaper`,[[`path`,{d:`M15 18h-5`,key:`95g1m2`}],[`path`,{d:`M18 14h-8`,key:`sponae`}],[`path`,{d:`M4 22h16a2 2 0 0 0 2-2V4a2 2 0 0 0-2-2H8a2 2 0 0 0-2 2v16a2 2 0 0 1-4 0v-9a2 2 0 0 1 2-2h2`,key:`39pd36`}],[`rect`,{width:`8`,height:`4`,x:`10`,y:`6`,rx:`1`,key:`aywv1n`}]]),Vt=o(`palette`,[[`path`,{d:`M12 22a1 1 0 0 1 0-20 10 9 0 0 1 10 9 5 5 0 0 1-5 5h-2.25a1.75 1.75 0 0 0-1.4 2.8l.3.4a1.75 1.75 0 0 1-1.4 2.8z`,key:`e79jfc`}],[`circle`,{cx:`13.5`,cy:`6.5`,r:`.5`,fill:`currentColor`,key:`1okk4w`}],[`circle`,{cx:`17.5`,cy:`10.5`,r:`.5`,fill:`currentColor`,key:`f64h9f`}],[`circle`,{cx:`6.5`,cy:`12.5`,r:`.5`,fill:`currentColor`,key:`qy21gx`}],[`circle`,{cx:`8.5`,cy:`7.5`,r:`.5`,fill:`currentColor`,key:`fotxhn`}]]),Ht=o(`pencil`,[[`path`,{d:`M21.174 6.812a1 1 0 0 0-3.986-3.987L3.842 16.174a2 2 0 0 0-.5.83l-1.321 4.352a.5.5 0 0 0 .623.622l4.353-1.32a2 2 0 0 0 .83-.497z`,key:`1a8usu`}],[`path`,{d:`m15 5 4 4`,key:`1mk7zo`}]]),Ut=o(`phone`,[[`path`,{d:`M13.832 16.568a1 1 0 0 0 1.213-.303l.355-.465A2 2 0 0 1 17 15h3a2 2 0 0 1 2 2v3a2 2 0 0 1-2 2A18 18 0 0 1 2 4a2 2 0 0 1 2-2h3a2 2 0 0 1 2 2v3a2 2 0 0 1-.8 1.6l-.468.351a1 1 0 0 0-.292 1.233 14 14 0 0 0 6.392 6.384`,key:`9njp5v`}]]),Wt=o(`piggy-bank`,[[`path`,{d:`M11 17h3v2a1 1 0 0 0 1 1h2a1 1 0 0 0 1-1v-3a3.16 3.16 0 0 0 2-2h1a1 1 0 0 0 1-1v-2a1 1 0 0 0-1-1h-1a5 5 0 0 0-2-4V3a4 4 0 0 0-3.2 1.6l-.3.4H11a6 6 0 0 0-6 6v1a5 5 0 0 0 2 4v3a1 1 0 0 0 1 1h2a1 1 0 0 0 1-1z`,key:`1piglc`}],[`path`,{d:`M16 10h.01`,key:`1m94wz`}],[`path`,{d:`M2 8v1a2 2 0 0 0 2 2h1`,key:`1env43`}]]),Gt=o(`play`,[[`path`,{d:`M5 5a2 2 0 0 1 3.008-1.728l11.997 6.998a2 2 0 0 1 .003 3.458l-12 7A2 2 0 0 1 5 19z`,key:`10ikf1`}]]),I=o(`plus`,[[`path`,{d:`M5 12h14`,key:`1ays0h`}],[`path`,{d:`M12 5v14`,key:`s699le`}]]),Kt=o(`repeat`,[[`path`,{d:`m17 2 4 4-4 4`,key:`nntrym`}],[`path`,{d:`M3 11v-1a4 4 0 0 1 4-4h14`,key:`84bu3i`}],[`path`,{d:`m7 22-4-4 4-4`,key:`1wqhfi`}],[`path`,{d:`M21 13v1a4 4 0 0 1-4 4H3`,key:`1rx37r`}]]),qt=o(`search`,[[`path`,{d:`m21 21-4.34-4.34`,key:`14j7rj`}],[`circle`,{cx:`11`,cy:`11`,r:`8`,key:`4ej97u`}]]),Jt=o(`send`,[[`path`,{d:`M14.536 21.686a.5.5 0 0 0 .937-.024l6.5-19a.496.496 0 0 0-.635-.635l-19 6.5a.5.5 0 0 0-.024.937l7.93 3.18a2 2 0 0 1 1.112 1.11z`,key:`1ffxy3`}],[`path`,{d:`m21.854 2.147-10.94 10.939`,key:`12cjpa`}]]),Yt=o(`settings`,[[`path`,{d:`M9.671 4.136a2.34 2.34 0 0 1 4.659 0 2.34 2.34 0 0 0 3.319 1.915 2.34 2.34 0 0 1 2.33 4.033 2.34 2.34 0 0 0 0 3.831 2.34 2.34 0 0 1-2.33 4.033 2.34 2.34 0 0 0-3.319 1.915 2.34 2.34 0 0 1-4.659 0 2.34 2.34 0 0 0-3.32-1.915 2.34 2.34 0 0 1-2.33-4.033 2.34 2.34 0 0 0 0-3.831A2.34 2.34 0 0 1 6.35 6.051a2.34 2.34 0 0 0 3.319-1.915`,key:`1i5ecw`}],[`circle`,{cx:`12`,cy:`12`,r:`3`,key:`1v7zrd`}]]),Xt=o(`share-2`,[[`circle`,{cx:`18`,cy:`5`,r:`3`,key:`gq8acd`}],[`circle`,{cx:`6`,cy:`12`,r:`3`,key:`w7nqdw`}],[`circle`,{cx:`18`,cy:`19`,r:`3`,key:`1xt0gg`}],[`line`,{x1:`8.59`,x2:`15.42`,y1:`13.51`,y2:`17.49`,key:`47mynk`}],[`line`,{x1:`15.41`,x2:`8.59`,y1:`6.51`,y2:`10.49`,key:`1n3mei`}]]),Zt=o(`shield-alert`,[[`path`,{d:`M20 13c0 5-3.5 7.5-7.66 8.95a1 1 0 0 1-.67-.01C7.5 20.5 4 18 4 13V6a1 1 0 0 1 1-1c2 0 4.5-1.2 6.24-2.72a1.17 1.17 0 0 1 1.52 0C14.51 3.81 17 5 19 5a1 1 0 0 1 1 1z`,key:`oel41y`}],[`path`,{d:`M12 8v4`,key:`1got3b`}],[`path`,{d:`M12 16h.01`,key:`1drbdi`}]]),Qt=o(`shield-check`,[[`path`,{d:`M20 13c0 5-3.5 7.5-7.66 8.95a1 1 0 0 1-.67-.01C7.5 20.5 4 18 4 13V6a1 1 0 0 1 1-1c2 0 4.5-1.2 6.24-2.72a1.17 1.17 0 0 1 1.52 0C14.51 3.81 17 5 19 5a1 1 0 0 1 1 1z`,key:`oel41y`}],[`path`,{d:`m9 12 2 2 4-4`,key:`dzmm74`}]]),$t=o(`shield-off`,[[`path`,{d:`m2 2 20 20`,key:`1ooewy`}],[`path`,{d:`M5 5a1 1 0 0 0-1 1v7c0 5 3.5 7.5 7.67 8.94a1 1 0 0 0 .67.01c2.35-.82 4.48-1.97 5.9-3.71`,key:`1jlk70`}],[`path`,{d:`M9.309 3.652A12.252 12.252 0 0 0 11.24 2.28a1.17 1.17 0 0 1 1.52 0C14.51 3.81 17 5 19 5a1 1 0 0 1 1 1v7a9.784 9.784 0 0 1-.08 1.264`,key:`18rp1v`}]]),en=o(`sliders-horizontal`,[[`path`,{d:`M10 5H3`,key:`1qgfaw`}],[`path`,{d:`M12 19H3`,key:`yhmn1j`}],[`path`,{d:`M14 3v4`,key:`1sua03`}],[`path`,{d:`M16 17v4`,key:`1q0r14`}],[`path`,{d:`M21 12h-9`,key:`1o4lsq`}],[`path`,{d:`M21 19h-5`,key:`1rlt1p`}],[`path`,{d:`M21 5h-7`,key:`1oszz2`}],[`path`,{d:`M8 10v4`,key:`tgpxqk`}],[`path`,{d:`M8 12H3`,key:`a7s4jb`}]]),tn=o(`smartphone`,[[`rect`,{width:`14`,height:`20`,x:`5`,y:`2`,rx:`2`,ry:`2`,key:`1yt0o3`}],[`path`,{d:`M12 18h.01`,key:`mhygvu`}]]),nn=o(`sparkles`,[[`path`,{d:`M11.017 2.814a1 1 0 0 1 1.966 0l1.051 5.558a2 2 0 0 0 1.594 1.594l5.558 1.051a1 1 0 0 1 0 1.966l-5.558 1.051a2 2 0 0 0-1.594 1.594l-1.051 5.558a1 1 0 0 1-1.966 0l-1.051-5.558a2 2 0 0 0-1.594-1.594l-5.558-1.051a1 1 0 0 1 0-1.966l5.558-1.051a2 2 0 0 0 1.594-1.594z`,key:`1s2grr`}],[`path`,{d:`M20 2v4`,key:`1rf3ol`}],[`path`,{d:`M22 4h-4`,key:`gwowj6`}],[`circle`,{cx:`4`,cy:`20`,r:`2`,key:`6kqj1y`}]]),rn=o(`square-check-big`,[[`path`,{d:`M21 10.656V19a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h12.344`,key:`2acyp4`}],[`path`,{d:`m9 11 3 3L22 4`,key:`1pflzl`}]]),an=o(`square-pen`,[[`path`,{d:`M12 3H5a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-7`,key:`1m0v6g`}],[`path`,{d:`M18.375 2.625a1 1 0 0 1 3 3l-9.013 9.014a2 2 0 0 1-.853.505l-2.873.84a.5.5 0 0 1-.62-.62l.84-2.873a2 2 0 0 1 .506-.852z`,key:`ohrbg2`}]]),on=o(`square-terminal`,[[`path`,{d:`m7 11 2-2-2-2`,key:`1lz0vl`}],[`path`,{d:`M11 13h4`,key:`1p7l4v`}],[`rect`,{width:`18`,height:`18`,x:`3`,y:`3`,rx:`2`,ry:`2`,key:`1m3agn`}]]),sn=o(`square`,[[`rect`,{width:`18`,height:`18`,x:`3`,y:`3`,rx:`2`,key:`afitv7`}]]),cn=o(`table-2`,[[`path`,{d:`M9 3H5a2 2 0 0 0-2 2v4m6-6h10a2 2 0 0 1 2 2v4M9 3v18m0 0h10a2 2 0 0 0 2-2V9M9 21H5a2 2 0 0 1-2-2V9m0 0h18`,key:`gugj83`}]]),ln=o(`tag`,[[`path`,{d:`M12.586 2.586A2 2 0 0 0 11.172 2H4a2 2 0 0 0-2 2v7.172a2 2 0 0 0 .586 1.414l8.704 8.704a2.426 2.426 0 0 0 3.42 0l6.58-6.58a2.426 2.426 0 0 0 0-3.42z`,key:`vktsd0`}],[`circle`,{cx:`7.5`,cy:`7.5`,r:`.5`,fill:`currentColor`,key:`kqv944`}]]),un=o(`target`,[[`circle`,{cx:`12`,cy:`12`,r:`10`,key:`1mglay`}],[`circle`,{cx:`12`,cy:`12`,r:`6`,key:`1vlfrh`}],[`circle`,{cx:`12`,cy:`12`,r:`2`,key:`1c9p78`}]]),dn=o(`terminal`,[[`path`,{d:`M12 19h8`,key:`baeox8`}],[`path`,{d:`m4 17 6-6-6-6`,key:`1yngyt`}]]),fn=o(`trash-2`,[[`path`,{d:`M10 11v6`,key:`nco0om`}],[`path`,{d:`M14 11v6`,key:`outv1u`}],[`path`,{d:`M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6`,key:`miytrc`}],[`path`,{d:`M3 6h18`,key:`d0wm0j`}],[`path`,{d:`M8 6V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2`,key:`e791ji`}]]),pn=o(`triangle-alert`,[[`path`,{d:`m21.73 18-8-14a2 2 0 0 0-3.48 0l-8 14A2 2 0 0 0 4 21h16a2 2 0 0 0 1.73-3`,key:`wmoenq`}],[`path`,{d:`M12 9v4`,key:`juzpu7`}],[`path`,{d:`M12 17h.01`,key:`p32p05`}]]),mn=o(`user-round`,[[`circle`,{cx:`12`,cy:`8`,r:`5`,key:`1hypcn`}],[`path`,{d:`M20 21a8 8 0 0 0-16 0`,key:`rfgkzh`}]]),hn=o(`users`,[[`path`,{d:`M16 21v-2a4 4 0 0 0-4-4H6a4 4 0 0 0-4 4v2`,key:`1yyitq`}],[`path`,{d:`M16 3.128a4 4 0 0 1 0 7.744`,key:`16gr8j`}],[`path`,{d:`M22 21v-2a4 4 0 0 0-3-3.87`,key:`kshegd`}],[`circle`,{cx:`9`,cy:`7`,r:`4`,key:`nufk8`}]]),gn=o(`wand-sparkles`,[[`path`,{d:`m21.64 3.64-1.28-1.28a1.21 1.21 0 0 0-1.72 0L2.36 18.64a1.21 1.21 0 0 0 0 1.72l1.28 1.28a1.2 1.2 0 0 0 1.72 0L21.64 5.36a1.2 1.2 0 0 0 0-1.72`,key:`ul74o6`}],[`path`,{d:`m14 7 3 3`,key:`1r5n42`}],[`path`,{d:`M5 6v4`,key:`ilb8ba`}],[`path`,{d:`M19 14v4`,key:`blhpug`}],[`path`,{d:`M10 2v2`,key:`7u0qdc`}],[`path`,{d:`M7 8H3`,key:`zfb6yr`}],[`path`,{d:`M21 16h-4`,key:`1cnmox`}],[`path`,{d:`M11 3H9`,key:`1obp7u`}]]),_n=o(`webhook`,[[`path`,{d:`M18 16.98h-5.99c-1.1 0-1.95.94-2.48 1.9A4 4 0 0 1 2 17c.01-.7.2-1.4.57-2`,key:`q3hayz`}],[`path`,{d:`m6 17 3.13-5.78c.53-.97.1-2.18-.5-3.1a4 4 0 1 1 6.89-4.06`,key:`1go1hn`}],[`path`,{d:`m12 6 3.13 5.73C15.66 12.7 16.9 13 18 13a4 4 0 0 1 0 8`,key:`qlwsc0`}]]),vn=o(`wifi-off`,[[`path`,{d:`M12 20h.01`,key:`zekei9`}],[`path`,{d:`M8.5 16.429a5 5 0 0 1 7 0`,key:`1bycff`}],[`path`,{d:`M5 12.859a10 10 0 0 1 5.17-2.69`,key:`1dl1wf`}],[`path`,{d:`M19 12.859a10 10 0 0 0-2.007-1.523`,key:`4k23kn`}],[`path`,{d:`M2 8.82a15 15 0 0 1 4.177-2.643`,key:`1grhjp`}],[`path`,{d:`M22 8.82a15 15 0 0 0-11.288-3.764`,key:`z3jwby`}],[`path`,{d:`m2 2 20 20`,key:`1ooewy`}]]),yn=o(`wrench`,[[`path`,{d:`M14.7 6.3a1 1 0 0 0 0 1.4l1.6 1.6a1 1 0 0 0 1.4 0l3.106-3.105c.32-.322.863-.22.983.218a6 6 0 0 1-8.259 7.057l-7.91 7.91a1 1 0 0 1-2.999-3l7.91-7.91a6 6 0 0 1 7.057-8.259c.438.12.54.662.219.984z`,key:`1ngwbx`}]]),L=p(x(),1),bn=p(Ue(),1),R=C();function xn({size:e=72,className:t}){return(0,R.jsx)(`img`,{src:`/icon.svg`,alt:`nanoMuse`,width:e,height:e,draggable:!1,className:i(`block shrink-0 select-none`,t),style:{width:e,height:e}})}function Sn(){return window.nanomuseDesktop??null}function Cn(){return!!window.nanomuseDesktop}function wn(){let e=Sn();e&&(document.documentElement.classList.add(`desktop`),document.documentElement.dataset.platform=e.platform)}var Tn=`nm.desktop.remote_hint`;function En(){let{state:e,setTab:t}=E(),n=s(),[r,i]=(0,L.useState)(()=>!Cn()||d(Tn)===`1`),a=e.hub,o=!r&&!!a&&a.state===`connected`&&a.remote_control&&a.account.signed_in;if((0,L.useEffect)(()=>{o&&f(Tn,`1`)},[o]),!o)return null;let c=()=>i(!0);return(0,R.jsxs)(`div`,{className:`flex items-center gap-2.5 border-b border-border bg-accent/10 px-4 py-2 text-[12.5px] text-fg`,children:[(0,R.jsx)(It,{size:16,className:`shrink-0 text-accent`}),(0,R.jsx)(`span`,{className:`min-w-0 flex-1`,children:n(`Your phone can now operate this computer: run commands, fetch files, hand over whole tasks. Each risky step still asks here first.`)}),(0,R.jsx)(`button`,{type:`button`,onClick:()=>{c(),t(`devices`)},className:`shrink-0 rounded-full border border-border bg-surface px-2.5 py-1 text-[12px] font-medium hover:bg-surface-2`,children:n(`Devices`)}),(0,R.jsx)(`button`,{type:`button`,onClick:c,"aria-label":n(`Dismiss`),className:`shrink-0 rounded-full p-1 text-muted hover:text-fg`,children:(0,R.jsx)(Fe,{size:15})})]})}var Dn=`a[href], button:not([disabled]), input:not([disabled]):not([type="hidden"]), select:not([disabled]), textarea:not([disabled]), [tabindex]:not([tabindex="-1"])`;function On(e,t){(0,L.useEffect)(()=>{if(!t)return;let n=e.current;if(!n)return;let r=document.activeElement,i=()=>Array.from(n.querySelectorAll(Dn)).filter(e=>e.offsetParent!==null||e===document.activeElement);if(!n.contains(document.activeElement)){let e=i()[0];e?e.focus():(n.tabIndex=-1,n.focus())}let a=e=>{if(e.key!==`Tab`)return;let t=i();if(t.length===0){e.preventDefault();return}let r=t[0],a=t[t.length-1],o=document.activeElement;e.shiftKey&&(o===r||!n.contains(o))?(e.preventDefault(),a.focus()):!e.shiftKey&&(o===a||!n.contains(o))&&(e.preventDefault(),r.focus())};return document.addEventListener(`keydown`,a,!0),()=>{document.removeEventListener(`keydown`,a,!0),r&&r.isConnected&&typeof r.focus==`function`&&r.focus()}},[e,t])}function kn(){let{state:e,setDrawer:t,setTab:n,openThread:r,toast:i,dispatch:a}=E(),o=s(),c=e.drawer,[l,u]=(0,L.useState)(``),[d,f]=(0,L.useState)(null),p=(0,L.useRef)(null);On(p,c),(0,L.useEffect)(()=>{if(!c)return;let e=e=>e.key===`Escape`&&t(!1);return window.addEventListener(`keydown`,e),()=>window.removeEventListener(`keydown`,e)},[c,t]),(0,L.useEffect)(()=>{c||(u(``),f(null))},[c]);let m=e.profile?.name||`nanoMuse`,h=(0,L.useMemo)(()=>{let t=l.trim().toLowerCase();return e.threads.filter(e=>e.id!==`main`).filter(e=>!t||(e.title||``).toLowerCase().includes(t)).sort((e,t)=>(t.updated_at||``).localeCompare(e.updated_at||``))},[e.threads,l]),g=(e.hub?.devices??[]).filter(e=>!e.this&&e.kind!==`web`),_=g.filter(e=>e.online).length,v=e.hub?.state===`connected`,y=g.some(e=>e.online&&e.kind===`computer`),b=e.tab===`chat`,x=e=>{r(e),n(`chat`),t(!1)},S=e=>{n(e),t(!1)},C=async()=>{try{let e=await N.createThread(o(`New chat`));a({type:`ws`,msg:{kind:`thread`,thread:e}}),x(e.id)}catch(e){i(e.message)}},w=async t=>{try{await N.deleteThread(t),a({type:`ws`,msg:{kind:`thread_deleted`,thread:t}}),e.activeThread===t&&r(`main`)}catch(e){i(e.message)}finally{f(null)}},T=t=>e.hub?.devices.find(e=>e.id===t)?.kind??`phone`,D=v?_===0?o(`Only this one`):o(`{n} online`,{n:_}):o(`Off`);return c?(0,R.jsxs)(`div`,{className:`fixed inset-0 z-50`,children:[(0,R.jsx)(`div`,{className:`rise absolute inset-0 bg-black/40`,onClick:()=>t(!1)}),(0,R.jsxs)(`nav`,{ref:p,role:`dialog`,"aria-modal":`true`,"aria-label":o(`Chats`),className:`drawer-in safe-top safe-bottom absolute inset-y-0 left-0 flex w-[82vw] max-w-[320px] flex-col bg-bg shadow-2xl`,children:[(0,R.jsx)(`div`,{className:`px-5 pt-5 pb-2 text-[24px] font-bold leading-7 tracking-tight`,children:m}),(0,R.jsx)(An,{icon:(0,R.jsx)(bt,{size:20}),label:o(`Main chat`),selected:b&&e.activeThread===`main`,onClick:()=>x(`main`)}),(0,R.jsx)(An,{icon:(0,R.jsx)(It,{size:20}),label:o(`Devices`),detail:D,selected:e.tab===`devices`,onClick:()=>S(`devices`)}),y&&(0,R.jsx)(An,{icon:(0,R.jsx)(dn,{size:20}),label:o(`Coding agents`),selected:e.tab===`coding`,onClick:()=>S(`coding`)}),(0,R.jsx)(`div`,{className:`mt-3 px-5 pb-1`,children:(0,R.jsx)(`span`,{className:`text-[14px] font-medium text-muted`,children:o(`Side chats`)})}),h.length===0&&!l?(0,R.jsxs)(`div`,{className:`flex flex-1 flex-col items-center justify-center px-8 text-center`,children:[(0,R.jsx)(Nt,{size:28,className:`mb-3 text-muted/70`}),(0,R.jsx)(`div`,{className:`text-[17px] font-semibold`,children:o(`Start a side chat`)}),(0,R.jsx)(`div`,{className:`mt-1 text-[13px] leading-snug text-muted`,children:o(`Side chats are an optional way to keep conversations organised by topic.`)})]}):(0,R.jsxs)(`ul`,{className:`min-h-0 flex-1 overflow-y-auto py-1`,children:[h.map(t=>(0,R.jsx)(jn,{thread:t,kind:t.device?T(t.device):void 0,selected:b&&e.activeThread===t.id,confirming:d===t.id,onPick:()=>x(t.id),onAskDelete:()=>f(t.id),onDelete:()=>void w(t.id),onKeep:()=>f(null)},t.id)),h.length===0&&(0,R.jsx)(`li`,{className:`px-5 py-3 text-[13px] text-muted`,children:o(`No chats match.`)})]}),(0,R.jsxs)(`div`,{className:`flex items-center gap-2 border-t border-border px-3 pt-2 pb-2`,children:[(0,R.jsx)(`button`,{type:`button`,onClick:()=>S(`you`),"aria-label":o(`Settings`),className:`flex h-10 w-10 items-center justify-center rounded-full text-fg hover:bg-surface-2`,children:(0,R.jsx)(Yt,{size:20})}),(0,R.jsx)(`button`,{type:`button`,onClick:()=>S(`memory`),"aria-label":o(`Memory`),className:`-ml-1 flex h-10 w-10 items-center justify-center rounded-full text-fg hover:bg-surface-2`,children:(0,R.jsx)(mt,{size:20})}),(0,R.jsxs)(`label`,{className:`flex min-w-0 flex-1 items-center gap-2 rounded-full bg-surface-2 px-3 py-2`,children:[(0,R.jsx)(qt,{size:16,className:`shrink-0 text-muted`}),(0,R.jsx)(`input`,{value:l,onChange:e=>u(e.target.value),placeholder:o(`Search`),className:`min-w-0 flex-1 bg-transparent text-[15px] outline-none placeholder:text-muted`}),l&&(0,R.jsx)(`button`,{type:`button`,onClick:()=>u(``),"aria-label":o(`Clear`),className:`text-muted`,children:(0,R.jsx)(Fe,{size:14})})]}),(0,R.jsx)(`button`,{type:`button`,onClick:()=>void C(),"aria-label":o(`New side chat`),className:`flex h-10 w-10 items-center justify-center rounded-full text-fg hover:bg-surface-2`,children:(0,R.jsx)(an,{size:20})})]})]})]}):null}function An({icon:e,label:t,detail:n,selected:r,onClick:a}){return(0,R.jsxs)(`button`,{type:`button`,onClick:a,className:i(`mx-2 flex items-center gap-3 rounded-2xl px-3 py-2.5 text-left`,r?`bg-surface-2`:`hover:bg-surface-2/60`),children:[(0,R.jsx)(`span`,{className:`text-fg`,children:e}),(0,R.jsx)(`span`,{className:`min-w-0 flex-1 truncate text-[16px]`,children:t}),n&&(0,R.jsx)(`span`,{className:`shrink-0 text-[13px] text-muted`,children:n})]})}function jn({thread:e,kind:t,selected:n,confirming:r,onPick:a,onAskDelete:o,onDelete:c,onKeep:l}){let u=s();return r?(0,R.jsxs)(`li`,{className:`mx-2 flex items-center gap-2 rounded-2xl bg-surface-2 px-3 py-2`,children:[(0,R.jsx)(`span`,{className:`min-w-0 flex-1 truncate text-[13.5px]`,children:u(`Delete this side chat and its history?`)}),(0,R.jsx)(`button`,{type:`button`,onClick:c,className:`rounded-full bg-rose-500 px-3 py-1 text-[12.5px] font-semibold text-white`,children:u(`Delete`)}),(0,R.jsx)(`button`,{type:`button`,onClick:l,className:`rounded-full px-2 py-1 text-[12.5px] text-muted`,children:u(`Keep`)})]}):(0,R.jsxs)(`li`,{className:i(`group mx-2 flex items-center gap-2 rounded-2xl px-3`,n?`bg-surface-2`:`hover:bg-surface-2/60`),children:[(0,R.jsxs)(`button`,{type:`button`,onClick:a,className:`flex min-w-0 flex-1 items-center gap-2 py-2.5 text-left`,children:[e.device?(0,R.jsx)(`span`,{className:`shrink-0 text-accent`,children:t===`computer`?(0,R.jsx)(Lt,{size:15}):(0,R.jsx)(tn,{size:15})}):e.remote_from?(0,R.jsx)(It,{size:15,className:`shrink-0 text-muted`}):null,(0,R.jsx)(`span`,{className:`min-w-0 flex-1 truncate text-[15px]`,children:e.title||u(`New chat`)}),e.busy&&(0,R.jsx)(`span`,{className:`h-1.5 w-1.5 shrink-0 animate-pulse rounded-full bg-amber-400`}),(0,R.jsx)(`span`,{className:`shrink-0 text-[12px] text-muted`,children:Mn(e.updated_at)})]}),(0,R.jsx)(`button`,{type:`button`,"aria-label":u(`Delete`),onClick:o,className:`p-1.5 text-muted/70 opacity-0 hover:text-rose-500 focus:opacity-100 group-hover:opacity-100`,children:(0,R.jsx)(fn,{size:15})})]})}function Mn(e,t=new Date){if(!e)return``;let n=new Date(e);if(Number.isNaN(n.getTime()))return``;let r=t.getTime()-n.getTime();return n.toDateString()===t.toDateString()?n.toLocaleTimeString(m(),{hour:`2-digit`,minute:`2-digit`}):r<6048e5?n.toLocaleDateString(m(),{weekday:`short`}):n.toLocaleDateString(m(),{month:`short`,day:`numeric`})}function Nn(e,t){let n=t||{};return(e[e.length-1]===``?[...e,``]:e).join((n.padRight?` `:``)+`,`+(n.padLeft===!1?``:` `)).trim()}var Pn=/^[$_\p{ID_Start}][$_\u{200C}\u{200D}\p{ID_Continue}]*$/u,Fn=/^[$_\p{ID_Start}][-$_\u{200C}\u{200D}\p{ID_Continue}]*$/u,In={};function Ln(e,t){return((t||In).jsx?Fn:Pn).test(e)}var Rn=/[ \t\n\f\r]/g;function zn(e){return typeof e==`object`?e.type===`text`&&Bn(e.value):Bn(e)}function Bn(e){return e.replace(Rn,``)===``}var Vn=class{constructor(e,t,n){this.normal=t,this.property=e,n&&(this.space=n)}};Vn.prototype.normal={},Vn.prototype.property={},Vn.prototype.space=void 0;function Hn(e,t){let n={},r={};for(let t of e)Object.assign(n,t.property),Object.assign(r,t.normal);return new Vn(n,r,t)}function Un(e){return e.toLowerCase()}var Wn=class{constructor(e,t){this.attribute=t,this.property=e}};Wn.prototype.attribute=``,Wn.prototype.booleanish=!1,Wn.prototype.boolean=!1,Wn.prototype.commaOrSpaceSeparated=!1,Wn.prototype.commaSeparated=!1,Wn.prototype.defined=!1,Wn.prototype.mustUseProperty=!1,Wn.prototype.number=!1,Wn.prototype.overloadedBoolean=!1,Wn.prototype.property=``,Wn.prototype.spaceSeparated=!1,Wn.prototype.space=void 0;var Gn=S({boolean:()=>z,booleanish:()=>qn,commaOrSpaceSeparated:()=>Xn,commaSeparated:()=>Yn,number:()=>B,overloadedBoolean:()=>Jn,spaceSeparated:()=>V}),Kn=0,z=Zn(),qn=Zn(),Jn=Zn(),B=Zn(),V=Zn(),Yn=Zn(),Xn=Zn();function Zn(){return 2**++Kn}var Qn=Object.keys(Gn),$n=class extends Wn{constructor(e,t,n,r){let i=-1;if(super(e,t),er(this,`space`,r),typeof n==`number`)for(;++i4&&n.slice(0,4)===`data`&&pr.test(t)){if(t.charAt(4)===`-`){let e=t.slice(5).replace(fr,gr);r=`data`+e.charAt(0).toUpperCase()+e.slice(1)}else{let e=t.slice(4);if(!fr.test(e)){let n=e.replace(dr,hr);n.charAt(0)!==`-`&&(n=`-`+n),t=`data`+n}}i=$n}return new i(r,t)}function hr(e){return`-`+e.toLowerCase()}function gr(e){return e.charAt(1).toUpperCase()}var _r=Hn([nr,ar,sr,cr,lr],`html`),vr=Hn([nr,or,sr,cr,lr],`svg`);function yr(e){return e.join(` `).trim()}var br=b(((e,t)=>{var n=/\/\*[^*]*\*+([^/*][^*]*\*+)*\//g,r=/\n/g,i=/^\s*/,a=/^(\*?[-#/*\\\w]+(\[[0-9a-z_-]+\])?)\s*/,o=/^:\s*/,s=/^((?:'(?:\\'|.)*?'|"(?:\\"|.)*?"|\([^)]*?\)|[^};])+)/,c=/^[;\s]*/,l=/^\s+|\s+$/g;function u(e,t){if(typeof e!=`string`)throw TypeError(`First argument must be a string`);if(!e)return[];t||={};var l=1,u=1;function f(e){var t=e.match(r);t&&(l+=t.length);var n=e.lastIndexOf(` -`);u=~n?e.length-n:u+e.length}function p(){var e={line:l,column:u};return function(t){return t.position=new m(e),_(),t}}function m(e){this.start=e,this.end={line:l,column:u},this.source=t.source}m.prototype.content=e;function h(n){var r=Error(t.source+`:`+l+`:`+u+`: `+n);if(r.reason=n,r.filename=t.source,r.line=l,r.column=u,r.source=e,!t.silent)throw r}function g(t){var n=t.exec(e);if(n){var r=n[0];return f(r),e=e.slice(r.length),n}}function _(){g(i)}function v(e){var t;for(e||=[];t=y();)t!==!1&&e.push(t);return e}function y(){var t=p();if(e.charAt(0)==`/`&&e.charAt(1)==`*`){for(var n=2;e.charAt(n)!=``&&(e.charAt(n)!=`*`||e.charAt(n+1)!=`/`);)++n;if(n+=2,e.charAt(n-1)===``)return h(`End of comment missing`);var r=e.slice(2,n-2);return u+=2,f(r),e=e.slice(n),u+=2,t({type:`comment`,comment:r})}}function b(){var e=p(),t=g(a);if(t){if(y(),!g(o))return h(`property missing ':'`);var r=g(s),i=e({type:`declaration`,property:d(t[0].replace(n,``)),value:r?d(r[0].replace(n,``)):``});return g(c),i}}function x(){var e=[];v(e);for(var t;t=b();)t!==!1&&(e.push(t),v(e));return e}return _(),x()}function d(e){return e?e.replace(l,``):``}t.exports=u})),xr=b((e=>{var t=e&&e.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};Object.defineProperty(e,"__esModule",{value:!0}),e.default=r;var n=t(br());function r(e,t){let r=null;if(!e||typeof e!=`string`)return r;let i=(0,n.default)(e),a=typeof t==`function`;return i.forEach(e=>{if(e.type!==`declaration`)return;let{property:n,value:i}=e;a?t(n,i,e):i&&(r||={},r[n]=i)}),r}})),Sr=b((e=>{Object.defineProperty(e,"__esModule",{value:!0}),e.camelCase=void 0;var t=/^--[a-zA-Z0-9_-]+$/,n=/-([a-z])/g,r=/^[^-]+$/,i=/^-(webkit|moz|ms|o|khtml)-/,a=/^-(ms)-/,o=function(e){return!e||r.test(e)||t.test(e)},s=function(e,t){return t.toUpperCase()},c=function(e,t){return`${t}-`};e.camelCase=function(e,t){return t===void 0&&(t={}),o(e)?e:(e=e.toLowerCase(),e=t.reactCompat?e.replace(a,c):e.replace(i,c),e.replace(n,s))}})),Cr=b(((e,t)=>{var n=(e&&e.__importDefault||function(e){return e&&e.__esModule?e:{default:e}})(xr()),r=Sr();function i(e,t){var i={};return!e||typeof e!=`string`||(0,n.default)(e,function(e,n){e&&n&&(i[(0,r.camelCase)(e,t)]=n)}),i}i.default=i,t.exports=i})),wr=Er(`end`),Tr=Er(`start`);function Er(e){return t;function t(t){let n=t&&t.position&&t.position[e]||{};if(typeof n.line==`number`&&n.line>0&&typeof n.column==`number`&&n.column>0)return{line:n.line,column:n.column,offset:typeof n.offset==`number`&&n.offset>-1?n.offset:void 0}}}function Dr(e){let t=Tr(e),n=wr(e);if(t&&n)return{start:t,end:n}}function Or(e){return!e||typeof e!=`object`?``:`position`in e||`type`in e?Ar(e.position):`start`in e||`end`in e?Ar(e):`line`in e||`column`in e?kr(e):``}function kr(e){return jr(e&&e.line)+`:`+jr(e&&e.column)}function Ar(e){return kr(e&&e.start)+`-`+kr(e&&e.end)}function jr(e){return e&&typeof e==`number`?e:1}var Mr=class extends Error{constructor(e,t,n){super(),typeof t==`string`&&(n=t,t=void 0);let r=``,i={},a=!1;if(t&&(i=`line`in t&&`column`in t||`start`in t&&`end`in t?{place:t}:`type`in t?{ancestors:[t],place:t.position}:{...t}),typeof e==`string`?r=e:!i.cause&&e&&(a=!0,r=e.message,i.cause=e),!i.ruleId&&!i.source&&typeof n==`string`){let e=n.indexOf(`:`);e===-1?i.ruleId=n:(i.source=n.slice(0,e),i.ruleId=n.slice(e+1))}if(!i.place&&i.ancestors&&i.ancestors){let e=i.ancestors[i.ancestors.length-1];e&&(i.place=e.position)}let o=i.place&&`start`in i.place?i.place.start:i.place;this.ancestors=i.ancestors||void 0,this.cause=i.cause||void 0,this.column=o?o.column:void 0,this.fatal=void 0,this.file=``,this.message=r,this.line=o?o.line:void 0,this.name=Or(i.place)||`1:1`,this.place=i.place||void 0,this.reason=this.message,this.ruleId=i.ruleId||void 0,this.source=i.source||void 0,this.stack=a&&i.cause&&typeof i.cause.stack==`string`?i.cause.stack:``,this.actual=void 0,this.expected=void 0,this.note=void 0,this.url=void 0}};Mr.prototype.file=``,Mr.prototype.name=``,Mr.prototype.reason=``,Mr.prototype.message=``,Mr.prototype.stack=``,Mr.prototype.column=void 0,Mr.prototype.line=void 0,Mr.prototype.ancestors=void 0,Mr.prototype.cause=void 0,Mr.prototype.fatal=void 0,Mr.prototype.place=void 0,Mr.prototype.ruleId=void 0,Mr.prototype.source=void 0;var Nr=p(Cr(),1),Pr={}.hasOwnProperty,Fr=new Map,Ir=/[A-Z]/g,Lr=new Set([`table`,`tbody`,`thead`,`tfoot`,`tr`]),Rr=new Set([`td`,`th`]),zr=`https://github.com/syntax-tree/hast-util-to-jsx-runtime`;function Br(e,t){if(!t||t.Fragment===void 0)throw TypeError("Expected `Fragment` in options");let n=t.filePath||void 0,r;if(t.development){if(typeof t.jsxDEV!=`function`)throw TypeError("Expected `jsxDEV` in options when `development: true`");r=Zr(n,t.jsxDEV)}else{if(typeof t.jsx!=`function`)throw TypeError("Expected `jsx` in production options");if(typeof t.jsxs!=`function`)throw TypeError("Expected `jsxs` in production options");r=Xr(n,t.jsx,t.jsxs)}let i={Fragment:t.Fragment,ancestors:[],components:t.components||{},create:r,elementAttributeNameCase:t.elementAttributeNameCase||`react`,evaluater:t.createEvaluater?t.createEvaluater():void 0,filePath:n,ignoreInvalidStyle:t.ignoreInvalidStyle||!1,passKeys:t.passKeys!==!1,passNode:t.passNode||!1,schema:t.space===`svg`?vr:_r,stylePropertyNameCase:t.stylePropertyNameCase||`dom`,tableCellAlignToStyle:t.tableCellAlignToStyle!==!1},a=Vr(i,e,void 0);return a&&typeof a!=`string`?a:i.create(e,i.Fragment,{children:a||void 0},void 0)}function Vr(e,t,n){if(t.type===`element`)return Hr(e,t,n);if(t.type===`mdxFlowExpression`||t.type===`mdxTextExpression`)return Ur(e,t);if(t.type===`mdxJsxFlowElement`||t.type===`mdxJsxTextElement`)return Gr(e,t,n);if(t.type===`mdxjsEsm`)return Wr(e,t);if(t.type===`root`)return Kr(e,t,n);if(t.type===`text`)return qr(e,t)}function Hr(e,t,n){let r=e.schema,i=r;t.tagName.toLowerCase()===`svg`&&r.space===`html`&&(i=vr,e.schema=i),e.ancestors.push(t);let a=ri(e,t.tagName,!1),o=Qr(e,t),s=ei(e,t);return Lr.has(t.tagName)&&(s=s.filter(function(e){return typeof e!=`string`||!zn(e)})),Jr(e,o,a,t),Yr(o,s),e.ancestors.pop(),e.schema=r,e.create(t,a,o,n)}function Ur(e,t){if(t.data&&t.data.estree&&e.evaluater){let n=t.data.estree.body[0];return n.type,e.evaluater.evaluateExpression(n.expression)}ii(e,t.position)}function Wr(e,t){if(t.data&&t.data.estree&&e.evaluater)return e.evaluater.evaluateProgram(t.data.estree);ii(e,t.position)}function Gr(e,t,n){let r=e.schema,i=r;t.name===`svg`&&r.space===`html`&&(i=vr,e.schema=i),e.ancestors.push(t);let a=t.name===null?e.Fragment:ri(e,t.name,!0),o=$r(e,t),s=ei(e,t);return Jr(e,o,a,t),Yr(o,s),e.ancestors.pop(),e.schema=r,e.create(t,a,o,n)}function Kr(e,t,n){let r={};return Yr(r,ei(e,t)),e.create(t,e.Fragment,r,n)}function qr(e,t){return t.value}function Jr(e,t,n,r){typeof n!=`string`&&n!==e.Fragment&&e.passNode&&(t.node=r)}function Yr(e,t){if(t.length>0){let n=t.length>1?t:t[0];n&&(e.children=n)}}function Xr(e,t,n){return r;function r(e,r,i,a){let o=Array.isArray(i.children)?n:t;return a?o(r,i,a):o(r,i)}}function Zr(e,t){return n;function n(n,r,i,a){let o=Array.isArray(i.children),s=Tr(n);return t(r,i,a,o,{columnNumber:s?s.column-1:void 0,fileName:e,lineNumber:s?s.line:void 0},void 0)}}function Qr(e,t){let n={},r,i;for(i in t.properties)if(i!==`children`&&Pr.call(t.properties,i)){let a=ti(e,i,t.properties[i]);if(a){let[i,o]=a;e.tableCellAlignToStyle&&i===`align`&&typeof o==`string`&&Rr.has(t.tagName)?r=o:n[i]=o}}if(r){let t=n.style||={};t[e.stylePropertyNameCase===`css`?`text-align`:`textAlign`]=r}return n}function $r(e,t){let n={};for(let r of t.attributes)if(r.type===`mdxJsxExpressionAttribute`){if(r.data&&r.data.estree&&e.evaluater){let t=r.data.estree.body[0];t.type;let i=t.expression;i.type;let a=i.properties[0];a.type,Object.assign(n,e.evaluater.evaluateExpression(a.argument))}else ii(e,t.position)}else{let i=r.name,a;if(r.value&&typeof r.value==`object`){if(r.value.data&&r.value.data.estree&&e.evaluater){let t=r.value.data.estree.body[0];t.type,a=e.evaluater.evaluateExpression(t.expression)}else ii(e,t.position)}else a=r.value===null||r.value;n[i]=a}return n}function ei(e,t){let n=[],r=-1,i=e.passKeys?new Map:Fr;for(;++ri?0:i+t:t>i?i:t,n=n>0?n:0,r.length<1e4)o=Array.from(r),o.unshift(t,n),e.splice(...o);else for(n&&e.splice(t,n);a0?(hi(e,e.length,0,t),e):t}var _i={}.hasOwnProperty;function vi(e){let t={},n=-1;for(;++n13&&n<32||n>126&&n<160||n>55295&&n<57344||n>64975&&n<65008||(n&65535)==65535||(n&65535)==65534||n>1114111?`�`:String.fromCodePoint(n)}function Si(e){return e.replace(/[\t\n\r ]+/g,` `).replace(/^ | $/g,``).toLowerCase().toUpperCase()}var Ci=Mi(/[A-Za-z]/),wi=Mi(/[\dA-Za-z]/),Ti=Mi(/[#-'*+\--9=?A-Z^-~]/);function Ei(e){return e!==null&&(e<32||e===127)}var Di=Mi(/\d/),Oi=Mi(/[\dA-Fa-f]/),ki=Mi(/[!-/:-@[-`{-~]/);function U(e){return e!==null&&e<-2}function W(e){return e!==null&&(e<0||e===32)}function G(e){return e===-2||e===-1||e===32}var Ai=Mi(/\p{P}|\p{S}/u),ji=Mi(/\s/);function Mi(e){return t;function t(t){return t!==null&&t>-1&&e.test(String.fromCharCode(t))}}function Ni(e){let t=[],n=-1,r=0,i=0;for(;++n55295&&a<57344){let t=e.charCodeAt(n+1);a<56320&&t>56319&&t<57344?(o=String.fromCharCode(a,t),i=1):o=`�`}else o=String.fromCharCode(a);o&&=(t.push(e.slice(r,n),encodeURIComponent(o)),r=n+i+1,``),i&&=(n+=i,0)}return t.join(``)+e.slice(r)}function K(e,t,n,r){let i=r?r-1:1/0,a=0;return o;function o(r){return G(r)?(e.enter(n),s(r)):t(r)}function s(r){return G(r)&&a++o))return;let n=t.events.length,a=n,s,c;for(;a--;)if(t.events[a][0]===`exit`&&t.events[a][1].type===`chunkFlow`){if(s){c=t.events[a][1].end;break}s=!0}for(_(r),e=n;er;){let r=n[i];t.containerState=r[1],r[0].exit.call(t,e)}n.length=r}function v(){i.write([null]),a=void 0,i=void 0,t.containerState._closeFlow=void 0}}function zi(e,t,n){return K(e,e.attempt(this.parser.constructs.document,t,n),`linePrefix`,this.parser.constructs.disable.null.includes(`codeIndented`)?void 0:4)}function Bi(e){if(e===null||W(e)||ji(e))return 1;if(Ai(e))return 2}function Vi(e,t,n){let r=[],i=-1;for(;++i1&&e[n][1].end.offset-e[n][1].start.offset>1?2:1;let d={...e[r][1].end},f={...e[n][1].start};Ui(d,-c),Ui(f,c),o={type:c>1?`strongSequence`:`emphasisSequence`,start:d,end:{...e[r][1].end}},s={type:c>1?`strongSequence`:`emphasisSequence`,start:{...e[n][1].start},end:f},a={type:c>1?`strongText`:`emphasisText`,start:{...e[r][1].end},end:{...e[n][1].start}},i={type:c>1?`strong`:`emphasis`,start:{...o.start},end:{...s.end}},e[r][1].end={...o.start},e[n][1].start={...s.end},l=[],e[r][1].end.offset-e[r][1].start.offset&&(l=gi(l,[[`enter`,e[r][1],t],[`exit`,e[r][1],t]])),l=gi(l,[[`enter`,i,t],[`enter`,o,t],[`exit`,o,t],[`enter`,a,t]]),l=gi(l,Vi(t.parser.constructs.insideSpan.null,e.slice(r+1,n),t)),l=gi(l,[[`exit`,a,t],[`enter`,s,t],[`exit`,s,t],[`exit`,i,t]]),e[n][1].end.offset-e[n][1].start.offset?(u=2,l=gi(l,[[`enter`,e[n][1],t],[`exit`,e[n][1],t]])):u=0,hi(e,r-1,n-r+3,l),n=r+l.length-u-2;break}}for(n=-1;++n0&&G(t)?K(e,v,`linePrefix`,a+1)(t):v(t)}function v(t){return t===null||U(t)?e.check(na,h,b)(t):(e.enter(`codeFlowValue`),y(t))}function y(t){return t===null||U(t)?(e.exit(`codeFlowValue`),v(t)):(e.consume(t),y)}function b(n){return e.exit(`codeFenced`),t(n)}function x(e,t,n){let i=0;return a;function a(t){return e.enter(`lineEnding`),e.consume(t),e.exit(`lineEnding`),c}function c(t){return e.enter(`codeFencedFence`),G(t)?K(e,l,`linePrefix`,r.parser.constructs.disable.null.includes(`codeIndented`)?void 0:4)(t):l(t)}function l(t){return t===s?(e.enter(`codeFencedFenceSequence`),u(t)):n(t)}function u(t){return t===s?(i++,e.consume(t),u):i>=o?(e.exit(`codeFencedFenceSequence`),G(t)?K(e,d,`whitespace`)(t):d(t)):n(t)}function d(r){return r===null||U(r)?(e.exit(`codeFencedFence`),t(r)):n(r)}}}function aa(e,t,n){let r=this;return i;function i(t){return t===null?n(t):(e.enter(`lineEnding`),e.consume(t),e.exit(`lineEnding`),a)}function a(e){return r.parser.lazy[r.now().line]?n(e):t(e)}}var oa={name:`codeIndented`,tokenize:ca},sa={partial:!0,tokenize:la};function ca(e,t,n){let r=this;return i;function i(t){return e.enter(`codeIndented`),K(e,a,`linePrefix`,5)(t)}function a(e){let t=r.events[r.events.length-1];return t&&t[1].type===`linePrefix`&&t[2].sliceSerialize(t[1],!0).length>=4?o(e):n(e)}function o(t){return t===null?c(t):U(t)?e.attempt(sa,o,c)(t):(e.enter(`codeFlowValue`),s(t))}function s(t){return t===null||U(t)?(e.exit(`codeFlowValue`),o(t)):(e.consume(t),s)}function c(n){return e.exit(`codeIndented`),t(n)}}function la(e,t,n){let r=this;return i;function i(t){return r.parser.lazy[r.now().line]?n(t):U(t)?(e.enter(`lineEnding`),e.consume(t),e.exit(`lineEnding`),i):K(e,a,`linePrefix`,5)(t)}function a(e){let a=r.events[r.events.length-1];return a&&a[1].type===`linePrefix`&&a[2].sliceSerialize(a[1],!0).length>=4?t(e):U(e)?i(e):n(e)}}var ua={name:`codeText`,previous:fa,resolve:da,tokenize:pa};function da(e){let t=e.length-4,n=3,r,i;if((e[n][1].type===`lineEnding`||e[n][1].type===`space`)&&(e[t][1].type===`lineEnding`||e[t][1].type===`space`)){for(r=n;++r=this.left.length+this.right.length)throw RangeError("Cannot access index `"+e+"` in a splice buffer of size `"+(this.left.length+this.right.length)+"`");return ethis.left.length?this.right.slice(this.right.length-n+this.left.length,this.right.length-e+this.left.length).reverse():this.left.slice(e).concat(this.right.slice(this.right.length-n+this.left.length).reverse())}splice(e,t,n){let r=t||0;this.setCursor(Math.trunc(e));let i=this.right.splice(this.right.length-r,1/0);return n&&ha(this.left,n),i.reverse()}pop(){return this.setCursor(1/0),this.left.pop()}push(e){this.setCursor(1/0),this.left.push(e)}pushMany(e){this.setCursor(1/0),ha(this.left,e)}unshift(e){this.setCursor(0),this.right.push(e)}unshiftMany(e){this.setCursor(0),ha(this.right,e.reverse())}setCursor(e){if(!(e===this.left.length||e>this.left.length&&this.right.length===0||e<0&&this.left.length===0)){if(e=4?t(i):e.interrupt(r.parser.constructs.flow,n,t)(i)}}function Sa(e,t,n,r,i,a,o,s,c){let l=c||1/0,u=0;return d;function d(t){return t===60?(e.enter(r),e.enter(i),e.enter(a),e.consume(t),e.exit(a),f):t===null||t===32||t===41||Ei(t)?n(t):(e.enter(r),e.enter(o),e.enter(s),e.enter(`chunkString`,{contentType:`string`}),h(t))}function f(n){return n===62?(e.enter(a),e.consume(n),e.exit(a),e.exit(i),e.exit(r),t):(e.enter(s),e.enter(`chunkString`,{contentType:`string`}),p(n))}function p(t){return t===62?(e.exit(`chunkString`),e.exit(s),f(t)):t===null||t===60||U(t)?n(t):(e.consume(t),t===92?m:p)}function m(t){return t===60||t===62||t===92?(e.consume(t),p):p(t)}function h(i){return!u&&(i===null||i===41||W(i))?(e.exit(`chunkString`),e.exit(s),e.exit(o),e.exit(r),t(i)):u999||l===null||l===91||l===93&&!c||l===94&&!s&&`_hiddenFootnoteSupport`in o.parser.constructs?n(l):l===93?(e.exit(a),e.enter(i),e.consume(l),e.exit(i),e.exit(r),t):U(l)?(e.enter(`lineEnding`),e.consume(l),e.exit(`lineEnding`),u):(e.enter(`chunkString`,{contentType:`string`}),d(l))}function d(t){return t===null||t===91||t===93||U(t)||s++>999?(e.exit(`chunkString`),u(t)):(e.consume(t),c||=!G(t),t===92?f:d)}function f(t){return t===91||t===92||t===93?(e.consume(t),s++,d):d(t)}}function wa(e,t,n,r,i,a){let o;return s;function s(t){return t===34||t===39||t===40?(e.enter(r),e.enter(i),e.consume(t),e.exit(i),o=t===40?41:t,c):n(t)}function c(n){return n===o?(e.enter(i),e.consume(n),e.exit(i),e.exit(r),t):(e.enter(a),l(n))}function l(t){return t===o?(e.exit(a),c(o)):t===null?n(t):U(t)?(e.enter(`lineEnding`),e.consume(t),e.exit(`lineEnding`),K(e,l,`linePrefix`)):(e.enter(`chunkString`,{contentType:`string`}),u(t))}function u(t){return t===o||t===null||U(t)?(e.exit(`chunkString`),l(t)):(e.consume(t),t===92?d:u)}function d(t){return t===o||t===92?(e.consume(t),u):u(t)}}function Ta(e,t){let n;return r;function r(i){return U(i)?(e.enter(`lineEnding`),e.consume(i),e.exit(`lineEnding`),n=!0,r):G(i)?K(e,r,n?`linePrefix`:`lineSuffix`)(i):t(i)}}var Ea={name:`definition`,tokenize:Oa},Da={partial:!0,tokenize:ka};function Oa(e,t,n){let r=this,i;return a;function a(t){return e.enter(`definition`),o(t)}function o(t){return Ca.call(r,e,s,n,`definitionLabel`,`definitionLabelMarker`,`definitionLabelString`)(t)}function s(t){return i=Si(r.sliceSerialize(r.events[r.events.length-1][1]).slice(1,-1)),t===58?(e.enter(`definitionMarker`),e.consume(t),e.exit(`definitionMarker`),c):n(t)}function c(t){return W(t)?Ta(e,l)(t):l(t)}function l(t){return Sa(e,u,n,`definitionDestination`,`definitionDestinationLiteral`,`definitionDestinationLiteralMarker`,`definitionDestinationRaw`,`definitionDestinationString`)(t)}function u(t){return e.attempt(Da,d,d)(t)}function d(t){return G(t)?K(e,f,`whitespace`)(t):f(t)}function f(a){return a===null||U(a)?(e.exit(`definition`),r.parser.defined.push(i),t(a)):n(a)}}function ka(e,t,n){return r;function r(t){return W(t)?Ta(e,i)(t):n(t)}function i(t){return wa(e,a,n,`definitionTitle`,`definitionTitleMarker`,`definitionTitleString`)(t)}function a(t){return G(t)?K(e,o,`whitespace`)(t):o(t)}function o(e){return e===null||U(e)?t(e):n(e)}}var Aa={name:`hardBreakEscape`,tokenize:ja};function ja(e,t,n){return r;function r(t){return e.enter(`hardBreakEscape`),e.consume(t),i}function i(r){return U(r)?(e.exit(`hardBreakEscape`),t(r)):n(r)}}var Ma={name:`headingAtx`,resolve:Na,tokenize:Pa};function Na(e,t){let n=e.length-2,r=3,i,a;return e[r][1].type===`whitespace`&&(r+=2),n-2>r&&e[n][1].type===`whitespace`&&(n-=2),e[n][1].type===`atxHeadingSequence`&&(r===n-1||n-4>r&&e[n-2][1].type===`whitespace`)&&(n-=r+1===n?2:4),n>r&&(i={type:`atxHeadingText`,start:e[r][1].start,end:e[n][1].end},a={type:`chunkText`,start:e[r][1].start,end:e[n][1].end,contentType:`text`},hi(e,r,n-r+1,[[`enter`,i,t],[`enter`,a,t],[`exit`,a,t],[`exit`,i,t]])),e}function Pa(e,t,n){let r=0;return i;function i(t){return e.enter(`atxHeading`),a(t)}function a(t){return e.enter(`atxHeadingSequence`),o(t)}function o(t){return t===35&&r++<6?(e.consume(t),o):t===null||W(t)?(e.exit(`atxHeadingSequence`),s(t)):n(t)}function s(n){return n===35?(e.enter(`atxHeadingSequence`),c(n)):n===null||U(n)?(e.exit(`atxHeading`),t(n)):G(n)?K(e,s,`whitespace`)(n):(e.enter(`atxHeadingText`),l(n))}function c(t){return t===35?(e.consume(t),c):(e.exit(`atxHeadingSequence`),s(t))}function l(t){return t===null||t===35||W(t)?(e.exit(`atxHeadingText`),s(t)):(e.consume(t),l)}}var Fa=`address.article.aside.base.basefont.blockquote.body.caption.center.col.colgroup.dd.details.dialog.dir.div.dl.dt.fieldset.figcaption.figure.footer.form.frame.frameset.h1.h2.h3.h4.h5.h6.head.header.hr.html.iframe.legend.li.link.main.menu.menuitem.nav.noframes.ol.optgroup.option.p.param.search.section.summary.table.tbody.td.tfoot.th.thead.title.tr.track.ul`.split(`.`),Ia=[`pre`,`script`,`style`,`textarea`],La={concrete:!0,name:`htmlFlow`,resolveTo:Ba,tokenize:Va},Ra={partial:!0,tokenize:Ua},za={partial:!0,tokenize:Ha};function Ba(e){let t=e.length;for(;t--&&(e[t][0]!==`enter`||e[t][1].type!==`htmlFlow`););return t>1&&e[t-2][1].type===`linePrefix`&&(e[t][1].start=e[t-2][1].start,e[t+1][1].start=e[t-2][1].start,e.splice(t-2,2)),e}function Va(e,t,n){let r=this,i,a,o,s,c;return l;function l(e){return u(e)}function u(t){return e.enter(`htmlFlow`),e.enter(`htmlFlowData`),e.consume(t),d}function d(s){return s===33?(e.consume(s),f):s===47?(e.consume(s),a=!0,h):s===63?(e.consume(s),i=3,r.interrupt?t:N):Ci(s)?(e.consume(s),o=String.fromCharCode(s),g):n(s)}function f(a){return a===45?(e.consume(a),i=2,p):a===91?(e.consume(a),i=5,s=0,m):Ci(a)?(e.consume(a),i=4,r.interrupt?t:N):n(a)}function p(i){return i===45?(e.consume(i),r.interrupt?t:N):n(i)}function m(i){return i===`CDATA[`.charCodeAt(s++)?(e.consume(i),s===6?r.interrupt?t:O:m):n(i)}function h(t){return Ci(t)?(e.consume(t),o=String.fromCharCode(t),g):n(t)}function g(s){if(s===null||s===47||s===62||W(s)){let c=s===47,l=o.toLowerCase();return!c&&!a&&Ia.includes(l)?(i=1,r.interrupt?t(s):O(s)):Fa.includes(o.toLowerCase())?(i=6,c?(e.consume(s),_):r.interrupt?t(s):O(s)):(i=7,r.interrupt&&!r.parser.lazy[r.now().line]?n(s):a?v(s):y(s))}return s===45||wi(s)?(e.consume(s),o+=String.fromCharCode(s),g):n(s)}function _(i){return i===62?(e.consume(i),r.interrupt?t:O):n(i)}function v(t){return G(t)?(e.consume(t),v):E(t)}function y(t){return t===47?(e.consume(t),E):t===58||t===95||Ci(t)?(e.consume(t),b):G(t)?(e.consume(t),y):E(t)}function b(t){return t===45||t===46||t===58||t===95||wi(t)?(e.consume(t),b):x(t)}function x(t){return t===61?(e.consume(t),S):G(t)?(e.consume(t),x):y(t)}function S(t){return t===null||t===60||t===61||t===62||t===96?n(t):t===34||t===39?(e.consume(t),c=t,C):G(t)?(e.consume(t),S):w(t)}function C(t){return t===c?(e.consume(t),c=null,T):t===null||U(t)?n(t):(e.consume(t),C)}function w(t){return t===null||t===34||t===39||t===47||t===60||t===61||t===62||t===96||W(t)?x(t):(e.consume(t),w)}function T(e){return e===47||e===62||G(e)?y(e):n(e)}function E(t){return t===62?(e.consume(t),D):n(t)}function D(t){return t===null||U(t)?O(t):G(t)?(e.consume(t),D):n(t)}function O(t){return t===45&&i===2?(e.consume(t),j):t===60&&i===1?(e.consume(t),M):t===62&&i===4?(e.consume(t),re):t===63&&i===3?(e.consume(t),N):t===93&&i===5?(e.consume(t),ne):U(t)&&(i===6||i===7)?(e.exit(`htmlFlowData`),e.check(Ra,P,k)(t)):t===null||U(t)?(e.exit(`htmlFlowData`),k(t)):(e.consume(t),O)}function k(t){return e.check(za,ee,P)(t)}function ee(t){return e.enter(`lineEnding`),e.consume(t),e.exit(`lineEnding`),A}function A(t){return t===null||U(t)?k(t):(e.enter(`htmlFlowData`),O(t))}function j(t){return t===45?(e.consume(t),N):O(t)}function M(t){return t===47?(e.consume(t),o=``,te):O(t)}function te(t){if(t===62){let n=o.toLowerCase();return Ia.includes(n)?(e.consume(t),re):O(t)}return Ci(t)&&o.length<8?(e.consume(t),o+=String.fromCharCode(t),te):O(t)}function ne(t){return t===93?(e.consume(t),N):O(t)}function N(t){return t===62?(e.consume(t),re):t===45&&i===2?(e.consume(t),N):O(t)}function re(t){return t===null||U(t)?(e.exit(`htmlFlowData`),P(t)):(e.consume(t),re)}function P(n){return e.exit(`htmlFlow`),t(n)}}function Ha(e,t,n){let r=this;return i;function i(t){return U(t)?(e.enter(`lineEnding`),e.consume(t),e.exit(`lineEnding`),a):n(t)}function a(e){return r.parser.lazy[r.now().line]?n(e):t(e)}}function Ua(e,t,n){return r;function r(r){return e.enter(`lineEnding`),e.consume(r),e.exit(`lineEnding`),e.attempt(Ki,t,n)}}var Wa={name:`htmlText`,tokenize:Ga};function Ga(e,t,n){let r=this,i,a,o;return s;function s(t){return e.enter(`htmlText`),e.enter(`htmlTextData`),e.consume(t),c}function c(t){return t===33?(e.consume(t),l):t===47?(e.consume(t),x):t===63?(e.consume(t),y):Ci(t)?(e.consume(t),w):n(t)}function l(t){return t===45?(e.consume(t),u):t===91?(e.consume(t),a=0,m):Ci(t)?(e.consume(t),v):n(t)}function u(t){return t===45?(e.consume(t),p):n(t)}function d(t){return t===null?n(t):t===45?(e.consume(t),f):U(t)?(o=d,M(t)):(e.consume(t),d)}function f(t){return t===45?(e.consume(t),p):d(t)}function p(e){return e===62?j(e):e===45?f(e):d(e)}function m(t){return t===`CDATA[`.charCodeAt(a++)?(e.consume(t),a===6?h:m):n(t)}function h(t){return t===null?n(t):t===93?(e.consume(t),g):U(t)?(o=h,M(t)):(e.consume(t),h)}function g(t){return t===93?(e.consume(t),_):h(t)}function _(t){return t===62?j(t):t===93?(e.consume(t),_):h(t)}function v(t){return t===null||t===62?j(t):U(t)?(o=v,M(t)):(e.consume(t),v)}function y(t){return t===null?n(t):t===63?(e.consume(t),b):U(t)?(o=y,M(t)):(e.consume(t),y)}function b(e){return e===62?j(e):y(e)}function x(t){return Ci(t)?(e.consume(t),S):n(t)}function S(t){return t===45||wi(t)?(e.consume(t),S):C(t)}function C(t){return U(t)?(o=C,M(t)):G(t)?(e.consume(t),C):j(t)}function w(t){return t===45||wi(t)?(e.consume(t),w):t===47||t===62||W(t)?T(t):n(t)}function T(t){return t===47?(e.consume(t),j):t===58||t===95||Ci(t)?(e.consume(t),E):U(t)?(o=T,M(t)):G(t)?(e.consume(t),T):j(t)}function E(t){return t===45||t===46||t===58||t===95||wi(t)?(e.consume(t),E):D(t)}function D(t){return t===61?(e.consume(t),O):U(t)?(o=D,M(t)):G(t)?(e.consume(t),D):T(t)}function O(t){return t===null||t===60||t===61||t===62||t===96?n(t):t===34||t===39?(e.consume(t),i=t,k):U(t)?(o=O,M(t)):G(t)?(e.consume(t),O):(e.consume(t),ee)}function k(t){return t===i?(e.consume(t),i=void 0,A):t===null?n(t):U(t)?(o=k,M(t)):(e.consume(t),k)}function ee(t){return t===null||t===34||t===39||t===60||t===61||t===96?n(t):t===47||t===62||W(t)?T(t):(e.consume(t),ee)}function A(e){return e===47||e===62||W(e)?T(e):n(e)}function j(r){return r===62?(e.consume(r),e.exit(`htmlTextData`),e.exit(`htmlText`),t):n(r)}function M(t){return e.exit(`htmlTextData`),e.enter(`lineEnding`),e.consume(t),e.exit(`lineEnding`),te}function te(t){return G(t)?K(e,ne,`linePrefix`,r.parser.constructs.disable.null.includes(`codeIndented`)?void 0:4)(t):ne(t)}function ne(t){return e.enter(`htmlTextData`),o(t)}}var Ka={name:`labelEnd`,resolveAll:Xa,resolveTo:Za,tokenize:Qa},qa={tokenize:$a},Ja={tokenize:eo},Ya={tokenize:to};function Xa(e){let t=-1,n=[];for(;++t=3&&(a===null||U(a))?(e.exit(`thematicBreak`),t(a)):n(a)}function c(t){return t===i?(e.consume(t),r++,c):(e.exit(`thematicBreakSequence`),G(t)?K(e,s,`whitespace`)(t):s(t))}}var uo={continuation:{tokenize:X},exit:go,name:`list`,tokenize:mo},fo={partial:!0,tokenize:_o},po={partial:!0,tokenize:ho};function mo(e,t,n){let r=this,i=r.events[r.events.length-1],a=i&&i[1].type===`linePrefix`?i[2].sliceSerialize(i[1],!0).length:0,o=0;return s;function s(t){let i=r.containerState.type||(t===42||t===43||t===45?`listUnordered`:`listOrdered`);if(i===`listUnordered`?!r.containerState.marker||t===r.containerState.marker:Di(t)){if(r.containerState.type||(r.containerState.type=i,e.enter(i,{_container:!0})),i===`listUnordered`)return e.enter(`listItemPrefix`),t===42||t===45?e.check(co,n,l)(t):l(t);if(!r.interrupt||t===49)return e.enter(`listItemPrefix`),e.enter(`listItemValue`),c(t)}return n(t)}function c(t){return Di(t)&&++o<10?(e.consume(t),c):(!r.interrupt||o<2)&&(r.containerState.marker?t===r.containerState.marker:t===41||t===46)?(e.exit(`listItemValue`),l(t)):n(t)}function l(t){return e.enter(`listItemMarker`),e.consume(t),e.exit(`listItemMarker`),r.containerState.marker=r.containerState.marker||t,e.check(Ki,r.interrupt?n:u,e.attempt(fo,f,d))}function u(e){return r.containerState.initialBlankLine=!0,a++,f(e)}function d(t){return G(t)?(e.enter(`listItemPrefixWhitespace`),e.consume(t),e.exit(`listItemPrefixWhitespace`),f):n(t)}function f(n){return r.containerState.size=a+r.sliceSerialize(e.exit(`listItemPrefix`),!0).length,t(n)}}function X(e,t,n){let r=this;return r.containerState._closeFlow=void 0,e.check(Ki,i,a);function i(n){return r.containerState.furtherBlankLines=r.containerState.furtherBlankLines||r.containerState.initialBlankLine,K(e,t,`listItemIndent`,r.containerState.size+1)(n)}function a(n){return r.containerState.furtherBlankLines||!G(n)?(r.containerState.furtherBlankLines=void 0,r.containerState.initialBlankLine=void 0,o(n)):(r.containerState.furtherBlankLines=void 0,r.containerState.initialBlankLine=void 0,e.attempt(po,t,o)(n))}function o(i){return r.containerState._closeFlow=!0,r.interrupt=void 0,K(e,e.attempt(uo,t,n),`linePrefix`,r.parser.constructs.disable.null.includes(`codeIndented`)?void 0:4)(i)}}function ho(e,t,n){let r=this;return K(e,i,`listItemIndent`,r.containerState.size+1);function i(e){let i=r.events[r.events.length-1];return i&&i[1].type===`listItemIndent`&&i[2].sliceSerialize(i[1],!0).length===r.containerState.size?t(e):n(e)}}function go(e){e.exit(this.containerState.type)}function _o(e,t,n){let r=this;return K(e,i,`listItemPrefixWhitespace`,r.parser.constructs.disable.null.includes(`codeIndented`)?void 0:5);function i(e){let i=r.events[r.events.length-1];return!G(e)&&i&&i[1].type===`listItemPrefixWhitespace`?t(e):n(e)}}var vo={name:`setextUnderline`,resolveTo:yo,tokenize:bo};function yo(e,t){let n=e.length,r,i,a;for(;n--;)if(e[n][0]===`enter`){if(e[n][1].type===`content`){r=n;break}e[n][1].type===`paragraph`&&(i=n)}else e[n][1].type===`content`&&e.splice(n,1),!a&&e[n][1].type===`definition`&&(a=n);let o={type:`setextHeading`,start:{...e[r][1].start},end:{...e[e.length-1][1].end}};return e[i][1].type=`setextHeadingText`,a?(e.splice(i,0,[`enter`,o,t]),e.splice(a+1,0,[`exit`,e[r][1],t]),e[r][1].end={...e[a][1].end}):e[r][1]=o,e.push([`exit`,o,t]),e}function bo(e,t,n){let r=this,i;return a;function a(t){let a=r.events.length,s;for(;a--;)if(r.events[a][1].type!==`lineEnding`&&r.events[a][1].type!==`linePrefix`&&r.events[a][1].type!==`content`){s=r.events[a][1].type===`paragraph`;break}return!r.parser.lazy[r.now().line]&&(r.interrupt||s)?(e.enter(`setextHeadingLine`),i=t,o(t)):n(t)}function o(t){return e.enter(`setextHeadingLineSequence`),s(t)}function s(t){return t===i?(e.consume(t),s):(e.exit(`setextHeadingLineSequence`),G(t)?K(e,c,`lineSuffix`)(t):c(t))}function c(r){return r===null||U(r)?(e.exit(`setextHeadingLine`),t(r)):n(r)}}var Z={tokenize:xo};function xo(e){let t=this,n=e.attempt(Ki,r,e.attempt(this.parser.constructs.flowInitial,i,K(e,e.attempt(this.parser.constructs.flow,i,e.attempt(va,i)),`linePrefix`)));return n;function r(r){if(r===null){e.consume(r);return}return e.enter(`lineEndingBlank`),e.consume(r),e.exit(`lineEndingBlank`),t.currentConstruct=void 0,n}function i(r){if(r===null){e.consume(r);return}return e.enter(`lineEnding`),e.consume(r),e.exit(`lineEnding`),t.currentConstruct=void 0,n}}var So={resolveAll:Eo()},Co=To(`string`),wo=To(`text`);function To(e){return{resolveAll:Eo(e===`text`?Do:void 0),tokenize:t};function t(t){let n=this,r=this.parser.constructs[e],i=t.attempt(r,a,o);return a;function a(e){return c(e)?i(e):o(e)}function o(e){if(e===null){t.consume(e);return}return t.enter(`data`),t.consume(e),s}function s(e){return c(e)?(t.exit(`data`),i(e)):(t.consume(e),s)}function c(e){if(e===null)return!0;let t=r[e],i=-1;if(t)for(;++iIo,contentInitial:()=>Ao,disable:()=>Lo,document:()=>ko,flow:()=>Mo,flowInitial:()=>jo,insideSpan:()=>Fo,string:()=>No,text:()=>Po}),ko={42:uo,43:uo,45:uo,48:uo,49:uo,50:uo,51:uo,52:uo,53:uo,54:uo,55:uo,56:uo,57:uo,62:Ji},Ao={91:Ea},jo={[-2]:oa,[-1]:oa,32:oa},Mo={35:Ma,42:co,45:[vo,co],60:La,61:vo,95:co,96:ra,126:ra},No={38:ea,92:Qi},Po={[-5]:oo,[-4]:oo,[-3]:oo,33:no,38:ea,42:q,60:[Wi,Wa],91:io,92:[Aa,Qi],93:Ka,95:q,96:ua},Fo={null:[q,So]},Io={null:[42,95]},Lo={null:[]};function Ro(e,t,n){let r={_bufferIndex:-1,_index:0,line:n&&n.line||1,column:n&&n.column||1,offset:n&&n.offset||0},i={},a=[],o=[],s=[],c={attempt:C(x),check:C(S),consume:v,enter:y,exit:b,interrupt:C(S,{interrupt:!0})},l={code:null,containerState:{},defineSkip:h,events:[],now:m,parser:e,previous:null,sliceSerialize:f,sliceStream:p,write:d},u=t.tokenize.call(l,c);return t.resolveAll&&a.push(t),l;function d(e){return o=gi(o,e),g(),o[o.length-1]===null?(w(t,0),l.events=Vi(a,l.events,l),l.events):[]}function f(e,t){return Bo(p(e),t)}function p(e){return zo(o,e)}function m(){let{_bufferIndex:e,_index:t,line:n,column:i,offset:a}=r;return{_bufferIndex:e,_index:t,line:n,column:i,offset:a}}function h(e){i[e.line]=e.column,E()}function g(){let e;for(;r._index-1){let e=o[0];typeof e==`string`?o[0]=e.slice(r):o.shift()}a>0&&o.push(e[i].slice(0,a))}return o}function Bo(e,t){let n=-1,r=[],i;for(;++n0){let e=a.tokenStack[a.tokenStack.length-1];(e[1]||es).call(a,void 0,e[0])}for(r.position={start:Zo(e.length>0?e[0][1].start:{line:1,column:1,offset:0}),end:Zo(e.length>0?e[e.length-2][1].end:{line:1,column:1,offset:0})},d=-1;++d0&&(r.className=[`language-`+i[0]]);let a={type:`element`,tagName:`code`,properties:r,children:[{type:`text`,value:n}]};return t.meta&&(a.data={meta:t.meta}),e.patch(t,a),a=e.applyData(t,a),a={type:`element`,tagName:`pre`,properties:{},children:[a]},e.patch(t,a),a}function as(e,t){let n={type:`element`,tagName:`del`,properties:{},children:e.all(t)};return e.patch(t,n),e.applyData(t,n)}function os(e,t){let n={type:`element`,tagName:`em`,properties:{},children:e.all(t)};return e.patch(t,n),e.applyData(t,n)}function ss(e,t){let n=typeof e.options.clobberPrefix==`string`?e.options.clobberPrefix:`user-content-`,r=String(t.identifier).toUpperCase(),i=Ni(r.toLowerCase()),a=e.footnoteOrder.indexOf(r),o,s=e.footnoteCounts.get(r);s===void 0?(s=0,e.footnoteOrder.push(r),o=e.footnoteOrder.length):o=a+1,s+=1,e.footnoteCounts.set(r,s);let c={type:`element`,tagName:`a`,properties:{href:`#`+n+`fn-`+i,id:n+`fnref-`+i+(s>1?`-`+s:``),dataFootnoteRef:!0,ariaDescribedBy:[`footnote-label`]},children:[{type:`text`,value:String(o)}]};e.patch(t,c);let l={type:`element`,tagName:`sup`,properties:{},children:[c]};return e.patch(t,l),e.applyData(t,l)}function cs(e,t){let n={type:`element`,tagName:`h`+t.depth,properties:{},children:e.all(t)};return e.patch(t,n),e.applyData(t,n)}function ls(e,t){if(e.options.allowDangerousHtml){let n={type:`raw`,value:t.value};return e.patch(t,n),e.applyData(t,n)}}function us(e,t){let n=t.referenceType,r=`]`;if(n===`collapsed`?r+=`[]`:n===`full`&&(r+=`[`+(t.label||t.identifier)+`]`),t.type===`imageReference`)return[{type:`text`,value:`![`+t.alt+r}];let i=e.all(t),a=i[0];a&&a.type===`text`?a.value=`[`+a.value:i.unshift({type:`text`,value:`[`});let o=i[i.length-1];return o&&o.type===`text`?o.value+=r:i.push({type:`text`,value:r}),i}function ds(e,t){let n=String(t.identifier).toUpperCase(),r=e.definitionById.get(n);if(!r)return us(e,t);let i={src:Ni(r.url||``),alt:t.alt};r.title!==null&&r.title!==void 0&&(i.title=r.title);let a={type:`element`,tagName:`img`,properties:i,children:[]};return e.patch(t,a),e.applyData(t,a)}function fs(e,t){let n={src:Ni(t.url)};t.alt!==null&&t.alt!==void 0&&(n.alt=t.alt),t.title!==null&&t.title!==void 0&&(n.title=t.title);let r={type:`element`,tagName:`img`,properties:n,children:[]};return e.patch(t,r),e.applyData(t,r)}function ps(e,t){let n={type:`text`,value:t.value.replace(/\r?\n|\r/g,` `)};e.patch(t,n);let r={type:`element`,tagName:`code`,properties:{},children:[n]};return e.patch(t,r),e.applyData(t,r)}function ms(e,t){let n=String(t.identifier).toUpperCase(),r=e.definitionById.get(n);if(!r)return us(e,t);let i={href:Ni(r.url||``)};r.title!==null&&r.title!==void 0&&(i.title=r.title);let a={type:`element`,tagName:`a`,properties:i,children:e.all(t)};return e.patch(t,a),e.applyData(t,a)}function hs(e,t){let n={href:Ni(t.url)};t.title!==null&&t.title!==void 0&&(n.title=t.title);let r={type:`element`,tagName:`a`,properties:n,children:e.all(t)};return e.patch(t,r),e.applyData(t,r)}function gs(e,t,n){let r=e.all(t),i=n?_s(n):vs(t),a={},o=[];if(typeof t.checked==`boolean`){let e=r[0],n;e&&e.type===`element`&&e.tagName===`p`?n=e:(n={type:`element`,tagName:`p`,properties:{},children:[]},r.unshift(n)),n.children.length>0&&n.children.unshift({type:`text`,value:` `}),n.children.unshift({type:`element`,tagName:`input`,properties:{type:`checkbox`,checked:t.checked,disabled:!0},children:[]}),a.className=[`task-list-item`]}let s=-1;for(;++s1}function ys(e,t){let n={},r=e.all(t),i=-1;for(typeof t.start==`number`&&t.start!==1&&(n.start=t.start);++i0){let r={type:`element`,tagName:`tbody`,properties:{},children:e.wrap(n,!0)},a=Tr(t.children[1]),o=wr(t.children[t.children.length-1]);a&&o&&(r.position={start:a,end:o}),i.push(r)}let a={type:`element`,tagName:`table`,properties:{},children:e.wrap(i,!0)};return e.patch(t,a),e.applyData(t,a)}function ws(e,t,n){let r=n?n.children:void 0,i=(r?r.indexOf(t):1)===0?`th`:`td`,a=n&&n.type===`table`?n.align:void 0,o=a?a.length:t.children.length,s=-1,c=[];for(;++s0,!0),r[0]),i=r.index+r[0].length,r=n.exec(t);return a.push(ks(t.slice(i),i>0,!1)),a.join(``)}function ks(e,t,n){let r=0,i=e.length;if(t){let t=e.codePointAt(r);for(;t===Es||t===Ds;)r++,t=e.codePointAt(r)}if(n){let t=e.codePointAt(i-1);for(;t===Es||t===Ds;)i--,t=e.codePointAt(i-1)}return i>r?e.slice(r,i):``}function As(e,t){let n={type:`text`,value:Os(String(t.value))};return e.patch(t,n),e.applyData(t,n)}function js(e,t){let n={type:`element`,tagName:`hr`,properties:{},children:[]};return e.patch(t,n),e.applyData(t,n)}var Ms={blockquote:ns,break:rs,code:is,delete:as,emphasis:os,footnoteReference:ss,heading:cs,html:ls,imageReference:ds,image:fs,inlineCode:ps,linkReference:ms,link:hs,listItem:gs,list:ys,paragraph:bs,root:xs,strong:Ss,table:Cs,tableCell:Ts,tableRow:ws,text:As,thematicBreak:js,toml:Ns,yaml:Ns,definition:Ns,footnoteDefinition:Ns};function Ns(){}var{defineProperty:Ps}=Object,Fs=typeof self==`object`?self:globalThis,Is=(e,t)=>{switch(e){case`Function`:case`SharedWorker`:case`Worker`:case`eval`:case`setInterval`:case`setTimeout`:throw TypeError(`unable to deserialize `+e)}return new Fs[e](t)},Ls=(e,t)=>{let n=(t,n)=>(e.set(n,t),t),r=i=>{if(e.has(i))return e.get(i);let[a,o]=t[i];switch(a){case 0:case-1:return n(o,i);case 1:{let e=n([],i);for(let t of o)e.push(r(t));return e}case 2:{let e=n({},i);for(let[t,n]of o){let i=r(t),a=r(n);i===`__proto__`?Ps(e,i,{value:a,configurable:!0,enumerable:!0,writable:!0}):e[i]=a}return e}case 3:return n(new Date(o),i);case 4:{let{source:e,flags:t}=o;return n(new RegExp(e,t),i)}case 5:{let e=n(new Map,i);for(let[t,n]of o)e.set(r(t),r(n));return e}case 6:{let e=n(new Set,i);for(let t of o)e.add(r(t));return e}case 7:{let{name:e,message:t}=o;return n(typeof Fs[e]==`function`?Is(e,t):Error(t),i)}case 8:return n(BigInt(o),i);case`BigInt`:return n(Object(BigInt(o)),i);case`ArrayBuffer`:return n(new Uint8Array(o).buffer,o);case`DataView`:{let{buffer:e}=new Uint8Array(o);return n(new DataView(e),o)}case`-0`:return-0}return n(Is(a,o),i)};return r},Rs=e=>Ls(new Map,e)(0),zs=``,{toString:Bs}={},{keys:Vs,is:Hs}=Object,Us=e=>{let t=typeof e;if(t!==`object`||!e)return[0,t];let n=Bs.call(e).slice(8,-1);switch(n){case`Array`:return[1,zs];case`Object`:return[2,zs];case`Date`:return[3,zs];case`RegExp`:return[4,zs];case`Map`:return[5,zs];case`Set`:return[6,zs];case`DataView`:return[1,n]}return n.includes(`Array`)?[1,n]:e instanceof Error?[7,e.name||`Error`]:[2,n]},Ws=([e,t])=>e===0&&(t===`function`||t===`symbol`),Gs=(e,t,n,r)=>{let i=(e,t)=>{let i=r.push(e)-1;return n.set(t,i),i},a=o=>{if(n.has(o))return n.get(o);let[s,c]=Us(o);switch(s){case 0:{let t=o;switch(c){case`bigint`:s=8,t=o.toString();break;case`number`:if(!o&&Hs(o,-0))return r.push([`-0`])-1;break;case`function`:case`symbol`:if(e)throw TypeError(`unable to serialize `+c);t=null;break;case`undefined`:return i([-1],o)}return i([s,t],o)}case 1:{if(c){let e=o;return c===`DataView`?e=new Uint8Array(o.buffer):c===`ArrayBuffer`&&(e=new Uint8Array(o)),i([c,[...e]],o)}let e=[],t=i([s,e],o);for(let t of o)e.push(a(t));return t}case 2:{if(c)switch(c){case`BigInt`:return i([c,o.toString()],o);case`Boolean`:case`Number`:case`String`:return i([c,o.valueOf()],o)}if(t&&`toJSON`in o)return a(o.toJSON());let n=[],r=i([s,n],o);for(let t of Vs(o))(e||!Ws(Us(o[t])))&&n.push([a(t),a(o[t])]);return r}case 3:return i([s,isNaN(o.getTime())?zs:o.toISOString()],o);case 4:{let{source:e,flags:t}=o;return i([s,{source:e,flags:t}],o)}case 5:{let t=[],n=i([s,t],o);for(let[n,r]of o)(e||!(Ws(Us(n))||Ws(Us(r))))&&t.push([a(n),a(r)]);return n}case 6:{let t=[],n=i([s,t],o);for(let n of o)(e||!Ws(Us(n)))&&t.push(a(n));return n}}let{message:l}=o;return i([s,{name:c,message:l}],o)};return a},Ks=(e,{json:t,lossy:n}={})=>{let r=[];return Gs(!(t||n),!!t,new Map,r)(e),r},qs=typeof structuredClone==`function`?(e,t)=>t&&(`json`in t||`lossy`in t)?Rs(Ks(e,t)):structuredClone(e):(e,t)=>Rs(Ks(e,t));function Js(e,t){let n=[{type:`text`,value:`↩`}];return t>1&&n.push({type:`element`,tagName:`sup`,properties:{},children:[{type:`text`,value:String(t)}]}),n}function Ys(e,t){return`Back to reference `+(e+1)+(t>1?`-`+t:``)}function Xs(e){let t=typeof e.options.clobberPrefix==`string`?e.options.clobberPrefix:`user-content-`,n=e.options.footnoteBackContent||Js,r=e.options.footnoteBackLabel||Ys,i=e.options.footnoteLabel||`Footnotes`,a=e.options.footnoteLabelTagName||`h2`,o=e.options.footnoteLabelProperties||{className:[`sr-only`]},s=[],c=-1;for(;++c0&&d.push({type:`text`,value:` `});let e=typeof n==`string`?n:n(c,u);typeof e==`string`&&(e={type:`text`,value:e}),d.push({type:`element`,tagName:`a`,properties:{href:`#`+t+`fnref-`+l+(u>1?`-`+u:``),dataFootnoteBackref:``,ariaLabel:typeof r==`string`?r:r(c,u),className:[`data-footnote-backref`]},children:Array.isArray(e)?e:[e]})}let p=a[a.length-1];if(p&&p.type===`element`&&p.tagName===`p`){let e=p.children[p.children.length-1];e&&e.type===`text`?e.value+=` `:p.children.push({type:`text`,value:` `}),p.children.push(...d)}else a.push(...d);let m={type:`element`,tagName:`li`,properties:{id:t+`fn-`+l},children:e.wrap(a,!0)};e.patch(i,m),s.push(m)}if(s.length!==0)return{type:`element`,tagName:`section`,properties:{dataFootnotes:!0,className:[`footnotes`]},children:[{type:`element`,tagName:a,properties:{...qs(o),id:`footnote-label`},children:[{type:`text`,value:i}]},{type:`text`,value:` -`},{type:`element`,tagName:`ol`,properties:{},children:e.wrap(s,!0)},{type:`text`,value:` -`}]}}var Zs=(function(e){if(e==null)return nc;if(typeof e==`function`)return tc(e);if(typeof e==`object`)return Array.isArray(e)?Qs(e):$s(e);if(typeof e==`string`)return ec(e);throw Error(`Expected function, string, or object as test`)});function Qs(e){let t=[],n=-1;for(;++n`:``))+`)`})}return u;function u(){let l=ac,u,d,f;if((!t||a(e,i,c[c.length-1]||void 0))&&(l=sc(n(e,c)),l[0]===!1))return l;if(`children`in e&&e.children){let t=e;if(t.children&&l[0]!==`skip`)for(d=(r?t.children.length:-1)+o,f=c.concat(t);d>-1&&d0&&n.push({type:`text`,value:` -`}),n}function hc(e){let t=0,n=e.charCodeAt(t);for(;n===9||n===32;)t++,n=e.charCodeAt(t);return e.slice(t)}function gc(e,t){let n=dc(e,t),r=n.one(e,void 0),i=Xs(n),a=Array.isArray(r)?{type:`root`,children:r}:r||{type:`root`,children:[]};return i&&(`children`in a,a.children.push({type:`text`,value:` -`},i)),a}function _c(e,t){return e&&`run`in e?async function(n,r){let i=gc(n,{file:r,...t});await e.run(i,r)}:function(n,r){return gc(n,{file:r,...e||t})}}function vc(e){if(e)throw e}var yc=b(((e,t)=>{var n=Object.prototype.hasOwnProperty,r=Object.prototype.toString,i=Object.defineProperty,a=Object.getOwnPropertyDescriptor,o=function(e){return typeof Array.isArray==`function`?Array.isArray(e):r.call(e)===`[object Array]`},s=function(e){if(!e||r.call(e)!==`[object Object]`)return!1;var t=n.call(e,`constructor`),i=e.constructor&&e.constructor.prototype&&n.call(e.constructor.prototype,`isPrototypeOf`);if(e.constructor&&!t&&!i)return!1;for(var a in e);return a===void 0||n.call(e,a)},c=function(e,t){i&&t.name===`__proto__`?i(e,t.name,{enumerable:!0,configurable:!0,value:t.newValue,writable:!0}):e[t.name]=t.newValue},l=function(e,t){if(t===`__proto__`){if(!n.call(e,t))return;if(a)return a(e,t).value}return e[t]};t.exports=function e(){var t,n,r,i,a,u,d=arguments[0],f=1,p=arguments.length,m=!1;for(typeof d==`boolean`&&(m=d,d=arguments[1]||{},f=2),(d==null||typeof d!=`object`&&typeof d!=`function`)&&(d={});ft.length,o;r&&t.push(i);try{o=e.apply(this,t)}catch(e){let t=e;if(r&&n)throw t;return i(t)}r||(o&&o.then&&typeof o.then==`function`?o.then(a,i):o instanceof Error?i(o):a(o))}function i(e,...r){n||(n=!0,t(e,...r))}function a(e){i(null,e)}}var Cc={basename:wc,dirname:Tc,extname:Ec,join:Dc,sep:`/`};function wc(e,t){if(t!==void 0&&typeof t!=`string`)throw TypeError(`"ext" argument must be a string`);Ac(e);let n=0,r=-1,i=e.length,a;if(t===void 0||t.length===0||t.length>e.length){for(;i--;)if(e.codePointAt(i)===47){if(a){n=i+1;break}}else r<0&&(a=!0,r=i+1);return r<0?``:e.slice(n,r)}if(t===e)return``;let o=-1,s=t.length-1;for(;i--;)if(e.codePointAt(i)===47){if(a){n=i+1;break}}else o<0&&(a=!0,o=i+1),s>-1&&(e.codePointAt(i)===t.codePointAt(s--)?s<0&&(r=i):(s=-1,r=o));return n===r?r=o:r<0&&(r=e.length),e.slice(n,r)}function Tc(e){if(Ac(e),e.length===0)return`.`;let t=-1,n=e.length,r;for(;--n;)if(e.codePointAt(n)===47){if(r){t=n;break}}else r||=!0;return t<0?e.codePointAt(0)===47?`/`:`.`:t===1&&e.codePointAt(0)===47?`//`:e.slice(0,t)}function Ec(e){Ac(e);let t=e.length,n=-1,r=0,i=-1,a=0,o;for(;t--;){let s=e.codePointAt(t);if(s===47){if(o){r=t+1;break}continue}n<0&&(o=!0,n=t+1),s===46?i<0?i=t:a!==1&&(a=1):i>-1&&(a=-1)}return i<0||n<0||a===0||a===1&&i===n-1&&i===r+1?``:e.slice(i,n)}function Dc(...e){let t=-1,n;for(;++t0&&e.codePointAt(e.length-1)===47&&(n+=`/`),t?`/`+n:n}function kc(e,t){let n=``,r=0,i=-1,a=0,o=-1,s,c;for(;++o<=e.length;){if(o2){if(c=n.lastIndexOf(`/`),c!==n.length-1){c<0?(n=``,r=0):(n=n.slice(0,c),r=n.length-1-n.lastIndexOf(`/`)),i=o,a=0;continue}}else if(n.length>0){n=``,r=0,i=o,a=0;continue}}t&&(n=n.length>0?n+`/..`:`..`,r=2)}else n.length>0?n+=`/`+e.slice(i+1,o):n=e.slice(i+1,o),r=o-i-1}i=o,a=0}else s===46&&a>-1?a++:a=-1}return n}function Ac(e){if(typeof e!=`string`)throw TypeError(`Path must be a string. Received `+JSON.stringify(e))}var jc={cwd:Mc};function Mc(){return`/`}function Nc(e){return!!(typeof e==`object`&&e&&`href`in e&&e.href&&`protocol`in e&&e.protocol&&e.auth===void 0)}function Pc(e){if(typeof e==`string`)e=new URL(e);else if(!Nc(e)){let t=TypeError('The "path" argument must be of type string or an instance of URL. Received `'+e+"`");throw t.code=`ERR_INVALID_ARG_TYPE`,t}if(e.protocol!==`file:`){let e=TypeError(`The URL must be of scheme file`);throw e.code=`ERR_INVALID_URL_SCHEME`,e}return Fc(e)}function Fc(e){if(e.hostname!==``){let e=TypeError(`File URL host must be "localhost" or empty on darwin`);throw e.code=`ERR_INVALID_FILE_URL_HOST`,e}let t=e.pathname,n=-1;for(;++n0){let[r,...a]=t,o=n[i][1];bc(o)&&bc(r)&&(r=(0,Hc.default)(!0,o,r)),n[i]=[e,r,...a]}}}}().freeze();function Gc(e,t){if(typeof t!=`function`)throw TypeError("Cannot `"+e+"` without `parser`")}function Kc(e,t){if(typeof t!=`function`)throw TypeError("Cannot `"+e+"` without `compiler`")}function qc(e,t){if(t)throw Error("Cannot call `"+e+"` on a frozen processor.\nCreate a new processor first, by calling it: use `processor()` instead of `processor`.")}function Jc(e){if(!bc(e)||typeof e.type!=`string`)throw TypeError("Expected node, got `"+e+"`")}function Yc(e,t,n){if(!n)throw Error("`"+e+"` finished async. Use `"+t+"` instead")}function Xc(e){return Zc(e)?e:new Lc(e)}function Zc(e){return!!(e&&typeof e==`object`&&`message`in e&&`messages`in e)}function Qc(e){return typeof e==`string`||$c(e)}function $c(e){return!!(e&&typeof e==`object`&&`byteLength`in e&&`byteOffset`in e)}var el=[],tl={allowDangerousHtml:!0},nl=/^(https?|ircs?|mailto|xmpp)$/i,rl=[{from:`astPlugins`,id:`remove-buggy-html-in-markdown-parser`},{from:`allowDangerousHtml`,id:`remove-buggy-html-in-markdown-parser`},{from:`allowNode`,id:`replace-allownode-allowedtypes-and-disallowedtypes`,to:`allowElement`},{from:`allowedTypes`,id:`replace-allownode-allowedtypes-and-disallowedtypes`,to:`allowedElements`},{from:`disallowedTypes`,id:`replace-allownode-allowedtypes-and-disallowedtypes`,to:`disallowedElements`},{from:`escapeHtml`,id:`remove-buggy-html-in-markdown-parser`},{from:`includeElementIndex`,id:`#remove-includeelementindex`},{from:`includeNodeIndex`,id:`change-includenodeindex-to-includeelementindex`},{from:`linkTarget`,id:`remove-linktarget`},{from:`plugins`,id:`change-plugins-to-remarkplugins`,to:`remarkPlugins`},{from:`rawSourcePos`,id:`#remove-rawsourcepos`},{from:`renderers`,id:`change-renderers-to-components`,to:`components`},{from:`source`,id:`change-source-to-children`,to:`children`},{from:`sourcePos`,id:`#remove-sourcepos`},{from:`transformImageUri`,id:`#add-urltransform`,to:`urlTransform`},{from:`transformLinkUri`,id:`#add-urltransform`,to:`urlTransform`}];function il(e){let t=al(e),n=ol(e);return sl(t.runSync(t.parse(n),n),e)}function al(e){let t=e.rehypePlugins||el,n=e.remarkPlugins||el,r=e.remarkRehypeOptions?{...e.remarkRehypeOptions,...tl}:tl;return Wc().use(ts).use(n).use(_c,r).use(t)}function ol(e){let t=e.children||``,n=new Lc;return typeof t==`string`?n.value=t:``+t,n}function sl(e,t){let n=t.allowedElements,r=t.allowElement,i=t.components,a=t.disallowedElements,o=t.skipHtml,s=t.unwrapDisallowed,c=t.urlTransform||cl;for(let e of rl)Object.hasOwn(t,e.from)&&``+e.from+(e.to?"use `"+e.to+"` instead":`remove it`)+e.id;return t.className&&(e={type:`element`,tagName:`div`,properties:{className:t.className},children:e.type===`root`?e.children:[e]}),cc(e,l),Br(e,{Fragment:R.Fragment,components:i,ignoreInvalidStyle:!0,jsx:R.jsx,jsxs:R.jsxs,passKeys:!0,passNode:!0});function l(e,t,i){if(e.type===`raw`&&i&&typeof t==`number`)return o?i.children.splice(t,1):i.children[t]={type:`text`,value:e.value},t;if(e.type===`element`){let t;for(t in si)if(Object.hasOwn(si,t)&&Object.hasOwn(e.properties,t)){let n=e.properties[t],r=si[t];(r===null||r.includes(e.tagName))&&(e.properties[t]=c(String(n||``),t,e))}}if(e.type===`element`){let o=n?!n.includes(e.tagName):a?a.includes(e.tagName):!1;if(!o&&r&&typeof t==`number`&&(o=!r(e,t,i)),o&&i&&typeof t==`number`)return s&&e.children?i.children.splice(t,1,...e.children):i.children.splice(t,1),t}}}function cl(e){let t=e.indexOf(`:`),n=e.indexOf(`?`),r=e.indexOf(`#`),i=e.indexOf(`/`);return t===-1||i!==-1&&t>i||n!==-1&&t>n||r!==-1&&t>r||nl.test(e.slice(0,t))?e:``}function ll(e,t){let n=String(e);if(typeof t!=`string`)throw TypeError(`Expected character`);let r=0,i=n.indexOf(t);for(;i!==-1;)r++,i=n.indexOf(t,i+t.length);return r}function ul(e){if(typeof e!=`string`)throw TypeError(`Expected a string`);return e.replace(/[|\\{}()[\]^$+*?.]/g,`\\$&`).replace(/-/g,`\\x2d`)}function dl(e,t,n){let r=Zs((n||{}).ignore||[]),i=fl(t),a=-1;for(;++a0?{type:`text`,value:a}:void 0),a===!1?r.lastIndex=n+1:(s!==n&&u.push({type:`text`,value:e.value.slice(s,n)}),Array.isArray(a)?u.push(...a):a&&u.push(a),s=n+d[0].length,l=!0),!r.global)break;d=r.exec(e.value)}return l?(s?\]}]+$/.exec(e);if(!t)return[e,void 0];e=e.slice(0,t.index);let n=t[0],r=n.indexOf(`)`),i=ll(e,`(`),a=ll(e,`)`);for(;r!==-1&&i>a;)e+=n.slice(0,r+1),n=n.slice(r+1),r=n.indexOf(`)`),a++;return[e,n]}function Al(e,t){let n=e.input.charCodeAt(e.index-1);return(e.index===0||ji(n)||Ai(n))&&(!t||n!==47)}Bl.peek=zl;function jl(){this.buffer()}function Ml(e){this.enter({type:`footnoteReference`,identifier:``,label:``},e)}function Nl(){this.buffer()}function Pl(e){this.enter({type:`footnoteDefinition`,identifier:``,label:``,children:[]},e)}function Fl(e){let t=this.resume(),n=this.stack[this.stack.length-1];n.type,n.identifier=Si(this.sliceSerialize(e)).toLowerCase(),n.label=t}function Il(e){this.exit(e)}function Ll(e){let t=this.resume(),n=this.stack[this.stack.length-1];n.type,n.identifier=Si(this.sliceSerialize(e)).toLowerCase(),n.label=t}function Rl(e){this.exit(e)}function zl(){return`[`}function Bl(e,t,n,r){let i=n.createTracker(r),a=i.move(`[^`),o=n.enter(`footnoteReference`),s=n.enter(`reference`);return a+=i.move(n.safe(n.associationId(e),{after:`]`,before:a})),s(),o(),a+=i.move(`]`),a}function Vl(){return{enter:{gfmFootnoteCallString:jl,gfmFootnoteCall:Ml,gfmFootnoteDefinitionLabelString:Nl,gfmFootnoteDefinition:Pl},exit:{gfmFootnoteCallString:Fl,gfmFootnoteCall:Il,gfmFootnoteDefinitionLabelString:Ll,gfmFootnoteDefinition:Rl}}}function Hl(e){let t=!1;return e&&e.firstLineBlank&&(t=!0),{handlers:{footnoteDefinition:n,footnoteReference:Bl},unsafe:[{character:`[`,inConstruct:[`label`,`phrasing`,`reference`]}]};function n(e,n,r,i){let a=r.createTracker(i),o=a.move(`[^`),s=r.enter(`footnoteDefinition`),c=r.enter(`label`);return o+=a.move(r.safe(r.associationId(e),{before:o,after:`]`})),c(),o+=a.move(`]:`),e.children&&e.children.length>0&&(a.shift(4),o+=a.move((t?` -`:` `)+r.indentLines(r.containerFlow(e,a.current()),t?Wl:Ul))),s(),o}}function Ul(e,t,n){return t===0?e:Wl(e,t,n)}function Wl(e,t,n){return(n?``:` `)+e}var Gl=[`autolink`,`destinationLiteral`,`destinationRaw`,`reference`,`titleQuote`,`titleApostrophe`];Xl.peek=Zl;function Kl(){return{canContainEols:[`delete`],enter:{strikethrough:Jl},exit:{strikethrough:Yl}}}function ql(){return{unsafe:[{character:`~`,inConstruct:`phrasing`,notInConstruct:Gl}],handlers:{delete:Xl}}}function Jl(e){this.enter({type:`delete`,children:[]},e)}function Yl(e){this.exit(e)}function Xl(e,t,n,r){let i=n.createTracker(r),a=n.enter(`strikethrough`),o=i.move(`~~`);return o+=n.containerPhrasing(e,{...i.current(),before:o,after:`~`}),o+=i.move(`~~`),a(),o}function Zl(){return`~`}function Ql(e){return e.length}function $l(e,t){let n=t||{},r=(n.align||[]).concat(),i=n.stringLength||Ql,a=[],o=[],s=[],c=[],l=0,u=-1;for(;++ul&&(l=e[u].length);++ac[a])&&(c[a]=e)}t.push(o)}o[u]=t,s[u]=r}let d=-1;if(typeof r==`object`&&`length`in r)for(;++dc[d]&&(c[d]=i),p[d]=i),f[d]=o}o.splice(1,0,f),s.splice(1,0,p),u=-1;let m=[];for(;++u `),a.shift(2);let o=n.indentLines(n.containerFlow(e,a.current()),ru);return i(),o}function ru(e,t,n){return`>`+(n?``:` `)+e}function iu(e,t){return au(e,t.inConstruct,!0)&&!au(e,t.notInConstruct,!1)}function au(e,t,n){if(typeof t==`string`&&(t=[t]),!t||t.length===0)return n;let r=-1;for(;++ro&&(o=a):a=1,i=r+t.length,r=n.indexOf(t,i);return o}function cu(e,t){return!(t.options.fences!==!1||!e.value||e.lang||!/[^ \r\n]/.test(e.value)||/^[\t ]*(?:[\r\n]|$)|(?:^|[\r\n])[\t ]*$/.test(e.value))}function lu(e){let t=e.options.fence||"`";if(t!=="`"&&t!==`~`)throw Error("Cannot serialize code with `"+t+"` for `options.fence`, expected `` ` `` or `~`");return t}function uu(e,t,n,r){let i=lu(n),a=e.value||``,o=i==="`"?`GraveAccent`:`Tilde`;if(cu(e,n)){let e=n.enter(`codeIndented`),t=n.indentLines(a,du);return e(),t}let s=n.createTracker(r),c=i.repeat(Math.max(su(a,i)+1,3)),l=n.enter(`codeFenced`),u=s.move(c);if(e.lang){let t=n.enter(`codeFencedLang${o}`);u+=s.move(n.safe(e.lang,{before:u,after:` `,encode:["`"],...s.current()})),t()}if(e.lang&&e.meta){let t=n.enter(`codeFencedMeta${o}`);u+=s.move(` `),u+=s.move(n.safe(e.meta,{before:u,after:` -`,encode:["`"],...s.current()})),t()}return u+=s.move(` -`),a&&(u+=s.move(a+` -`)),u+=s.move(c),l(),u}function du(e,t,n){return(n?``:` `)+e}function fu(e){let t=e.options.quote||`"`;if(t!==`"`&&t!==`'`)throw Error("Cannot serialize title with `"+t+"` for `options.quote`, expected `\"`, or `'`");return t}function pu(e,t,n,r){let i=fu(n),a=i===`"`?`Quote`:`Apostrophe`,o=n.enter(`definition`),s=n.enter(`label`),c=n.createTracker(r),l=c.move(`[`);return l+=c.move(n.safe(n.associationId(e),{before:l,after:`]`,...c.current()})),l+=c.move(`]: `),s(),!e.url||/[\0- \u007F]/.test(e.url)?(s=n.enter(`destinationLiteral`),l+=c.move(`<`),l+=c.move(n.safe(e.url,{before:l,after:`>`,...c.current()})),l+=c.move(`>`)):(s=n.enter(`destinationRaw`),l+=c.move(n.safe(e.url,{before:l,after:e.title?` `:` -`,...c.current()}))),s(),e.title&&(s=n.enter(`title${a}`),l+=c.move(` `+i),l+=c.move(n.safe(e.title,{before:l,after:i,...c.current()})),l+=c.move(i),s()),o(),l}function mu(e){let t=e.options.emphasis||`*`;if(t!==`*`&&t!==`_`)throw Error("Cannot serialize emphasis with `"+t+"` for `options.emphasis`, expected `*`, or `_`");return t}function hu(e){return`&#x`+e.toString(16).toUpperCase()+`;`}function gu(e,t,n){let r=Bi(e),i=Bi(t);return r===void 0?i===void 0?n===`_`?{inside:!0,outside:!0}:{inside:!1,outside:!1}:i===1?{inside:!0,outside:!0}:{inside:!1,outside:!0}:r===1?i===void 0?{inside:!1,outside:!1}:i===1?{inside:!0,outside:!0}:{inside:!1,outside:!1}:i===void 0?{inside:!1,outside:!1}:i===1?{inside:!0,outside:!1}:{inside:!1,outside:!1}}_u.peek=vu;function _u(e,t,n,r){let i=mu(n),a=n.enter(`emphasis`),o=n.createTracker(r),s=o.move(i),c=o.move(n.containerPhrasing(e,{after:i,before:s,...o.current()})),l=c.charCodeAt(0),u=gu(r.before.charCodeAt(r.before.length-1),l,i);u.inside&&(c=hu(l)+c.slice(1));let d=c.charCodeAt(c.length-1),f=gu(r.after.charCodeAt(0),d,i);f.inside&&(c=c.slice(0,-1)+hu(d));let p=o.move(i);return a(),n.attentionEncodeSurroundingInfo={after:f.outside,before:u.outside},s+c+p}function vu(e,t,n){return n.options.emphasis||`*`}function yu(e,t){let n=!1;return cc(e,function(e){if(`value`in e&&/\r?\n|\r/.test(e.value)||e.type===`break`)return n=!0,!1}),!!((!e.depth||e.depth<3)&&li(e)&&(t.options.setext||n))}function bu(e,t,n,r){let i=Math.max(Math.min(6,e.depth||1),1),a=n.createTracker(r);if(yu(e,n)){let t=n.enter(`headingSetext`),r=n.enter(`phrasing`),o=n.containerPhrasing(e,{...a.current(),before:` -`,after:` -`});return r(),t(),o+` -`+(i===1?`=`:`-`).repeat(o.length-(Math.max(o.lastIndexOf(`\r`),o.lastIndexOf(` -`))+1))}let o=`#`.repeat(i),s=n.enter(`headingAtx`),c=n.enter(`phrasing`);a.move(o+` `);let l=n.containerPhrasing(e,{before:`# `,after:` -`,...a.current()});return/^[\t ]/.test(l)&&(l=hu(l.charCodeAt(0))+l.slice(1)),l=l?o+` `+l:o,n.options.closeAtx&&(l+=` `+o),c(),s(),l}xu.peek=Su;function xu(e){return e.value||``}function Su(){return`<`}Cu.peek=wu;function Cu(e,t,n,r){let i=fu(n),a=i===`"`?`Quote`:`Apostrophe`,o=n.enter(`image`),s=n.enter(`label`),c=n.createTracker(r),l=c.move(`![`);return l+=c.move(n.safe(e.alt,{before:l,after:`]`,...c.current()})),l+=c.move(`](`),s(),!e.url&&e.title||/[\0- \u007F]/.test(e.url)?(s=n.enter(`destinationLiteral`),l+=c.move(`<`),l+=c.move(n.safe(e.url,{before:l,after:`>`,...c.current()})),l+=c.move(`>`)):(s=n.enter(`destinationRaw`),l+=c.move(n.safe(e.url,{before:l,after:e.title?` `:`)`,...c.current()}))),s(),e.title&&(s=n.enter(`title${a}`),l+=c.move(` `+i),l+=c.move(n.safe(e.title,{before:l,after:i,...c.current()})),l+=c.move(i),s()),l+=c.move(`)`),o(),l}function wu(){return`!`}Tu.peek=Eu;function Tu(e,t,n,r){let i=e.referenceType,a=n.enter(`imageReference`),o=n.enter(`label`),s=n.createTracker(r),c=s.move(`![`),l=n.safe(e.alt,{before:c,after:`]`,...s.current()});c+=s.move(l+`][`),o();let u=n.stack;n.stack=[],o=n.enter(`reference`);let d=n.safe(n.associationId(e),{before:c,after:`]`,...s.current()});return o(),n.stack=u,a(),i===`full`||!l||l!==d?c+=s.move(d+`]`):i===`shortcut`?c=c.slice(0,-1):c+=s.move(`]`),c}function Eu(){return`!`}Du.peek=Ou;function Du(e,t,n){let r=e.value||``,i="`",a=-1;for(;RegExp("(^|[^`])"+i+"([^`]|$)").test(r);)i+="`";for(/[^ \r\n]/.test(r)&&(/^[ \r\n]/.test(r)&&/[ \r\n]$/.test(r)||/^`|`$/.test(r))&&(r=` `+r+` `);++a\u007F]/.test(e.url))}Au.peek=ju;function Au(e,t,n,r){let i=fu(n),a=i===`"`?`Quote`:`Apostrophe`,o=n.createTracker(r),s,c;if(ku(e,n)){let t=n.stack;n.stack=[],s=n.enter(`autolink`);let r=o.move(`<`);return r+=o.move(n.containerPhrasing(e,{before:r,after:`>`,...o.current()})),r+=o.move(`>`),s(),n.stack=t,r}s=n.enter(`link`),c=n.enter(`label`);let l=o.move(`[`);return l+=o.move(n.containerPhrasing(e,{before:l,after:`](`,...o.current()})),l+=o.move(`](`),c(),!e.url&&e.title||/[\0- \u007F]/.test(e.url)?(c=n.enter(`destinationLiteral`),l+=o.move(`<`),l+=o.move(n.safe(e.url,{before:l,after:`>`,...o.current()})),l+=o.move(`>`)):(c=n.enter(`destinationRaw`),l+=o.move(n.safe(e.url,{before:l,after:e.title?` `:`)`,...o.current()}))),c(),e.title&&(c=n.enter(`title${a}`),l+=o.move(` `+i),l+=o.move(n.safe(e.title,{before:l,after:i,...o.current()})),l+=o.move(i),c()),l+=o.move(`)`),s(),l}function ju(e,t,n){return ku(e,n)?`<`:`[`}Mu.peek=Nu;function Mu(e,t,n,r){let i=e.referenceType,a=n.enter(`linkReference`),o=n.enter(`label`),s=n.createTracker(r),c=s.move(`[`),l=n.containerPhrasing(e,{before:c,after:`]`,...s.current()});c+=s.move(l+`][`),o();let u=n.stack;n.stack=[],o=n.enter(`reference`);let d=n.safe(n.associationId(e),{before:c,after:`]`,...s.current()});return o(),n.stack=u,a(),i===`full`||!l||l!==d?c+=s.move(d+`]`):i===`shortcut`?c=c.slice(0,-1):c+=s.move(`]`),c}function Nu(){return`[`}function Pu(e){let t=e.options.bullet||`*`;if(t!==`*`&&t!==`+`&&t!==`-`)throw Error("Cannot serialize items with `"+t+"` for `options.bullet`, expected `*`, `+`, or `-`");return t}function Fu(e){let t=Pu(e),n=e.options.bulletOther;if(!n)return t===`*`?`-`:`*`;if(n!==`*`&&n!==`+`&&n!==`-`)throw Error("Cannot serialize items with `"+n+"` for `options.bulletOther`, expected `*`, `+`, or `-`");if(n===t)throw Error("Expected `bullet` (`"+t+"`) and `bulletOther` (`"+n+"`) to be different");return n}function Iu(e){let t=e.options.bulletOrdered||`.`;if(t!==`.`&&t!==`)`)throw Error("Cannot serialize items with `"+t+"` for `options.bulletOrdered`, expected `.` or `)`");return t}function Lu(e){let t=e.options.rule||`*`;if(t!==`*`&&t!==`-`&&t!==`_`)throw Error("Cannot serialize rules with `"+t+"` for `options.rule`, expected `*`, `-`, or `_`");return t}function Ru(e,t,n,r){let i=n.enter(`list`),a=n.bulletCurrent,o=e.ordered?Iu(n):Pu(n),s=e.ordered?o===`.`?`)`:`.`:Fu(n),c=t&&n.bulletLastUsed?o===n.bulletLastUsed:!1;if(!e.ordered){let t=e.children?e.children[0]:void 0;if((o===`*`||o===`-`)&&t&&(!t.children||!t.children[0])&&n.stack[n.stack.length-1]===`list`&&n.stack[n.stack.length-2]===`listItem`&&n.stack[n.stack.length-3]===`list`&&n.stack[n.stack.length-4]===`listItem`&&n.indexStack[n.indexStack.length-1]===0&&n.indexStack[n.indexStack.length-2]===0&&n.indexStack[n.indexStack.length-3]===0&&(c=!0),Lu(n)===o&&t){let t=-1;for(;++t-1?t.start:1)+(n.options.incrementListMarker===!1?0:t.children.indexOf(e))+a);let o=a.length+1;(i===`tab`||i===`mixed`&&(t&&t.type===`list`&&t.spread||e.spread))&&(o=Math.ceil(o/4)*4);let s=n.createTracker(r);s.move(a+` `.repeat(o-a.length)),s.shift(o);let c=n.enter(`listItem`),l=n.indentLines(n.containerFlow(e,s.current()),u);return c(),l;function u(e,t,n){return t?(n?``:` `.repeat(o))+e:(n?a:a+` `.repeat(o-a.length))+e}}function Vu(e,t,n,r){let i=n.enter(`paragraph`),a=n.enter(`phrasing`),o=n.containerPhrasing(e,r);return a(),i(),o}var Hu=Zs([`break`,`delete`,`emphasis`,`footnote`,`footnoteReference`,`image`,`imageReference`,`inlineCode`,`inlineMath`,`link`,`linkReference`,`mdxJsxTextElement`,`mdxTextExpression`,`strong`,`text`,`textDirective`]);function Uu(e,t,n,r){return(e.children.some(function(e){return Hu(e)})?n.containerPhrasing:n.containerFlow).call(n,e,r)}function Wu(e){let t=e.options.strong||`*`;if(t!==`*`&&t!==`_`)throw Error("Cannot serialize strong with `"+t+"` for `options.strong`, expected `*`, or `_`");return t}Gu.peek=Ku;function Gu(e,t,n,r){let i=Wu(n),a=n.enter(`strong`),o=n.createTracker(r),s=o.move(i+i),c=o.move(n.containerPhrasing(e,{after:i,before:s,...o.current()})),l=c.charCodeAt(0),u=gu(r.before.charCodeAt(r.before.length-1),l,i);u.inside&&(c=hu(l)+c.slice(1));let d=c.charCodeAt(c.length-1),f=gu(r.after.charCodeAt(0),d,i);f.inside&&(c=c.slice(0,-1)+hu(d));let p=o.move(i+i);return a(),n.attentionEncodeSurroundingInfo={after:f.outside,before:u.outside},s+c+p}function Ku(e,t,n){return n.options.strong||`*`}function qu(e,t,n,r){return n.safe(e.value,r)}function Ju(e){let t=e.options.ruleRepetition||3;if(t<3)throw Error("Cannot serialize rules with repetition `"+t+"` for `options.ruleRepetition`, expected `3` or more");return t}function Yu(e,t,n){let r=(Lu(n)+(n.options.ruleSpaces?` `:``)).repeat(Ju(n));return n.options.ruleSpaces?r.slice(0,-1):r}var Xu={blockquote:nu,break:ou,code:uu,definition:pu,emphasis:_u,hardBreak:ou,heading:bu,html:xu,image:Cu,imageReference:Tu,inlineCode:Du,link:Au,linkReference:Mu,list:Ru,listItem:Bu,paragraph:Vu,root:Uu,strong:Gu,text:qu,thematicBreak:Yu};function Zu(){return{enter:{table:Qu,tableData:nd,tableHeader:nd,tableRow:ed},exit:{codeText:rd,table:$u,tableData:td,tableHeader:td,tableRow:td}}}function Qu(e){let t=e._align;this.enter({type:`table`,align:t.map(function(e){return e===`none`?null:e}),children:[]},e),this.data.inTable=!0}function $u(e){this.exit(e),this.data.inTable=void 0}function ed(e){this.enter({type:`tableRow`,children:[]},e)}function td(e){this.exit(e)}function nd(e){this.enter({type:`tableCell`,children:[]},e)}function rd(e){let t=this.resume();this.data.inTable&&(t=t.replace(/\\([\\|])/g,id));let n=this.stack[this.stack.length-1];n.type,n.value=t,this.exit(e)}function id(e,t){return t===`|`?t:e}function ad(e){let t=e||{},n=t.tableCellPadding,r=t.tablePipeAlign,i=t.stringLength,a=n?` `:`|`;return{unsafe:[{character:`\r`,inConstruct:`tableCell`},{character:` -`,inConstruct:`tableCell`},{atBreak:!0,character:`|`,after:`[ :-]`},{character:`|`,inConstruct:`tableCell`},{atBreak:!0,character:`:`,after:`-`},{atBreak:!0,character:`-`,after:`[:|-]`}],handlers:{inlineCode:f,table:o,tableCell:c,tableRow:s}};function o(e,t,n,r){return l(u(e,n,r),e.align)}function s(e,t,n,r){let i=l([d(e,n,r)]);return i.slice(0,i.indexOf(` -`))}function c(e,t,n,r){let i=n.enter(`tableCell`),o=n.enter(`phrasing`),s=n.containerPhrasing(e,{...r,before:a,after:a});return o(),i(),s}function l(e,t){return $l(e,{align:t,alignDelimiters:r,padding:n,stringLength:i})}function u(e,t,n){let r=e.children,i=-1,a=[],o=t.enter(`table`);for(;++i0&&!n&&(e[e.length-1][1]._gfmAutolinkLiteralWalkedInto=!0),n}var Ld={tokenize:Gd,partial:!0};function Rd(){return{document:{91:{name:`gfmFootnoteDefinition`,tokenize:Hd,continuation:{tokenize:Ud},exit:Wd}},text:{91:{name:`gfmFootnoteCall`,tokenize:Vd},93:{name:`gfmPotentialFootnoteCall`,add:`after`,tokenize:zd,resolveTo:Bd}}}}function zd(e,t,n){let r=this,i=r.events.length,a=r.parser.gfmFootnotes||(r.parser.gfmFootnotes=[]),o;for(;i--;){let e=r.events[i][1];if(e.type===`labelImage`){o=e;break}if(e.type===`gfmFootnoteCall`||e.type===`labelLink`||e.type===`label`||e.type===`image`||e.type===`link`)break}return s;function s(i){if(!o||!o._balanced)return n(i);let s=Si(r.sliceSerialize({start:o.end,end:r.now()}));return s.codePointAt(0)!==94||!a.includes(s.slice(1))?n(i):(e.enter(`gfmFootnoteCallLabelMarker`),e.consume(i),e.exit(`gfmFootnoteCallLabelMarker`),t(i))}}function Bd(e,t){let n=e.length;for(;n--;)if(e[n][1].type===`labelImage`&&e[n][0]===`enter`){e[n][1];break}e[n+1][1].type=`data`,e[n+3][1].type=`gfmFootnoteCallLabelMarker`;let r={type:`gfmFootnoteCall`,start:Object.assign({},e[n+3][1].start),end:Object.assign({},e[e.length-1][1].end)},i={type:`gfmFootnoteCallMarker`,start:Object.assign({},e[n+3][1].end),end:Object.assign({},e[n+3][1].end)};i.end.column++,i.end.offset++,i.end._bufferIndex++;let a={type:`gfmFootnoteCallString`,start:Object.assign({},i.end),end:Object.assign({},e[e.length-1][1].start)},o={type:`chunkString`,contentType:`string`,start:Object.assign({},a.start),end:Object.assign({},a.end)},s=[e[n+1],e[n+2],[`enter`,r,t],e[n+3],e[n+4],[`enter`,i,t],[`exit`,i,t],[`enter`,a,t],[`enter`,o,t],[`exit`,o,t],[`exit`,a,t],e[e.length-2],e[e.length-1],[`exit`,r,t]];return e.splice(n,e.length-n+1,...s),e}function Vd(e,t,n){let r=this,i=r.parser.gfmFootnotes||(r.parser.gfmFootnotes=[]),a=0,o;return s;function s(t){return e.enter(`gfmFootnoteCall`),e.enter(`gfmFootnoteCallLabelMarker`),e.consume(t),e.exit(`gfmFootnoteCallLabelMarker`),c}function c(t){return t===94?(e.enter(`gfmFootnoteCallMarker`),e.consume(t),e.exit(`gfmFootnoteCallMarker`),e.enter(`gfmFootnoteCallString`),e.enter(`chunkString`).contentType=`string`,l):n(t)}function l(s){if(a>999||s===93&&!o||s===null||s===91||W(s))return n(s);if(s===93){e.exit(`chunkString`);let a=e.exit(`gfmFootnoteCallString`);return i.includes(Si(r.sliceSerialize(a)))?(e.enter(`gfmFootnoteCallLabelMarker`),e.consume(s),e.exit(`gfmFootnoteCallLabelMarker`),e.exit(`gfmFootnoteCall`),t):n(s)}return W(s)||(o=!0),a++,e.consume(s),s===92?u:l}function u(t){return t===91||t===92||t===93?(e.consume(t),a++,l):l(t)}}function Hd(e,t,n){let r=this,i=r.parser.gfmFootnotes||(r.parser.gfmFootnotes=[]),a,o=0,s;return c;function c(t){return e.enter(`gfmFootnoteDefinition`)._container=!0,e.enter(`gfmFootnoteDefinitionLabel`),e.enter(`gfmFootnoteDefinitionLabelMarker`),e.consume(t),e.exit(`gfmFootnoteDefinitionLabelMarker`),l}function l(t){return t===94?(e.enter(`gfmFootnoteDefinitionMarker`),e.consume(t),e.exit(`gfmFootnoteDefinitionMarker`),e.enter(`gfmFootnoteDefinitionLabelString`),e.enter(`chunkString`).contentType=`string`,u):n(t)}function u(t){if(o>999||t===93&&!s||t===null||t===91||W(t))return n(t);if(t===93){e.exit(`chunkString`);let n=e.exit(`gfmFootnoteDefinitionLabelString`);return a=Si(r.sliceSerialize(n)),e.enter(`gfmFootnoteDefinitionLabelMarker`),e.consume(t),e.exit(`gfmFootnoteDefinitionLabelMarker`),e.exit(`gfmFootnoteDefinitionLabel`),f}return W(t)||(s=!0),o++,e.consume(t),t===92?d:u}function d(t){return t===91||t===92||t===93?(e.consume(t),o++,u):u(t)}function f(t){return t===58?(e.enter(`definitionMarker`),e.consume(t),e.exit(`definitionMarker`),i.includes(a)||i.push(a),K(e,p,`gfmFootnoteDefinitionWhitespace`)):n(t)}function p(e){return t(e)}}function Ud(e,t,n){return e.check(Ki,t,e.attempt(Ld,t,n))}function Wd(e){e.exit(`gfmFootnoteDefinition`)}function Gd(e,t,n){let r=this;return K(e,i,`gfmFootnoteDefinitionIndent`,5);function i(e){let i=r.events[r.events.length-1];return i&&i[1].type===`gfmFootnoteDefinitionIndent`&&i[2].sliceSerialize(i[1],!0).length===4?t(e):n(e)}}function Kd(e){let t=(e||{}).singleTilde,n={name:`strikethrough`,tokenize:i,resolveAll:r};return t??=!0,{text:{126:n},insideSpan:{null:[n]},attentionMarkers:{null:[126]}};function r(e,t){let n=-1;for(;++n1?r(a):(e.consume(a),o++,c);if(o<2&&!t)return r(a);let l=e.exit(`strikethroughSequenceTemporary`),u=Bi(a);return l._open=!u||u===2&&!!s,l._close=!s||s===2&&!!u,n(a)}}}var qd=class{constructor(){this.map=[],this.index=new Map}add(e,t,n){Jd(this,e,t,n)}consume(e){if(this.map.sort(function(e,t){return e[0]-t[0]}),this.map.length===0)return;let t=this.map.length,n=[];for(;t>0;)--t,n.push(e.slice(this.map[t][0]+this.map[t][1]),this.map[t][2]),e.length=this.map[t][0];n.push(e.slice()),e.length=0;let r=n.pop();for(;r;){for(let t of r)e.push(t);r=n.pop()}this.map.length=0,this.index.clear()}};function Jd(e,t,n,r){if(n===0&&r.length===0)return;let i=e.index.get(t);if(i){i[1]+=n,i[2].push(...r);return}let a=[t,n,r];e.map.push(a),e.index.set(t,a)}function Yd(e,t){let n=!1,r=[];for(;t-1;){let{type:e}=r.events[t][1];if(e===`lineEnding`||e===`linePrefix`)t--;else break}let i=t>-1?r.events[t][1].type:null,a=i===`tableHead`||i===`tableRow`?S:c;return a===S&&r.parser.lazy[r.now().line]?n(e):a(e)}function c(t){return e.enter(`tableHead`),e.enter(`tableRow`),l(t)}function l(e){return e===124?u(e):(o=!0,a+=1,u(e))}function u(t){return t===null?n(t):U(t)?a>1?(a=0,r.interrupt=!0,e.exit(`tableRow`),e.enter(`lineEnding`),e.consume(t),e.exit(`lineEnding`),p):n(t):G(t)?K(e,u,`whitespace`)(t):(a+=1,o&&(o=!1,i+=1),t===124?(e.enter(`tableCellDivider`),e.consume(t),e.exit(`tableCellDivider`),o=!0,u):(e.enter(`data`),d(t)))}function d(t){return t===null||t===124||W(t)?(e.exit(`data`),u(t)):(e.consume(t),t===92?f:d)}function f(t){return t===92||t===124?(e.consume(t),d):d(t)}function p(t){return r.interrupt=!1,r.parser.lazy[r.now().line]?n(t):(e.enter(`tableDelimiterRow`),o=!1,G(t)?K(e,m,`linePrefix`,r.parser.constructs.disable.null.includes(`codeIndented`)?void 0:4)(t):m(t))}function m(t){return t===45||t===58?g(t):t===124?(o=!0,e.enter(`tableCellDivider`),e.consume(t),e.exit(`tableCellDivider`),h):x(t)}function h(t){return G(t)?K(e,g,`whitespace`)(t):g(t)}function g(t){return t===58?(a+=1,o=!0,e.enter(`tableDelimiterMarker`),e.consume(t),e.exit(`tableDelimiterMarker`),_):t===45?(a+=1,_(t)):t===null||U(t)?b(t):x(t)}function _(t){return t===45?(e.enter(`tableDelimiterFiller`),v(t)):x(t)}function v(t){return t===45?(e.consume(t),v):t===58?(o=!0,e.exit(`tableDelimiterFiller`),e.enter(`tableDelimiterMarker`),e.consume(t),e.exit(`tableDelimiterMarker`),y):(e.exit(`tableDelimiterFiller`),y(t))}function y(t){return G(t)?K(e,b,`whitespace`)(t):b(t)}function b(n){return n===124?m(n):n===null||U(n)?!o||i!==a?x(n):(e.exit(`tableDelimiterRow`),e.exit(`tableHead`),t(n)):x(n)}function x(e){return n(e)}function S(t){return e.enter(`tableRow`),C(t)}function C(n){return n===124?(e.enter(`tableCellDivider`),e.consume(n),e.exit(`tableCellDivider`),C):n===null||U(n)?(e.exit(`tableRow`),t(n)):G(n)?K(e,C,`whitespace`)(n):(e.enter(`data`),w(n))}function w(t){return t===null||t===124||W(t)?(e.exit(`data`),C(t)):(e.consume(t),t===92?T:w)}function T(t){return t===92||t===124?(e.consume(t),w):w(t)}}function Qd(e,t){let n=-1,r=!0,i=0,a=[0,0,0,0],o=[0,0,0,0],s=!1,c=0,l,u,d,f=new qd;for(;++nn[2]+1){let t=n[2]+1,r=n[3]-n[2]-1;e.add(t,r,[])}}e.add(n[3]+1,0,[[`exit`,o,t]])}return i!==void 0&&(a.end=Object.assign({},tf(t.events,i)),e.add(i,0,[[`exit`,a,t]]),a=void 0),a}function ef(e,t,n,r,i){let a=[],o=tf(t.events,n);i&&(i.end=Object.assign({},o),a.push([`exit`,i,t])),r.end=Object.assign({},o),a.push([`exit`,r,t]),e.add(n+1,0,a)}function tf(e,t){let n=e[t],r=n[0]===`enter`?`start`:`end`;return n[1][r]}var nf={name:`tasklistCheck`,tokenize:af};function rf(){return{text:{91:nf}}}function af(e,t,n){let r=this;return i;function i(t){return r.previous!==null||!r._gfmTasklistFirstContentOfListItem?n(t):(e.enter(`taskListCheck`),e.enter(`taskListCheckMarker`),e.consume(t),e.exit(`taskListCheckMarker`),a)}function a(t){return W(t)?(e.enter(`taskListCheckValueUnchecked`),e.consume(t),e.exit(`taskListCheckValueUnchecked`),o):t===88||t===120?(e.enter(`taskListCheckValueChecked`),e.consume(t),e.exit(`taskListCheckValueChecked`),o):n(t)}function o(t){return t===93?(e.enter(`taskListCheckMarker`),e.consume(t),e.exit(`taskListCheckMarker`),e.exit(`taskListCheck`),s):n(t)}function s(r){return U(r)?t(r):G(r)?e.check({tokenize:of},t,n)(r):n(r)}}function of(e,t,n){return K(e,r,`whitespace`);function r(e){return e===null?n(e):t(e)}}function sf(e){return vi([Sd(),Rd(),Kd(e),Xd(),rf()])}var cf={};function lf(e){let t=this,n=e||cf,r=t.data(),i=r.micromarkExtensions||=[],a=r.fromMarkdownExtensions||=[],o=r.toMarkdownExtensions||=[];i.push(sf(n)),a.push(dd()),o.push(fd(n))}function uf(e,t){let n=e.trim().replace(/^\.?\//,``);if(!n||t.length===0)return null;if(t.includes(n))return n;let r=t.filter(e=>e.endsWith(`/${n}`));return r.length===1?r[0]:null}var df=e=>e.replace(/[.*+?^${}()|[\]\\/-]/g,`\\$&`);function ff(e,t){if(!e||t.length===0)return e;let n=new Set(t);for(let e of t){let r=e.slice(e.lastIndexOf(`/`)+1);r.includes(`.`)&&uf(r,t)===e&&n.add(r)}let r=[...n].sort((e,t)=>t.length-e.length).map(df),i=RegExp(`(?]*>)/).map((e,t)=>t%2==1?e:e.replace(i,"`$1`")).join(``)}function pf(e){let t=typeof e.children==`string`?e.children:``;return!String(e.className??``).includes(`language-`)&&!t.includes(` -`)}function mf(e){let t=[],n=[],r=null,i=()=>{let e=n.join(` -`).trim();if(n=[],!e)return;let r=e.trimStart(),i=r.startsWith("```")||r.startsWith(`~~~`)||r.startsWith(`|`)||r.startsWith(`<`),a=t[t.length-1];if(a&&!a.bare&&/^#{1,6}\s/.test(a.text)&&!a.text.includes(` -`)&&!i){a.text=`${a.text}\n\n${e}`;return}t.push({text:e,bare:i})};for(let t of e.split(` -`)){let e=/^\s*(```|~~~)/.exec(t);if(r){n.push(t),e&&e[1]===r&&(r=null);continue}if(e){n.length&&i(),r=e[1],n.push(t);continue}if(t.trim()===``){i();continue}n.push(t)}return i(),t}function hf({text:e,files:t=[],onOpenFile:n}){let r=e=>n&&e&&t.length>0?uf(e,t):null,i=e=>n?.(e),a=n&&t.length>0?ff(e,t):e;return(0,R.jsx)(`div`,{className:`md text-[15px] leading-[1.5] break-words`,children:(0,R.jsx)(il,{remarkPlugins:[lf],components:{a:({href:e,children:t,...n})=>{let a=e&&!/^[a-z]+:/i.test(e)?r(O(e)):null;return a?(0,R.jsx)(`button`,{type:`button`,className:`md-file`,onClick:()=>i(a),children:t}):(0,R.jsx)(`a`,{href:e,...n,target:`_blank`,rel:`noreferrer noopener`,children:t})},code:({children:e,...t})=>{let n=pf({children:e,...t})&&typeof e==`string`?r(e):null;return n?(0,R.jsx)(`button`,{type:`button`,className:`md-file`,onClick:()=>i(n),title:n,children:e}):(0,R.jsx)(`code`,{...t,children:e})}},children:a})})}function gf({path:e,onClose:t}){let n=s(),i=(0,L.useRef)(null);if(On(i,!!e),(0,L.useEffect)(()=>{if(!e)return;let n=e=>e.key===`Escape`&&t();return window.addEventListener(`keydown`,n),()=>window.removeEventListener(`keydown`,n)},[e,t]),!e)return null;let a=e.split(`/`).pop()??e,o=r(a);return(0,R.jsxs)(`div`,{ref:i,role:`dialog`,"aria-modal":`true`,"aria-label":a,className:`fixed inset-0 z-[60] flex flex-col bg-bg`,children:[(0,R.jsxs)(`header`,{className:`safe-top shrink-0 flex items-center gap-2 border-b border-border bg-surface/90 px-3 py-2 backdrop-blur`,children:[(0,R.jsx)(`button`,{type:`button`,onClick:t,"aria-label":n(`Close`),className:`p-2 rounded-full text-muted hover:bg-surface-2`,children:(0,R.jsx)(Fe,{size:20})}),(0,R.jsxs)(`div`,{className:`flex-1 min-w-0`,children:[(0,R.jsx)(`div`,{className:`font-semibold text-[15px] truncate`,children:a}),(0,R.jsx)(`div`,{className:`text-[12px] text-muted truncate`,children:e})]}),o!==`html`&&(0,R.jsx)(`a`,{href:h(e),target:`_blank`,rel:`noreferrer noopener`,"aria-label":n(`Open in a new tab`),className:`p-2 rounded-full text-muted hover:bg-surface-2`,children:(0,R.jsx)(Ae,{size:19})}),(0,R.jsx)(`a`,{href:h(e,!0),"aria-label":n(`Download`),className:`p-2 rounded-full text-muted hover:bg-surface-2`,children:(0,R.jsx)(ft,{size:19})})]}),(0,R.jsx)(`div`,{className:`min-h-0 flex-1 overflow-auto`,children:(0,R.jsx)(_f,{path:e,kind:o})})]})}function _f({path:e,kind:t}){let n=s();return t===`image`?(0,R.jsx)(`div`,{className:`flex h-full items-center justify-center p-3`,children:(0,R.jsx)(`img`,{src:h(e),alt:e,className:`max-h-full max-w-full rounded-2xl object-contain`})}):t===`pdf`?(0,R.jsx)(`iframe`,{title:e,src:h(e),className:`h-full w-full bg-white`}):t===`html`?(0,R.jsx)(yf,{path:e}):t===`event`?(0,R.jsx)(bf,{path:e}):t===`text`||t===`code`||t===`data`?(0,R.jsx)(Cf,{path:e,kind:t}):(0,R.jsxs)(`div`,{className:`p-8 text-center text-muted text-[14px]`,children:[n(`No preview for this file type.`),` `,(0,R.jsx)(`a`,{href:h(e,!0),className:`text-accent font-medium`,children:n(`Download it`)})]})}function vf(e){let[t,n]=(0,L.useState)(null),[r,i]=(0,L.useState)(null);return(0,L.useEffect)(()=>{let t=!0;return n(null),i(null),N.fileText(e).then(e=>t&&n(e)).catch(e=>t&&i(e.message)),()=>{t=!1}},[e]),{text:t,error:r}}function yf({path:e}){let{text:t,error:n}=vf(e);return n?(0,R.jsx)(Ef,{error:n}):t===null?(0,R.jsx)(Tf,{}):(0,R.jsx)(`iframe`,{title:e,srcDoc:t,sandbox:`allow-scripts allow-popups allow-forms allow-modals`,referrerPolicy:`no-referrer`,className:`h-full w-full bg-white`})}function bf({path:e}){let t=s(),{text:n,error:r}=vf(e);if(r)return(0,R.jsx)(Ef,{error:r});if(n===null)return(0,R.jsx)(Tf,{});let i=xf(n);return(0,R.jsxs)(`div`,{className:`mx-auto max-w-[560px] px-5 py-6 space-y-4`,children:[i.length===0&&(0,R.jsx)(`div`,{className:`text-center text-muted text-[14px]`,children:t(`No event in this file.`)}),i.map((e,n)=>(0,R.jsxs)(`div`,{className:`rounded-3xl border border-border/70 bg-surface shadow-sm p-5`,children:[(0,R.jsxs)(`div`,{className:`flex items-start gap-3`,children:[(0,R.jsx)(`div`,{className:`rounded-2xl bg-accent/12 text-accent p-2.5`,children:(0,R.jsx)(tt,{size:22})}),(0,R.jsxs)(`div`,{className:`min-w-0 flex-1`,children:[(0,R.jsx)(`div`,{className:`text-[18px] font-semibold leading-snug`,children:e.summary||t(`Untitled event`)}),(0,R.jsx)(`div`,{className:`mt-1 text-[14px] text-muted`,children:Sf(e)}),e.location&&(0,R.jsxs)(`div`,{className:`mt-1 flex items-center gap-1 text-[14px] text-muted`,children:[(0,R.jsx)(Dt,{size:14}),` `,e.location]})]})]}),e.description&&(0,R.jsx)(`div`,{className:`mt-4 whitespace-pre-wrap text-[14px] leading-relaxed`,children:e.description})]},n)),(0,R.jsxs)(`a`,{href:h(e,!0),download:!0,className:`flex items-center justify-center gap-2 rounded-2xl bg-accent text-accent-fg px-4 py-3 text-[15px] font-medium`,children:[(0,R.jsx)(nt,{size:18}),` `,t(`Add to calendar`)]}),(0,R.jsx)(`p`,{className:`text-center text-[12.5px] text-muted`,children:t(`Opens in your calendar app, which asks before it saves anything.`)})]})}function xf(e){let t=e.replace(/\r\n/g,` -`).replace(/\n[ \t]/g,``).split(` -`),n=[],r=null,i=e=>e.replace(/\\n/gi,` -`).replace(/\\([,;\\])/g,`$1`),a=(e,t)=>{if(/VALUE=DATE(?![-])/i.test(t)||/^\d{8}$/.test(e)){let t=/^(\d{4})(\d{2})(\d{2})/.exec(e);return{at:t?new Date(+t[1],t[2]-1,+t[3]):null,allDay:!0}}let n=/^(\d{4})(\d{2})(\d{2})T(\d{2})(\d{2})(\d{2})?(Z?)$/.exec(e);if(!n)return{at:null,allDay:!1};let r=[+n[1],n[2]-1,+n[3],+n[4],+n[5],+(n[6]??0)];return{at:n[7]?new Date(Date.UTC(...r)):new Date(...r),allDay:!1}};for(let e of t)if(e===`BEGIN:VEVENT`)r={summary:``,location:``,description:``,start:null,end:null,allDay:!1};else if(e===`END:VEVENT`&&r)n.push(r),r=null;else if(r){let t=e.indexOf(`:`);if(t<0)continue;let[n,...o]=e.slice(0,t).split(`;`),s=e.slice(t+1),c=o.join(`;`);if(n===`SUMMARY`)r.summary=i(s);else if(n===`LOCATION`)r.location=i(s);else if(n===`DESCRIPTION`)r.description=i(s);else if(n===`DTSTART`){let e=a(s,c);r.start=e.at,r.allDay=e.allDay}else n===`DTEND`&&(r.end=a(s,c).at)}return n}function Sf(e){if(!e.start)return``;let t=m(),n=e=>e.toLocaleDateString(t,{weekday:`short`,year:`numeric`,month:`short`,day:`numeric`}),r=e=>e.toLocaleTimeString(t,{hour:`numeric`,minute:`2-digit`});if(e.allDay){let t=e.end?new Date(e.end.getTime()-864e5):e.start;return t>e.start?`${n(e.start)} – ${n(t)}`:`${n(e.start)} · ${_(`all day`)}`}return e.end?e.start.toDateString()===e.end.toDateString()?`${n(e.start)} ${r(e.start)}–${r(e.end)}`:`${n(e.start)} ${r(e.start)} – ${n(e.end)} ${r(e.end)}`:`${n(e.start)} ${r(e.start)}`}function Cf({path:e,kind:t}){let{text:n,error:r}=vf(e);return r?(0,R.jsx)(Ef,{error:r}):n===null?(0,R.jsx)(Tf,{}):t===`text`&&/\.md$/i.test(e)?(0,R.jsx)(`div`,{className:`mx-auto max-w-[720px] px-5 py-4`,children:(0,R.jsx)(hf,{text:n})}):t===`data`&&/\.csv$/i.test(e)?(0,R.jsx)(wf,{text:n}):(0,R.jsx)(`pre`,{className:`whitespace-pre-wrap break-words px-4 py-3 font-mono text-[12.5px] leading-relaxed`,children:n})}function wf({text:e}){let t=s(),n=e.split(/\r?\n/).filter(e=>e.trim()).slice(0,500).map(e=>e.split(`,`));if(!n.length)return(0,R.jsx)(`div`,{className:`p-6 text-muted text-center`,children:t(`Empty file.`)});let[r,...i]=n;return(0,R.jsx)(`div`,{className:`overflow-auto p-3`,children:(0,R.jsxs)(`table`,{className:`min-w-full text-[13px] border-separate border-spacing-0`,children:[(0,R.jsx)(`thead`,{children:(0,R.jsx)(`tr`,{children:r.map((e,t)=>(0,R.jsx)(`th`,{className:`sticky top-0 bg-surface-2 text-left font-semibold px-3 py-2 border-b border-border whitespace-nowrap`,children:e},t))})}),(0,R.jsx)(`tbody`,{children:i.map((e,t)=>(0,R.jsx)(`tr`,{className:`odd:bg-surface`,children:e.map((e,t)=>(0,R.jsx)(`td`,{className:`px-3 py-1.5 border-b border-border/60 whitespace-nowrap`,children:e},t))},t))})]})})}function Tf(){return(0,R.jsx)(`div`,{className:`flex h-full items-center justify-center text-muted`,children:(0,R.jsx)(A,{className:`animate-spin`,size:22})})}function Ef({error:e}){let t=s();return(0,R.jsx)(`div`,{className:`p-8 text-center text-rose-600 dark:text-rose-300 text-[14px]`,children:t(`Could not load the file: {error}`,{error:e})})}var Df=`OpenAI's terms cover using a ChatGPT plan inside OpenAI's own Codex; other apps have had this access cut off before (OpenCode, January 2026). If it stops working, an API key does.`,Of=2e3,kf=6e5;function Af({compact:e,onChanged:t}){let n=s(),{toast:r}=E(),[a,o]=(0,L.useState)(null),[c,l]=(0,L.useState)(`unknown`),[u,d]=(0,L.useState)(null),[f,p]=(0,L.useState)(null),[m,h]=(0,L.useState)(!0),[g,_]=(0,L.useState)(``),[v,y]=(0,L.useState)(null),b=(0,L.useRef)(0),x=(0,L.useCallback)(async()=>{try{let e=await N.chatgptStatus();return o(e),l(`yes`),e}catch(e){return/not found/i.test(e.message)?l(`no`):y(e.message),null}},[]);(0,L.useEffect)(()=>{x().then(e=>{e?.pending&&e.url&&(b.current=Date.now(),h(e.port_bound!==!1),p(e.url))})},[x]),(0,L.useEffect)(()=>{if(!f)return;let e=setInterval(()=>{x().then(e=>{e?.signed_in?(p(null),Ee(),r(n(`Signed in with {label}.`,{label:e.label||`ChatGPT`})),t?.()):e&&e.pending===!1&&e.error?(p(null),y(n(e.error))):Date.now()-b.current>kf&&(p(null),y(n(`The sign-in did not finish in ten minutes. Try again.`)))})},Of);return()=>clearInterval(e)},[f,x,t,r,n]);let S=async()=>{d(`login`),y(null);try{let e=await N.chatgptLogin();b.current=Date.now(),h(e.port_bound!==!1),_(``),p(e.url),window.open(e.url,`_blank`,`noopener`)}catch(e){/not found/i.test(e.message)?l(`no`):y(e.message)}finally{d(null)}},C=async()=>{let e=g.trim();if(e){d(`paste`),y(null);try{await N.chatgptCallback(e),_(``)}catch(e){let t=e.message;/state/i.test(t)?y(n(`That address belongs to another sign-in attempt. Open the page again and paste the address it ends on.`)):/no sign-in|409/i.test(t)?(p(null),y(n(`The sign-in did not finish in ten minutes. Try again.`))):y(t)}finally{d(null)}}},w=async()=>{d(`use`),y(null);try{await N.setLLM({provider:`chatgpt`,model:a?.models?.[0]??``,base_url:``,api_key:``}),Ee(),r(n(`ChatGPT answers the chat now.`)),t?.()}catch(e){y(e.message)}finally{d(null)}},T=async()=>{d(`logout`),y(null);try{await N.chatgptLogout(),Ee(),await x(),t?.()}catch(e){y(e.message)}finally{d(null)}},D=n(`Covers chat and the hands. Pictures and clips are not part of it; those need a provider with image or video models.`);return(0,R.jsxs)(`div`,{className:i(`space-y-2`,!e&&`rounded-2xl bg-surface-2/60 p-3`),children:[!e&&(0,R.jsxs)(`div`,{className:`flex items-center gap-2 text-[13px] font-medium`,children:[(0,R.jsx)(Mt,{size:15,className:`text-accent`}),` `,n(`Sign in with ChatGPT`)]}),c===`no`?(0,R.jsxs)(`p`,{className:`text-[12.5px] text-muted`,children:[n(`This nanoMuse has no sign-in route yet. In a terminal on this computer, run`),` `,(0,R.jsx)(`code`,{className:`rounded bg-surface-2 px-1 py-0.5 text-[12px]`,children:`nanomuse chatgpt login`}),` `,n(`and reload this page.`)]}):a?.signed_in?(0,R.jsxs)(`div`,{className:`space-y-2`,children:[(0,R.jsxs)(`p`,{className:`text-[12.5px]`,children:[(0,R.jsx)(`span`,{className:`font-medium`,children:n(`Signed in with {label}.`,{label:a.label||`ChatGPT`})}),` `,(0,R.jsx)(`span`,{className:`text-muted`,children:D})]}),(0,R.jsxs)(`div`,{className:`flex flex-wrap gap-2`,children:[(0,R.jsxs)(`button`,{type:`button`,disabled:u!==null,onClick:()=>void w(),className:i(Ne,`inline-flex items-center gap-1.5 py-2`),children:[u===`use`?(0,R.jsx)(A,{size:14,className:`animate-spin`}):(0,R.jsx)(Mt,{size:14}),` `,n(`Use it for the chat`)]}),(0,R.jsxs)(`button`,{type:`button`,disabled:u!==null,onClick:()=>void T(),className:i(je,`inline-flex items-center gap-1.5`),children:[u===`logout`?(0,R.jsx)(A,{size:14,className:`animate-spin`}):(0,R.jsx)(Tt,{size:14}),` `,n(`Sign out of ChatGPT`)]})]})]}):f?(0,R.jsxs)(`div`,{className:`space-y-2`,children:[(0,R.jsxs)(`p`,{className:`flex items-start gap-2 text-[12.5px] text-muted`,children:[(0,R.jsx)(A,{size:14,className:`mt-0.5 shrink-0 animate-spin`}),(0,R.jsx)(`span`,{children:n(m?`A page from OpenAI opened in a new tab. Sign in there; this card follows on its own.`:`A page from OpenAI opened in a new tab. Sign in there; when the browser ends on an address that will not load, paste that address below.`)})]}),(0,R.jsxs)(`div`,{className:`flex flex-wrap gap-2`,children:[(0,R.jsxs)(`a`,{href:f,target:`_blank`,rel:`noopener noreferrer`,className:i(je,`inline-flex items-center gap-1.5`),children:[(0,R.jsx)(Ae,{size:14}),` `,n(`Open the page again`)]}),(0,R.jsx)(`button`,{type:`button`,onClick:()=>p(null),className:je,children:n(`Cancel`)})]}),(0,R.jsxs)(`form`,{className:`flex flex-wrap items-center gap-2`,onSubmit:e=>{e.preventDefault(),C()},children:[(0,R.jsx)(`input`,{type:`url`,value:g,onChange:e=>_(e.target.value),placeholder:`http://localhost:1455/auth/callback?code=…`,"aria-label":n(`The address the browser ended on`),className:`min-w-0 flex-1 rounded-lg border border-border bg-surface px-2 py-1.5 text-[12.5px]`}),(0,R.jsxs)(`button`,{type:`submit`,disabled:u!==null||!g.trim(),className:i(je,`inline-flex items-center gap-1.5`),children:[u===`paste`?(0,R.jsx)(A,{size:14,className:`animate-spin`}):null,` `,n(`Use this address`)]})]}),!m&&(0,R.jsx)(`p`,{className:`text-[11.5px] text-muted`,children:n(`This nanoMuse runs where the browser cannot reach port 1455, so it cannot pick the sign-in up by itself.`)})]}):(0,R.jsxs)(`div`,{className:`space-y-2`,children:[(0,R.jsx)(`p`,{className:`text-[12.5px] text-muted`,children:D}),(0,R.jsxs)(`button`,{type:`button`,disabled:u!==null||c===`unknown`,onClick:()=>void S(),className:i(Ne,`inline-flex items-center gap-1.5 py-2`),children:[u===`login`?(0,R.jsx)(A,{size:14,className:`animate-spin`}):(0,R.jsx)(wt,{size:14}),` `,n(`Sign in with ChatGPT`)]})]}),(0,R.jsx)(`p`,{className:`text-[11.5px] leading-snug text-muted`,children:n(Df)}),v&&(0,R.jsx)(`p`,{className:`text-[12px] text-rose-600 dark:text-rose-300`,children:v})]})}var jf=xe,Mf=`nm.connections.preset`;function Nf(e,t=_e().preset){try{sessionStorage.setItem(Mf,t)}catch{}e(`connections`)}function Pf(){try{let e=sessionStorage.getItem(Mf);return e&&sessionStorage.removeItem(Mf),e}catch{return null}}function Ff({info:e,exhausted:t,compact:n}){let r=s(),{toast:a,setTab:o,state:l}=E(),u=l.hub?.account,d=_e(u),f=ae(u),p=c(),m=e.invite_bonus_cny??5,h=e.own_key_docs||e.guidance?.docs||jf,g=e.invite_url||``,[_,v]=(0,L.useState)(!1),[y,b]=(0,L.useState)(!1),x=(e.guidance?.providers??de(f)).filter(e=>e.id!==d.id).map(e=>({id:e.id,name:De(e,p),keyUrl:e.key_url,covers:`covers`in e?e.covers:e.capabilities})),S=Oe().map(e=>e.name),C=async e=>{try{await navigator.clipboard.writeText(e),a(r(`Copied`))}catch{a(e)}},w=async()=>{let e=r(`Try nanoMuse with me, a fully open-source personal agent, free to use. Sign up with my link: {link}`,{link:g}),t=navigator;if(t.share)try{await t.share({text:e});return}catch{}await C(e)},T=Ce(),[D,O]=me(`exhausted`,t),k=ve(be(r,`exhausted`)),ee=t?r(`The free allowance is used up.`):r(`Nearly used up: ¥{left} of ¥{grant} left.`,{left:(e.left??0).toFixed(2),grant:(e.grant??0).toFixed(0)});return(0,R.jsxs)(`div`,{className:i(`space-y-2.5`,!n&&`pt-1`),children:[(0,R.jsxs)(`div`,{children:[(0,R.jsx)(`div`,{className:i(`font-semibold`,n?`text-[13.5px]`:`text-[15px]`),children:ee}),(0,R.jsx)(`div`,{className:`mt-0.5 text-[12.5px] text-muted`,children:r(`Three ways on; your sign-in and your devices keep working whichever you pick.`)})]}),(0,R.jsxs)(If,{icon:(0,R.jsx)(xt,{size:16}),tone:`bg-accent/12 text-accent`,title:r(`Use your own model key`),children:[(0,R.jsx)(`p`,{className:`text-[12.5px] text-muted`,children:ie(r,u)}),(0,R.jsxs)(`div`,{className:`flex flex-wrap gap-2`,children:[(0,R.jsxs)(`button`,{type:`button`,onClick:()=>Nf(o,d.preset),className:i(Ne,`inline-flex items-center gap-1.5 py-2`),children:[(0,R.jsx)(xt,{size:14}),` `,r(`Set it up`)]}),(0,R.jsxs)(`a`,{href:d.keyUrl,target:`_blank`,rel:`noopener noreferrer`,className:i(je,`inline-flex items-center gap-1.5`),children:[(0,R.jsx)(Ae,{size:14}),` `,r(`Get a key from {vendor}`,{vendor:d.label})]}),(0,R.jsxs)(`a`,{href:h,target:`_blank`,rel:`noopener noreferrer`,className:i(je,`inline-flex items-center gap-1.5`),children:[(0,R.jsx)(Ae,{size:14}),` `,r(`Step-by-step guide`)]})]}),x.length>0&&(0,R.jsxs)(`div`,{children:[(0,R.jsxs)(`button`,{type:`button`,onClick:()=>v(!_),className:`inline-flex items-center gap-1 text-[12px] text-muted`,children:[_?(0,R.jsx)(Le,{size:13}):(0,R.jsx)(Me,{size:13}),` `,r(`Other providers and what each key covers`)]}),_&&(0,R.jsx)(`ul`,{className:`mt-1.5 space-y-1 text-[12.5px]`,children:x.map(e=>(0,R.jsxs)(`li`,{className:`flex flex-wrap items-baseline justify-between gap-x-3`,children:[(0,R.jsxs)(`span`,{children:[(0,R.jsx)(`span`,{className:`font-medium`,children:e.name}),` `,(0,R.jsxs)(`span`,{className:`text-muted`,children:[`· `,he(r,e.covers)]})]}),(0,R.jsxs)(`span`,{className:`flex gap-2`,children:[(0,R.jsx)(`button`,{type:`button`,onClick:()=>Nf(o,pe(e.id)),className:`text-accent`,children:r(`Set it up`)}),(0,R.jsxs)(`a`,{href:e.keyUrl,target:`_blank`,rel:`noopener noreferrer`,className:`inline-flex items-center gap-0.5 text-accent`,children:[r(`Get a key`),` `,(0,R.jsx)(Ae,{size:11})]})]})]},e.id))})]})]}),(0,R.jsxs)(If,{icon:(0,R.jsx)(wt,{size:16}),tone:`bg-emerald-500/12 text-emerald-600 dark:text-emerald-300`,title:r(`Sign in with a plan you already pay for`),children:[(0,R.jsx)(`p`,{className:`text-[12.5px] text-muted`,children:r(`{plans}: the plan's models answer here, no key to make. ChatGPT works on every device, the others on the phones. A ChatGPT sign-in covers chat and the hands; pictures and clips still want a key.`,{plans:S.join(r(`, `))})}),y?(0,R.jsx)(Af,{compact:!0,onChanged:()=>b(!1)}):(0,R.jsxs)(`button`,{type:`button`,onClick:()=>b(!0),className:i(je,`inline-flex items-center gap-1.5`),children:[(0,R.jsx)(wt,{size:14}),` `,r(`Sign in with ChatGPT`)]})]}),(0,R.jsx)(If,{icon:(0,R.jsx)(hn,{size:16}),tone:`bg-violet-500/12 text-violet-600 dark:text-violet-300`,title:r(`Invite a friend: +¥{bonus} for you and +¥{bonus} for them, for each new person who signs up with your link.`,{bonus:m.toFixed(0)}),children:g?(0,R.jsxs)(`div`,{className:`flex flex-wrap gap-2`,children:[(0,R.jsxs)(`button`,{type:`button`,onClick:()=>void w(),className:i(je,`inline-flex items-center gap-1.5`),children:[(0,R.jsx)(Xt,{size:14}),` `,r(`Share the link`)]}),(0,R.jsxs)(`button`,{type:`button`,onClick:()=>void C(g),className:i(je,`inline-flex items-center gap-1.5`),children:[(0,R.jsx)(ut,{size:14}),` `,r(`Copy the link`)]})]}):(0,R.jsxs)(`button`,{type:`button`,onClick:()=>o(`account`),className:i(je,`inline-flex items-center gap-1.5`),children:[(0,R.jsx)(Xt,{size:14}),` `,r(`Your invite link is under Account`)]})}),t&&D&&(0,R.jsxs)(If,{icon:(0,R.jsx)(ce,{size:16}),tone:`bg-amber-400/15 text-amber-600 dark:text-amber-300`,title:k,children:[(0,R.jsxs)(`button`,{type:`button`,onClick:()=>fe(T.repo_url),className:i(`flex items-center justify-center gap-1.5 rounded-2xl border border-border px-4 py-2.5 text-[14px] font-medium text-muted disabled:opacity-40`,`inline-flex items-center gap-1.5`),children:[(0,R.jsx)(ce,{size:14}),` `,r(`Star on GitHub`)]}),(0,R.jsx)(`button`,{type:`button`,onClick:()=>{ge(),O(!1)},className:i(`flex items-center justify-center gap-1.5 rounded-2xl border border-border px-4 py-2.5 text-[14px] font-medium text-muted disabled:opacity-40`,`inline-flex items-center gap-1.5`),children:r(`I already starred`)})]})]})}function If({icon:e,tone:t,title:n,children:r}){return(0,R.jsxs)(`div`,{className:`flex gap-3 rounded-2xl bg-surface-2/60 p-3`,children:[(0,R.jsx)(`span`,{className:i(`flex h-8 w-8 shrink-0 items-center justify-center rounded-xl`,t),children:e}),(0,R.jsxs)(`div`,{className:`min-w-0 flex-1 space-y-2`,children:[(0,R.jsx)(`div`,{className:`text-[13px] font-medium leading-snug`,children:n}),r]})]})}var Lf=`nm.cloud.warned_grant`;function Rf(){let e=s(),{state:t,setTab:n}=E(),[r,i]=(0,L.useState)(null),a=(0,L.useRef)(0),o=t.hub?.account,c=!!o?.signed_in&&!!o.is_model,l=t.finishedAt;if((0,L.useEffect)(()=>{if(!c||!l||r||Date.now()-a.current<6e4)return;a.current=Date.now();let e=!1;return N.cloudMe().then(t=>{if(e)return;let n=t.spend,r=n.grant??n.allowance_cny??0,a=n.left??null;if(n.unlimited||!n.warn||a===null||a<=0)return;let o=null;try{o=localStorage.getItem(Lf)}catch{}o!==String(r)&&i({left:a,grant:r,invite_url:t.invite?.url,invite_bonus_cny:n.invite_bonus_cny,invitee_bonus_cny:n.invitee_bonus_cny,own_key_docs:n.own_key_docs,guidance:n.guidance})}).catch(()=>{}),()=>{e=!0}},[c,l,r]),!r)return null;let u=()=>{try{localStorage.setItem(Lf,String(r.grant??0))}catch{}i(null)};return(0,R.jsxs)(`div`,{className:`rise mx-3 mb-1.5 flex items-start gap-2 rounded-2xl bg-amber-500/12 px-3 py-2 text-[12.5px] leading-snug text-amber-800 dark:text-amber-200`,children:[(0,R.jsx)(nn,{size:14,className:`mt-0.5 shrink-0`}),(0,R.jsxs)(`div`,{className:`min-w-0 flex-1`,children:[e(`Nearly used up: ¥{left} of ¥{grant} left.`,{left:(r.left??0).toFixed(2),grant:(r.grant??0).toFixed(0)}),` `,e(`Invite a friend (+¥{invite} for each of you) or bring your own key; your sign-in keeps working either way.`,{invite:(r.invite_bonus_cny??5).toFixed(0)}),` `,(0,R.jsx)(`button`,{type:`button`,onClick:()=>{u(),n(`account`)},className:`font-semibold underline decoration-dotted underline-offset-2`,children:e(`See the ways`)})]}),(0,R.jsx)(`button`,{type:`button`,onClick:u,"aria-label":e(`Dismiss`),className:`shrink-0 rounded-full p-0.5 opacity-70 hover:opacity-100`,children:(0,R.jsx)(Fe,{size:14})})]})}var zf=`nm.cloud.first_sign_in`,Bf=`nm:first-sign-in`;function Vf(){try{sessionStorage.setItem(zf,`1`)}catch{}window.dispatchEvent(new Event(Bf))}function Hf(){try{sessionStorage.removeItem(zf)}catch{}window.dispatchEvent(new Event(Bf))}function Uf(){try{return sessionStorage.getItem(zf)===`1`}catch{return!1}}function Wf(){let[e,t]=(0,L.useState)(Uf);return(0,L.useEffect)(()=>{let e=()=>t(Uf());return window.addEventListener(Bf,e),()=>window.removeEventListener(Bf,e)},[]),e}function Gf(){let e=s(),{toast:t,refreshHub:n,setTab:r,state:a}=E(),o=_e(a.hub?.account),[c,l]=(0,L.useState)(`password`),[u,d]=(0,L.useState)(``),[f,p]=(0,L.useState)(``),[m,h]=(0,L.useState)(!1),[g,_]=(0,L.useState)(null),v=async()=>{Hf(),await n().catch(()=>void 0)},y=async()=>{if(!(u.length<8||u!==f)){h(!0),_(null);try{await N.cloudPassword(u),t(e(`Password set.`)),d(``),p(``),l(`source`)}catch(t){_(e(t.message))}finally{h(!1)}}},b=async()=>{await v(),Nf(r,o.preset)},x=(0,L.useRef)(null);On(x,!0);let S=f.length>0&&f!==u;return(0,R.jsx)(`div`,{className:`fixed inset-0 z-50 flex items-end justify-center bg-black/40 backdrop-blur-[2px] sm:items-center`,role:`dialog`,"aria-modal":`true`,children:(0,R.jsxs)(`div`,{ref:x,className:`safe-bottom w-full max-w-[520px] rounded-t-[28px] bg-bg p-6 shadow-2xl sm:rounded-[28px]`,children:[(0,R.jsxs)(`div`,{className:`mb-4 flex gap-1`,children:[(0,R.jsx)(`span`,{className:i(`h-1.5 w-5 rounded-full bg-accent`)}),(0,R.jsx)(`span`,{className:i(`h-1.5 rounded-full transition-all`,c===`source`?`w-5 bg-accent`:`w-1.5 bg-border`)})]}),c===`password`?(0,R.jsxs)(`form`,{className:`space-y-4`,onSubmit:e=>{e.preventDefault(),y()},children:[(0,R.jsxs)(`div`,{className:`flex items-start gap-3`,children:[(0,R.jsx)(`span`,{className:`flex h-11 w-11 shrink-0 items-center justify-center rounded-2xl bg-accent/12 text-accent`,children:(0,R.jsx)(xt,{size:20})}),(0,R.jsxs)(`div`,{children:[(0,R.jsx)(`h2`,{className:`text-[20px] font-bold tracking-tight`,children:e(`Set a password`)}),(0,R.jsx)(`p`,{className:`mt-1 text-[13.5px] leading-relaxed text-muted`,children:e(`Your account is in. With a password, your phone and your other computers sign in at once, without waiting for a code. Optional; you can set one later under Account.`)})]})]}),(0,R.jsxs)(`div`,{className:`space-y-2`,children:[(0,R.jsx)(`input`,{type:`password`,value:u,onChange:e=>d(e.target.value),autoComplete:`new-password`,autoFocus:!0,placeholder:e(`At least 8 characters`),className:Ie}),(0,R.jsx)(`input`,{type:`password`,value:f,onChange:e=>p(e.target.value),autoComplete:`new-password`,placeholder:e(`Once more`),className:i(Ie,S&&`border-rose-400`)}),S&&(0,R.jsx)(`p`,{className:`text-[12px] text-rose-600 dark:text-rose-300`,children:e(`The two do not match.`)})]}),g&&(0,R.jsx)(`div`,{className:`rounded-2xl bg-rose-500/12 px-3 py-2 text-[12.5px] text-rose-700 dark:text-rose-300`,children:g}),(0,R.jsxs)(`div`,{className:`flex gap-2`,children:[(0,R.jsx)(`button`,{type:`button`,disabled:m,onClick:()=>l(`source`),className:je,children:e(`Skip`)}),(0,R.jsxs)(`button`,{type:`submit`,disabled:m||u.length<8||u!==f,className:i(Ne,`flex-1 py-3`),children:[m?(0,R.jsx)(A,{size:15,className:`animate-spin`}):null,` `,e(`Set the password`),` `,(0,R.jsx)(qe,{size:16})]})]})]}):(0,R.jsxs)(`div`,{className:`space-y-4`,children:[(0,R.jsxs)(`div`,{className:`flex items-start gap-3`,children:[(0,R.jsx)(`span`,{className:`flex h-11 w-11 shrink-0 items-center justify-center rounded-2xl bg-accent/12 text-accent`,children:(0,R.jsx)(ot,{size:20})}),(0,R.jsxs)(`div`,{children:[(0,R.jsx)(`h2`,{className:`text-[20px] font-bold tracking-tight`,children:e(`Which model answers?`)}),(0,R.jsx)(`p`,{className:`mt-1 text-[13.5px] leading-relaxed text-muted`,children:e(`Your account already brings one. You can add your own API key as well and switch at any time.`)})]})]}),(0,R.jsxs)(`ul`,{className:`space-y-2 text-[13px] leading-snug`,children:[(0,R.jsxs)(`li`,{className:`flex items-start gap-2.5 rounded-2xl bg-surface-2 px-3 py-2.5`,children:[(0,R.jsx)(ot,{size:16,className:`mt-0.5 shrink-0 text-accent`}),(0,R.jsxs)(`span`,{children:[(0,R.jsx)(`span`,{className:`font-medium`,children:e(`Use the nanoMuse Cloud model`)}),(0,R.jsx)(`span`,{className:`block text-muted`,children:e(`DeepSeek for the chat and Qwen for the hands, with a free allowance per account paid by the developer. Nothing to configure.`)})]})]}),(0,R.jsxs)(`li`,{className:`flex items-start gap-2.5 rounded-2xl bg-surface-2 px-3 py-2.5`,children:[(0,R.jsx)(xt,{size:16,className:`mt-0.5 shrink-0 text-accent`}),(0,R.jsxs)(`span`,{children:[(0,R.jsx)(`span`,{className:`font-medium`,children:e(`I have my own API key`)}),(0,R.jsx)(`span`,{className:`block text-muted`,children:o.preset===`qwen`?e(`Alibaba Cloud Bailian first (one key covers chat, the hands, pictures and clips), then DeepSeek, Kimi, Zhipu, OpenAI, OpenRouter and any OpenAI-compatible endpoint. The key stays on this device.`):e(`OpenRouter first (one account, one key, pay as you go), then OpenAI, Anthropic, Gemini, DeepSeek and any OpenAI-compatible endpoint. The key stays on this device.`)})]})]}),(0,R.jsxs)(`li`,{className:`flex items-start gap-2.5 rounded-2xl bg-surface-2 px-3 py-2.5`,children:[(0,R.jsx)(wt,{size:16,className:`mt-0.5 shrink-0 text-accent`}),(0,R.jsxs)(`span`,{children:[(0,R.jsx)(`span`,{className:`font-medium`,children:e(`Sign in with a plan you already pay for`)}),(0,R.jsx)(`span`,{className:`block text-muted`,children:e(`A ChatGPT plan signs in from Connections and answers the chat and the hands. Pictures and clips still want a key.`)})]})]})]}),(0,R.jsxs)(`div`,{className:`flex gap-2`,children:[(0,R.jsx)(`button`,{type:`button`,disabled:m,onClick:()=>void b(),className:je,children:e(`I have my own API key`)}),(0,R.jsxs)(`button`,{type:`button`,disabled:m,onClick:()=>void v(),className:i(Ne,`flex-1 py-3`),children:[e(`Use the nanoMuse Cloud model`),` `,(0,R.jsx)(qe,{size:16})]})]})]})]})})}var Kf=`nanomuse_devtools`;function qf(){try{return localStorage.getItem(Kf)===`1`}catch{return!1}}var Jf=qf(),Yf=new Set;function Xf(){return Jf}function Zf(e){Jf=e;try{localStorage.setItem(Kf,e?`1`:`0`)}catch{}Yf.forEach(e=>e())}function Qf(e){return Yf.add(e),()=>Yf.delete(e)}function $f(){return(0,L.useSyncExternalStore)(Qf,Xf,Xf)}function ep(e,t,n){if(!n.signedIn||n.chatOnCloud||n.deviceChat)return;let r=e[t];if(r?.type===`notice`&&r.level===`error`&&r.code&&r.code!==`allowance`&&!r.model_used)for(let n=t-1;n>=0;n--){let t=e[n];if(t?.type===`user`){let e=(t.files??[]).map(e=>e.path);return t.text||e.length>0?{text:t.text,files:e}:void 0}}}var tp=[`idle`,`working`,`waiting`,`happy`,`error`];function np({event:e,name:t=`nanoMuse`}){let n=s(),{toast:r}=E(),[a,o]=(0,L.useState)(null),c=e.cost??{},l=e.candidates??[null,null,null,null],u=e.moods??{},d=e.clips??{},f=async(e,t)=>{o(e);try{await t()}catch(e){r(e.message)}finally{o(null)}},p=e.stage===`estimate`||e.stage===`drawing`||e.stage===`choose`||e.stage===`posing`||e.stage===`animating`,m=c.clips?n(`{n} pictures and {c} clips`,{n:c.pictures??8,c:c.clips}):n(`{n} pictures`,{n:c.pictures??8}),g=(()=>{if(c.cloud===!1)return n(`{what}, made with your own key at your provider's prices.`,{what:m});if(c.error)return n(`The cost could not be checked: {error}`,{error:c.error});if(typeof c.cny!=`number`)return n(`Checking the cost…`);if(c.unlimited)return n(`About ¥{cny} for {what}; your account has no limit.`,{cny:c.cny.toFixed(2),what:m});let e=typeof c.left_cny==`number`?c.left_cny.toFixed(2):`?`;return c.affordable===!1?n(`About ¥{cny} for {what}, more than the ¥{left} left in your allowance.`,{cny:c.cny.toFixed(2),what:m,left:e}):n(`About ¥{cny} for {what}; ¥{left} left in your allowance.`,{cny:c.cny.toFixed(2),what:m,left:e})})();return(0,R.jsx)(`div`,{className:`rise flex justify-start pr-8`,children:(0,R.jsxs)(`div`,{className:i(`w-full max-w-[360px] overflow-hidden rounded-3xl rounded-tl-lg border bg-surface shadow-sm`,p?`border-accent/50`:`border-border/70`),children:[(0,R.jsxs)(`div`,{className:`flex items-start gap-3 px-4 pt-3.5 pb-2`,children:[(0,R.jsx)(`div`,{className:i(`mt-0.5 rounded-full p-2`,p?`bg-accent/12 text-accent`:`bg-surface-2 text-fg/80`),children:(0,R.jsx)(nn,{size:18})}),(0,R.jsxs)(`div`,{className:`min-w-0 flex-1`,children:[(0,R.jsxs)(`div`,{className:`text-[12.5px] font-medium text-muted`,children:[e.stage===`estimate`&&n(`A new look for {name}`,{name:t}),e.stage===`drawing`&&n(`Drawing four to choose from…`),e.stage===`choose`&&n(`Pick one: tap it, or say which`),e.stage===`posing`&&n(`Drawing the poses…`),e.stage===`animating`&&n(`The new look is on; making the clips…`),e.stage===`done`&&n(`The new look is on`),e.stage===`cancelled`&&n(`Not this time`),e.stage===`failed`&&n(`That did not work`)]}),(0,R.jsx)(`div`,{className:`mt-0.5 text-[14px] leading-snug`,children:e.description}),e.reference&&(0,R.jsxs)(`div`,{className:`mt-1.5 flex items-center gap-2 text-[12px] text-muted`,children:[(0,R.jsx)(`img`,{src:h(e.reference),alt:``,draggable:!1,className:`h-9 w-9 rounded-lg object-cover`}),n(`drawn from the picture you attached`)]})]})]}),e.stage===`estimate`&&(0,R.jsxs)(`div`,{className:`px-4 pb-3.5 space-y-2.5`,children:[(0,R.jsx)(`p`,{className:`text-[12.5px] text-muted`,children:g}),(0,R.jsxs)(`div`,{className:`flex gap-2`,children:[(0,R.jsxs)(`button`,{type:`button`,disabled:a!==null||c.cloud!==!1&&typeof c.cny!=`number`&&!c.error,onClick:()=>f(`start`,()=>N.avatarStart(e.session)),className:i(`flex items-center justify-center gap-1.5 rounded-2xl bg-accent text-accent-fg px-4 py-2.5 text-[14px] font-medium disabled:opacity-40`,`inline-flex items-center gap-1.5 py-2`),children:[a===`start`?(0,R.jsx)(A,{size:14,className:`animate-spin`}):(0,R.jsx)(nn,{size:14}),` `,n(`Draw`)]}),(0,R.jsxs)(`button`,{type:`button`,disabled:a!==null,onClick:()=>f(`cancel`,()=>N.avatarCancel(e.session)),className:i(`flex items-center justify-center gap-1.5 rounded-2xl border border-border px-4 py-2.5 text-[14px] font-medium text-muted disabled:opacity-40`,`inline-flex items-center gap-1.5`),children:[(0,R.jsx)(Fe,{size:14}),` `,n(`Not now`)]})]})]}),(e.stage===`drawing`||e.stage===`choose`)&&(0,R.jsxs)(`div`,{className:`px-4 pb-3.5 space-y-2.5`,children:[(0,R.jsx)(`div`,{className:`grid grid-cols-2 gap-2`,children:l.map((t,r)=>(0,R.jsxs)(`button`,{type:`button`,disabled:!t||e.stage!==`choose`||a!==null,onClick:()=>f(`pick${r}`,()=>N.avatarChoose(e.session,r)),"aria-label":n(`Candidate {n}`,{n:r+1}),className:i(`relative aspect-square overflow-hidden rounded-2xl bg-[#f1efeb] transition`,t&&e.stage===`choose`?`hover:ring-2 hover:ring-accent`:``),children:[t?(0,R.jsx)(`img`,{src:h(t),alt:``,draggable:!1,className:`h-full w-full object-cover`}):(0,R.jsx)(`span`,{className:`absolute inset-0 flex items-center justify-center text-muted`,children:e.stage===`drawing`?(0,R.jsx)(A,{size:20,className:`animate-spin`}):(0,R.jsx)(Fe,{size:18,className:`opacity-50`})}),a===`pick${r}`&&(0,R.jsx)(`span`,{className:`absolute inset-0 flex items-center justify-center bg-bg/60`,children:(0,R.jsx)(A,{size:20,className:`animate-spin`})}),(0,R.jsx)(`span`,{className:`absolute left-1.5 top-1.5 rounded-full bg-bg/80 px-1.5 text-[10.5px] font-semibold text-fg/80`,children:r+1})]},r))}),e.errors&&e.errors.length>0&&(0,R.jsx)(`p`,{className:`text-[12px] text-rose-600 dark:text-rose-300`,children:n(e.errors[0])}),e.stage===`choose`&&(0,R.jsxs)(`div`,{className:`flex gap-2`,children:[(0,R.jsxs)(`button`,{type:`button`,disabled:a!==null,onClick:()=>f(`redraw`,()=>N.avatarStart(e.session)),className:i(`flex items-center justify-center gap-1.5 rounded-2xl border border-border px-4 py-2.5 text-[14px] font-medium text-muted disabled:opacity-40`,`inline-flex items-center gap-1.5`),children:[a===`redraw`?(0,R.jsx)(A,{size:14,className:`animate-spin`}):(0,R.jsx)(Re,{size:14}),` `,n(`Redraw`)]}),(0,R.jsxs)(`button`,{type:`button`,disabled:a!==null,onClick:()=>f(`cancel`,()=>N.avatarCancel(e.session)),className:i(`flex items-center justify-center gap-1.5 rounded-2xl border border-border px-4 py-2.5 text-[14px] font-medium text-muted disabled:opacity-40`,`inline-flex items-center gap-1.5`),children:[(0,R.jsx)(Fe,{size:14}),` `,n(`Not now`)]})]})]}),(e.stage===`posing`||e.stage===`animating`||e.stage===`done`)&&(0,R.jsxs)(`div`,{className:`px-4 pb-3.5 space-y-2`,children:[(0,R.jsx)(`div`,{className:`flex gap-1.5`,children:tp.map(t=>(0,R.jsxs)(`div`,{className:`relative aspect-square flex-1 overflow-hidden rounded-xl bg-[#f1efeb]`,children:[d[t]?(0,R.jsx)(`video`,{src:h(d[t]),poster:u[t]?h(u[t]):void 0,autoPlay:!0,loop:!0,muted:!0,playsInline:!0,disablePictureInPicture:!0,className:`h-full w-full object-cover`},d[t]):u[t]?(0,R.jsx)(`img`,{src:h(u[t]),alt:``,draggable:!1,className:`h-full w-full object-cover`}):(0,R.jsx)(`span`,{className:`absolute inset-0 flex items-center justify-center text-muted`,children:(0,R.jsx)(A,{size:14,className:`animate-spin`})}),e.stage===`animating`&&u[t]&&!d[t]&&t!==`error`&&(0,R.jsx)(`span`,{className:`absolute bottom-1 right-1 rounded-full bg-white/80 p-0.5 text-muted`,children:(0,R.jsx)(A,{size:10,className:`animate-spin`})})]},t))}),e.stage===`done`?(0,R.jsxs)(`p`,{className:`flex items-center gap-1.5 text-[12.5px] text-muted`,children:[(0,R.jsx)(ke,{size:14,className:`text-emerald-600`}),` `,n(`Idle, working, waiting, happy, sorry: the face follows what {name} is doing.`,{name:t})]}):e.stage===`animating`?(0,R.jsx)(`p`,{className:`text-[12.5px] text-muted`,children:n(`The face is already on; four short clips are being made from the poses, a few minutes.`)}):(0,R.jsx)(`p`,{className:`text-[12.5px] text-muted`,children:n(`Four more pictures from the one you picked; this takes a minute or two.`)}),e.errors&&e.errors.length>0&&e.stage===`done`&&(0,R.jsxs)(`p`,{className:`text-[12px] text-muted`,children:[e.errors.some(e=>!e.includes(` clip:`))&&n(`Some poses could not be drawn and show the idle picture instead.`),` `,e.errors.some(e=>e.includes(` clip:`))&&n(`Some clips could not be made; those moods stay still.`)]})]}),(e.stage===`failed`||e.stage===`cancelled`)&&e.message&&(0,R.jsx)(`p`,{className:`px-4 pb-3.5 text-[12.5px] text-muted`,children:n(e.message)})]})})}function rp(){let e=ip();if(!e||typeof e.keepRunning!=`function`)return null;try{return JSON.parse(e.keepRunning())}catch{return null}}function ip(){return window.NanoMuseAndroid??null}function ap(){let e=ip();return!!e&&typeof e.takeOverBrowser==`function`&&(typeof e.hasBrowser!=`function`||e.hasBrowser())}function op(){let e=ip();if(!e||typeof e.accessibilityState!=`function`)return null;let t=e.accessibilityState();return t===`on`||t===`off`||t===`unsupported`?t:null}function sp(e,t=15){switch(e){case`web_search`:return(0,R.jsx)(qt,{size:t});case`web_fetch`:case`browser`:return(0,R.jsx)(gt,{size:t});case`files`:return(0,R.jsx)(mt,{size:t});case`shell`:return(0,R.jsx)(dn,{size:t});case`python_execute`:return(0,R.jsx)(ct,{size:t});case`read_emails`:case`send_email`:return(0,R.jsx)(Et,{size:t});case`goals`:return(0,R.jsx)(un,{size:t});case`remember`:case`recall`:case`forget`:return(0,R.jsx)(Qe,{size:t});case`ask_user`:return(0,R.jsx)(kt,{size:t});case`devices`:return(0,R.jsx)(It,{size:t});case`device_shell`:return(0,R.jsx)(dn,{size:t});case`device_files`:case`device_get`:case`device_put`:return(0,R.jsx)(mt,{size:t});case`device_open`:return(0,R.jsx)(Ae,{size:t});case`device_screen`:return(0,R.jsx)(Lt,{size:t});case`device_notify`:return(0,R.jsx)(Xe,{size:t});case`delegate`:return(0,R.jsx)(Jt,{size:t});case`computer_screen`:return(0,R.jsx)(Lt,{size:t});case`computer_act`:return(0,R.jsx)(zt,{size:t});case`computer_task`:case`computer_app`:return(0,R.jsx)(vt,{size:t});case`phone_screen`:case`phone_act`:case`phone_task`:return(0,R.jsx)(tn,{size:t});default:return(0,R.jsx)(Ze,{size:t})}}function cp({device:e,className:t}){let n=s();return(0,R.jsxs)(`span`,{className:i(`inline-flex max-w-full items-center gap-1 rounded-full bg-accent/12 px-2 py-0.5 text-[11px] font-medium text-accent`,t),children:[(0,R.jsx)(It,{size:11,className:`shrink-0`}),` `,(0,R.jsx)(`span`,{className:`truncate`,children:n(`on {device}`,{device:e})})]})}var lp={safe:`bg-emerald-500/15 text-emerald-700 dark:text-emerald-300`,moderate:`bg-amber-500/15 text-amber-700 dark:text-amber-300`,sensitive:`bg-rose-500/15 text-rose-700 dark:text-rose-300`};function up({risk:e}){return(0,R.jsx)(`span`,{className:i(`px-2 py-0.5 rounded-full text-[11px] font-semibold uppercase tracking-wide`,lp[e]),children:_(e)})}function dp({args:e}){let t=Object.entries(e??{}).filter(([,e])=>e!=null&&e!==``);return t.length?(0,R.jsx)(`dl`,{className:`mt-2 grid grid-cols-[auto_1fr] gap-x-3 gap-y-1 text-[13px]`,children:t.map(([e,t])=>(0,R.jsxs)(`div`,{className:`contents`,children:[(0,R.jsx)(`dt`,{className:`text-muted`,children:e}),(0,R.jsx)(`dd`,{className:`break-words whitespace-pre-wrap font-mono text-[12.5px] leading-snug`,children:String(t)})]},e))}):null}function fp({event:e}){let[t,n]=(0,L.useState)(!1),r=e.status===`running`?(0,R.jsx)(A,{size:14,className:`animate-spin text-accent`}):e.status===`ok`?(0,R.jsx)(ke,{size:14,className:`text-emerald-500`}):e.status===`blocked`?(0,R.jsx)(Ye,{size:14,className:`text-rose-500`}):(0,R.jsx)(Fe,{size:14,className:`text-rose-500`});return(0,R.jsx)(`div`,{className:`rise flex justify-start pr-8`,children:(0,R.jsxs)(`button`,{type:`button`,onClick:()=>n(e=>!e),className:`max-w-full text-left rounded-2xl bg-surface-2/80 border border-border/60 px-3 py-1.5 text-[13px] text-muted hover:text-fg transition`,children:[(0,R.jsxs)(`span`,{className:`flex items-center gap-2`,children:[(0,R.jsx)(`span`,{className:`text-muted`,children:sp(e.tool)}),(0,R.jsx)(`span`,{className:`truncate flex-1`,children:e.title||e.summary||e.tool}),e.device&&(0,R.jsx)(cp,{device:e.device}),r,e.output?t?(0,R.jsx)(Me,{size:13}):(0,R.jsx)(rt,{size:13}):null]}),t&&(0,R.jsxs)(`div`,{className:`mt-2 text-fg`,children:[(0,R.jsx)(dp,{args:e.args}),e.output&&(0,R.jsx)(`pre`,{className:`mt-2 max-h-52 overflow-auto whitespace-pre-wrap break-words rounded-xl bg-bg p-2 text-[12px] leading-snug`,children:e.output})]})]})})}function pp(e,t,n){if(!t)return e.replace(/_/g,` `);switch(e){case`shell`:return _(`{what} commands`,{what:t.split(`,`).join(`, `)});case`send_email`:return _(`email to {who}`,{who:t.split(`,`).join(`, `)});case`remote_control`:return _(`the device {name}`,{name:typeof n?.device==`string`&&n.device?n.device:t});case`computer_app`:return _(`the hands in {app}`,{app:typeof n?.name==`string`&&n.name?n.name:t});default:return t}}function mp(e,t,n,r){switch(e){case`once`:return _(`Once`);case`conversation`:return _(`For this conversation`);case`session`:return _(`Until restart`);case`24h`:return _(`For 24 hours`);case`always`:return _(`Always for {subject}`,{subject:pp(t,n,r)});default:return e}}function hp({event:e,name:t=`nanoMuse`,onDecide:n}){let[r,a]=(0,L.useState)(!1),[o,c]=(0,L.useState)(!1),[l,d]=(0,L.useState)(!1),[f,p]=(0,L.useState)(!1),m=(e,t)=>{f||(p(!0),Promise.resolve(n(e,t)).finally(()=>p(!1)))},h=(0,L.useRef)(null),g=(0,L.useRef)(null),_=s(),y=e.status===`pending`,b=e.risk===`sensitive`,x=(e.grant_options??[`once`]).filter(e=>e!==`once`),S=e.egress_target||([`web_fetch`,`browser`,`web_search`].includes(e.tool)?e.target:null),C=e.tool===`send_email`?e.target:null,w=Object.values(e.args??{}).some(e=>e!=null&&e!==``);return(0,L.useEffect)(()=>{let e=g.current;e&&!r&&d(e.scrollHeight>e.clientHeight+2)},[e.args,r]),(0,L.useEffect)(()=>{(r||o)&&h.current?.scrollIntoView({block:`end`,behavior:`smooth`})},[r,o]),(0,R.jsx)(`div`,{className:`rise flex justify-start`,ref:h,children:(0,R.jsxs)(`div`,{className:i(`w-full max-w-[600px] overflow-hidden rounded-[22px] bg-surface shadow-[0_2px_12px_rgba(0,0,0,0.12)] dark:border dark:border-border dark:shadow-none`,y&&b&&`border border-rose-400/60 dark:border-rose-400/60`),children:[(0,R.jsxs)(`div`,{className:`flex items-start gap-3 px-4 pt-4 pb-2`,children:[(0,R.jsx)(`div`,{className:i(`flex h-10 w-10 shrink-0 items-center justify-center rounded-full`,b?`bg-rose-500/12 text-rose-500`:`bg-surface-2 text-fg`),children:b?(0,R.jsx)(Zt,{size:22}):sp(e.tool,22)}),(0,R.jsxs)(`div`,{className:`min-w-0 flex-1`,children:[(0,R.jsxs)(`div`,{className:`flex flex-wrap items-center gap-1.5 text-[12.5px] font-medium text-muted`,children:[(0,R.jsx)(`span`,{children:e.remote?_(`{name} on {device} wants to`,{name:t,device:e.remote.name}):_(`{name} wants to`,{name:t})}),e.remote&&(0,R.jsx)(cp,{device:e.remote.name})]}),(0,R.jsx)(`div`,{className:`mt-0.5 break-words text-[17px] font-semibold leading-[22px]`,children:e.summary}),S?(0,R.jsxs)(`div`,{className:`mt-1 flex items-center gap-1 text-[13px] text-muted`,children:[(0,R.jsx)(gt,{size:12}),` `,(0,R.jsx)(`span`,{className:`truncate`,children:_(`at {host}`,{host:S})})]}):C?(0,R.jsxs)(`div`,{className:`mt-1 flex items-center gap-1 text-[13px] text-muted`,children:[(0,R.jsx)(Et,{size:12}),` `,(0,R.jsx)(`span`,{className:`truncate`,children:_(`to {recipient}`,{recipient:C})})]}):null,e.purpose&&(0,R.jsx)(`div`,{className:`mt-1.5 break-words text-[13px] leading-snug text-muted line-clamp-2`,children:e.purpose}),b&&(0,R.jsx)(`div`,{className:`mt-1.5`,children:(0,R.jsx)(up,{risk:e.risk})})]})]}),e.warnings?.length>0&&(0,R.jsx)(`div`,{className:`space-y-1 px-4 pb-2`,children:e.warnings.map(e=>(0,R.jsxs)(`div`,{className:`flex items-start gap-1.5 text-[12.5px] text-rose-600 dark:text-rose-300`,children:[(0,R.jsx)(pn,{size:13,className:`mt-0.5 shrink-0`}),` `,(0,R.jsx)(`span`,{children:_(e)})]},e))}),(w||e.reasons?.length>0)&&(0,R.jsx)(`div`,{className:`px-4 pb-2`,children:(0,R.jsxs)(`div`,{className:`rounded-xl bg-surface-2 px-3 py-2.5`,children:[(0,R.jsx)(`div`,{className:`text-[11px] font-medium text-muted`,children:_(`Exactly what will run`)}),(0,R.jsxs)(`div`,{ref:g,className:i(`-mt-1`,!r&&`max-h-40 overflow-hidden`),children:[(0,R.jsx)(dp,{args:e.args}),e.reasons?.length>0&&(0,R.jsx)(`div`,{className:`mt-1.5 text-[12px] text-muted`,children:_(`Why it asks: {reasons}`,{reasons:e.reasons.map(v).join(` · `)})})]}),(l||r)&&(0,R.jsxs)(`button`,{type:`button`,className:`mt-1 flex items-center gap-1 text-[12.5px] text-accent`,onClick:()=>a(e=>!e),children:[r?(0,R.jsx)(Me,{size:13}):(0,R.jsx)(rt,{size:13}),` `,_(r?`Fewer options`:`Show all`)]})]})}),y?(0,R.jsxs)(`div`,{className:`flex flex-col gap-2 px-4 pb-4 pt-2`,children:[(0,R.jsx)(`button`,{type:`button`,onClick:()=>m(!0,`once`),disabled:f,className:`h-[46px] w-full rounded-full bg-accent text-[15px] font-semibold text-accent-fg transition active:scale-[0.98] disabled:opacity-60`,children:_(`Allow once`)}),x.filter(e=>o||e===`conversation`||e===`always`).map(t=>(0,R.jsx)(`button`,{type:`button`,onClick:()=>m(!0,t),disabled:f,className:`h-11 w-full truncate rounded-full bg-surface-2 px-4 text-[15px] font-medium transition active:scale-[0.98] disabled:opacity-60`,children:mp(t,e.tool,e.target,e.args)},t)),(0,R.jsx)(`button`,{type:`button`,onClick:()=>m(!1,`once`),disabled:f,className:`h-11 w-full rounded-full bg-surface-2 text-[15px] font-medium transition active:scale-[0.98] disabled:opacity-60`,children:_(`Deny`)}),x.length===0?(0,R.jsx)(`div`,{className:`text-center text-[12px] text-muted`,children:_(`This kind of action is approved one at a time.`)}):!o&&x.some(e=>e!==`conversation`&&e!==`always`)&&(0,R.jsx)(`button`,{type:`button`,className:`self-center text-[12.5px] text-muted`,onClick:()=>c(!0),children:_(`Allow {subject} for longer…`,{subject:pp(e.tool,e.target,e.args)})})]}):(0,R.jsxs)(`div`,{className:i(`flex items-center gap-1.5 border-t border-border px-4 py-2.5 text-[13px] font-medium`,e.status===`approved`?`text-emerald-600 dark:text-emerald-300`:`text-muted`),children:[e.status===`approved`?(0,R.jsx)(ke,{size:15}):(0,R.jsx)(Fe,{size:15}),e.status===`approved`?`${_(`Approved`)}${e.scope&&e.scope!==`once`?` · ${mp(e.scope,e.tool,e.target).toLowerCase()}`:``}`:e.status===`denied`?_(`Denied`):_(`Expired without an answer`),(0,R.jsx)(`span`,{className:`ml-auto font-normal`,children:u(e.updated_ts??e.ts)})]})]})})}function gp({event:e,name:t}){let n=s();return(0,R.jsx)(`div`,{className:`rise flex justify-start pr-8`,children:(0,R.jsxs)(`div`,{className:`max-w-full rounded-[20px] rounded-bl-md border border-accent/30 bg-surface px-4 py-3`,children:[(0,R.jsxs)(`div`,{className:`flex items-center gap-1.5 text-[12.5px] font-medium text-accent`,children:[(0,R.jsx)(kt,{size:14}),` `,n(`{name} asks`,{name:t})]}),(0,R.jsx)(`div`,{className:`mt-1 text-[15px] leading-snug whitespace-pre-wrap break-words`,children:e.text}),e.status===`pending`&&(0,R.jsx)(`div`,{className:`mt-1.5 text-[12.5px] text-muted`,children:n(`Reply below to continue.`)}),e.status===`answered`&&e.answer&&(0,R.jsxs)(`div`,{className:`mt-2 text-[13px] text-muted border-t border-border pt-2`,children:[n(`You:`),` `,(0,R.jsx)(`span`,{className:`text-fg`,children:e.answer})]})]})})}function _p(e){return e.source===`reminder`||e.source===`memory`?t(e.text):_(e.text,e.vars)}function vp({event:e,onCloudRetry:t}){let n=s(),[r,a]=(0,L.useState)(!1),[o,c]=(0,L.useState)(!1),[l,u]=(0,L.useState)(null),d=e.detail&&e.detail!==e.text?e.detail:null;return e.code===`allowance`&&e.allowance?(0,R.jsxs)(`div`,{className:`rise flex flex-col items-center gap-2 px-6`,children:[(0,R.jsx)(`div`,{className:`max-w-full rounded-2xl bg-amber-500/12 px-3 py-1.5 text-center text-[12.5px] leading-snug text-amber-700 dark:text-amber-300`,children:n(e.text)}),(0,R.jsx)(`div`,{className:`w-full max-w-[520px]`,children:(0,R.jsx)(Ff,{info:e.allowance,exhausted:!0,compact:!0})})]}):(0,R.jsx)(`div`,{className:`rise flex justify-center px-6`,children:(0,R.jsxs)(`div`,{className:i(`max-w-full rounded-2xl px-3 py-1.5 text-center text-[12.5px] leading-snug`,e.level===`info`&&`bg-surface-2/70 text-muted`,e.level===`warn`&&`bg-amber-500/12 text-amber-700 dark:text-amber-300`,e.level===`error`&&`bg-rose-500/12 text-rose-700 dark:text-rose-300`),children:[_p(e),d&&(0,R.jsxs)(R.Fragment,{children:[` `,(0,R.jsx)(`button`,{type:`button`,onClick:()=>a(e=>!e),className:`underline decoration-dotted underline-offset-2 opacity-70 hover:opacity-100`,children:n(r?`Hide details`:`Details`)}),r&&(0,R.jsx)(`div`,{className:`mt-1.5 break-all text-left font-mono text-[11px] opacity-80`,children:d})]}),t&&(0,R.jsxs)(`div`,{className:`mt-1.5 flex flex-col items-center gap-1`,children:[(0,R.jsx)(`button`,{type:`button`,disabled:o,onClick:()=>{t&&(c(!0),u(null),t().catch(e=>u(n(e.message||`Could not send`))).finally(()=>c(!1)))},className:`rounded-full bg-accent/12 px-3 py-1 text-[12px] font-medium text-accent disabled:opacity-50`,children:n(`Use nanoMuse Cloud this time`)}),l&&(0,R.jsx)(`div`,{className:`text-[12px] text-rose-700 dark:text-rose-300`,children:l})]})]})})}function yp({event:e,onOpen:t}){let[r,i]=(0,L.useState)(!1),a=s(),o=e.status===`live`,c=e.url;try{c=new URL(e.url).host}catch{}return(0,R.jsx)(`div`,{className:`rise flex justify-start pr-8`,children:(0,R.jsxs)(`button`,{type:`button`,onClick:()=>t(e.id),"aria-label":a(`Browser: {title}`,{title:e.title||c}),className:`w-full max-w-[340px] overflow-hidden rounded-3xl rounded-tl-lg border border-border bg-surface shadow-sm hover:bg-surface-2 transition text-left`,children:[(0,R.jsxs)(`div`,{className:`relative aspect-[16/10] bg-surface-2`,children:[r?(0,R.jsxs)(`div`,{className:`absolute inset-0 flex flex-col items-center justify-center gap-1 text-muted`,children:[(0,R.jsx)(gt,{size:22}),(0,R.jsx)(`span`,{className:`text-[12px]`,children:a(`Frame no longer available`)})]}):(0,R.jsx)(`img`,{src:n(e.thread,e.frame),alt:e.title||c,onError:()=>i(!0),className:`absolute inset-0 h-full w-full object-cover object-top`},e.frame),(0,R.jsx)(`div`,{className:`absolute left-2.5 top-2.5 flex items-center gap-1.5 rounded-full bg-black/60 px-2 py-0.5 text-[10.5px] font-semibold text-white`,children:o?(0,R.jsxs)(R.Fragment,{children:[(0,R.jsx)(`span`,{className:`h-1.5 w-1.5 rounded-full bg-rose-400 animate-pulse`}),` `,a(`LIVE`)]}):(0,R.jsxs)(R.Fragment,{children:[(0,R.jsx)(gt,{size:11}),` `,a(`BROWSER`)]})})]}),(0,R.jsxs)(`div`,{className:`flex items-center gap-2 px-3.5 py-2.5`,children:[(0,R.jsxs)(`div`,{className:`min-w-0 flex-1`,children:[(0,R.jsx)(`div`,{className:`text-[13.5px] font-medium truncate`,children:e.title||c}),(0,R.jsxs)(`div`,{className:`text-[12px] text-muted truncate`,children:[e.by_user&&e.action.startsWith(`You`)?a(`You`)+e.action.slice(3):e.action,` · `,c]})]}),(0,R.jsx)(rt,{size:16,className:`text-muted shrink-0`})]})]})})}function bp({event:e,name:t=`nanoMuse`}){let n=s(),{state:r,toast:a}=E(),[o,c]=(0,L.useState)(!1),[l,d]=(0,L.useState)(!1),f=e.status===`live`,p=e.last,m=[e.app,e.title].filter(Boolean).join(` · `),h=r.holds.find(t=>t.thread===e.thread&&t.tool===`computer`),g=async()=>{c(!0);try{await N.stopHands()}catch{}finally{c(!1)}},_=async()=>{d(!0);try{await N.openHold(e.thread,`computer`)}catch(e){a(e.message)}finally{d(!1)}};return(0,R.jsx)(`div`,{className:`rise flex justify-start pr-8`,children:(0,R.jsxs)(`div`,{className:i(`w-full max-w-[360px] overflow-hidden rounded-3xl rounded-tl-lg border bg-surface shadow-sm`,f?`border-accent/50`:`border-border/70`),children:[(0,R.jsxs)(`div`,{className:`flex items-start gap-3 px-4 pt-3.5 pb-2`,children:[(0,R.jsx)(`div`,{className:i(`mt-0.5 rounded-full p-2`,f?`bg-accent/12 text-accent`:`bg-surface-2 text-fg/80`),children:(0,R.jsx)(vt,{size:18})}),(0,R.jsxs)(`div`,{className:`min-w-0 flex-1`,children:[(0,R.jsxs)(`div`,{className:`flex items-center gap-2 text-[12.5px] font-medium text-muted`,children:[(0,R.jsx)(`span`,{children:f?n(`{name} is using this computer`,{name:t}):e.status===`stopped`?n(`Hands stopped`):n(`Hands done`)}),f&&(0,R.jsxs)(`span`,{className:`flex items-center gap-1 rounded-full bg-accent/12 px-2 py-0.5 text-[10.5px] font-semibold text-accent`,children:[(0,R.jsx)(`span`,{className:`h-1.5 w-1.5 animate-pulse rounded-full bg-accent`}),` `,n(`LIVE`)]})]}),e.text&&(0,R.jsx)(`div`,{className:`mt-0.5 break-words text-[15px] font-semibold leading-snug`,children:e.text}),p?.action&&(0,R.jsxs)(`div`,{className:`mt-1.5 flex items-center gap-1.5 text-[13px] text-fg/90`,children:[(0,R.jsx)(zt,{size:13,className:`shrink-0 text-muted`}),(0,R.jsx)(`span`,{className:`truncate`,children:Tp(p,n)})]}),m&&(0,R.jsx)(`div`,{className:`mt-1 truncate text-[12px] text-muted`,children:m}),e.notice&&(0,R.jsx)(`div`,{className:`mt-1.5 rounded-2xl bg-amber-500/12 px-3 py-1.5 text-[12.5px] text-amber-700 dark:text-amber-300`,children:e.notice}),f&&h&&(0,R.jsx)(xp,{hold:h})]})]}),(0,R.jsxs)(`div`,{className:`flex items-center gap-2 border-t border-border/70 px-4 py-2 text-[12px] text-muted`,children:[(0,R.jsx)(`span`,{children:n(`{n} steps`,{n:e.steps})}),(0,R.jsx)(`span`,{className:`ml-auto`,children:u(e.updated_ts??e.ts)}),f&&!h&&(0,R.jsxs)(`button`,{type:`button`,onClick:()=>void _(),disabled:l,className:`ml-1 inline-flex items-center gap-1.5 rounded-full bg-accent/12 px-3 py-1 text-[12.5px] font-semibold text-accent transition active:scale-95 disabled:opacity-60`,children:[(0,R.jsx)(vt,{size:11}),` `,n(`Take over`)]}),f&&(0,R.jsxs)(`button`,{type:`button`,onClick:()=>void g(),disabled:o,className:`ml-1 inline-flex items-center gap-1.5 rounded-full bg-fg px-3 py-1 text-[12.5px] font-semibold text-bg transition active:scale-95 disabled:opacity-60`,children:[(0,R.jsx)(sn,{size:10,fill:`currentColor`}),` `,n(`Stop`)]})]})]})})}function xp({hold:e,compact:t}){let n=s(),[r,a]=(0,L.useState)(!1),o=async()=>{a(!0);try{await N.doneHold(e.id)}catch{}finally{a(!1)}};return(0,R.jsxs)(`div`,{className:i(`flex items-center gap-2 rounded-2xl bg-amber-500/12 px-3 text-amber-800 dark:text-amber-200`,t?`py-1.5 text-[12.5px]`:`mt-1.5 py-2 text-[13px]`),children:[(0,R.jsx)(vt,{size:14,className:`shrink-0`}),(0,R.jsx)(`span`,{className:`min-w-0 flex-1 leading-snug`,children:Cp(e,n)}),(0,R.jsx)(`button`,{type:`button`,onClick:()=>void o(),disabled:r,className:`shrink-0 rounded-full bg-fg px-3 py-1 text-[12.5px] font-semibold text-bg transition active:scale-95 disabled:opacity-60`,children:r?(0,R.jsx)(A,{size:13,className:`animate-spin`}):n(`Done`)})]})}function Sp(e,t){return t(e===`browser`?`the browser`:e===`phone`?`the phone`:`this computer`)}function Cp(e,t){return e.by===`agent`?e.reason?t(`Your turn: {reason}`,{reason:e.reason}):t(`Your turn`):t(`You took over {thing}`,{thing:Sp(e.tool,t)})}function wp({event:e,name:t=`nanoMuse`}){let n=s(),[r,a]=(0,L.useState)(!1),o=e.status===`on`,c=Sp(e.tool,n),l=async()=>{a(!0);try{await N.doneHold(e.id)}catch{}finally{a(!1)}},d=e.timed_out?n(`{name} waited ten minutes and went on without you.`,{name:t}):e.stale?n(`Ended when the runtime restarted.`):e.by===`agent`?n(`You did it; {name} carried on.`,{name:t}):n(`Handed back; {name} carried on.`,{name:t});return(0,R.jsx)(`div`,{className:`rise flex justify-start pr-8`,children:(0,R.jsxs)(`div`,{className:i(`w-full max-w-[360px] overflow-hidden rounded-3xl rounded-tl-lg border bg-surface shadow-sm`,o?`border-amber-500/50`:`border-border/70 opacity-70`),children:[(0,R.jsxs)(`div`,{className:`flex items-start gap-3 px-4 pt-3.5 pb-3`,children:[(0,R.jsx)(`div`,{className:i(`mt-0.5 rounded-full p-2`,o?`bg-amber-500/15 text-amber-700 dark:text-amber-300`:`bg-surface-2 text-fg/70`),children:(0,R.jsx)(vt,{size:18})}),(0,R.jsxs)(`div`,{className:`min-w-0 flex-1`,children:[(0,R.jsx)(`div`,{className:`text-[12.5px] font-medium text-muted`,children:e.tool===`browser`?n(`The browser`):e.tool===`phone`?n(`The phone`):n(`This computer`)}),(0,R.jsx)(`div`,{className:`mt-0.5 break-words text-[15px] font-semibold leading-snug`,children:e.by===`agent`?n(`Your turn`):n(`You took over {thing}`,{thing:c})}),e.by===`agent`&&e.reason&&(0,R.jsx)(`div`,{className:`mt-1 break-words text-[13.5px] leading-snug text-fg/90`,children:e.reason}),(0,R.jsx)(`div`,{className:`mt-1.5 text-[12.5px] leading-snug text-muted`,children:o?e.by===`agent`?n(`Do this part yourself, then press Done. {name} looks again and carries on from there.`,{name:t}):n(`{name} waits. Press Done when you are finished and it looks again.`,{name:t}):d})]})]}),(0,R.jsxs)(`div`,{className:`flex items-center gap-2 border-t border-border/70 px-4 py-2 text-[12px] text-muted`,children:[(0,R.jsx)(`span`,{children:u(e.ts)}),o&&(0,R.jsxs)(`button`,{type:`button`,onClick:()=>void l(),disabled:r,className:`ml-auto inline-flex items-center gap-1.5 rounded-full bg-fg px-3.5 py-1 text-[12.5px] font-semibold text-bg transition active:scale-95 disabled:opacity-60`,children:[r?(0,R.jsx)(A,{size:13,className:`animate-spin`}):(0,R.jsx)(ke,{size:12}),` `,n(`Done`)]})]})]})})}function Tp(e,t){let n=e.label?`“${e.label}”`:``;switch(e.action){case`click`:return n?t(`Clicked {label}`,{label:n}):t(`Clicked`);case`double_click`:return n?t(`Double-clicked {label}`,{label:n}):t(`Double-clicked`);case`right_click`:case`middle_click`:return n?t(`Right-clicked {label}`,{label:n}):t(`Right-clicked`);case`move`:return n?t(`Pointed at {label}`,{label:n}):t(`Moved the mouse`);case`type`:return t(`Typed {n} characters`,{n:(e.text??``).length});case`key`:return t(`Pressed {keys}`,{keys:(e.keys??[]).join(`+`)});case`scroll`:return t(`Scrolled`);case`drag`:return t(`Dragged`);case`open_app`:return n?t(`Opened {label}`,{label:n}):t(`Opened an application`);case`wait`:return t(`Waited`);default:return e.action??``}}function Ep({event:e,onOpen:t}){let n=s(),a=r(e.name),o=n(a===`html`?`Page`:a===`image`?`Image`:a===`data`?`Data`:a===`code`?`Code`:a===`event`?`Event`:`Document`),c=e.action===`update`?`${o} · ${n(`updated`)}`:o,l=a===`html`||a===`image`;return(0,R.jsx)(`div`,{className:`rise flex justify-start pr-8`,children:(0,R.jsxs)(`button`,{type:`button`,onClick:()=>t(e.path),className:i(`max-w-full overflow-hidden rounded-[20px] border border-border bg-surface text-left shadow-[0_4px_20px_-12px_rgba(0,0,0,0.2)] transition hover:bg-surface-2`,l?`w-[300px]`:``),children:[l&&(0,R.jsx)(Dp,{path:e.path,kind:a}),(0,R.jsxs)(`div`,{className:`flex items-center gap-3 px-4 py-3`,children:[!l&&(0,R.jsx)(`div`,{className:`rounded-2xl bg-accent/12 p-2.5 text-accent`,children:a===`code`?(0,R.jsx)(ct,{size:20}):a===`event`?(0,R.jsx)(tt,{size:20}):(0,R.jsx)(mt,{size:20})}),(0,R.jsxs)(`div`,{className:`min-w-0 flex-1`,children:[(0,R.jsx)(`div`,{className:`text-[11px] font-semibold uppercase tracking-wide text-muted`,children:c}),(0,R.jsx)(`div`,{className:`truncate text-[14.5px] font-medium`,children:e.name}),(0,R.jsx)(`div`,{className:`truncate text-[12px] text-muted`,children:e.path})]}),(0,R.jsx)(rt,{size:16,className:`ml-1 shrink-0 text-muted`})]})]})})}function Dp({path:e,kind:t}){return t===`image`?(0,R.jsx)(`img`,{src:h(e),alt:``,loading:`lazy`,className:`h-40 w-full object-cover`}):(0,R.jsx)(`div`,{className:`pointer-events-none relative h-40 w-full overflow-hidden bg-white`,children:(0,R.jsx)(`iframe`,{title:e,src:h(e),sandbox:``,tabIndex:-1,loading:`lazy`,scrolling:`no`,className:`absolute left-0 top-0 h-[480px] w-[900px] origin-top-left scale-[0.3333] border-0`})})}function Op({open:e,onClose:t,title:n,children:r,footer:i}){let a=s(),o=(0,L.useRef)(null),c=(0,L.useId)();return On(o,e),(0,L.useEffect)(()=>{if(!e)return;let n=e=>e.key===`Escape`&&t();return window.addEventListener(`keydown`,n),()=>window.removeEventListener(`keydown`,n)},[e,t]),e?(0,R.jsxs)(`div`,{className:`fixed inset-0 z-50 flex items-end sm:items-center sm:justify-center`,children:[(0,R.jsx)(`div`,{className:`absolute inset-0 bg-black/45 backdrop-blur-[2px]`,onClick:t}),(0,R.jsxs)(`div`,{ref:o,role:`dialog`,"aria-modal":`true`,"aria-labelledby":n?c:void 0,className:`sheet-in relative w-full sm:max-w-lg max-h-[92dvh] flex flex-col bg-surface rounded-t-3xl sm:rounded-3xl shadow-2xl border border-border`,children:[(0,R.jsxs)(`div`,{className:`flex items-center gap-3 px-5 pt-4 pb-2`,children:[(0,R.jsx)(`div`,{className:`sm:hidden absolute left-1/2 -translate-x-1/2 top-2 h-1 w-10 rounded-full bg-border`}),(0,R.jsx)(`div`,{id:c,className:`flex-1 font-semibold text-[17px] mt-1`,children:n}),(0,R.jsx)(`button`,{type:`button`,onClick:t,"aria-label":a(`Close`),className:`p-2 -mr-2 rounded-full text-muted hover:bg-surface-2`,children:(0,R.jsx)(Fe,{size:20})})]}),(0,R.jsx)(`div`,{className:`flex-1 overflow-y-auto px-5 pb-4`,children:r}),i&&(0,R.jsx)(`div`,{className:`px-5 pt-2 pb-4 safe-bottom border-t border-border`,children:i})]})]}):null}var kp=1e3;function Ap({thread:e,eventId:t,onClose:r}){let{state:a,toast:o}=E(),c=s(),l=(a.events[e]??[]).find(e=>e.id===t),u=a.holds.find(t=>t.thread===e&&t.tool===`browser`),[d,f]=(0,L.useState)(null),[p,m]=(0,L.useState)(null),[h,g]=(0,L.useState)(``),[_,v]=(0,L.useState)(``),[y,b]=(0,L.useState)(!1),x=(0,L.useRef)(null),S=d?d===`on`:!!u;(0,L.useEffect)(()=>b(!1),[l?.frame]),(0,L.useEffect)(()=>f(null),[u?.id,u?.status]);let C=l?.backend===`device`&&ap();(0,L.useEffect)(()=>{if(!C)return;let t=t=>{let n=t.detail;n?.thread&&n.thread!==e||N.browserControl(e,{action:`handed_back`}).catch(e=>o(e.message))};return window.addEventListener(`nanomuse:browser-handed-back`,t),()=>window.removeEventListener(`nanomuse:browser-handed-back`,t)},[C,e,o]);let w=(0,L.useCallback)(async t=>{m(t.action);try{await N.browserControl(e,t)}catch(e){o(e.message)}finally{m(null)}},[e,o]),T=()=>{if(C){ip()?.takeOverBrowser?.(e),N.browserControl(e,{action:`take_over`}).catch(()=>void 0);return}f(`on`),w({action:`take_over`})},D=()=>{f(`off`),w({action:`handed_back`})};(0,L.useEffect)(()=>{if(!S||C||!l||l.status!==`live`)return;let t=window.setInterval(()=>{document.hidden||N.browserControl(e,{action:`look`}).catch(()=>void 0)},kp);return()=>window.clearInterval(t)},[S,C,e,l]);let O=e=>{if(!S||p)return;let t=e.currentTarget.getBoundingClientRect(),n=(e.clientX-t.left)/t.width,r=(e.clientY-t.top)/t.height;w({action:`click`,x:Math.min(Math.max(n,0),1),y:Math.min(Math.max(r,0),1)})},k=e=>{!S||p||Math.abs(e.deltaY)<8||w({action:`scroll`,dy:Math.max(-2e3,Math.min(2e3,Math.round(e.deltaY*2)))})};if(!l)return null;let ee=l.url;try{ee=new URL(l.url).host}catch{}let j=l.status===`live`,M=a.profile?.name??`nanoMuse`,te=u?c(`{name} is waiting for you`,{name:M}):a.status.state!==`idle`&&a.status.thread===e?c(`{name} is working`,{name:M}):l.action;return(0,R.jsxs)(Op,{open:!0,onClose:r,title:(0,R.jsxs)(`div`,{className:`flex items-center gap-2 min-w-0`,children:[(0,R.jsx)(gt,{size:17,className:`text-accent shrink-0`}),(0,R.jsx)(`span`,{className:`truncate`,children:l.title||ee}),j&&(0,R.jsxs)(`span`,{className:`ml-1 flex items-center gap-1 rounded-full bg-rose-500/12 px-2 py-0.5 text-[10.5px] font-semibold text-rose-500`,children:[(0,R.jsx)(`span`,{className:`h-1.5 w-1.5 rounded-full bg-rose-500 animate-pulse`}),` `,c(`LIVE`)]})]}),footer:S?(0,R.jsxs)(`div`,{className:`space-y-2`,children:[(0,R.jsxs)(`form`,{className:`flex items-center gap-2`,onSubmit:e=>{e.preventDefault(),h&&w({action:`type`,text:h}).then(()=>g(``))},children:[(0,R.jsx)(`input`,{value:h,onChange:e=>g(e.target.value),placeholder:c(`Type into the focused field…`),"aria-label":c(`Type into the focused field…`),className:`flex-1 rounded-2xl bg-surface-2 px-3.5 py-2.5 text-[14px] outline-none`,autoComplete:`off`,autoCapitalize:`off`}),(0,R.jsx)(`button`,{type:`submit`,disabled:!h||!!p,"aria-label":c(`Type`),className:`rounded-full bg-accent p-2.5 text-white disabled:opacity-40`,children:p===`type`?(0,R.jsx)(A,{size:16,className:`animate-spin`}):(0,R.jsx)(qe,{size:16})}),(0,R.jsx)(`button`,{type:`button`,onClick:()=>void w({action:`key`,key:`Enter`}),disabled:!!p,"aria-label":c(`Press Enter`),className:`rounded-full bg-surface-2 p-2.5 text-fg disabled:opacity-40`,children:(0,R.jsx)(dt,{size:16})})]}),(0,R.jsxs)(`form`,{className:`flex items-center gap-2`,onSubmit:e=>{e.preventDefault(),_&&w({action:`navigate`,url:_}).then(()=>v(``))},children:[(0,R.jsx)(`button`,{type:`button`,onClick:()=>void w({action:`back`}),disabled:!!p,"aria-label":c(`Back`),className:`rounded-full bg-surface-2 p-2 text-fg disabled:opacity-40`,children:(0,R.jsx)(Ke,{size:15})}),(0,R.jsx)(`input`,{value:_,onChange:e=>v(e.target.value),placeholder:c(`Open a URL…`),"aria-label":c(`Open a URL…`),inputMode:`url`,autoCapitalize:`off`,className:`flex-1 min-w-0 rounded-2xl bg-surface-2 px-3.5 py-2 text-[13px] outline-none`}),(0,R.jsx)(`button`,{type:`submit`,disabled:!_||!!p,className:`rounded-2xl bg-surface-2 px-3 py-2 text-[13px] font-medium disabled:opacity-40`,children:c(`Go`)}),(0,R.jsx)(`button`,{type:`button`,onClick:()=>void w({action:`scroll`,dy:-600}),disabled:!!p,"aria-label":c(`Scroll up`),className:`rounded-full bg-surface-2 p-2 text-fg disabled:opacity-40`,children:(0,R.jsx)(Je,{size:15})}),(0,R.jsx)(`button`,{type:`button`,onClick:()=>void w({action:`scroll`,dy:600}),disabled:!!p,"aria-label":c(`Scroll down`),className:`rounded-full bg-surface-2 p-2 text-fg disabled:opacity-40`,children:(0,R.jsx)(Ge,{size:15})})]}),(0,R.jsxs)(`div`,{className:`flex items-center justify-between gap-2`,children:[(0,R.jsx)(`span`,{className:`min-w-0 truncate text-[12px] text-muted`,children:c(`Tap the page to click. If the browser was closed, open a URL first.`)}),(0,R.jsxs)(`button`,{type:`button`,onClick:D,disabled:p===`handed_back`,className:`flex shrink-0 items-center gap-1.5 whitespace-nowrap rounded-full bg-fg px-3.5 py-1.5 text-[13px] font-semibold text-bg disabled:opacity-60`,children:[p===`handed_back`?(0,R.jsx)(A,{size:14,className:`animate-spin`}):(0,R.jsx)(ke,{size:14}),` `,c(`Done`)]})]})]}):(0,R.jsxs)(`div`,{className:`flex items-center justify-between gap-2`,children:[(0,R.jsxs)(`div`,{className:`min-w-0 text-[12.5px] text-muted truncate`,children:[te,` · `,ee]}),(0,R.jsxs)(`div`,{className:`flex items-center gap-2 shrink-0`,children:[(0,R.jsx)(`button`,{type:`button`,onClick:()=>void w({action:`look`}),disabled:!!p,"aria-label":c(`Refresh`),className:`rounded-full bg-surface-2 p-2 text-muted disabled:opacity-40`,children:p===`look`?(0,R.jsx)(A,{size:15,className:`animate-spin`}):(0,R.jsx)(Re,{size:15})}),(0,R.jsxs)(`button`,{type:`button`,onClick:T,disabled:d===`on`,className:`flex items-center gap-1.5 rounded-full bg-accent px-3.5 py-2 text-[13px] font-semibold text-white disabled:opacity-60`,children:[(0,R.jsx)(vt,{size:14}),` `,c(`Take over`)]})]})]}),children:[u&&u.by===`agent`&&(0,R.jsx)(`div`,{className:`mb-2`,children:(0,R.jsx)(xp,{hold:u,compact:!0})}),(0,R.jsxs)(`div`,{className:i(`relative overflow-hidden rounded-2xl border border-border bg-surface-2`,S&&`ring-2 ring-accent`),children:[y?(0,R.jsxs)(`div`,{className:`flex aspect-[16/10] flex-col items-center justify-center gap-1 text-muted`,children:[(0,R.jsx)(gt,{size:24}),(0,R.jsx)(`span`,{className:`text-[12.5px]`,children:c(`This frame is no longer available.`)}),(0,R.jsx)(`button`,{type:`button`,onClick:()=>void w({action:`look`}),className:`text-accent text-[13px] font-medium`,children:c(`Look again`)})]}):(0,R.jsx)(`img`,{ref:x,src:n(e,l.frame),alt:l.title||ee,onError:()=>b(!0),onClick:O,onWheel:k,draggable:!1,className:i(`block w-full select-none`,S?`cursor-crosshair`:``)},l.frame),p&&p!==`look`&&(0,R.jsx)(`div`,{className:`absolute inset-0 flex items-center justify-center bg-black/20`,children:(0,R.jsx)(A,{size:26,className:`animate-spin text-white`})})]}),(0,R.jsxs)(`div`,{className:`mt-2 flex items-center justify-between text-[12px] text-muted`,children:[(0,R.jsx)(`span`,{className:`truncate`,children:l.url}),(0,R.jsx)(`span`,{className:`shrink-0 ml-2`,children:l.frames===1?c(`1 frame`):c(`{n} frames`,{n:l.frames})})]}),S&&(0,R.jsxs)(`div`,{className:`mt-3 rounded-2xl bg-accent/8 px-3.5 py-2.5 text-[13px] leading-snug`,children:[(0,R.jsx)(`div`,{className:`font-medium`,children:u&&u.by===`agent`?Cp(u,c):c(`You have the page. Press Done when you are finished.`)}),(0,R.jsx)(`div`,{className:`mt-1 text-muted`,children:c(`{name} waits meanwhile, then looks at the page as you left it and carries on. Passwords you type here go to the website, never to the model.`,{name:M})})]})]})}function jp(){if(typeof window>`u`)return null;let e=window;return e.SpeechRecognition??e.webkitSpeechRecognition??null}function Mp(){return jp()!==null}function Np(e,t){let[n,r]=(0,L.useState)(!1),i=(0,L.useRef)(null),a=(0,L.useRef)(``),o=s(),c=(0,L.useCallback)(()=>{i.current?.stop()},[]),l=(0,L.useCallback)(()=>{let n=jp();if(!n)return;let s=new n;s.lang=navigator.language||`en-US`,s.continuous=!0,s.interimResults=!0,a.current=``,s.onresult=t=>{let n=``;for(let e=t.resultIndex;e{let n=e.error||``;n!==`aborted`&&n!==`no-speech`&&t?.(n===`not-allowed`||n===`service-not-allowed`?o(`The microphone is not allowed. Allow it in the browser and try again.`):o(`Voice input stopped ({code}).`,{code:n}))},s.onend=()=>{i.current=null,r(!1)},i.current=s;try{s.start(),r(!0)}catch{i.current=null,r(!1)}},[e,t,o]),u=(0,L.useCallback)(()=>{i.current?c():l()},[l,c]);return(0,L.useEffect)(()=>()=>i.current?.abort(),[]),{supported:Mp(),listening:n,toggle:u,stop:c}}function Pp({listening:e,onClick:t,className:n}){let r=s();return(0,R.jsx)(`button`,{type:`button`,onClick:t,"aria-label":r(e?`Stop voice input`:`Voice input`),"aria-pressed":e,className:i(`flex h-9 w-9 shrink-0 items-center justify-center rounded-full transition active:scale-95`,e?`bg-accent/15 text-accent animate-pulse`:`text-fg/70 hover:bg-surface-2`,n),children:e?(0,R.jsx)(Pt,{size:19}):(0,R.jsx)(Ft,{size:19})})}function Fp({lines:e}){return(0,R.jsx)(`div`,{className:`flex items-end gap-2 pr-10`,children:(0,R.jsx)(`div`,{className:`min-w-0 max-w-full`,children:e.map((e,t)=>(0,R.jsx)(`div`,{className:`my-1 max-w-[340px] rounded-[20px] bg-surface-2 px-3.5 py-2.5 text-[14.5px] leading-snug whitespace-pre-wrap break-words wide:max-w-[600px]`,children:e},t))})})}function Ip({chips:e,chosen:t,busy:n,onPick:r,onElse:a}){let o=s();return e.length===0&&!t?null:(0,R.jsxs)(`section`,{className:`rise mx-1 my-2 rounded-[22px] border border-border/70 bg-surface p-3.5`,children:[(0,R.jsxs)(`div`,{className:`flex items-center gap-2 text-[13px] font-medium text-fg`,children:[(0,R.jsx)(nn,{size:14,className:`text-accent`}),` `,o(`Pick a name for me, or type one`)]}),(0,R.jsxs)(`div`,{className:`mt-2.5 flex flex-wrap gap-2`,children:[e.map(e=>{let a=t===e;return(0,R.jsxs)(`button`,{type:`button`,disabled:n||!!t,onClick:()=>r(e),className:i(`inline-flex items-center gap-1.5 rounded-full px-3.5 py-1.5 text-[13.5px] font-medium transition-colors disabled:opacity-60`,a?`bg-accent text-accent-fg`:`bg-surface-2 hover:bg-border/60`),children:[a&&(0,R.jsx)(ke,{size:13,strokeWidth:3}),e]},e)}),!t&&(0,R.jsx)(`button`,{type:`button`,disabled:n,onClick:a,className:`rounded-full border border-border px-3.5 py-1.5 text-[13.5px] text-muted hover:bg-surface-2 disabled:opacity-60`,children:o(`Something else`)})]})]})}var Lp=[{id:`pink`,background:`#F9D9E3`,accent:`#B5476A`,mood:`idle`},{id:`blue`,background:`#D6E6FA`,accent:`#2F5FA8`,mood:`working`},{id:`yellow`,background:`#FBEFC7`,accent:`#9A6B12`,mood:`waiting`},{id:`purple`,background:`#E4DDF7`,accent:`#5D44A6`,mood:`happy`},{id:`green`,background:`#D9F0DF`,accent:`#2E7D4F`,mood:`error`}],Rp=`github.com/nano-muse/nanoMuse`,zp=540,Bp=720;function Vp(e,t){return!e||w(e.avatar)?M(t):e.avatar?ne(e.avatar,t):null}function Hp(e){return new Promise(t=>{let n=new Image;n.crossOrigin=`anonymous`,n.onload=()=>t(n),n.onerror=()=>t(null),n.src=e})}function Up(e,t,n){let r=t.includes(` `)?t.split(` `):Array.from(t),i=t.includes(` `)?` `:``,a=[],o=``;for(let t of r){let r=o?o+i+t:t;e.measureText(r).width>n&&o?(a.push(o),o=t):o=r}return o&&a.push(o),a}function Wp(e,t,n,r,i,a){e.beginPath(),e.moveTo(t+a,n),e.arcTo(t+r,n,t+r,n+i,a),e.arcTo(t+r,n+i,t,n+i,a),e.arcTo(t,n+i,t,n,a),e.arcTo(t,n,t+r,n,a),e.closePath()}async function Gp(e,t,n,r,i,a=2){let o=document.createElement(`canvas`);o.width=zp*a,o.height=Bp*a;let s=o.getContext(`2d`);if(!s)return o;s.scale(a,a),s.fillStyle=e.background,Wp(s,0,0,zp,Bp,36),s.fill(),s.font=`600 22px system-ui, -apple-system, 'Segoe UI', sans-serif`;let c=Up(s,r,400),l=Math.max(...c.map(e=>s.measureText(e).width))+48,u=c.length*30+36,d=(zp-l)/2;s.fillStyle=`#ffffff`,Wp(s,d,56,l,u,24),s.fill(),s.beginPath(),s.moveTo(zp/2-14,56+u-1),s.lineTo(zp/2,56+u+18),s.lineTo(284,56+u-1),s.closePath(),s.fill(),s.fillStyle=e.accent,s.textAlign=`center`,s.textBaseline=`top`,c.forEach((e,t)=>s.fillText(e,zp/2,74+t*30+3));let f=56+u+54;s.fillStyle=`#ffffff`,s.beginPath(),s.arc(zp/2,f+150,158,0,Math.PI*2),s.fill();let p=Vp(t,e.mood),m=p?await Hp(p):null;return s.save(),s.beginPath(),s.arc(zp/2,f+150,150,0,Math.PI*2),s.clip(),m?(s.fillStyle=`#f1efeb`,s.fillRect(120,f,300,300),s.drawImage(m,120,f,300,300)):(s.fillStyle=t?.color??`#0064d4`,s.fillRect(120,f,300,300),s.font=`150px system-ui, 'Apple Color Emoji', 'Segoe UI Emoji', sans-serif`,s.textAlign=`center`,s.textBaseline=`middle`,s.fillStyle=`#ffffff`,s.fillText(t?.emoji??`✨`,zp/2,f+150+6)),s.restore(),s.fillStyle=e.accent,s.textAlign=`center`,s.textBaseline=`top`,s.font=`700 30px system-ui, -apple-system, 'Segoe UI', sans-serif`,s.fillText(n,zp/2,f+300+34),s.font=`500 15px system-ui, -apple-system, 'Segoe UI', sans-serif`,s.globalAlpha=.8,Up(s,i,460).forEach((e,t)=>s.fillText(e,zp/2,644+t*22)),s.globalAlpha=1,o}function Kp(e){return new Promise(t=>e.toBlob(t,`image/png`))}function qp({open:e,onClose:t}){let{state:n,toast:r}=E(),a=s(),o=n.profile,c=o?.name??`nanoMuse`,[l,u]=(0,L.useState)(0),[d,f]=(0,L.useState)([]),[p,m]=(0,L.useState)(!1),h=(0,L.useRef)(!0),g=a(`Hi, I'm {name}, a personal AI agent. Meet nanoMuse: open source, runs on your phone.`,{name:c}),_=a(`Your personal AI agent, open source · {repo}`,{repo:Rp});(0,L.useEffect)(()=>{if(h.current=!0,e)return u(0),(async()=>{let e=[];for(let t of Lp){let n=await Gp(t,o,c,g,_,1);e.push(n.toDataURL(`image/png`))}h.current&&f(e)})(),()=>{h.current=!1}},[e,o?.avatar,o?.emoji,o?.color,c]);let v=async()=>{m(!0);try{let e=await Kp(await Gp(Lp[l]??Lp[0],o,c,g,_,2));if(!e)throw Error(a(`The card could not be drawn.`));let n=new File([e],`${c}-nanomuse.png`,{type:`image/png`}),i=`${g}\nhttps://${Rp}`,s=navigator;if(typeof s.share==`function`&&(!s.canShare||s.canShare({files:[n]})))try{await s.share({files:[n],text:i,title:c}),t();return}catch(e){if(e.name===`AbortError`)return}let u=document.createElement(`a`);u.href=URL.createObjectURL(e),u.download=n.name,u.click(),window.setTimeout(()=>URL.revokeObjectURL(u.href),2e3),r(a(`Saved the card as a picture.`))}catch(e){r(e.message)}finally{m(!1)}};return(0,R.jsxs)(Op,{open:e,onClose:t,title:a(`Share my avatar`),children:[(0,R.jsx)(`p`,{className:`mb-3 text-[13px] text-muted`,children:a(`Pick a card. It goes out through the system share sheet, or saves as a picture where there is none.`)}),(0,R.jsx)(`div`,{className:`grid grid-cols-3 gap-2.5 sm:grid-cols-5`,children:Lp.map((e,t)=>(0,R.jsx)(`button`,{type:`button`,"aria-label":e.id,"aria-pressed":l===t,onClick:()=>u(t),className:i(`overflow-hidden rounded-2xl border-2 transition`,l===t?`border-accent`:`border-transparent`),style:{background:e.background,aspectRatio:`${zp} / ${Bp}`},children:d[t]?(0,R.jsx)(`img`,{src:d[t],alt:``,className:`h-full w-full object-cover`}):(0,R.jsx)(A,{size:18,className:`mx-auto my-8 animate-spin text-muted`})},e.id))}),d[l]&&(0,R.jsx)(`img`,{src:d[l],alt:``,className:`mx-auto mt-4 w-[260px] rounded-[20px] shadow-md`}),(0,R.jsxs)(`div`,{className:`mt-4 flex justify-end gap-2`,children:[(0,R.jsx)(`button`,{type:`button`,onClick:t,className:je,children:a(`Later`)}),(0,R.jsxs)(`button`,{type:`button`,disabled:p||!d.length,onClick:()=>void v(),className:Ne,children:[p?(0,R.jsx)(A,{size:15,className:`animate-spin`}):typeof navigator.share==`function`?(0,R.jsx)(Xt,{size:15}):(0,R.jsx)(ft,{size:15}),` `,typeof navigator.share==`function`?a(`Share`):a(`Save picture`)]})]})]})}function Jp({message:e,onRetry:t}){let n=s();return(0,R.jsxs)(`div`,{className:`flex flex-col items-center gap-3 px-8 py-10 text-center`,children:[(0,R.jsx)(`p`,{className:`text-[14px] text-rose-600 dark:text-rose-300`,children:n(e)||n(`Could not load.`)}),(0,R.jsxs)(`button`,{type:`button`,onClick:t,className:`flex h-10 items-center gap-1.5 rounded-full bg-surface px-4 text-[13.5px] font-medium shadow-[0_1px_4px_rgba(0,0,0,0.14)] dark:border dark:border-border dark:shadow-none`,children:[(0,R.jsx)(Re,{size:14}),` `,n(`Try again`)]})]})}var Yp=[{id:`health`,label:`Health`,icon:e=>(0,R.jsx)(yt,{...e}),tone:`bg-rose-500/12 text-rose-600 dark:text-rose-300`},{id:`finance`,label:`Finance`,icon:e=>(0,R.jsx)(Wt,{...e}),tone:`bg-emerald-500/12 text-emerald-600 dark:text-emerald-300`},{id:`career`,label:`Career`,icon:e=>(0,R.jsx)($e,{...e}),tone:`bg-sky-500/12 text-sky-600 dark:text-sky-300`},{id:`learning`,label:`Learning`,icon:e=>(0,R.jsx)(_t,{...e}),tone:`bg-violet-500/12 text-violet-600 dark:text-violet-300`},{id:`relationships`,label:`Relationships`,icon:e=>(0,R.jsx)(le,{...e}),tone:`bg-pink-500/12 text-pink-600 dark:text-pink-300`},{id:`family`,label:`Family`,icon:e=>(0,R.jsx)(hn,{...e}),tone:`bg-amber-500/12 text-amber-600 dark:text-amber-300`},{id:`home`,label:`Home`,icon:e=>(0,R.jsx)(bt,{...e}),tone:`bg-orange-500/12 text-orange-600 dark:text-orange-300`},{id:`travel`,label:`Travel`,icon:e=>(0,R.jsx)(lt,{...e}),tone:`bg-cyan-500/12 text-cyan-600 dark:text-cyan-300`},{id:`creative`,label:`Creative`,icon:e=>(0,R.jsx)(Vt,{...e}),tone:`bg-fuchsia-500/12 text-fuchsia-600 dark:text-fuchsia-300`},{id:`other`,label:`Other`,icon:e=>(0,R.jsx)(ln,{...e}),tone:`bg-surface-2 text-muted`}];function Xp(e){return Yp.find(t=>t.id===e)??null}var Zp=[{id:``,label:`No reminders`},{id:`daily`,label:`Every day`},{id:`weekdays`,label:`Weekdays`},{id:`weekly`,label:`Once a week`},{id:`monthly`,label:`Once a month`}],Qp=[`mon`,`tue`,`wed`,`thu`,`fri`,`sat`,`sun`];function $p(e){let t=/^(daily|weekdays|weekly|monthly)(?:\s+(\S+?))?(?:\s+(\d{1,2}:\d{2}))?$/.exec(e.trim());if(!t)return{cadence:``,anchor:``,time:`09:00`};let n=t[2]??``,r=t[3]??`09:00`;return n&&/^\d{1,2}:\d{2}$/.test(n)&&(r=n,n=``),{cadence:t[1],anchor:n,time:r.padStart(5,`0`)}}function em(e,t,n){return e?[e,t,n].filter(Boolean).join(` `):``}function tm(e){let t=Qp.indexOf(e);return t<0?e:new Date(2024,0,1+t).toLocaleDateString(m(),{weekday:`long`})}function nm(e){let{cadence:t,anchor:n,time:r}=$p(e);switch(t){case`daily`:return _(`Daily at {time}`,{time:r});case`weekdays`:return _(`Weekdays at {time}`,{time:r});case`weekly`:return n&&Qp.includes(n)?_(`{day}s at {time}`,{day:tm(n),time:r}):_(`Weekly at {time}`,{time:r});case`monthly`:return _(`Monthly on the {day} at {time}`,{day:rm(Number(n||1)),time:r});default:return``}}function rm(e){if(c()!==`en`)return String(e);let t=[`th`,`st`,`nd`,`rd`],n=e%100;return`${e}${t[(n-20)%10]??t[n]??t[0]}`}function im(e,t){if(!e)return``;let n=new Date(`${e}T00:00:00`),r=n.toLocaleDateString(m(),{month:`short`,day:`numeric`,year:n.getFullYear()===new Date().getFullYear()?void 0:`numeric`});if(t)return _(`Was due {date}`,{date:r});let i=Math.ceil((n.getTime()-Date.now())/864e5);return i<=0?_(`Due today`):i===1?_(`Due tomorrow`):i<=14?_(`Due in {n} days`,{n:i}):_(`By {date}`,{date:r})}function am({open:e,onClose:t}){let{state:n,setTab:r,draft:a,toast:o}=E(),[c,l]=(0,L.useState)(0),[u,d]=(0,L.useState)(!1),[f,p]=(0,L.useState)(!1),[m,h]=(0,L.useState)(!1),g=n.profile?.name??`nanoMuse`,_=n.pendingApprovals.length,v=s();(0,L.useEffect)(()=>{e&&(l(+(_>0)),d(!1),p(!1))},[e]);let y=(e,n)=>{t(),n&&history.replaceState(null,``,`${window.location.pathname}${window.location.search}#${n}`),r(e)},b=n.status.state===`working`,x=_>0?_>1?v(`{n} approvals waiting for you`,{n:_}):v(`1 approval waiting for you`):b?n.status.detail||v(`On it`):n.status.state===`waiting`?v(`Waiting for you`):v(`online`),S=async()=>{h(!0);try{(await N.stopThread(n.status.thread||`main`)).ok||o(v(`Nothing to stop`))}catch(e){o(e.message)}finally{h(!1)}},C=[{icon:(0,R.jsx)(it,{size:22}),label:v(`Activity`)},{icon:(0,R.jsx)(Qt,{size:22}),label:v(`Approvals`),badge:_},{icon:(0,R.jsx)(at,{size:22}),label:v(`Daily`)},{icon:(0,R.jsx)(ht,{size:22}),label:v(`Soul & memory`)}];return(0,R.jsxs)(Op,{open:e,onClose:t,children:[(0,R.jsxs)(`div`,{className:`relative flex flex-col items-center px-1 pb-3 text-center`,children:[(0,R.jsx)(`button`,{type:`button`,"aria-label":v(`Share avatar`),title:v(`Share avatar`),onClick:()=>p(!0),className:`absolute right-0 top-0 flex h-9 w-9 items-center justify-center rounded-full bg-surface-2/70 text-fg hover:bg-surface-2`,children:(0,R.jsx)(Xt,{size:16})}),(0,R.jsxs)(`div`,{className:`relative`,children:[(0,R.jsx)(D,{profile:n.profile,status:n.status,size:72}),(0,R.jsx)(`button`,{type:`button`,"aria-label":v(`Edit`),"aria-expanded":u,onClick:()=>d(e=>!e),className:`absolute -bottom-0.5 -right-0.5 flex h-6 w-6 items-center justify-center rounded-full bg-surface text-fg shadow-[0_1px_4px_rgba(0,0,0,0.18)] hover:bg-surface-2 dark:border dark:border-border`,children:(0,R.jsx)(Ht,{size:13})}),u&&(0,R.jsxs)(`div`,{className:`absolute left-1/2 top-full z-20 mt-2 w-56 -translate-x-1/2 overflow-hidden rounded-2xl border border-border/70 bg-surface py-1 text-left text-[14px] shadow-lg`,children:[(0,R.jsx)(`button`,{type:`button`,onClick:()=>{a(v(`Change your avatar to `)),t(),r(`chat`)},className:`block w-full px-4 py-2.5 text-left hover:bg-surface-2`,children:v(`Change avatar`)}),(0,R.jsx)(`button`,{type:`button`,onClick:()=>y(`you`,`who`),className:`block w-full px-4 py-2.5 text-left hover:bg-surface-2`,children:v(`Edit name`)}),(0,R.jsx)(`button`,{type:`button`,onClick:()=>y(`avatar`),className:`block w-full px-4 py-2.5 text-left text-muted hover:bg-surface-2`,children:v(`Avatar studio…`)})]})]}),(0,R.jsx)(`div`,{className:`mt-2.5 text-[21px] font-semibold leading-[26px]`,children:g}),(0,R.jsxs)(`div`,{className:i(`mt-0.5 flex items-center gap-1.5 text-[14px]`,b||_>0?`text-fg`:`text-muted`),children:[b&&(0,R.jsx)(A,{size:13,className:`animate-spin text-accent`}),(0,R.jsx)(`span`,{className:`line-clamp-2`,children:x})]}),(b||n.status.state===`waiting`)&&(0,R.jsxs)(`button`,{type:`button`,onClick:()=>void S(),disabled:m,className:`mt-2.5 inline-flex items-center gap-1.5 rounded-full bg-fg px-4 py-1.5 text-[13.5px] font-semibold text-bg transition active:scale-95 disabled:opacity-60`,children:[(0,R.jsx)(sn,{size:12,fill:`currentColor`}),` `,v(`Stop`)]})]}),(0,R.jsx)(`div`,{role:`tablist`,className:`mb-5 flex rounded-2xl bg-surface-2/60 p-1`,children:C.map((e,t)=>(0,R.jsxs)(`button`,{type:`button`,role:`tab`,"aria-selected":c===t,"aria-label":e.label,title:e.label,onClick:()=>l(t),className:i(`relative flex h-11 flex-1 items-center justify-center rounded-[13px] text-fg transition`,c===t&&`bg-surface shadow-sm`),children:[e.icon,e.badge?(0,R.jsx)(`span`,{className:`absolute right-1.5 top-1 flex h-[17px] min-w-[17px] items-center justify-center rounded-full bg-rose-500 px-1 text-[10px] font-bold text-white`,children:e.badge}):null]},e.label))}),c===0&&(0,R.jsx)(ym,{open:e}),c===1&&(0,R.jsxs)(R.Fragment,{children:[_>0&&(0,R.jsx)(cm,{onDone:()=>void 0}),(0,R.jsx)(bm,{open:e})]}),c===2&&(0,R.jsx)(lm,{onSettings:()=>y(`you`,`proactivity`)}),c===3&&(0,R.jsx)(om,{name:g,onEdit:()=>y(`you`,`who`),onMemory:()=>y(`memory`)}),(0,R.jsx)(qp,{open:f,onClose:()=>p(!1)})]})}function om({name:e,onEdit:t,onMemory:n}){let{state:r}=E(),i=s(),a=r.profile?.tagline?.trim()??``;return(0,R.jsxs)(`div`,{className:`pb-2`,children:[(0,R.jsx)(`div`,{className:`px-1 text-[15px]`,children:e}),(0,R.jsxs)(`button`,{type:`button`,onClick:t,className:`mt-2 flex h-[50px] w-full items-center justify-center gap-2 rounded-2xl bg-surface-2/70 text-[15px] font-medium hover:bg-surface-2`,children:[(0,R.jsx)(Ht,{size:18}),` `,i(`Edit`)]}),(0,R.jsxs)(`div`,{className:`mt-4 grid grid-cols-2 gap-3`,children:[(0,R.jsx)(sm,{title:`SOUL`,caption:i(`Handle with care`),foot:a,colors:`from-[#7d6bc7] to-[#574494]`,onClick:t}),(0,R.jsx)(sm,{title:i(`Memory`),caption:i(`Handle with care`),foot:r.settings?.memory_enabled===!1?i(`Off`):``,colors:`from-[#b0413e] to-[#7a1f1f]`,onClick:n})]})]})}function sm({title:e,caption:t,foot:n,colors:r,onClick:a}){return(0,R.jsxs)(`button`,{type:`button`,onClick:a,className:i(`flex h-[130px] flex-col items-start rounded-[18px] bg-gradient-to-b p-3.5 text-left text-white transition active:scale-[0.98]`,r),children:[(0,R.jsx)(`span`,{className:`text-[17px] font-semibold`,children:e}),(0,R.jsx)(`span`,{className:`mt-0.5 text-[11px] text-white/85`,children:t}),(0,R.jsx)(`span`,{className:`mt-auto text-[12px] text-white/90`,children:n})]})}function cm({onDone:e}){let{state:t,decide:n,openThread:r,toast:i}=E(),a=t.profile?.name??`nanoMuse`,o=s(),c=[...t.pendingApprovals].sort((e,t)=>e.ts.localeCompare(t.ts)),l=e=>{let n=t.threads.find(t=>t.id===e);return n?n.id===`main`?o(n.title):n.title:e};return(0,L.useEffect)(()=>{if(c.length===0){let t=window.setTimeout(e,600);return()=>window.clearTimeout(t)}},[c.length,e]),c.length===0?(0,R.jsxs)(`div`,{className:`py-10 text-center text-muted text-[14px]`,children:[(0,R.jsx)(ke,{size:26,className:`mx-auto mb-2 text-emerald-500`}),o(`Nothing is waiting for you.`)]}):(0,R.jsxs)(`div`,{className:`space-y-4 pb-2`,children:[(0,R.jsx)(`p`,{className:`text-[12.5px] text-muted`,children:o(`Actions {name} wants to take but cannot without you. Each one shows what will run and why; a permission you grant is bound to that exact tool and target.`,{name:a})}),c.map(e=>(0,R.jsxs)(`div`,{children:[(0,R.jsxs)(`button`,{type:`button`,onClick:()=>r(e.thread),className:`mb-1 px-1 text-[12px] font-semibold uppercase tracking-wide text-muted hover:text-accent`,children:[l(e.thread),` · `,u(e.ts)]}),(0,R.jsx)(`div`,{className:`rounded-[22px] border border-border/70`,children:(0,R.jsx)(hp,{event:e,onDecide:(t,r)=>n(e.id,t,r).catch(e=>i(e.message))})})]},e.id))]})}function lm({onSettings:t}){let{state:n,refreshSettings:r,toast:a}=E(),[o,c]=(0,L.useState)(null),[l,d]=(0,L.useState)(null),[f,p]=(0,L.useState)(null),m=n.profile?.name??`nanoMuse`,h=s(),g=()=>N.upcoming().then(e=>{c(e),d(null)}).catch(e=>o===null?d(e.message):a(e.message));(0,L.useEffect)(()=>{g()},[n.goalsVersion,n.remindersVersion,n.profile?.proactive,n.profile?.goal_interval_minutes]);let _=async()=>{try{await N.updateSettings({profile:{proactive:!n.profile?.proactive}}),await r()}catch(e){a(e.message)}},v=async e=>{p(e);try{await N.advanceGoal(e),a(h(`{name} is working on it in the main chat`,{name:m}))}catch(e){a(e.message)}finally{p(null)}};return o?(0,R.jsxs)(`div`,{className:`space-y-4 pb-2`,children:[(0,R.jsxs)(`div`,{className:`rounded-2xl border border-border p-3.5`,children:[(0,R.jsxs)(`div`,{className:`flex items-center justify-between gap-3`,children:[(0,R.jsxs)(`div`,{children:[(0,R.jsx)(`div`,{className:`font-medium`,children:h(`Background work`)}),(0,R.jsx)(`div`,{className:`text-[12.5px] text-muted`,children:o.proactive?`${h(o.proactivity[0].toUpperCase()+o.proactivity.slice(1))} · ${h(`every {n} min {name} picks one active goal and works on its next step.`,{n:o.effective_interval_minutes,name:m})}${o.quiet_until?` ${h(`Quiet hours until {time}.`,{time:u(o.quiet_until)})}`:o.next_pass_at?` ${h(`Next around {time}.`,{time:u(o.next_pass_at)})}`:``}`:h(`Off. {name} only works when you ask.`,{name:m})})]}),(0,R.jsx)(`button`,{type:`button`,role:`switch`,"aria-checked":o.proactive,onClick:()=>void _(),className:i(`relative h-7 w-12 shrink-0 rounded-full transition`,o.proactive?`bg-accent`:`bg-border`),children:(0,R.jsx)(`span`,{className:i(`absolute top-0.5 h-6 w-6 rounded-full bg-white shadow transition`,o.proactive?`left-[26px]`:`left-0.5`)})})]}),(0,R.jsx)(`button`,{type:`button`,onClick:t,className:`mt-2 text-[12.5px] text-accent font-medium`,children:h(`Level, interval and quiet hours in Settings`)})]}),(0,R.jsxs)(`div`,{children:[(0,R.jsx)(`div`,{className:`text-[12px] uppercase tracking-wide text-muted font-semibold mb-1.5`,children:h(`In line`)}),o.queue.length===0?(0,R.jsx)(`div`,{className:`text-[13px] text-muted`,children:h(`No active goal has a next step. Add one in Goals and {name} will pick it up.`,{name:m})}):(0,R.jsx)(`ul`,{className:`space-y-1.5`,children:o.queue.map((e,t)=>(0,R.jsxs)(`li`,{className:`flex items-center gap-2.5 rounded-2xl bg-surface-2/60 px-3 py-2`,children:[(0,R.jsx)(`span`,{className:`w-5 text-center text-[12px] font-semibold text-muted`,children:t+1}),(0,R.jsxs)(`div`,{className:`min-w-0 flex-1`,children:[(0,R.jsx)(`div`,{className:`text-[13.5px] font-medium truncate`,children:e.title}),(0,R.jsxs)(`div`,{className:`text-[11.5px] text-muted truncate`,children:[e.next_step??h(`No next step`),` · `,h(`{done}/{total} done`,{done:e.progress.done,total:e.progress.total})]})]}),(0,R.jsx)(`button`,{type:`button`,onClick:()=>void v(e.goal_id),disabled:f!==null||o.busy,"aria-label":h(`Work on {title} now`,{title:e.title}),className:`rounded-full bg-accent/12 p-2 text-accent disabled:opacity-50`,children:f===e.goal_id?(0,R.jsx)(A,{size:15,className:`animate-spin`}):(0,R.jsx)(Gt,{size:15})})]},e.goal_id))})]}),o.check_ins.length>0&&(0,R.jsxs)(`div`,{children:[(0,R.jsx)(`div`,{className:`text-[12px] uppercase tracking-wide text-muted font-semibold mb-1.5`,children:h(`Check-ins`)}),(0,R.jsx)(`ul`,{className:`space-y-1.5`,children:o.check_ins.map(t=>(0,R.jsxs)(`li`,{className:`flex items-center gap-2.5 rounded-2xl bg-surface-2/60 px-3 py-2`,children:[(0,R.jsx)(Xe,{size:15,className:`text-muted shrink-0`}),(0,R.jsxs)(`div`,{className:`min-w-0 flex-1`,children:[(0,R.jsx)(`div`,{className:`text-[13.5px] font-medium truncate`,children:t.title}),(0,R.jsxs)(`div`,{className:`text-[11.5px] text-muted truncate`,children:[e(t.at),` · `,u(t.at),` · `,nm(t.cadence).toLowerCase()]})]})]},t.goal_id))}),(0,R.jsx)(`div`,{className:`mt-1.5 text-[12px] text-muted`,children:h(`Goal nudges you asked for; they arrive whatever the proactivity level, but wait out quiet hours.`)})]}),(0,R.jsx)(um,{items:o.reminders,name:m,onChange:()=>void g()}),(0,R.jsx)(mm,{data:o.triggers,name:m,onChange:()=>void g()})]}):l?(0,R.jsx)(Jp,{message:l,onRetry:()=>void g()}):(0,R.jsx)(`div`,{className:`py-10 flex justify-center text-muted`,children:(0,R.jsx)(A,{className:`animate-spin`,size:20})})}function um({items:t,name:n,onChange:r}){let{toast:i}=E(),a=s(),[o,c]=(0,L.useState)(null),[l,d]=(0,L.useState)(!1),f=t.filter(e=>e.status===`active`),p=t.filter(e=>e.status!==`active`),m=async e=>{c(e.id);try{await N.cancelReminder(e.id),r()}catch(e){i(e.message)}finally{c(null)}},h=async e=>{c(e.id);try{await N.fireReminder(e.id),i(e.kind===`task`?a(`{name} is on it`,{name:n}):a(`{name} will say it now`,{name:n})),r()}catch(e){i(e.message)}finally{c(null)}};return(0,R.jsxs)(`div`,{children:[(0,R.jsxs)(`div`,{className:`flex items-center justify-between mb-1.5`,children:[(0,R.jsx)(`div`,{className:`text-[12px] uppercase tracking-wide text-muted font-semibold`,children:a(`Reminders & routines`)}),!l&&(0,R.jsx)(`button`,{type:`button`,onClick:()=>d(!0),className:`text-[12.5px] text-accent font-medium`,children:a(`+ Add`)})]}),l&&(0,R.jsx)(dm,{onDone:()=>{d(!1),r()},onCancel:()=>d(!1)}),f.length===0&&!l?(0,R.jsx)(`div`,{className:`text-[13px] text-muted`,children:a(`Nothing scheduled. Tell {name} “remind me at six to call mum” or “every weekday morning, summarise my unread email”.`,{name:n})}):(0,R.jsx)(`ul`,{className:`space-y-1.5`,children:f.map(t=>(0,R.jsxs)(`li`,{className:`flex items-center gap-2.5 rounded-2xl bg-surface-2/60 px-3 py-2`,children:[t.kind===`task`?(0,R.jsx)(Kt,{size:15,className:`text-muted shrink-0`}):(0,R.jsx)(We,{size:15,className:`text-muted shrink-0`}),(0,R.jsxs)(`div`,{className:`min-w-0 flex-1`,children:[(0,R.jsx)(`div`,{className:`text-[13.5px] font-medium truncate`,children:t.text}),(0,R.jsxs)(`div`,{className:`text-[11.5px] text-muted truncate`,children:[t.next_at?`${e(t.next_at)} · ${u(t.next_at)}`:a(`Not scheduled`),t.repeat&&` · ${nm(t.repeat).toLowerCase()}`,t.kind===`task`&&` · ${a(`does the work`)}`]})]}),(0,R.jsx)(`button`,{type:`button`,onClick:()=>void h(t),disabled:o!==null,"aria-label":t.kind===`task`?a(`Do “{text}” now`,{text:t.text}):a(`Remind me now: {text}`,{text:t.text}),className:`rounded-full bg-accent/12 p-2 text-accent disabled:opacity-50`,children:o===t.id?(0,R.jsx)(A,{size:15,className:`animate-spin`}):(0,R.jsx)(Gt,{size:15})}),(0,R.jsx)(`button`,{type:`button`,onClick:()=>void m(t),disabled:o!==null,"aria-label":a(`Cancel: {text}`,{text:t.text}),className:`rounded-full p-2 text-muted hover:text-fg disabled:opacity-50`,children:(0,R.jsx)(Fe,{size:15})})]},t.id))}),p.length>0&&(0,R.jsxs)(`details`,{className:`mt-2`,children:[(0,R.jsx)(`summary`,{className:`text-[12px] text-muted cursor-pointer select-none`,children:a(`{n} finished recently`,{n:p.length})}),(0,R.jsx)(`ul`,{className:`mt-1.5 space-y-1`,children:p.map(t=>(0,R.jsxs)(`li`,{className:`flex items-center gap-2 px-3 text-[12.5px] text-muted`,children:[(0,R.jsx)(`span`,{className:`min-w-0 flex-1 truncate line-through decoration-border`,children:t.text}),(0,R.jsx)(`span`,{className:`shrink-0`,children:t.status===`done`?t.last_fired_at?e(t.last_fired_at):a(`done`):a(`cancelled`)})]},t.id))})]}),(0,R.jsx)(`div`,{className:`mt-1.5 text-[12px] text-muted`,children:a(`A time you named is kept whatever the level or the quiet hours. Reminders just say it; routines do the work and report.`)})]})}function dm({onDone:e,onCancel:t}){let{toast:n}=E(),r=s(),[a,o]=(0,L.useState)(``),[c,l]=(0,L.useState)(`remind`),[u,d]=(0,L.useState)(`once`),[f,p]=(0,L.useState)(()=>_m()),[h,g]=(0,L.useState)(`daily`),[_,v]=(0,L.useState)(`09:00`),[y,b]=(0,L.useState)(`mon`),[x,S]=(0,L.useState)(`1`),[C,w]=(0,L.useState)(!1),T=h===`weekly`?`weekly ${y} ${_}`:h===`monthly`?`monthly ${x} ${_}`:`${h} ${_}`,D=async()=>{if(a.trim()){w(!0);try{await N.createReminder(u===`once`?{text:a.trim(),kind:c,at:f.replace(`T`,` `)}:{text:a.trim(),kind:c,repeat:T}),e()}catch(e){n(e.message)}finally{w(!1)}}},O=`h-9 rounded-xl bg-surface border border-border px-3 text-[13px] outline-none focus:border-accent`;return(0,R.jsxs)(`div`,{className:`mb-2 rounded-2xl border border-border p-3 space-y-2`,children:[(0,R.jsx)(`input`,{autoFocus:!0,value:a,onChange:e=>o(e.target.value),placeholder:r(c===`task`?`What should be done…`:`What to remind you of…`),className:i(O,`w-full h-10 text-[14px]`)}),(0,R.jsxs)(`div`,{className:`flex gap-1.5 text-[12.5px]`,children:[(0,R.jsx)(gm,{options:[[`remind`,r(`Remind me`)],[`task`,r(`Do it for me`)]],value:c,onChange:e=>l(e)}),(0,R.jsx)(gm,{options:[[`once`,r(`Once`)],[`repeat`,r(`Repeat`)]],value:u,onChange:e=>d(e)})]}),u===`once`?(0,R.jsx)(`input`,{type:`datetime-local`,value:f,onChange:e=>p(e.target.value),className:i(O,`w-full`)}):(0,R.jsxs)(`div`,{className:`flex flex-wrap gap-1.5`,children:[(0,R.jsxs)(`select`,{value:h,onChange:e=>g(e.target.value),className:O,children:[(0,R.jsx)(`option`,{value:`daily`,children:r(`Every day`)}),(0,R.jsx)(`option`,{value:`weekdays`,children:r(`Weekdays`)}),(0,R.jsx)(`option`,{value:`weekly`,children:r(`Weekly`)}),(0,R.jsx)(`option`,{value:`monthly`,children:r(`Monthly`)})]}),h===`weekly`&&(0,R.jsx)(`select`,{value:y,onChange:e=>b(e.target.value),className:O,children:[`mon`,`tue`,`wed`,`thu`,`fri`,`sat`,`sun`].map((e,t)=>(0,R.jsx)(`option`,{value:e,children:new Date(2024,0,1+t).toLocaleDateString(m(),{weekday:`long`})},e))}),h===`monthly`&&(0,R.jsx)(`select`,{value:x,onChange:e=>S(e.target.value),className:O,children:Array.from({length:28},(e,t)=>String(t+1)).map(e=>(0,R.jsx)(`option`,{value:e,children:r(`Day {d}`,{d:e})},e))}),(0,R.jsx)(`input`,{type:`time`,value:_,onChange:e=>v(e.target.value),className:O})]}),(0,R.jsxs)(`div`,{className:`flex justify-end gap-2 pt-0.5`,children:[(0,R.jsx)(`button`,{type:`button`,onClick:t,className:`rounded-full px-3 py-1.5 text-[13px] text-muted`,children:r(`Cancel`)}),(0,R.jsx)(`button`,{type:`button`,onClick:()=>void D(),disabled:C||!a.trim(),className:`rounded-full bg-accent px-3.5 py-1.5 text-[13px] font-medium text-accent-fg disabled:opacity-50`,children:r(C?`Saving…`:u===`once`?`Set reminder`:`Set routine`)})]})]})}var fm={mail:Et,event:et,hook:_n};function pm(e,t){if(e.kind===`mail`)return e.match?t(`mail matching “{match}”`,{match:e.match}):t(`any new mail`);if(e.kind===`event`){let n=e.match?t(`events matching “{match}”`,{match:e.match}):t(`any event`);return t(`{n} min before {what}`,{n:e.lead_minutes,what:n})}return e.match?t(`webhook “{match}”`,{match:e.match}):t(`webhook`)}function mm({data:t,name:n,onChange:r}){let{toast:a}=E(),o=s(),[c,l]=(0,L.useState)(null),[u,d]=(0,L.useState)(!1),f=t.items.filter(e=>e.status===`active`),p=f.some(e=>e.kind===`mail`),m=async e=>{l(e.id);try{await N.cancelTrigger(e.id),r()}catch(e){a(e.message)}finally{l(null)}},h=async e=>{l(e.id);try{await N.fireTrigger(e.id),a(o(`{name} is on it`,{name:n})),r()}catch(e){a(e.message)}finally{l(null)}},g=async e=>{if(e.url)try{await navigator.clipboard.writeText(e.url),a(o(`Webhook URL copied`))}catch{a(e.url)}};return(0,R.jsxs)(`div`,{children:[(0,R.jsxs)(`div`,{className:`flex items-center justify-between mb-1.5`,children:[(0,R.jsx)(`div`,{className:`text-[12px] uppercase tracking-wide text-muted font-semibold`,children:o(`When something happens`)}),!u&&(0,R.jsx)(`button`,{type:`button`,onClick:()=>d(!0),className:`text-[12.5px] text-accent font-medium`,children:o(`+ Add`)})]}),u&&(0,R.jsx)(hm,{available:t.available,onDone:()=>{d(!1),r()},onCancel:()=>d(!1)}),f.length===0&&!u?(0,R.jsx)(`div`,{className:`text-[13px] text-muted`,children:o(`Nothing yet. Tell {name} “when the landlord writes back, summarise it and draft a reply” or “half an hour before any review, brief me”.`,{name:n})}):(0,R.jsx)(`ul`,{className:`space-y-1.5`,children:f.map(t=>{let n=fm[t.kind];return(0,R.jsxs)(`li`,{className:`flex items-start gap-2.5 rounded-2xl bg-surface-2/60 px-3 py-2`,children:[(0,R.jsx)(n,{size:15,className:`text-muted shrink-0 mt-[3px]`}),(0,R.jsxs)(`div`,{className:`min-w-0 flex-1`,children:[(0,R.jsx)(`div`,{className:`text-[13.5px] font-medium`,children:pm(t,o)}),(0,R.jsx)(`div`,{className:`text-[12px] leading-snug text-fg/80 line-clamp-2`,children:t.text}),(0,R.jsxs)(`div`,{className:`text-[11.5px] text-muted flex flex-wrap items-center gap-x-1.5`,children:[t.fired>0?(0,R.jsxs)(`span`,{children:[o(`fired {n}×`,{n:t.fired}),t.last_fired_at&&` · ${e(t.last_fired_at)}`]}):(0,R.jsx)(`span`,{children:o(`not fired yet`)}),t.kind===`hook`&&t.url&&(0,R.jsxs)(`button`,{type:`button`,onClick:()=>void g(t),className:`inline-flex items-center gap-1 text-accent font-medium`,children:[(0,R.jsx)(ut,{size:11}),` `,o(`Copy URL`)]})]})]}),(0,R.jsx)(`button`,{type:`button`,onClick:()=>void h(t),disabled:c!==null,"aria-label":o(`Run now: {text}`,{text:t.text}),className:`rounded-full bg-accent/12 p-2 text-accent disabled:opacity-50`,children:c===t.id?(0,R.jsx)(A,{size:15,className:`animate-spin`}):(0,R.jsx)(Gt,{size:15})}),(0,R.jsx)(`button`,{type:`button`,onClick:()=>void m(t),disabled:c!==null,"aria-label":o(`Cancel: {text}`,{text:t.text}),className:`rounded-full p-2 text-muted hover:text-fg disabled:opacity-50`,children:(0,R.jsx)(Fe,{size:15})})]},t.id)})}),p&&(0,R.jsx)(`div`,{className:i(`mt-1.5 text-[12px]`,t.mail_error?`text-rose-500`:`text-muted`),children:t.mail_error?o(`The inbox could not be read: {error}`,{error:t.mail_error}):t.mail_checked_at?o(`Inbox checked {when}; {name} looks every {n} min.`,{when:e(t.mail_checked_at),name:n,n:t.mail_poll_minutes}):o(`{name} will look at the inbox shortly, then every {n} min.`,{name:n,n:t.mail_poll_minutes})}),(0,R.jsx)(`div`,{className:`mt-1.5 text-[12px] text-muted`,children:o(`Each time it happens {name} does the work in the chat it was set from and reports in the Feed. A mail or a request is treated as data, never as instructions.`,{name:n})})]})}function hm({available:e,onDone:t,onCancel:n}){let{toast:r}=E(),a=s(),o=[`mail`,`event`,`hook`].find(t=>e[t])??`hook`,[c,l]=(0,L.useState)(o),[u,d]=(0,L.useState)(``),[f,p]=(0,L.useState)(`30`),[m,h]=(0,L.useState)(``),[g,_]=(0,L.useState)(!1),[v,y]=(0,L.useState)(null),b=async()=>{if(m.trim()){_(!0);try{let e=await N.createTrigger({kind:c,text:m.trim(),match:u.trim(),lead_minutes:Number(f)||30});e.kind===`hook`&&e.url?y(e):t()}catch(e){r(e.message)}finally{_(!1)}}},x=`h-9 rounded-xl bg-surface border border-border px-3 text-[13px] outline-none focus:border-accent`;if(v)return(0,R.jsxs)(`div`,{className:`mb-2 rounded-2xl border border-border p-3 space-y-2`,children:[(0,R.jsx)(`div`,{className:`text-[13.5px] font-medium`,children:a(`Webhook ready`)}),(0,R.jsx)(`div`,{className:`text-[12.5px] text-muted`,children:a(`POST anything to this URL and the work starts. The key is in the URL; share it only with the program that will call it.`)}),(0,R.jsx)(`code`,{className:`block break-all rounded-xl bg-surface-2 px-3 py-2 text-[12px]`,children:v.url}),(0,R.jsxs)(`div`,{className:`flex justify-end gap-2 pt-0.5`,children:[(0,R.jsx)(`button`,{type:`button`,onClick:()=>void navigator.clipboard.writeText(v.url??``).then(()=>r(a(`Webhook URL copied`)),()=>r(v.url??``)),className:`rounded-full px-3 py-1.5 text-[13px] text-accent font-medium`,children:a(`Copy`)}),(0,R.jsx)(`button`,{type:`button`,onClick:t,className:`rounded-full bg-accent px-3.5 py-1.5 text-[13px] font-medium text-accent-fg`,children:a(`Done`)})]})]});let S=[[`mail`,a(`New mail`)],[`event`,a(`Before an event`)],[`hook`,a(`Webhook`)]];return(0,R.jsxs)(`div`,{className:`mb-2 rounded-2xl border border-border p-3 space-y-2`,children:[(0,R.jsx)(gm,{options:S,value:c,onChange:e=>l(e)}),!e[c]&&(0,R.jsx)(`div`,{className:`text-[12.5px] text-rose-500`,children:a(c===`mail`?`Connect a mailbox under Connections first.`:`Add a calendar under Connections first.`)}),(0,R.jsxs)(`div`,{className:`flex gap-1.5`,children:[(0,R.jsx)(`input`,{value:u,onChange:e=>d(e.target.value),placeholder:a(c===`mail`?`Words in the sender or subject (empty: any mail)`:c===`event`?`Words in the title or place (empty: any event)`:`A name for this hook`),className:i(x,`min-w-0 flex-1`)}),c===`event`&&(0,R.jsxs)(`label`,{className:`flex items-center gap-1 text-[12.5px] text-muted`,children:[(0,R.jsx)(`input`,{type:`number`,min:0,max:1440,value:f,onChange:e=>p(e.target.value),className:i(x,`w-[64px] px-2`),"aria-label":a(`Minutes before`)}),a(`min before`)]})]}),(0,R.jsx)(`input`,{value:m,onChange:e=>h(e.target.value),placeholder:a(`What should be done each time…`),className:i(x,`w-full h-10 text-[14px]`)}),(0,R.jsx)(`div`,{className:`text-[12px] text-muted`,children:a(`When {condition}`,{condition:pm({kind:c,match:u.trim(),lead_minutes:Number(f)||30},a)})}),(0,R.jsxs)(`div`,{className:`flex justify-end gap-2 pt-0.5`,children:[(0,R.jsx)(`button`,{type:`button`,onClick:n,className:`rounded-full px-3 py-1.5 text-[13px] text-muted`,children:a(`Cancel`)}),(0,R.jsx)(`button`,{type:`button`,onClick:()=>void b(),disabled:g||!m.trim()||!e[c],className:`rounded-full bg-accent px-3.5 py-1.5 text-[13px] font-medium text-accent-fg disabled:opacity-50`,children:a(g?`Saving…`:`Set trigger`)})]})]})}function gm({options:e,value:t,onChange:n}){return(0,R.jsx)(`div`,{className:`flex rounded-full bg-surface-2 p-0.5`,children:e.map(([e,r])=>(0,R.jsx)(`button`,{type:`button`,onClick:()=>n(e),className:i(`rounded-full px-2.5 py-1 transition`,t===e?`bg-surface shadow-sm font-medium`:`text-muted`),children:r},e))})}function _m(){let e=new Date(Date.now()+36e5);e.setMinutes(0,0,0);let t=e=>String(e).padStart(2,`0`);return`${e.getFullYear()}-${t(e.getMonth()+1)}-${t(e.getDate())}T${t(e.getHours())}:${t(e.getMinutes())}`}function vm(e){let[t,n]=(0,L.useState)(null),[r,i]=(0,L.useState)(null),a=async()=>{try{n(await N.activity(150)),i(null)}catch(e){i(e.message||`Could not load.`)}};return(0,L.useEffect)(()=>{if(!e)return;a();let t=window.setInterval(()=>void a(),4e3);return()=>window.clearInterval(t)},[e]),[t,a,r]}function ym({open:e}){let[t,n,r]=vm(e),{state:i}=E(),a=s(),o=i.profile?.name??`nanoMuse`,c=(t?.audit??[]).filter(e=>e.event===`tool_call`).reverse(),l=c.filter(e=>e.channel===`gui`).length;return(0,R.jsxs)(`div`,{className:`pb-2`,children:[(0,R.jsx)(`p`,{className:`text-[12.5px] text-muted mb-2`,children:a(`Every tool call goes through the Sentinel and is written to the audit log, including the ones it refused.`)}),l>0&&(0,R.jsx)(`p`,{className:`text-[12.5px] text-muted mb-2`,children:a(`On the phone's screen: {gui} of {total} steps ({pct}%). The screen is the last resort; a skill, a fetch or the browser comes first.`,{gui:String(l),total:String(c.length),pct:String(Math.round(l/c.length*100))})}),!t&&r&&(0,R.jsx)(Jp,{message:r,onRetry:()=>void n()}),!t&&!r&&(0,R.jsx)(`div`,{className:`py-10 flex justify-center text-muted`,children:(0,R.jsx)(A,{className:`animate-spin`,size:20})}),t&&c.length===0&&(0,R.jsx)(`div`,{className:`py-8 text-center text-muted text-[14px]`,children:a(`Nothing yet today. What you ask for and what {name} does about it shows up here.`,{name:o})}),(0,R.jsx)(`ul`,{className:`space-y-1.5`,children:c.map((e,t)=>(0,R.jsx)(Tm,{entry:e},`${e.ts}-${t}`))})]})}function bm({open:e}){let{state:t,toast:n}=E(),r=s(),[i,a]=vm(e),o=async()=>{if(window.confirm(r(`Forget every permission you granted? {name} will ask again next time.`,{name:t.profile?.name??`nanoMuse`})))try{await N.resetApprovals(),await a(),n(r(`Permissions reset`))}catch(e){n(e.message)}},c=async e=>{try{await N.revokeGrant(e.key),await a(),n(r(`Revoked: {subject}`,{subject:pp(e.tool,e.target)}))}catch(e){n(e.message)}},l=t.settings?.sentinel.mode;return(0,R.jsxs)(`div`,{className:`space-y-4 pb-2`,children:[(0,R.jsxs)(`div`,{className:`rounded-2xl border border-border p-3.5`,children:[(0,R.jsxs)(`div`,{className:`flex items-center gap-2 font-medium`,children:[(0,R.jsx)(Qt,{size:18,className:`text-accent`}),` `,r(`Sentinel mode:`),` `,(0,R.jsx)(`span`,{className:`capitalize`,children:l===`ask`?r(`balanced`):l===`strict`?r(`cautious`):l===`auto`?r(`hands-off`):l})]}),(0,R.jsxs)(`p`,{className:`mt-1 text-[12.5px] text-muted`,children:[l===`ask`&&r(`Safe and moderate actions run freely; anything sensitive (email, shell, purchases) waits for you.`),l===`strict`&&r(`Moderate and sensitive actions both wait for your approval.`),l===`auto`&&r(`Everything is approved automatically except explicit deny rules. Use with care.`)]}),i?.tainted&&(0,R.jsxs)(`p`,{className:`mt-2 text-[12.5px] text-amber-600 dark:text-amber-300 flex items-center gap-1.5`,children:[(0,R.jsx)($t,{size:14}),` `,r(`Private data was read this session: network calls to new destinations need approval.`)]})]}),(0,R.jsx)(Cm,{grants:i?.grants??[],onRevoke:c}),(0,R.jsx)(wm,{title:r(`Always ask (from config)`),tools:t.settings?.sentinel.always_ask_tools??[],muted:!0}),(i?.grants.length??0)>0&&(0,R.jsx)(`button`,{type:`button`,onClick:()=>void o(),className:`w-full rounded-2xl border border-border py-2.5 text-[14px] font-medium`,children:r(`Reset all granted permissions`)})]})}function xm(e,t){switch(e.scope){case`conversation`:return t(`for this conversation`);case`session`:return t(`until restart`);case`24h`:return e.expires_at?t(`until {time}`,{time:u(e.expires_at)}):t(`for 24 hours`);case`always`:return t(`always`);default:return e.scope}}var Sm=[`sensitive`,`moderate`,`low`,`safe`];function Cm({grants:e,onRevoke:t}){let n=s(),{state:r}=E(),i=e=>r.settings?.tools.find(t=>t.name===e)?.risk??`moderate`,a=Sm.map(t=>({risk:t,rows:e.filter(e=>i(e.tool)===t)})).filter(e=>e.rows.length>0);return(0,R.jsx)(`div`,{className:`space-y-3`,children:e.length===0?(0,R.jsxs)(`div`,{children:[(0,R.jsx)(`div`,{className:`text-[12px] uppercase tracking-wide text-muted font-semibold mb-1.5`,children:n(`Permissions you granted`)}),(0,R.jsx)(`div`,{className:`text-[13px] text-muted`,children:n(`No standing approvals. When you answer “always allow” to a risky step, it is listed here and can be revoked; approvals you give once are not kept.`)})]}):a.map((e,r)=>(0,R.jsxs)(`div`,{children:[(0,R.jsxs)(`div`,{className:`text-[12px] uppercase tracking-wide text-muted font-semibold mb-1.5`,children:[r===0?`${n(`Permissions you granted`)} · `:``,n(e.risk)]}),(0,R.jsx)(`ul`,{className:`space-y-1.5`,children:e.rows.map(e=>(0,R.jsxs)(`li`,{className:`flex items-center gap-2.5 rounded-2xl bg-surface-2/60 px-3 py-2`,children:[(0,R.jsx)(`span`,{className:`text-accent`,children:sp(e.tool,15)}),(0,R.jsxs)(`div`,{className:`min-w-0 flex-1`,children:[(0,R.jsx)(`div`,{className:`text-[13.5px] font-medium truncate`,children:pp(e.tool,e.target)}),(0,R.jsxs)(`div`,{className:`text-[11.5px] text-muted`,children:[e.tool,` · `,xm(e,n),` · `,n(`granted {time}`,{time:u(e.granted_at)})]})]}),(0,R.jsx)(`button`,{type:`button`,"aria-label":n(`Revoke {what}`,{what:mp(e.scope,e.tool,e.target)}),onClick:()=>t(e),className:`rounded-full p-1.5 text-muted hover:bg-surface active:scale-95`,children:(0,R.jsx)(Fe,{size:15})})]},e.key))})]},e.risk))})}function wm({title:e,tools:t,muted:n}){let r=s();return(0,R.jsxs)(`div`,{children:[(0,R.jsx)(`div`,{className:`text-[12px] uppercase tracking-wide text-muted font-semibold mb-1.5`,children:e}),t.length===0?(0,R.jsx)(`div`,{className:`text-[13px] text-muted`,children:r(`None`)}):(0,R.jsx)(`div`,{className:`flex flex-wrap gap-1.5`,children:t.map(e=>(0,R.jsxs)(`span`,{className:i(`rounded-full px-2.5 py-1 text-[12.5px] flex items-center gap-1`,n?`bg-surface-2 text-muted`:`bg-accent/12 text-accent`),children:[sp(e,12),` `,e]},e))})]})}function Tm({entry:e}){let t=s(),n=e.decision===`deny`,r=e.ok===!1&&!n;return(0,R.jsxs)(`li`,{className:`flex items-start gap-2.5 rounded-2xl bg-surface-2/60 px-3 py-2`,children:[(0,R.jsx)(`div`,{className:i(`mt-0.5`,n?`text-rose-500`:r?`text-amber-500`:`text-muted`),children:n||r?(0,R.jsx)(Ye,{size:15}):(0,R.jsx)(ke,{size:15})}),(0,R.jsxs)(`div`,{className:`min-w-0 flex-1`,children:[(0,R.jsxs)(`div`,{className:`flex items-center gap-2 text-[13.5px]`,children:[(0,R.jsx)(`span`,{className:`text-muted`,children:sp(e.tool??``,13)}),(0,R.jsx)(`span`,{className:`font-medium truncate`,children:e.summary||e.tool})]}),(0,R.jsxs)(`div`,{className:`mt-0.5 flex flex-wrap items-center gap-x-2 gap-y-0.5 text-[11.5px] text-muted`,children:[(0,R.jsx)(`span`,{children:u(e.ts)}),e.risk&&(0,R.jsx)(up,{risk:e.risk}),e.approved===!0&&(0,R.jsxs)(`span`,{className:`text-emerald-600 dark:text-emerald-300`,children:[t(`approved by you`),e.approval_scope&&e.approval_scope!==`once`?` (${e.approval_scope})`:``]}),e.approved==null&&e.approval_scope&&e.approval_scope!==`once`&&(0,R.jsx)(`span`,{className:`text-emerald-600 dark:text-emerald-300`,children:t(`covered by your {scope} permission`,{scope:e.approval_scope})}),n&&(0,R.jsx)(`span`,{className:`text-rose-500`,children:t(`blocked`)}),r&&(0,R.jsx)(`span`,{className:`text-amber-600`,children:t(`failed`)}),typeof e.duration_ms==`number`&&(0,R.jsxs)(`span`,{children:[(e.duration_ms/1e3).toFixed(1),`s`]})]}),n&&e.reasons&&e.reasons.length>0&&(0,R.jsx)(`div`,{className:`mt-0.5 text-[12px] text-muted`,children:e.reasons.map(v).join(` · `)})]})]})}function Em({title:e,actions:t=[],trailing:n,children:r}){let{state:i,setDrawer:a}=E(),o=s(),[c,l]=(0,L.useState)(!1),u=i.profile?.name||`nanoMuse`,d=i.pendingApprovals.length,f=d>0?d>1?o(`{n} approvals waiting for you`,{n:d}):o(`1 approval waiting for you`):i.status.state===`working`?i.status.detail||o(`On it`):i.status.state===`waiting`?o(`Waiting for you`):null;return(0,R.jsxs)(R.Fragment,{children:[(0,R.jsx)(te,{profile:i.profile,status:i.status,name:u,statusLine:f,statusTone:f?`accent`:`muted`,spinning:i.status.state===`working`&&d===0,badge:d,onAvatar:()=>l(!0),leading:(0,R.jsx)(j,{onClick:()=>a(!0),label:o(`Chats`),className:`wide:invisible`,children:(0,R.jsx)(Ot,{size:22})}),trailing:n??(0,R.jsx)(Dm,{actions:t})}),(e||r)&&(0,R.jsxs)(`div`,{className:`flex shrink-0 items-center gap-3 pr-5`,children:[(0,R.jsx)(k,{className:`flex-1`,children:e}),r]}),(0,R.jsx)(am,{open:c,onClose:()=>l(!1)})]})}function Dm({actions:e=[]}){let{setTab:t}=E(),n=s(),[r,i]=(0,L.useState)(!1),a=(0,L.useRef)(null);(0,L.useEffect)(()=>{if(!r)return;let e=e=>{a.current?.contains(e.target)||i(!1)},t=e=>{e.key===`Escape`&&i(!1)};return window.addEventListener(`pointerdown`,e),window.addEventListener(`keydown`,t),()=>{window.removeEventListener(`pointerdown`,e),window.removeEventListener(`keydown`,t)}},[r]);let o=e=>{i(!1),t(e)},c=[...e.map(e=>({label:e.label,onClick:()=>{i(!1),e.onClick()}})),{label:n(`Memory`),onClick:()=>o(`memory`)},{label:n(`Settings`),onClick:()=>o(`you`)}];return(0,R.jsxs)(`div`,{ref:a,className:`relative`,children:[(0,R.jsx)(j,{onClick:()=>i(e=>!e),label:n(`More`),expanded:r,children:(0,R.jsx)(pt,{size:22})}),r&&(0,R.jsx)(`ul`,{role:`menu`,className:`absolute right-0 top-12 z-30 min-w-[180px] overflow-hidden rounded-2xl border border-border bg-surface py-1 shadow-xl`,children:c.map(e=>(0,R.jsx)(`li`,{children:(0,R.jsx)(`button`,{type:`button`,role:`menuitem`,onClick:e.onClick,className:`w-full px-4 py-2.5 text-left text-[14.5px] hover:bg-surface-2`,children:e.label})},e.label))})]})}var Om=`nanomuse-naming`;function km(e){return e.replace(/[.*+?^${}()|[\]\\]/g,`\\$&`)}function Am(e,t,n=!1){let r="```"+t,i=e;if(i.includes(r)){let e=RegExp("```"+km(t)+"[ \\t]*\\r?\\n[\\s\\S]*?```",`g`);i=i.replace(e,``);let n=i.lastIndexOf(r);n>=0&&(i=i.slice(0,n))}if(n){let e=i.lastIndexOf("```");e>=0&&r.startsWith(i.slice(e))&&(i=i.slice(0,e))}return i===e?e:i.replace(/\s+$/,``)}function jm(e,t=!1){return Am(e,Om,t)}function Mm(e){return e.filter(e=>!e.this&&e.kind!==`web`&&e.name.trim()!==``)}function Nm(e){let t=/^@([^\s,:;,:;]*)$/.exec(e);return t?t[1]:null}function Pm(e,t,n=6){let r=Nm(e);if(r===null)return[];let i=r.toLowerCase();return Mm(t).filter(e=>e.name.toLowerCase().startsWith(i)).sort((e,t)=>Number(t.online)-Number(e.online)||e.name.localeCompare(t.name)).slice(0,n)}function Fm(e,t){let n=e.trimStart();if(!n.startsWith(`@`))return null;let r=n.slice(1),i=r.toLowerCase(),a=Mm(t),o=a.filter(e=>{let t=e.name.trim().toLowerCase();if(!i.startsWith(t))return!1;let n=r.charAt(t.length);return n===``||/[\s,:;,:;]/.test(n)}).sort((e,t)=>t.name.length-e.name.length);if(o[0])return o[0];let s=/^[^\s,:;,:;]+/.exec(r)?.[0]?.toLowerCase()??``;if(!s)return null;let c=a.filter(e=>e.name.trim().toLowerCase().startsWith(s));if(c.length===1)return c[0];let l=c.filter(e=>e.online);return l.length===1?l[0]:null}var Im=`nm.show_steps`;function Lm(){try{return localStorage.getItem(Im)!==`0`}catch{return!0}}var Rm=Lm(),zm=new Set;function Bm(){return Rm}function Vm(e){Rm=e;try{localStorage.setItem(Im,e?`1`:`0`)}catch{}zm.forEach(e=>e())}function Hm(e){return zm.add(e),()=>zm.delete(e)}function Um(){return(0,L.useSyncExternalStore)(Hm,Bm,Bm)}function Wm(){let{state:e,send:t,sendViaCloud:n,decide:r,loadEvents:i,openFile:a,toast:o,setDrawer:c,setTab:l}=E(),u=s(),{profile:d,status:f,activeThread:p,threads:m}=e,h=e.events[p],g=(0,L.useMemo)(()=>h??[],[h]),_=h!==void 0,v=e.streams[p],b=m.find(e=>e.id===p),[x,S]=(0,L.useState)(!1),[C,w]=(0,L.useState)(null),T=d?.name??`nanoMuse`,D=b?.device?e.hub?.devices.find(e=>e.id===b.device)?.online??null:null,O=nh(e.working[p]),k=(0,L.useRef)(null),ee=(0,L.useRef)(null),A=(0,L.useRef)(!0),[M,ne]=(0,L.useState)(!1),[re,P]=(0,L.useState)(!1),ie=(0,L.useRef)(null),[ae,oe]=(0,L.useState)(0);(0,L.useLayoutEffect)(()=>{let e=ie.current;if(!e||(oe(e.offsetHeight),typeof ResizeObserver>`u`))return;let t=new ResizeObserver(()=>oe(e.offsetHeight));return t.observe(e),()=>t.disconnect()},[]);let se=e.firstrun,ce=!!se&&se.phase!==`none`&&se.session_id===p,le=ce&&se.running,ue=y()===`zh-CN`?`zh`:`en`,[de,fe]=(0,L.useState)(null);(0,L.useEffect)(()=>{if(!ce||de?.lang===ue)return;let e=!0;return N.firstrun(ue).then(t=>e&&t.intro&&fe({lang:ue,lines:t.intro})).catch(()=>void 0),()=>{e=!1}},[ce,ue,de?.lang]);let pe=e=>{N.firstrunPick(e).then(()=>t(p,e)).catch(e=>o(e.message||u(`Could not send`)))},me=()=>window.dispatchEvent(new Event(`nanomuse:quick-chat`)),[he,ge]=(0,L.useState)(null),_e=e.settings?.onboarded===!0,ve=(0,L.useRef)(!1),be=(0,L.useRef)(!1);(0,L.useEffect)(()=>{if(b?.busy){ve.current||(be.current=le),ve.current=!0;return}ve.current&&(ve.current=!1,_e&&!be.current&&!le&&ch(g)&&ge(Se()))},[b?.busy,g,_e,le]);let[xe,Ce]=(0,L.useState)(null);(0,L.useEffect)(()=>{let{days:e,fresh:t}=ye();t&&Ce(e)},[]);let Te=(0,L.useCallback)(()=>{let e=k.current;e&&(e.scrollTop=e.scrollHeight,ne(!1),P(!1))},[]),Ee=(0,L.useCallback)(()=>{let e=k.current;if(!e)return;let t=e.scrollHeight-e.scrollTop-e.clientHeight;A.current=t<120,ne(t>400),P(t>8)},[]),De=(0,L.useRef)(null);(0,L.useLayoutEffect)(()=>{De.current!==p&&(De.current=p,A.current=!0),A.current&&Te()},[g,v?.text,p,Te]),(0,L.useEffect)(()=>{let e=k.current,t=ee.current;if(!e||!t||typeof ResizeObserver>`u`)return;let n=new ResizeObserver(()=>{A.current?Te():Ee()});return n.observe(e),n.observe(t),()=>n.disconnect()},[Te,Ee]);let Oe=()=>{let e=k.current;e&&e.scrollTo({top:e.scrollHeight,behavior:`smooth`})},ke=e.pendingApprovals.length,Ae=e.pendingApprovals.filter(e=>e.thread===p).length,je=(0,L.useMemo)(()=>{let e=!f.thread||f.thread===p;if(Ae>0&&!(e&&f.state===`working`))return Ae>1?u(`{n} approvals waiting for you`,{n:Ae}):u(`1 approval waiting for you`);if(!e)return b?.busy?u(`On it`):void 0;if(f.state===`idle`&&!b?.busy)return;if(f.detail)return f.detail;if(f.state===`waiting`)return u(`Waiting for you`);let t=sh(g);return t?u(`On it: {request}`,{request:t}):u(`On it`)},[f,b,p,Ae,g,u]),Ne=g.filter(e=>e.type===`approval`&&e.status===`pending`).length,Pe=Um(),Fe=(0,L.useMemo)(()=>Pe?g:g.filter(e=>e.type!==`tool`),[g,Pe]),Ie={signedIn:!!e.hub?.account.signed_in,chatOnCloud:!!e.settings?.llm.cloud,deviceChat:!!b?.device},Le=e=>{let t=ep(Fe,e,Ie);return t?()=>n(p,t.text,t.files):void 0},Re=(0,L.useMemo)(()=>Array.from(new Set(g.flatMap(e=>e.type===`artifact`?[e.path]:[]))),[g]);return(0,R.jsxs)(`div`,{className:`relative flex h-full flex-col`,children:[(0,R.jsx)(`div`,{ref:ie,className:`pointer-events-none absolute inset-x-0 top-0 z-10`,children:(0,R.jsx)(te,{scrim:!0,profile:d,status:f,name:T,statusLine:je,statusTone:f.state===`idle`&&!b?.busy?`muted`:`accent`,spinning:(f.state===`working`&&f.thread===p||!!b?.busy)&&Ae===0,badge:ke,onAvatar:()=>S(!0),leading:(0,R.jsx)(j,{onClick:()=>c(!0),label:u(`Chats`),dot:m.length>1&&p!==`main`,className:`wide:invisible`,children:(0,R.jsx)(Ot,{size:22})}),trailing:(0,R.jsx)(Dm,{actions:[{label:u(`Coding agents`),onClick:()=>l(`coding`)}]}),under:b&&b.id!==`main`?b.device?(0,R.jsxs)(`span`,{className:`flex max-w-full items-center gap-1 rounded-full bg-accent/12 px-2.5 py-0.5 text-[11.5px] font-medium text-accent`,children:[D===!1?(0,R.jsx)(`span`,{className:`h-1.5 w-1.5 rounded-full bg-border`}):(0,R.jsx)(`span`,{className:`h-1.5 w-1.5 rounded-full bg-emerald-500`}),(0,R.jsx)(`span`,{className:`truncate`,children:u(`on {device}`,{device:b.device_name||b.device})})]}):b.remote_from?(0,R.jsxs)(`span`,{className:`flex max-w-full items-center gap-1 rounded-full bg-surface-2 px-2.5 py-0.5 text-[11.5px] font-medium text-fg/80`,children:[(0,R.jsx)(It,{size:11}),` `,(0,R.jsx)(`span`,{className:`truncate`,children:u(`from {device}`,{device:b.remote_from.name})})]}):(0,R.jsx)(`span`,{className:`truncate rounded-full bg-surface-2 px-2.5 py-0.5 text-[11.5px] font-medium text-fg/80`,children:b.title}):void 0})}),(0,R.jsx)(`div`,{"aria-hidden":!0,className:`list-fade-top pointer-events-none absolute inset-x-0 top-0 z-[5] h-20`,style:{opacity:+!!re}}),(0,R.jsxs)(`div`,{ref:k,onScroll:Ee,className:`relative flex-1 overflow-y-auto px-3 pb-3`,children:[(0,R.jsxs)(`div`,{ref:ee,className:`space-y-2.5`,children:[(0,R.jsx)(`div`,{"aria-hidden":!0,style:{height:ae}}),e.hasMore[p]&&g.length>0&&(0,R.jsx)(`div`,{className:`flex justify-center`,children:(0,R.jsx)(`button`,{type:`button`,className:`text-[12.5px] text-accent px-3 py-1 rounded-full bg-surface-2`,onClick:()=>void i(p,g[0]?.id),children:u(`Load earlier messages`)})}),ce&&_&&!e.hasMore[p]&&de&&(0,R.jsx)(Fp,{lines:de.lines}),_&&g.length===0&&!v&&!ce&&(0,R.jsx)(ih,{name:T,device:b?.device?b.device_name||b.device:void 0,onSend:e=>t(p,e).catch(e=>o(e.message||u(`Could not send`)))}),Fe.map((e,t)=>(0,R.jsx)(Gm,{event:e,prev:Fe[t-1],name:T,onDecide:(t,n)=>r(e.id,t,n).catch(e=>o(e.message||u(`Could not send decision`))),onOpenFile:a,onOpenBrowser:w,files:Re,onCloudRetry:Le(t)},e.id)),v&&v.text&&(0,R.jsx)($m,{text:v.text,streaming:!0,files:Re,onOpenFile:a}),(b?.busy||f.state!==`idle`)&&!v?.text&&f.state!==`waiting`&&(0,R.jsx)(th,{label:b?.queued?u(`{n} queued`,{n:b.queued}):void 0}),ce&&se.phase===`ask_agent_name`&&!b?.busy&&(0,R.jsx)(Ip,{chips:se.chips,chosen:se.chosen,onPick:pe,onElse:me}),O&&!b?.busy&&(0,R.jsx)(rh,{who:O}),!b?.busy&&f.state===`idle`&&he!==null&&(0,R.jsx)(we,{moment:`tasks`,n:he,className:`mx-1 my-2`}),!b?.busy&&f.state===`idle`&&xe!==null&&(0,R.jsx)(we,{moment:`days_used`,n:xe,className:`mx-1 my-2`})]}),M&&(0,R.jsxs)(`button`,{type:`button`,onClick:Oe,className:`sticky bottom-2 left-1/2 -translate-x-1/2 rounded-full bg-ink text-ink-fg shadow px-3 py-1.5 text-[12.5px] font-medium flex items-center gap-1`,children:[(0,R.jsx)(Me,{size:14}),` `,u(`Latest`),Ne?` · ${u(`{n} approval`,{n:Ne})}`:``]})]}),(0,R.jsx)(Rf,{}),(0,R.jsx)(ah,{name:T,busy:!!b?.busy&&Ne===0,waiting:g.some(e=>e.type===`question`&&e.status===`pending`),onSend:(e,n)=>t(p,e,n).catch(e=>{throw o(e.message||u(`Could not send`)),e})}),(0,R.jsx)(am,{open:x,onClose:()=>S(!1)}),C&&(0,R.jsx)(Ap,{thread:p,eventId:C,onClose:()=>w(null)})]})}function Gm({event:e,prev:t,name:n,onDecide:r,onOpenFile:i,onOpenBrowser:a,files:o,onCloudRetry:s}){let c=qm(t,e)?(0,R.jsx)(Jm,{ts:e.ts}):null,l=(()=>{switch(e.type){case`user`:return(0,R.jsx)(Ym,{event:e,onOpenFile:i});case`assistant`:return e.quiet?(0,R.jsx)(eh,{text:e.text,about:e.about,ts:e.ts}):(0,R.jsx)($m,{text:e.text,reasoning:e.reasoning,continued:t?.type===`assistant`,files:o,onOpenFile:i,spoken:e.via===`call`,modelUsed:e.model_used});case`tool`:return(0,R.jsx)(fp,{event:e});case`approval`:return(0,R.jsx)(hp,{event:e,name:n,onDecide:r});case`question`:return(0,R.jsx)(gp,{event:e,name:n});case`notice`:return(0,R.jsx)(vp,{event:e,onCloudRetry:s});case`artifact`:return(0,R.jsx)(Ep,{event:e,onOpen:i});case`browser`:return(0,R.jsx)(yp,{event:e,onOpen:a});case`hands`:return(0,R.jsx)(bp,{event:e,name:n});case`hold`:return(0,R.jsx)(wp,{event:e,name:n});case`avatar`:return(0,R.jsx)(np,{event:e,name:n});default:return null}})();return l?(0,R.jsxs)(R.Fragment,{children:[c,l]}):null}var Km=6e5;function qm(e,t){return t.ts?!e?.ts||new Date(t.ts).getTime()-new Date(e.ts).getTime()>=Km:!1}function Jm({ts:e}){let t=l(e);return t?(0,R.jsx)(`div`,{className:`pt-2 pb-0.5 text-center text-[11.5px] font-medium text-muted`,children:t}):null}function Ym({event:e,onOpenFile:t}){let n=s(),r=e.files??[],a=r.filter(e=>e.kind===`image`),o=r.filter(e=>e.kind!==`image`);return(0,R.jsxs)(`div`,{className:`rise flex flex-col items-end pl-12`,children:[e.via===`call`?(0,R.jsxs)(`span`,{className:`mb-1 flex items-center gap-1 text-[11.5px] font-medium text-muted`,children:[(0,R.jsx)(Ut,{size:11}),` `,n(`said on a call`)]}):e.via?(0,R.jsx)(`span`,{className:`mb-1 text-[11.5px] font-medium text-muted`,children:n(`asked from {device}`,{device:e.via})}):e.to_device_name||e.to_device?(0,R.jsxs)(`span`,{className:`mb-1 flex items-center gap-1 text-[11.5px] font-medium text-accent`,children:[(0,R.jsx)(It,{size:11}),` `,n(`to {device}`,{device:e.to_device_name||e.to_device||``})]}):(e.via_device_name||e.via_device)&&(0,R.jsx)(`span`,{className:`mb-1 text-[11.5px] font-medium text-muted`,children:n(`From {device}`,{device:e.via_device_name||e.via_device||``})}),a.length>0&&(0,R.jsx)(`div`,{className:`mb-1 flex max-w-full flex-wrap justify-end gap-1.5`,children:a.map(e=>(0,R.jsx)(`button`,{type:`button`,onClick:()=>t(e.path),"aria-label":e.name,className:i(`overflow-hidden rounded-2xl border border-border/60 bg-surface-2 shadow-sm active:scale-[0.98] transition`,a.length===1?`max-h-64 max-w-[240px]`:`h-28 w-28`),children:(0,R.jsx)(`img`,{src:h(e.path),alt:e.name,loading:`lazy`,className:i(`object-cover`,a.length===1?`max-h-64 w-auto max-w-full`:`h-full w-full`)})},e.path))}),o.map(e=>(0,R.jsxs)(`button`,{type:`button`,onClick:()=>t(e.path),className:`mb-1 flex max-w-full items-center gap-2.5 rounded-2xl border border-border bg-surface px-3 py-2 text-left shadow-sm hover:bg-surface-2 active:scale-[0.98] transition`,children:[(0,R.jsx)(`span`,{className:`rounded-xl bg-accent/12 p-2 text-accent`,children:e.kind===`data`?(0,R.jsx)(cn,{size:17}):(0,R.jsx)(mt,{size:17})}),(0,R.jsxs)(`span`,{className:`min-w-0`,children:[(0,R.jsx)(`span`,{className:`block truncate text-[14px] font-medium`,children:e.name}),(0,R.jsx)(`span`,{className:`block text-[11.5px] text-muted`,children:Xm(e.size)})]})]},e.path)),e.text&&(0,R.jsx)(`div`,{className:`bubble-user max-w-full rounded-[20px] bg-bubble-user px-4 py-2.5 text-bubble-user-fg`,children:(0,R.jsx)(`div`,{className:`md text-[15px] leading-[1.45] whitespace-pre-wrap break-words`,children:e.text})})]})}function Xm(e){return e<1024?`${e} B`:e<1048576?`${Math.round(e/1024)} KB`:`${(e/1048576).toFixed(1)} MB`}function Zm(e){let t=e.toLowerCase().split(`.`).pop()??``;return[`csv`,`tsv`,`json`,`xlsx`,`xls`].includes(t)?`data`:`other`}var Qm=`image/*,.pdf,.txt,.md,.csv,.tsv,.json,.log,.html,.xml,.yaml,.yml,.toml,.ics,.vcf,.xlsx,.xls,.docx`;function $m({text:e,reasoning:t,streaming:n,continued:r,files:a,onOpenFile:o,spoken:c,modelUsed:l}){let[u,d]=(0,L.useState)(!1),f=s(),p=(0,L.useMemo)(()=>mf(jm(e,!!n)),[e,n]);return p.length===0&&!n&&!t?null:(0,R.jsx)(`div`,{className:i(`rise flex items-end gap-2 pr-10`,r&&`-mt-1`),children:(0,R.jsxs)(`div`,{className:`min-w-0 max-w-full`,children:[t&&(0,R.jsx)(`button`,{type:`button`,className:`mb-1 ml-1 text-[12px] text-muted`,onClick:()=>d(e=>!e),children:f(u?`Hide thinking`:`Show thinking`)}),t&&u&&(0,R.jsx)(`div`,{className:`mb-1.5 rounded-2xl bg-surface-2/70 px-3 py-2 text-[13px] text-muted whitespace-pre-wrap break-words`,children:t}),p.map((e,t)=>e.bare?(0,R.jsx)(`div`,{className:`my-1 max-w-full`,children:(0,R.jsx)(hf,{text:e.text,files:a,onOpenFile:o})},t):(0,R.jsxs)(`div`,{className:i(`my-1 max-w-[340px] rounded-[20px] bg-bubble-agent px-3.5 py-2.5 wide:max-w-[600px]`,c&&`border border-accent/15`),children:[c&&t===0&&(0,R.jsxs)(`div`,{className:`mb-0.5 flex items-center gap-1 text-[11px] font-medium text-accent/80`,children:[(0,R.jsx)(Ut,{size:10}),` `,f(`said on a call`)]}),(0,R.jsx)(hf,{text:e.text,files:a,onOpenFile:o}),n&&t===p.length-1&&(0,R.jsx)(`span`,{className:`inline-block w-1.5 h-4 ml-0.5 align-middle bg-accent/70 animate-pulse rounded-sm`})]},t)),p.length===0&&n&&(0,R.jsx)(`div`,{className:`my-1 rounded-[20px] bg-bubble-agent px-3.5 py-2.5`,children:(0,R.jsx)(`span`,{className:`inline-block w-1.5 h-4 align-middle bg-accent/70 animate-pulse rounded-sm`})}),l&&!n&&(0,R.jsx)(`div`,{className:`ml-1 text-[11px] text-muted`,children:f(`Answered by nanoMuse Cloud this time ({model})`,{model:l})})]})})}function eh({text:e,about:n,ts:r}){let[i,a]=(0,L.useState)(!1),o=s(),c=n?t(n.replace(/^Working on your goal: /,``)):o(`background check`);return(0,R.jsx)(`div`,{className:`rise flex justify-center px-6`,children:(0,R.jsxs)(`button`,{type:`button`,onClick:()=>a(e=>!e),className:`max-w-full rounded-2xl px-3 py-1.5 text-[12px] text-muted text-center leading-snug`,children:[(0,R.jsxs)(`span`,{className:`inline-flex items-center gap-1.5`,children:[(0,R.jsx)(Rt,{size:12}),` `,o(`Checked on {label}: nothing new`,{label:c}),r?` · ${u(r)}`:``]}),i&&(0,R.jsx)(`span`,{className:`block mt-1 text-left whitespace-pre-wrap text-[12.5px]`,children:e})]})})}function th({label:e}){return(0,R.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,R.jsxs)(`div`,{className:`rounded-[20px] rounded-bl-md bg-bubble-agent px-3.5 py-2.5 flex items-center gap-1`,children:[(0,R.jsx)(`span`,{className:`typing-dot h-2 w-2 rounded-full bg-muted`}),(0,R.jsx)(`span`,{className:`typing-dot h-2 w-2 rounded-full bg-muted`}),(0,R.jsx)(`span`,{className:`typing-dot h-2 w-2 rounded-full bg-muted`})]}),e&&(0,R.jsx)(`span`,{className:`text-[12px] text-muted`,children:e})]})}function nh(e){let t=e?e.at*1e3+re:0,[n,r]=(0,L.useState)(0);return(0,L.useEffect)(()=>{if(!t)return;let e=t-Date.now();if(e<=0){r(t);return}let n=window.setTimeout(()=>r(t),e+50);return()=>window.clearTimeout(n)},[t]),!e||n===t?null:e}function rh({who:e}){let t=s();return(0,R.jsxs)(`div`,{className:`flex items-center gap-1.5 px-1 text-[12px] text-muted`,children:[(0,R.jsx)(A,{size:12,className:`animate-spin`}),(0,R.jsx)(`span`,{children:t(`{device} is working…`,{device:e.device_name||e.device})})]})}function ih({name:e,device:t,onSend:n}){let r=s(),i=t?[r(`What is on your screen right now?`),r(`Which folder are you in, and what is in it?`),r(`Check for updates and tell me what needs a restart`)]:[r(`What can you do for me?`),r(`Plan my week: ask me what's on my plate`),r(`Research and compare two options for me`),r(`Set up a long-term goal and track it`)];return(0,R.jsxs)(`div`,{className:`flex flex-col items-center text-center px-6 pt-10 pb-6 gap-3`,children:[(0,R.jsx)(`div`,{className:`text-[20px] font-semibold`,children:t?r(`This chat goes to {device}.`,{device:t}):r(`Hi, I'm {name}.`,{name:e})}),(0,R.jsx)(`p`,{className:`text-muted text-[14.5px] leading-snug max-w-sm`,children:t?r(`Whatever you ask here, the {name} on {device} does where it is: its shell, its files, its screen. Every step shows up here, and anything that needs an approval asks you here.`,{name:e,device:t}):r(`I don't just answer; I get things done: research, plans, files, code, email, long-running goals. Everything I do shows up here, and anything hard to undo waits for your approval.`)}),(0,R.jsx)(`div`,{className:`mt-2 flex flex-wrap justify-center gap-2`,children:i.map(e=>(0,R.jsx)(`button`,{type:`button`,onClick:()=>n(e),className:`rounded-full bg-surface-2 px-3.5 py-1.5 text-[13.5px] hover:bg-border/60`,children:e},e))})]})}function ah({name:e,busy:t,waiting:n,onSend:r}){let{state:a,draft:o,draftFiles:c,toast:l}=E(),[u,d]=(0,L.useState)(``),[f,p]=(0,L.useState)(!1),m=(0,L.useRef)(``),g=Np((0,L.useCallback)((e,t)=>{let n=m.current,r=n&&!/\s$/.test(n)?` `:``;d(n+r+e+t)},[]),(0,L.useCallback)(e=>l(e),[l])),_=()=>{g.listening||(m.current=u),g.toggle()},[v,y]=(0,L.useState)([]),[b,x]=(0,L.useState)([]);(0,L.useEffect)(()=>{if(!a.draftFiles)return;let e=a.draftFiles.map(e=>({key:`shared-${e.path}`,file:new File([],e.name),preview:e.kind===`image`?h(e.path):null,info:e,error:null}));x(t=>[...t.filter(t=>!e.some(e=>e.key===t.key)),...e].slice(0,10)),c(null)},[a.draftFiles]);let S=(0,L.useRef)(null),C=(0,L.useRef)(null),w=s();(0,L.useEffect)(()=>()=>b.forEach(e=>e.preview?.startsWith(`blob:`)&&URL.revokeObjectURL(e.preview)),[b]),(0,L.useEffect)(()=>{let e=()=>S.current?.focus();return window.addEventListener(`nanomuse:quick-chat`,e),()=>window.removeEventListener(`nanomuse:quick-chat`,e)},[]);let T=e=>{let t=Array.from(e).slice(0,Math.max(0,10-b.length));if(t.length===0)return;let n=t.map(e=>({key:`${e.name}-${e.size}-${e.lastModified}-${Math.random().toString(36).slice(2,7)}`,file:e,preview:e.type.startsWith(`image/`)?URL.createObjectURL(e):null,info:null,error:null}));x(e=>[...e,...n]);for(let e of n)N.upload(e.file).then(t=>x(n=>n.map(n=>n.key===e.key?{...n,info:t}:n))).catch(t=>{let n=t.message?P(t.message):w(`Upload failed`);x(t=>t.map(t=>t.key===e.key?{...t,error:n}:t)),l(n)})},D=e=>x(t=>t.filter(t=>t.key!==e)),O=b.some(e=>!e.info&&!e.error),k=b.flatMap(e=>e.info?[e.info.path]:[]);(0,L.useEffect)(()=>{let e=S.current;e&&(e.style.height=`0px`,e.style.height=`${Math.min(e.scrollHeight,160)}px`)},[u]),(0,L.useEffect)(()=>{if(a.draft===null)return;d(a.draft),o(null);let e=S.current;e&&(e.focus(),e.setSelectionRange(e.value.length,e.value.length))},[a.draft]);let ee=a.settings?.skills?.enabled!==!1;(0,L.useEffect)(()=>{ee&&N.skills().then(e=>y(e.skills.filter(e=>e.enabled))).catch(()=>y([]))},[ee,a.skillsVersion]);let j=/^\/([a-z0-9-]*)$/i.exec(u),M=j?v.filter(e=>e.name.startsWith(j[1].toLowerCase())).slice(0,6):[],te=e=>{d(`/${e.name} `),S.current?.focus()},ne=a.hub?.devices??[],re=Pm(u,ne),ie=re.length===0?Fm(u,ne):null,ae=e=>{d(`@${e.name} `),S.current?.focus()},oe=e=>{e?.preventDefault();let t=u.trim();if(!t&&k.length===0||O||f)return;g.listening&&g.stop();let n=b;p(!0),d(``),x([]),S.current?.focus(),r(t,k).catch(()=>{d(e=>e||t),x(e=>e.length?e:n)}).finally(()=>p(!1))};return(0,R.jsxs)(`form`,{onSubmit:oe,className:`shrink-0 bg-bg px-3 pt-1.5 pb-1`,children:[t&&!n&&(0,R.jsx)(`div`,{className:`px-2 pb-1 text-[12px] text-muted`,children:w(`{name} is working; anything you send now is picked up right away.`,{name:e})}),M.length>0&&(0,R.jsx)(`ul`,{className:`mb-2 max-h-72 overflow-y-auto rounded-3xl border border-border/70 bg-surface shadow-lg divide-y divide-border/70`,role:`listbox`,"aria-label":w(`Skills`),children:M.map(e=>(0,R.jsx)(`li`,{children:(0,R.jsxs)(`button`,{type:`button`,onClick:()=>te(e),className:`flex w-full items-center gap-3 px-4 py-2.5 text-left hover:bg-surface-2/70 active:bg-surface-2`,children:[(0,R.jsx)(gn,{size:16,className:`shrink-0 text-accent`}),(0,R.jsxs)(`span`,{className:`min-w-0 flex-1`,children:[(0,R.jsxs)(`span`,{className:`block text-[14px] font-medium`,children:[`/`,e.name]}),(0,R.jsx)(`span`,{className:`block truncate text-[12.5px] text-muted`,children:e.description})]})]})},e.name))}),re.length>0&&(0,R.jsx)(`ul`,{className:`mb-2 max-h-72 overflow-y-auto rounded-3xl border border-border/70 bg-surface shadow-lg divide-y divide-border/70`,role:`listbox`,"aria-label":w(`Devices`),children:re.map(e=>(0,R.jsx)(`li`,{children:(0,R.jsxs)(`button`,{type:`button`,onClick:()=>ae(e),className:`flex w-full items-center gap-3 px-4 py-2.5 text-left hover:bg-surface-2/70 active:bg-surface-2`,children:[(0,R.jsx)(`span`,{className:`shrink-0 text-accent`,children:e.kind===`computer`?(0,R.jsx)(Lt,{size:16}):(0,R.jsx)(tn,{size:16})}),(0,R.jsxs)(`span`,{className:`min-w-0 flex-1`,children:[(0,R.jsxs)(`span`,{className:`block text-[14px] font-medium`,children:[`@`,e.name]}),(0,R.jsx)(`span`,{className:`block truncate text-[12.5px] text-muted`,children:e.online?w(`Runs this there and reports back`):w(`Offline`)})]})]})},e.id))}),ie&&(0,R.jsxs)(`div`,{className:`flex items-center gap-1.5 px-2 pb-1 text-[12px] text-muted`,children:[(0,R.jsx)(It,{size:12}),` `,w(`This goes to {device}.`,{device:ie.name})]}),b.length>0&&(0,R.jsx)(`div`,{className:`mb-1 flex gap-2.5 overflow-x-auto px-1 pt-2.5 pb-1 pr-3`,role:`list`,"aria-label":w(`Attachments`),children:b.map(e=>(0,R.jsxs)(`div`,{role:`listitem`,className:i(`relative shrink-0 rounded-2xl border bg-surface-2`,e.error?`border-danger/60`:`border-border/70`),children:[e.preview?(0,R.jsx)(`img`,{src:e.preview,alt:e.file.name,className:`h-16 w-16 rounded-2xl object-cover`}):(0,R.jsxs)(`div`,{className:`flex h-16 w-40 items-center gap-2 px-2.5`,children:[(0,R.jsx)(`span`,{className:`rounded-xl bg-accent/12 p-1.5 text-accent`,children:Zm(e.file.name)===`data`?(0,R.jsx)(cn,{size:16}):(0,R.jsx)(mt,{size:16})}),(0,R.jsxs)(`span`,{className:`min-w-0`,children:[(0,R.jsx)(`span`,{className:`block truncate text-[12.5px] font-medium`,children:e.file.name}),(0,R.jsx)(`span`,{className:`block text-[11px] text-muted`,children:e.error?w(`Upload failed`):Xm(e.info?.size??e.file.size)})]})]}),!e.info&&!e.error&&(0,R.jsx)(`div`,{className:`absolute inset-0 flex items-center justify-center rounded-2xl bg-bg/50`,children:(0,R.jsx)(A,{size:18,className:`animate-spin text-accent`})}),(0,R.jsx)(`button`,{type:`button`,onClick:()=>D(e.key),"aria-label":w(`Remove`),className:`absolute -right-1.5 -top-1.5 flex h-6 w-6 items-center justify-center rounded-full border border-border bg-surface text-muted shadow-sm`,children:(0,R.jsx)(Fe,{size:13})})]},e.key))}),(0,R.jsxs)(`div`,{className:`flex items-end gap-2 rounded-[26px] border border-border bg-surface px-1.5 py-1.5 shadow-[0_2px_12px_-6px_rgba(0,0,0,0.12)] focus-within:border-fg/20`,children:[(0,R.jsx)(`input`,{ref:C,type:`file`,multiple:!0,accept:Qm,className:`hidden`,onChange:e=>{e.target.files&&T(e.target.files),e.target.value=``}}),(0,R.jsx)(`button`,{type:`button`,onClick:()=>C.current?.click(),"aria-label":w(`Attach a file`),className:`flex h-9 w-9 shrink-0 items-center justify-center rounded-full text-fg/70 transition hover:bg-surface-2 active:scale-95`,children:(0,R.jsx)(I,{size:22})}),(0,R.jsx)(`textarea`,{ref:S,value:u,onChange:e=>d(e.target.value),onPaste:e=>{let t=Array.from(e.clipboardData?.files??[]);t.length>0&&(e.preventDefault(),T(t))},onKeyDown:e=>{if(e.key===`Tab`&&M.length>0&&M[0]){e.preventDefault(),te(M[0]);return}if(e.key===`Tab`&&re.length>0&&re[0]){e.preventDefault(),ae(re[0]);return}e.key===`Enter`&&!e.shiftKey&&!e.nativeEvent.isComposing&&(e.preventDefault(),oe())},rows:1,placeholder:n?w(`Answer {name}…`,{name:e}):b.length>0?w(`Say what to do with it…`):w(`Message`),"aria-label":w(`Message`),className:`flex-1 resize-none bg-transparent px-1 py-2 text-[15px] leading-[1.4] outline-none placeholder:text-muted`}),g.supported&&(0,R.jsx)(Pp,{listening:g.listening,onClick:_}),(0,R.jsx)(`button`,{type:`submit`,disabled:!u.trim()&&k.length===0||O,"aria-label":w(`Send`),className:i(`flex h-9 w-9 shrink-0 items-center justify-center rounded-full transition active:scale-95`,u.trim()||k.length>0?`bg-ink text-ink-fg`:`bg-surface-2 text-muted`,`disabled:opacity-60`),children:(0,R.jsx)(Je,{size:19,strokeWidth:2.5})})]})]})}function oh({threads:e,active:t,onPick:n,onCleared:r,compact:a=!1,grouped:o=!1}){let{state:c,toast:l,dispatch:d}=E(),f=s(),[p,m]=(0,L.useState)(``),[h,g]=(0,L.useState)(!1),_=(0,L.useRef)(null),v=(c.hub?.devices??[]).filter(e=>!e.this&&e.kind!==`web`&&e.online),y=e=>c.hub?.devices.find(t=>t.id===e)?.kind??`phone`,b=async e=>{try{let t=await N.askDevice(e.id);d({type:`ws`,msg:{kind:`thread`,thread:t.thread}}),n(t.thread.id)}catch(e){l(e.message)}},x=async()=>{g(!0);try{let e=await N.createThread(p.trim()||f(`Side chat`));d({type:`ws`,msg:{kind:`thread`,thread:e}}),m(``),n(e.id)}catch(e){l(e.message)}finally{g(!1)}},S=async e=>{if(window.confirm(f(`Delete this side chat and its history?`)))try{await N.deleteThread(e),d({type:`ws`,msg:{kind:`thread_deleted`,thread:e}})}catch(e){l(e.message)}},C=async e=>{if(window.confirm(f(`Clear this conversation? Memory and goals are kept.`)))try{await N.clearThread(e),d({type:`ws`,msg:{kind:`thread_cleared`,thread:e}}),r?.()}catch(e){l(e.message)}},w=e=>(0,R.jsxs)(`li`,{className:i(`group flex items-center gap-2 px-3`,a?`py-2 rounded-xl hover:bg-surface-2/60`:`py-2.5`,e.id===t&&`bg-surface-2/60`),children:[(0,R.jsxs)(`button`,{type:`button`,onClick:()=>n(e.id),className:`flex-1 text-left min-w-0`,children:[(0,R.jsxs)(`div`,{className:i(`font-medium truncate flex items-center gap-2`,a?`text-[13.5px]`:`text-[15px]`),children:[e.device?(0,R.jsx)(`span`,{className:`text-accent`,children:y(e.device)===`computer`?(0,R.jsx)(Lt,{size:14}):(0,R.jsx)(tn,{size:14})}):e.remote_from?(0,R.jsx)(It,{size:14,className:`text-muted`}):null,(0,R.jsx)(`span`,{className:`truncate`,children:e.id===`main`?f(e.title):e.title}),e.busy&&(0,R.jsx)(`span`,{className:`h-1.5 w-1.5 shrink-0 rounded-full bg-amber-400 animate-pulse`})]}),(0,R.jsxs)(`div`,{className:i(`text-muted`,a?`text-[11.5px]`:`text-[12px]`),children:[f(`{n} events`,{n:e.events}),e.queued?` · ${f(`{n} queued`,{n:e.queued})}`:``,` · `,u(e.updated_at)]})]}),(0,R.jsx)(`button`,{type:`button`,"aria-label":f(`Clear`),onClick:()=>void C(e.id),className:i(`p-2 text-muted hover:text-fg`,a&&`opacity-0 group-hover:opacity-100 focus:opacity-100`),children:(0,R.jsx)(Fe,{size:16})}),e.id!==`main`&&(0,R.jsx)(`button`,{type:`button`,"aria-label":f(`Delete`),onClick:()=>void S(e.id),className:i(`p-2 text-muted hover:text-rose-500`,a&&`opacity-0 group-hover:opacity-100 focus:opacity-100`),children:(0,R.jsx)(fn,{size:16})})]},e.id),T=i(`divide-y divide-border overflow-hidden`,a?`rounded-xl`:`rounded-2xl border border-border`),D=`px-3 pb-1 pt-3 text-[11.5px] font-semibold uppercase tracking-wide text-muted`;return(0,R.jsxs)(`div`,{children:[o?(0,R.jsxs)(R.Fragment,{children:[(0,R.jsx)(`div`,{className:D,children:f(`Main chat`)}),(0,R.jsx)(`ul`,{className:T,children:e.filter(e=>e.id===`main`).map(w)}),(0,R.jsxs)(`div`,{className:i(D,`flex items-center justify-between pr-1`),children:[(0,R.jsx)(`span`,{children:f(`Side chats`)}),(0,R.jsx)(`button`,{type:`button`,"aria-label":f(`New side chat`),onClick:()=>_.current?.focus(),className:`flex h-6 w-6 items-center justify-center rounded-full text-muted hover:bg-surface-2 hover:text-fg`,children:(0,R.jsx)(I,{size:15})})]}),(0,R.jsx)(`ul`,{className:T,children:e.filter(e=>e.id!==`main`).map(w)}),e.every(e=>e.id===`main`)&&(0,R.jsx)(`p`,{className:`px-3 py-2 text-[12px] text-muted`,children:f(`A side chat keeps one topic apart from the rest.`)})]}):(0,R.jsx)(`ul`,{className:T,children:e.map(w)}),v.length>0&&(0,R.jsxs)(`div`,{className:`mt-4`,children:[(0,R.jsx)(`div`,{className:`mb-1.5 text-[12px] font-medium text-muted`,children:f(`Ask one of your devices`)}),(0,R.jsx)(`div`,{className:`flex flex-wrap gap-2`,children:v.map(e=>(0,R.jsxs)(`button`,{type:`button`,onClick:()=>void b(e),className:`flex items-center gap-1.5 rounded-full border border-border bg-surface px-3 py-1.5 text-[13px] font-medium hover:bg-surface-2`,children:[e.kind===`phone`?(0,R.jsx)(tn,{size:14,className:`text-accent`}):(0,R.jsx)(Lt,{size:14,className:`text-accent`}),e.name]},e.id))})]}),(0,R.jsxs)(`div`,{className:i(`flex gap-2`,a?`mt-3`:`mt-4`),children:[(0,R.jsx)(`input`,{ref:_,value:p,onChange:e=>m(e.target.value),onKeyDown:e=>{e.key===`Enter`&&!h&&x()},placeholder:f(a?`New side chat`:`New side chat, e.g. “Trip to Kyoto”`),className:i(`min-w-0 flex-1 bg-surface-2 outline-none focus:ring-2 focus:ring-accent/40`,a?`rounded-xl px-3 py-2 text-[13px]`:`rounded-2xl px-3.5 py-2.5 text-[14px]`)}),(0,R.jsxs)(`button`,{type:`button`,disabled:h,onClick:()=>void x(),"aria-label":f(`New`),className:i(`flex items-center gap-1.5 bg-accent text-accent-fg font-medium disabled:opacity-50`,a?`rounded-xl px-2.5`:`rounded-2xl px-3.5 py-2.5`),children:[(0,R.jsx)(jt,{size:18}),` `,!a&&f(`New`)]})]})]})}function sh(e){let t=[...e].reverse().find(e=>e.type===`user`),n=(((t?.type===`user`?t.text:``)||``).split(/\r?\n/).map(e=>e.trim()).find(e=>e.length>0)??``).replace(/\s+/g,` `);if(n.length<=36)return n;let r=n.slice(0,36),i=r.lastIndexOf(` `);return(i>16?r.slice(0,i):r).trimEnd()+`…`}function ch(e){let t=!1;for(let n=e.length-1;n>=0;n--){let r=e[n];if(r.type===`assistant`){if(!r.text||r.quiet)return!1;t=!0;continue}if(r.type===`user`)return t&&!r.via;if(r.type===`notice`)return!1}return!1}function lh(e){let t=Sn(),n=t?`Desktop app (${t.platform}, shell ${t.version})`:`Web app (${navigator.userAgent})`;return`https://github.com/nano-muse/nanoMuse/issues/new?${new URLSearchParams({template:`bug_report.yml`,version:e||``,os:n}).toString()}`}function uh(){let{state:e,setTab:t,openThread:n}=E(),r=s(),[a,o]=(0,L.useState)(!1),[c,l]=(0,L.useState)(!1),[u,d]=(0,L.useState)(``),f=(0,L.useRef)(null),p=$f(),{profile:m,status:h}=e,g=m?.name??`nanoMuse`,_=e.pendingApprovals.length,v=e.goals.filter(e=>e.proposal&&e.status!==`cancelled`).length,y=e.pendingApprovals.filter(t=>t.ts>e.feedSeenAt).length,b=(e.hub?.devices??[]).filter(e=>!e.this&&e.kind!==`web`&&e.online).length,x=_>0?_>1?r(`{n} approvals waiting for you`,{n:_}):r(`1 approval waiting for you`):h.state===`idle`?r(`Idle`):h.detail||(h.state===`waiting`?r(`Waiting for you`):r(`Working…`));(0,L.useEffect)(()=>{if(!c)return;let e=e=>{f.current?.contains(e.target)||l(!1)},t=e=>{e.key===`Escape`&&l(!1)};return document.addEventListener(`mousedown`,e),document.addEventListener(`keydown`,t),()=>{document.removeEventListener(`mousedown`,e),document.removeEventListener(`keydown`,t)}},[c]);let S=[{id:`chat`,label:`Chat`,icon:(0,R.jsx)(At,{size:21}),badge:_},{id:`feed`,label:`Feed`,icon:(0,R.jsx)(Bt,{size:21}),badge:y},{id:`ideas`,label:`Ideas`,icon:(0,R.jsx)(Ct,{size:21})},{id:`goals`,label:`Goals`,icon:(0,R.jsx)(rn,{size:21}),badge:v},{id:`library`,label:`Library`,icon:(0,R.jsx)(St,{size:21})},{id:`devices`,label:`Devices`,icon:(0,R.jsx)(It,{size:21}),dot:b>0},...p?[{id:`coding`,label:`Coding`,icon:(0,R.jsx)(on,{size:21})}]:[]],C=u.trim().toLowerCase(),w=C?e.threads.filter(e=>e.id===`main`||(e.id===`main`?r(e.title):e.title).toLowerCase().includes(C)||(e.device_name??``).toLowerCase().includes(C)):e.threads,T=e=>i(`relative flex w-[60px] flex-col items-center gap-[3px] rounded-xl py-1.5 text-[10.5px] font-medium leading-none transition`,e?`bg-surface-2 text-fg`:`text-fg/65 hover:bg-surface-2/60 hover:text-fg`);return(0,R.jsxs)(`div`,{className:`flex h-full shrink-0`,children:[(0,R.jsxs)(`aside`,{className:`relative flex h-full w-[76px] shrink-0 flex-col items-center border-r border-border bg-surface/70`,children:[(0,R.jsx)(`div`,{className:`titlebar-room`}),(0,R.jsxs)(`button`,{type:`button`,onClick:()=>o(!0),className:`relative mt-3 rounded-full transition hover:scale-[1.04]`,"aria-label":r(`Activity`),title:`${g} · ${x}`,children:[(0,R.jsx)(D,{profile:m,status:h,size:44}),_>0&&(0,R.jsx)(`span`,{className:`pointer-events-none absolute -right-1 -top-1 flex h-[18px] min-w-[18px] items-center justify-center rounded-full border-2 border-surface bg-rose-500 px-1 text-[10.5px] font-bold text-white`,children:_})]}),(0,R.jsx)(`span`,{className:`mt-1.5 max-w-[68px] truncate px-1 text-[11px] font-semibold leading-tight`,children:g}),(0,R.jsx)(`nav`,{className:`mt-3 flex w-full flex-1 flex-col items-center gap-0.5 overflow-y-auto overflow-x-hidden px-2`,children:S.map(n=>{let a=e.tab===n.id;return(0,R.jsxs)(`button`,{type:`button`,onClick:()=>t(n.id),"aria-current":a?`page`:void 0,className:T(a),children:[(0,R.jsx)(`span`,{className:i(a?`text-accent`:`text-fg/60`),children:n.icon}),(0,R.jsx)(`span`,{className:`max-w-full truncate`,children:r(n.label)}),n.badge?(0,R.jsx)(`span`,{className:`absolute right-1.5 top-1 flex h-[17px] min-w-[17px] items-center justify-center rounded-full bg-rose-500 px-1 text-[10px] font-bold text-white`,children:n.badge}):n.dot?(0,R.jsxs)(R.Fragment,{children:[(0,R.jsx)(`span`,{"aria-hidden":`true`,className:`absolute right-3 top-2 h-2 w-2 rounded-full border-2 border-surface bg-emerald-500`}),(0,R.jsx)(`span`,{className:`sr-only`,children:r(`{n} online`,{n:b})})]}):null]},n.id)})}),(0,R.jsxs)(`div`,{className:`flex w-full flex-col items-center gap-0.5 px-2 pb-3 pt-2`,children:[(0,R.jsxs)(`button`,{type:`button`,onClick:()=>t(`account`),"aria-current":e.tab===`account`?`page`:void 0,className:T(e.tab===`account`),title:e.hub?.account.signed_in?e.hub.account.hint:r(`Account`),children:[(0,R.jsx)(mn,{size:21,className:e.tab===`account`?`text-accent`:`text-fg/60`}),(0,R.jsx)(`span`,{className:`max-w-full truncate`,children:r(`Account`)})]}),(0,R.jsxs)(`button`,{type:`button`,onClick:()=>t(`you`),"aria-current":e.tab===`you`?`page`:void 0,className:T(e.tab===`you`),children:[(0,R.jsx)(en,{size:21,className:e.tab===`you`?`text-accent`:`text-fg/60`}),(0,R.jsx)(`span`,{className:`max-w-full truncate`,children:r(`Settings`)})]}),(0,R.jsxs)(`div`,{ref:f,className:`relative w-full`,children:[(0,R.jsxs)(`button`,{type:`button`,onClick:()=>l(e=>!e),"aria-expanded":c,"aria-haspopup":`menu`,className:i(T(c),`mx-auto`),children:[(0,R.jsx)(Ot,{size:21,className:`text-fg/60`}),(0,R.jsx)(`span`,{children:r(`More`)})]}),c&&(0,R.jsxs)(`div`,{role:`menu`,className:`absolute bottom-0 left-[68px] z-30 w-[232px] rounded-2xl border border-border bg-surface p-1.5 shadow-[0_12px_40px_-12px_rgba(0,0,0,0.3)]`,children:[(0,R.jsxs)(`a`,{role:`menuitem`,href:lh(e.version),target:`_blank`,rel:`noreferrer`,onClick:()=>l(!1),className:`flex items-center gap-2.5 rounded-xl px-2.5 py-2 text-[13px] font-medium hover:bg-surface-2`,children:[(0,R.jsx)(ue,{size:16,className:`text-fg/60`}),` `,r(`Report a bug`)]}),(0,R.jsxs)(`button`,{type:`button`,role:`menuitem`,onClick:()=>{l(!1),t(`you`),window.location.hash=`developer`},className:`flex w-full items-center gap-2.5 rounded-xl px-2.5 py-2 text-left text-[13px] font-medium hover:bg-surface-2`,children:[(0,R.jsx)(yn,{size:16,className:`text-fg/60`}),(0,R.jsx)(`span`,{className:`flex-1`,children:r(`Developer tools`)}),(0,R.jsx)(`span`,{className:`text-[11.5px] font-normal text-muted`,children:r(p?`On`:`Off`)})]}),e.version&&(0,R.jsxs)(`div`,{className:`px-2.5 pb-1 pt-1.5 text-[11.5px] text-muted`,children:[`nanoMuse `,e.version]})]})]})]}),(0,R.jsx)(am,{open:a,onClose:()=>o(!1)})]}),e.tab===`chat`&&(0,R.jsxs)(`section`,{className:`flex h-full w-[248px] shrink-0 flex-col border-r border-border bg-surface/40`,"aria-label":r(`Chats`),children:[(0,R.jsx)(`div`,{className:`titlebar-room`}),(0,R.jsxs)(`div`,{className:`px-3 pb-2 pt-4`,children:[(0,R.jsx)(`h2`,{className:`px-1 text-[15px] font-semibold tracking-tight`,children:r(`Chats`)}),(0,R.jsxs)(`label`,{className:`mt-2 flex items-center gap-2 rounded-xl bg-surface-2 px-2.5 py-1.5 text-muted focus-within:ring-2 focus-within:ring-accent/40`,children:[(0,R.jsx)(qt,{size:14,className:`shrink-0`}),(0,R.jsx)(`input`,{value:u,onChange:e=>d(e.target.value),placeholder:r(`Search`),"aria-label":r(`Search chats`),className:`min-w-0 flex-1 bg-transparent text-[13px] text-fg outline-none placeholder:text-muted`}),u&&(0,R.jsx)(`button`,{type:`button`,onClick:()=>d(``),"aria-label":r(`Clear`),className:`shrink-0 hover:text-fg`,children:(0,R.jsx)(Fe,{size:14})})]})]}),(0,R.jsx)(`div`,{className:`min-h-0 flex-1 overflow-y-auto px-2 pb-3`,children:(0,R.jsx)(oh,{threads:w,active:e.activeThread,onPick:e=>n(e),compact:!0,grouped:!0})})]})]})}function dh(){let{state:e,send:t,openThread:n,openFile:r,markFeedSeen:i,setTab:a,toast:o}=E(),[c,l]=(0,L.useState)(null),[u,p]=(0,L.useState)(null),[h,g]=(0,L.useState)(null),[_,v]=(0,L.useState)(null),b=e.profile?.name??`nanoMuse`,x=s(),S=y();(0,L.useEffect)(()=>{let e=!0;return N.feed(80).then(t=>e&&l(t)).catch(e=>o(e.message)),N.upcoming().then(t=>e&&g(t)).catch(()=>void 0),N.feedPosts().then(t=>e&&p(t)).catch(()=>void 0),()=>{e=!1}},[e.feedVersion,e.remindersVersion]),(0,L.useEffect)(()=>{let e=!0;return N.calendar().then(t=>e&&v(t)).catch(()=>void 0),()=>{e=!1}},[e.calendarVersion,e.connectionsVersion]),(0,L.useEffect)(()=>{c&&c.length&&c[0].ts>e.feedSeenAt&&i(c[0].ts)},[c,e.feedSeenAt,i]);let C=(0,L.useMemo)(()=>kh(c??[]),[c,S]),[w,T]=(0,L.useState)(!1),[D,O]=(0,L.useState)(null),[k,ee]=(0,L.useState)(()=>d(fh)===`1`),[M,te]=(0,L.useState)(!1),ne=()=>{f(fh,`1`),ee(!0)},re=async()=>{te(!0);try{let e=await N.refreshFeedPosts();p(e),e.error&&o(x(`Could not write posts: {error}`,{error:e.error}))}catch(e){o(e.message)}finally{te(!1)}},P=e=>{t(`main`,e.prompt||`${x(`About this post from my feed:`)}\n\n**${e.title}**\n\n${e.body.slice(0,1200)}`).catch(e=>o(e.message||x(`Could not send`))),n(`main`)},ie=(0,L.useMemo)(()=>mh(u?.posts??[]),[u]),ae=u!==null&&u.posts.length===0;return(0,R.jsxs)(`div`,{className:`flex h-full flex-col`,children:[(0,R.jsx)(Em,{title:``,trailing:(0,R.jsx)(j,{onClick:()=>T(!0),label:x(`Feed settings`),children:(0,R.jsx)(en,{size:22})})}),(0,R.jsxs)(`div`,{className:`flex-1 overflow-y-auto px-3.5 pb-7`,children:[ie.length===0&&(0,R.jsxs)(R.Fragment,{children:[(0,R.jsx)(gh,{text:hh(ph(),new Date)}),!k&&(0,R.jsx)(xh,{instructions:u?.instructions??``,onEdit:()=>T(!0),onAck:ne}),ae&&(0,R.jsxs)(R.Fragment,{children:[(0,R.jsx)(Sh,{emoji:`🖼️`,title:x(`Nothing in the feed yet`),body:x(`As we get to know each other, new posts will show up here. Every day at {time} I read what I remember about you (your memory files, the last week of diary, your goals) and write a few short posts.`,{time:u?.time??`08:00`})}),(0,R.jsx)(Sh,{emoji:`📝`,title:x(`Steer it with one sentence`),body:x(`Tap the sliders at the top right to tell me what you want more of, switch the daily routine off, or have me write the first day now.`)}),e.settings&&!e.settings.llm_ready&&(0,R.jsx)(_h,{children:(0,R.jsxs)(`button`,{type:`button`,onClick:()=>a(`you`),className:`flex w-full items-center gap-2 p-4 text-left text-[14px] text-muted`,children:[(0,R.jsx)(F,{size:16,className:`shrink-0 text-accent`}),` `,x(`Add a model first; the feed is written by your agent.`)]})}),(0,R.jsx)(_h,{children:(0,R.jsx)(`div`,{className:`p-4`,children:M?(0,R.jsxs)(`div`,{className:`flex items-center justify-center gap-2.5 text-[15px]`,children:[(0,R.jsx)(A,{size:18,className:`animate-spin text-accent`}),` `,x(`Writing…`)]}):(0,R.jsx)(`button`,{type:`button`,onClick:()=>void re(),className:`h-[46px] w-full rounded-full bg-accent text-[15px] font-semibold text-accent-fg`,children:x(`Write it now`)})})})]})]}),ie.map(([e,t],n)=>(0,R.jsxs)(`section`,{children:[(0,R.jsx)(gh,{text:hh(e,new Date(t[0].ts))}),n===0&&!k&&(0,R.jsx)(xh,{instructions:u?.instructions??``,onEdit:()=>T(!0),onAck:ne}),n===0&&M&&(0,R.jsx)(_h,{children:(0,R.jsxs)(`div`,{className:`flex items-center gap-2.5 p-4 text-[15px]`,children:[(0,R.jsx)(A,{size:18,className:`animate-spin text-accent`}),` `,x(`Writing…`)]})}),t.map(e=>(0,R.jsx)(bh,{post:e,onDiscuss:()=>P(e),onInfo:()=>O(e)},e.id))]},e)),(0,R.jsxs)(`div`,{className:`space-y-4 px-0.5 pt-3`,children:[h&&(0,R.jsx)(Th,{data:h,name:b,onSettings:()=>a(`you`),onGoals:()=>a(`goals`)}),_?.configured&&(0,R.jsx)(Eh,{data:_,onAsk:()=>n(`main`)}),c&&c.length===0&&(!u||u.posts.length===0)&&(0,R.jsxs)(`div`,{className:`py-10 text-center text-muted text-[14px] px-6`,children:[(0,R.jsx)(Rt,{size:28,className:`mx-auto mb-2 opacity-60`}),x(`Nothing yet. Once {name} works on a goal in the background or needs your approval, it shows up here.`,{name:b})]}),c&&c.length>0&&(0,R.jsx)(`div`,{className:`px-1 pt-1 text-[12px] font-semibold uppercase tracking-wide text-muted`,children:x(`While you were away`)}),C.map(([t,i])=>(0,R.jsxs)(`section`,{children:[(0,R.jsx)(`div`,{className:`px-1 mb-1.5 text-[12px] uppercase tracking-wide text-muted font-semibold`,children:t}),(0,R.jsx)(`ul`,{className:`space-y-2`,children:i.map(t=>(0,R.jsx)(`li`,{children:(0,R.jsx)(Oh,{item:t,unseen:t.ts>e.feedSeenAt,onOpen:()=>{t.kind===`artifact`&&t.path?r(t.path):n(t.thread)}})},t.id))})]},t))]})]}),(0,R.jsx)(wh,{open:w,onClose:()=>T(!1),data:u,writing:M,onChange:p,onWriteNow:()=>void re()}),(0,R.jsx)(Op,{open:D!==null,onClose:()=>O(null),title:D?.title,children:D&&(0,R.jsxs)(`div`,{className:`space-y-3 px-1 pb-2`,children:[(0,R.jsx)(Ch,{label:x(`Post type`),value:yh(D.area)}),(0,R.jsx)(Ch,{label:x(`Written`),value:new Date(D.ts).toLocaleString(m(),{dateStyle:`medium`,timeStyle:`short`})}),(0,R.jsx)(`button`,{type:`button`,onClick:async()=>{let e=D.id;O(null);try{await N.deleteFeedPost(e),p(t=>t&&{...t,posts:t.posts.filter(t=>t.id!==e)})}catch(e){o(e.message)}},className:`w-full rounded-full bg-surface-2 py-2.5 text-[15px] font-medium text-rose-500`,children:x(`Delete this post`)})]})})]})}var fh=`nanomuse.feed.introAck`;function ph(){let e=new Date;return`${e.getFullYear()}-${String(e.getMonth()+1).padStart(2,`0`)}-${String(e.getDate()).padStart(2,`0`)}`}function mh(e){let t=new Map;for(let n of e){let e=new Date(n.ts),r=`${e.getFullYear()}-${String(e.getMonth()+1).padStart(2,`0`)}-${String(e.getDate()).padStart(2,`0`)}`,i=t.get(r);i?i.push(n):t.set(r,[n])}return[...t.entries()]}function hh(e,t){let n=ph(),r=new Date;r.setDate(r.getDate()-1);let i=`${r.getFullYear()}-${String(r.getMonth()+1).padStart(2,`0`)}-${String(r.getDate()).padStart(2,`0`)}`,a=t.toLocaleDateString(m(),{weekday:`long`});if(e===n){let e=new Date().getHours(),t=_(e<12?`morning`:e<18?`afternoon`:`evening`);return _(`{weekday} {part}`,{weekday:a,part:t})}return e===i?_(`Yesterday`):`${a} · ${t.toLocaleDateString(m(),{month:`short`,day:`numeric`})}`}function gh({text:e}){return(0,R.jsx)(`h2`,{className:`px-1.5 pt-3.5 pb-2 text-[22px] font-bold leading-7`,children:e})}function _h({children:e,className:t}){return(0,R.jsx)(`div`,{className:i(`my-1.5 overflow-hidden rounded-[18px] bg-surface dark:border dark:border-border`,t),children:e})}var vh={planning:`🗓️`,research:`🔍`,goals:`🎯`,money:`💰`,health:`🌿`,home:`🏠`,learning:`📚`,people:`👥`,files:`📄`,fun:`🎈`};function yh(e){switch(e){case`planning`:return _(`Planning`);case`research`:return _(`Research`);case`goals`:return _(`Goals`);case`money`:return _(`Money`);case`health`:return _(`Health`);case`home`:return _(`Home`);case`learning`:return _(`Learning`);case`people`:return _(`People`);case`files`:return _(`Files`);case`fun`:return _(`Fun`);default:return _(`Note`)}}function bh({post:e,onDiscuss:t,onInfo:n}){let r=s();return(0,R.jsx)(_h,{children:(0,R.jsxs)(`article`,{className:`pl-3.5 pr-2.5 pt-3.5 pb-1.5`,children:[(0,R.jsxs)(`div`,{className:`flex items-start gap-3`,children:[(0,R.jsx)(`div`,{className:`flex h-11 w-11 shrink-0 items-center justify-center rounded-xl bg-surface-2 text-[22px] leading-none`,children:vh[e.area]??`📝`}),(0,R.jsxs)(`div`,{className:`min-w-0 flex-1`,children:[(0,R.jsx)(`h3`,{className:`text-[16px] font-semibold leading-[22px]`,children:e.title}),(0,R.jsx)(`div`,{className:`md mt-1 text-[15px] leading-[22px] text-fg/85`,children:(0,R.jsx)(hf,{text:e.body})})]})]}),(0,R.jsxs)(`div`,{className:`mt-1.5 flex items-center`,children:[(0,R.jsxs)(`button`,{type:`button`,onClick:t,className:`flex items-center gap-1.5 rounded-full px-2 py-2 text-[14px] hover:bg-surface-2`,children:[(0,R.jsx)(At,{size:22,strokeWidth:1.8}),` `,r(`Discuss`)]}),(0,R.jsx)(`button`,{type:`button`,onClick:n,"aria-label":r(`About this post`),className:`ml-auto rounded-full p-2 hover:bg-surface-2`,children:(0,R.jsx)(F,{size:22,strokeWidth:1.8})})]})]})})}function xh({instructions:e,onEdit:t,onAck:n}){let r=s();return(0,R.jsxs)(_h,{children:[(0,R.jsxs)(`div`,{className:`px-4 py-3.5`,children:[(0,R.jsx)(`div`,{className:`text-[17px] font-semibold`,children:r(`About the feed`)}),(0,R.jsx)(`p`,{className:`mt-1 text-[13px] leading-[18px] text-muted`,children:r(`Short posts your agent writes for you from what it remembers: your memory files, the last week of diary, your goals. The sentence below steers every post from now on; edit it any time.`)})]}),(0,R.jsxs)(`div`,{className:`border-t border-border/70 px-4 py-3.5`,children:[(0,R.jsx)(`p`,{className:`text-[15px] leading-[22px]`,children:e||r(`Build me a feed about what I care about. Keep it short and direct, easy to skim, no clickbait.`)}),(0,R.jsxs)(`div`,{className:`mt-3.5 flex justify-end gap-2.5`,children:[(0,R.jsx)(`button`,{type:`button`,onClick:t,className:`rounded-full bg-surface-2 px-6 py-2.5 text-[15px] font-medium`,children:r(`Edit`)}),(0,R.jsx)(`button`,{type:`button`,onClick:n,className:`rounded-full bg-accent px-6 py-2.5 text-[15px] font-semibold text-accent-fg`,children:r(`Got it`)})]})]})]})}function Sh({emoji:e,title:t,body:n}){return(0,R.jsx)(_h,{children:(0,R.jsxs)(`div`,{className:`flex items-start gap-3 p-3.5`,children:[(0,R.jsx)(`div`,{className:`flex h-11 w-11 shrink-0 items-center justify-center rounded-xl bg-surface-2 text-[22px] leading-none`,children:e}),(0,R.jsxs)(`div`,{className:`min-w-0 flex-1`,children:[(0,R.jsx)(`div`,{className:`text-[16px] font-semibold leading-[22px]`,children:t}),(0,R.jsx)(`p`,{className:`mt-1 text-[15px] leading-[22px] text-fg/85`,children:n})]})]})})}function Ch({label:e,value:t}){return(0,R.jsxs)(`div`,{className:`flex items-start gap-3 text-[14.5px]`,children:[(0,R.jsx)(`span`,{className:`w-14 shrink-0 text-muted`,children:e}),(0,R.jsx)(`span`,{className:`min-w-0 flex-1 break-words`,children:t})]})}function wh({open:e,onClose:t,data:n,writing:r,onChange:i,onWriteNow:a}){let{toast:o,state:c}=E(),l=s(),[u,d]=(0,L.useState)(``),[f,p]=(0,L.useState)(!1);(0,L.useEffect)(()=>{e&&d(n?.instructions??``)},[e,n]);let m=async()=>{p(!0);try{i(await N.setFeedInstructions({instructions:u})),t()}catch(e){o(e.message)}finally{p(!1)}},h=async e=>{try{i(await N.setFeedInstructions(e))}catch(e){o(e.message)}},g=c.settings?.llm_ready!==!1;return(0,R.jsx)(Op,{open:e,onClose:t,title:l(`Feed`),children:(0,R.jsxs)(`div`,{className:`space-y-3 px-1 pb-2`,children:[(0,R.jsx)(`p`,{className:`text-[13px] leading-[18px] text-muted`,children:l(`Your feed is driven by the instruction below. Any edit you make here applies to every post from now on.`)}),(0,R.jsx)(`textarea`,{value:u,onChange:e=>d(e.target.value),rows:4,maxLength:2e3,placeholder:l(`Build me a feed about what I care about. Keep it short and direct, easy to skim, no clickbait.`),className:`w-full resize-none rounded-2xl bg-surface-2 px-3.5 py-2.5 text-[15px] leading-snug outline-none focus:ring-2 focus:ring-accent/40`}),(0,R.jsxs)(`div`,{className:`space-y-2 rounded-2xl bg-surface-2 px-3.5 py-2.5`,children:[(0,R.jsx)(Pe,{label:l(`Write it every day`),hint:n?.daily===!1?void 0:l(`Daily at {time}`,{time:n?.time??`08:00`}),checked:n?.daily!==!1,onChange:e=>void h({daily:e}),disabled:!n}),n?.daily!==!1&&(0,R.jsxs)(`label`,{className:`flex items-center justify-between gap-3 text-[13px] text-muted`,children:[(0,R.jsx)(`span`,{children:l(`Time of day`)}),(0,R.jsx)(`input`,{type:`time`,value:n?.time??`08:00`,onChange:e=>e.target.value&&void h({time:e.target.value}),className:`rounded-lg bg-surface px-2 py-1 text-[13px] text-fg outline-none focus:ring-2 focus:ring-accent/40`})]}),!g&&(0,R.jsx)(`div`,{className:`text-[12.5px] text-muted`,children:l(`Add a model first; the feed is written by your agent.`)})]}),(0,R.jsxs)(`button`,{type:`button`,onClick:a,disabled:r||!n||!g,className:`flex w-full items-center justify-center gap-2 rounded-full bg-surface-2 py-2.5 text-[15px] font-medium disabled:opacity-60`,children:[r?(0,R.jsx)(A,{size:16,className:`animate-spin`}):(0,R.jsx)(nn,{size:16,className:`text-accent`}),l(r?`Writing…`:`Write it now`)]}),(0,R.jsx)(`button`,{type:`button`,onClick:()=>void m(),disabled:f,className:`h-[46px] w-full rounded-full bg-accent text-[15px] font-semibold text-accent-fg disabled:opacity-60`,children:l(`Save`)})]})})}function Th({data:t,name:n,onSettings:r,onGoals:i}){let a=s(),o=t.queue[0],c=t.reminders.filter(e=>e.status===`active`&&!!e.next_at),l=c[0],d=c.length;return(0,R.jsxs)(`div`,{className:`rounded-3xl border border-border/70 bg-surface shadow-sm px-4 py-3.5`,children:[(0,R.jsxs)(`div`,{className:`flex items-center gap-2 text-[12px] uppercase tracking-wide text-muted font-semibold`,children:[(0,R.jsx)(Xe,{size:13}),` `,a(`Next up`)]}),t.proactive?o?(0,R.jsxs)(`div`,{className:`mt-1.5 text-[14px] leading-snug`,children:[t.busy?a(`Working now`):t.quiet_until?a(`Quiet hours after {time}`,{time:u(t.quiet_until)}):t.next_pass_at?a(`Around {time}`,{time:u(t.next_pass_at)}):a(`Soon`),`: `,(0,R.jsx)(`span`,{className:`font-medium`,children:o.title}),o.next_step&&(0,R.jsxs)(`span`,{className:`text-muted`,children:[` · `,o.next_step]}),o.overdue&&(0,R.jsxs)(`span`,{className:`text-rose-500 font-medium`,children:[` · `,a(`overdue`)]}),t.queue.length>1&&(0,R.jsxs)(`span`,{className:`text-muted`,children:[` · `,a(`{n} more in line`,{n:t.queue.length-1})]})]}):(0,R.jsxs)(`div`,{className:`mt-1.5 text-[14px] leading-snug`,children:[a(`No goal has a next step to work on.`),` `,(0,R.jsx)(`button`,{type:`button`,onClick:i,className:`text-accent font-medium`,children:a(`Add one`)})]}):(0,R.jsxs)(`div`,{className:`mt-1.5 text-[14px] leading-snug`,children:[a(`Background work is off. {name} only acts when you ask.`,{name:n}),` `,(0,R.jsx)(`button`,{type:`button`,onClick:r,className:`text-accent font-medium`,children:a(`Turn it on`)})]}),t.check_ins[0]&&(0,R.jsxs)(`div`,{className:`mt-1.5 text-[12.5px] text-muted`,children:[a(`Check-in on`),` `,(0,R.jsx)(`span`,{className:`font-medium text-fg`,children:t.check_ins[0].title}),` `,e(t.check_ins[0].at),t.check_ins.length>1&&` · ${a(`{n} more`,{n:t.check_ins.length-1})}`]}),l&&(0,R.jsxs)(`div`,{className:`mt-1.5 text-[12.5px] text-muted`,children:[l.kind===`task`?a(`Routine`):a(`Reminder`),` `,(0,R.jsx)(`span`,{className:`font-medium text-fg`,children:l.text}),` `,e(l.next_at),d>1&&` · ${a(`{n} more`,{n:d-1})}`]})]})}function Eh({data:e,onAsk:t}){let n=s(),r=t=>t.start.slice(0,10)<=e.today,a=e.events.filter(r),o=e.events.filter(e=>!r(e)),c=new Date,l=e=>!e.all_day&&new Date(e.end)e.error),d=a.every(l)&&o.length>0,f=d?o:a;return(0,R.jsxs)(`div`,{className:`rounded-3xl border border-border/70 bg-surface shadow-sm px-4 py-3.5`,children:[(0,R.jsxs)(`div`,{className:`flex items-center gap-2 text-[12px] uppercase tracking-wide text-muted font-semibold`,children:[(0,R.jsx)(tt,{size:13}),` `,n(d?`Tomorrow`:`Today`),f.length>0&&(0,R.jsx)(`span`,{className:`ml-auto normal-case tracking-normal font-normal`,children:n(`{n} scheduled`,{n:f.length})})]}),f.length===0?(0,R.jsx)(`div`,{className:`mt-1.5 text-[14px] leading-snug text-muted`,children:n(`Nothing on the calendar today.`)}):(0,R.jsx)(`ul`,{className:`mt-1.5 space-y-1`,children:f.map(e=>(0,R.jsxs)(`li`,{className:i(`flex items-baseline gap-2.5 text-[14px] leading-snug`,!d&&l(e)&&`opacity-50`),children:[(0,R.jsx)(`span`,{className:`w-[86px] shrink-0 tabular-nums text-[12.5px] text-muted`,children:e.all_day?n(`all day`):`${e.start.slice(11,16)}–${e.end.slice(11,16)}`}),(0,R.jsxs)(`span`,{className:`min-w-0 flex-1`,children:[(0,R.jsx)(`span`,{className:`font-medium`,children:e.summary}),e.location&&(0,R.jsxs)(`span`,{className:`text-muted text-[12.5px]`,children:[` `,(0,R.jsx)(Dt,{size:11,className:`inline -mt-0.5`}),` `,e.location]})]})]},`${e.uid}-${e.start}`))}),u.length>0&&(0,R.jsx)(`div`,{className:`mt-1.5 text-[12px] text-rose-500`,children:n(`{name} could not be read`,{name:u.map(e=>e.name).join(`, `)})}),(0,R.jsx)(`button`,{type:`button`,onClick:t,className:`mt-2 text-[12.5px] text-accent font-medium`,children:n(`Ask about your week`)})]})}function Dh(e){return e.replace(/```[\s\S]*?```/g,` `).replace(/^#{1,6}\s+/gm,``).replace(/(\*\*|__|`)/g,``).replace(/^\s*[-*+]\s+/gm,`• `).replace(/\[([^\]]+)\]\([^)]*\)/g,`$1`).trim()}function Oh({item:n,unseen:r,onOpen:a}){let o=s(),c=n.kind===`approval`?(0,R.jsx)(Zt,{size:18}):n.kind===`question`?(0,R.jsx)(kt,{size:18}):n.kind===`artifact`?(0,R.jsx)(mt,{size:18}):n.quiet?(0,R.jsx)(Rt,{size:18}):n.title.startsWith(`New mail: `)?(0,R.jsx)(Et,{size:18}):n.title.startsWith(`Coming up: `)?(0,R.jsx)(et,{size:18}):n.title.startsWith(`Webhook: `)?(0,R.jsx)(_n,{size:18}):(0,R.jsx)(nn,{size:18}),l=n.kind===`approval`?`bg-amber-500/12 text-amber-600 dark:text-amber-300`:n.kind===`question`?`bg-accent/12 text-accent`:`bg-surface-2 text-muted`;return n.quiet?(0,R.jsxs)(`button`,{type:`button`,onClick:a,className:`w-full text-left px-2 py-1.5 flex items-center gap-2 text-[12.5px] text-muted`,children:[(0,R.jsx)(Rt,{size:13,className:`shrink-0`}),(0,R.jsxs)(`span`,{className:`truncate`,children:[o(`{label}: nothing new`,{label:t(n.title.replace(/^Working on your goal: /,``))}),n.text?`: ${n.text}`:``]}),(0,R.jsx)(`span`,{className:`ml-auto shrink-0`,children:e(n.ts)})]}):(0,R.jsx)(`button`,{type:`button`,onClick:a,className:i(`w-full text-left rounded-3xl border bg-surface shadow-sm px-4 py-3 active:scale-[0.99] transition`,r?`border-accent/40`:`border-border/70`),children:(0,R.jsxs)(`div`,{className:`flex items-start gap-3`,children:[(0,R.jsx)(`div`,{className:i(`rounded-2xl p-2 mt-0.5`,l),children:c}),(0,R.jsxs)(`div`,{className:`flex-1 min-w-0`,children:[(0,R.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,R.jsx)(`div`,{className:`font-semibold text-[14.5px] leading-snug truncate`,children:t(n.title)}),r&&(0,R.jsx)(`span`,{className:`h-2 w-2 rounded-full bg-accent shrink-0`})]}),n.text&&(0,R.jsx)(`div`,{className:`mt-0.5 text-[13.5px] text-muted leading-snug line-clamp-3 whitespace-pre-wrap`,children:Dh(n.text)}),(0,R.jsxs)(`div`,{className:`mt-1.5 flex items-center gap-2 text-[12px] text-muted`,children:[(0,R.jsx)(`span`,{children:e(n.ts)}),(0,R.jsx)(`span`,{children:`·`}),(0,R.jsx)(`span`,{className:`truncate`,children:n.thread===`main`?o(n.thread_title):n.thread_title}),(0,R.jsxs)(`span`,{className:`ml-auto flex items-center gap-1 text-accent font-medium`,children:[n.kind===`artifact`?o(`Open`):n.kind===`approval`||n.kind===`question`?o(`Answer`):o(`Open chat`),(0,R.jsx)(qe,{size:13})]})]})]})]})})}function kh(e){let t=new Date,n=new Date(t);n.setDate(t.getDate()-1);let r=e=>{let r=new Date(e);return r.toDateString()===t.toDateString()?_(`Today`):r.toDateString()===n.toDateString()?_(`Yesterday`):r.toLocaleDateString(m(),{weekday:`long`,month:`short`,day:`numeric`})},i=new Map;for(let t of e){let e=r(t.ts);i.set(e,[...i.get(e)??[],t])}return[...i.entries()]}function Ah({children:e,className:t}){return(0,R.jsx)(`div`,{className:i(`mx-4 overflow-hidden rounded-2xl bg-surface dark:border dark:border-border`,t),children:e})}function jh({inset:e=52}){return(0,R.jsx)(`div`,{className:i(`border-t border-border/60`,e===52?`ml-[52px]`:`ml-4`)})}function Mh({icon:e,label:t,value:n,onClick:r,external:a=!1,trailing:o,chevron:s=!0}){let c=(0,R.jsxs)(R.Fragment,{children:[e&&(0,R.jsx)(`span`,{className:`shrink-0 text-fg`,children:e}),(0,R.jsx)(`span`,{className:i(`min-w-0 truncate text-[16px] leading-[21px]`,n?`max-w-[60%] shrink-0`:`flex-1`),children:t}),n&&(0,R.jsx)(`span`,{className:`min-w-0 flex-1 truncate pl-3 text-right text-[14px] leading-[18px] text-muted`,children:n}),o??(s?a?(0,R.jsx)(Ae,{size:16,className:`shrink-0 text-muted/70`}):(0,R.jsx)(rt,{size:18,className:`shrink-0 text-muted/70`}):null)]}),l=`flex min-h-[54px] w-full items-center gap-3.5 px-4 py-2 text-left`;return r?(0,R.jsx)(`button`,{type:`button`,onClick:r,className:i(l,`hover:bg-surface-2/60`),children:c}):(0,R.jsx)(`div`,{className:l,children:c})}function Nh({icon:e,label:t,value:n,checked:r,disabled:a=!1,onChange:o}){return(0,R.jsxs)(`button`,{type:`button`,role:`switch`,"aria-checked":r,disabled:a,onClick:()=>o(!r),className:i(`flex min-h-[54px] w-full items-center gap-3.5 px-4 py-2 text-left`,a?`opacity-60`:`hover:bg-surface-2/60`),children:[e&&(0,R.jsx)(`span`,{className:`shrink-0 text-fg`,children:e}),(0,R.jsx)(`span`,{className:i(`min-w-0 truncate text-[16px] leading-[21px]`,n?`max-w-[60%] shrink-0`:`flex-1`),children:t}),n&&(0,R.jsx)(`span`,{className:`min-w-0 flex-1 truncate pl-3 text-right text-[14px] leading-[18px] text-muted`,children:n}),(0,R.jsx)(Ph,{checked:r})]})}function Ph({checked:e}){return(0,R.jsx)(`span`,{"aria-hidden":!0,className:i(`relative h-7 w-12 shrink-0 rounded-full transition`,e?`bg-accent`:`bg-surface-2 border border-border`),children:(0,R.jsx)(`span`,{className:i(`absolute top-0.5 h-6 w-6 rounded-full bg-white shadow transition`,e?`left-[22px]`:`left-0.5`)})})}function Fh({children:e,className:t}){return(0,R.jsx)(`p`,{className:i(`px-8 py-2 text-[13px] leading-[18px] text-muted`,t),children:e})}function Ih({children:e}){return(0,R.jsx)(`p`,{className:`px-8 pb-2 pt-[18px] text-[13px] leading-[18px] text-muted`,children:e})}var Lh=`https://nanomuse.cn/privacy/`;function Rh({me:e,onChanged:t,flush:n=!1}){let r=s(),{state:a,toast:o}=E(),c=!!a.hub?.account.signed_in,[l,u]=(0,L.useState)(null),[d,f]=(0,L.useState)(!1),p=e??l,m=async()=>{if(c&&!e)try{u(await N.cloudMe())}catch{}};(0,L.useEffect)(()=>{m()},[c,e]);let h=p?.contribute??{on:!1,samples:0},g=h.samples??0,_=h.privacy_url||`https://nanomuse.cn/privacy/`,v=async n=>{f(!0);try{await N.cloudContribute(n),o(r(n?`On. Turn it off here at any time.`:`Off. Nothing more is kept.`)),e?t?.():await m()}catch(e){o(e.message)}finally{f(!1)}},y=async()=>{if(window.confirm(r(`The kept conversations are removed from the server. This cannot be undone.`))){f(!0);try{let n=await N.cloudDeleteSamples();o(r(`{n} turns deleted`,{n:String(n.deleted)})),e?t?.():await m()}catch(e){o(e.message)}finally{f(!1)}}};return(0,R.jsxs)(`div`,{className:i(n&&`-mx-4`),children:[(0,R.jsx)(zh,{signedIn:c}),(0,R.jsx)(Ah,{children:(0,R.jsx)(Nh,{label:r(`Help improve nanoMuse's AI models`),checked:c&&h.on,disabled:d||!c||!p,onChange:e=>void v(e)})}),(0,R.jsxs)(Fh,{children:[r(`While this is on, the text of your chats with the nanoMuse Cloud models (what you wrote, what it answered and the tools it chose to call) is kept on the relay to train the community's own open model. Not your memory or SOUL (the system prompt), not what tools returned, not pictures, and never next to who you are. Your own API key never passes through the relay.`),` `,c?h.default_on!==void 0&&(h.default_on?r(`New accounts start with it on.`):r(`New accounts start with it off.`)):r(`Sign in to nanoMuse Cloud to use it.`),` `,c&&g>0&&r(`{n} turns kept so far.`,{n:String(g)}),` `,(0,R.jsx)(`a`,{href:_,target:`_blank`,rel:`noopener noreferrer`,className:`text-accent underline-offset-2 hover:underline`,children:r(`Privacy policy`)})]}),c&&g>0&&(0,R.jsxs)(Ah,{className:`mt-3`,children:[(0,R.jsx)(Mh,{icon:d?(0,R.jsx)(A,{size:22,className:`animate-spin`}):(0,R.jsx)(fn,{size:22}),label:r(`Delete the kept conversations`),value:r(`{n} turns`,{n:String(g)}),onClick:()=>void y(),chevron:!1}),(0,R.jsx)(jh,{inset:16}),(0,R.jsx)(Fh,{className:`px-4 pb-2.5 pt-2`,children:r(`Removes every turn kept from this account, whether the switch is on or off now. Turning the switch off keeps what was kept until you delete it here.`)})]})]})}function zh({signedIn:e}){let t=s(),{toast:n}=E(),[r,i]=(0,L.useState)(null),[a,o]=(0,L.useState)(!1),c=r?.relay?.counts??{conversations:0,messages:0},l=e&&(c.conversations>0||c.messages>0),u=async()=>{try{i(await N.syncState())}catch{}};(0,L.useEffect)(()=>{u()},[e]);let d=async(e,t)=>{o(!0);try{i(await e()),n(t)}catch(e){n(e.message),await u()}finally{o(!1)}},f=e=>{(e||!l||window.confirm(t(`Off deletes the synced conversations from nanoMuse Cloud. The chats on each device stay.`)))&&d(()=>N.syncSetState(e),t(e?`On. Your devices show the same conversations from now on.`:`Off. Nothing is kept on nanoMuse Cloud any more.`))},p=()=>{window.confirm(t(`The synced conversations are removed from nanoMuse Cloud. The chats on each device stay. This cannot be undone.`))&&d(()=>N.syncDelete(),t(`Synced conversations deleted.`))},m=e=>{d(()=>N.syncSetSideChats(e),t(e?`On. This device's side chats go to the account; the other devices' are on their way.`:`Off. Side chats stay on this device from now on.`))},h=e&&!!r?.enabled;return(0,R.jsxs)(`div`,{className:`mb-6`,children:[(0,R.jsx)(Ah,{children:(0,R.jsx)(Nh,{label:t(`Sync conversations between my devices`),checked:h,disabled:a||!e||!r,onChange:f})}),(0,R.jsxs)(Fh,{children:[t(`The text of your chats is kept on nanoMuse Cloud so every device shows the same conversations. Files and images stay on the device they were made on.`),` `,e?r?.paused?t(`Paused: sign in again to continue.`):l&&t(`{c} chats, {m} messages kept so far.`,{c:String(c.conversations),m:String(c.messages)}):t(`Sign in to nanoMuse Cloud to use it.`)]}),r&&`side_chats`in r&&(0,R.jsxs)(R.Fragment,{children:[(0,R.jsx)(Ah,{className:`mt-3`,children:(0,R.jsx)(Nh,{label:t(`Also sync side chats`),checked:h&&!!r.side_chats,disabled:a||!h,onChange:m})}),(0,R.jsx)(Fh,{children:t(`Off: side chats stay on this device. On: this device's side chats go to the account and the other devices' side chats come here.`)})]}),l&&(0,R.jsxs)(Ah,{className:`mt-3`,children:[(0,R.jsx)(Mh,{icon:a?(0,R.jsx)(A,{size:22,className:`animate-spin`}):(0,R.jsx)(fn,{size:22}),label:t(`Delete synced conversations`),value:t(`{n} chats`,{n:String(c.conversations)}),onClick:p,chevron:!1}),(0,R.jsx)(jh,{inset:16}),(0,R.jsx)(Fh,{className:`px-4 pb-2.5 pt-2`,children:t(`Removes what nanoMuse Cloud stores for this account; the chats on each device stay, and the switch stays on. Deleting a chat on one device deletes it on all of them.`)})]})]})}var Bh=`nm.invite`;function Vh(){try{let e=new URLSearchParams(window.location.search).get(`invite`);if(e){let t=Hh(e);t&&localStorage.setItem(Bh,t)}return localStorage.getItem(Bh)??``}catch{return``}}function Hh(e){return e.toUpperCase().replace(/[^A-Z0-9]/g,``).slice(0,8)}function Uh(e){return/^\s*[+\d]/.test(e)?`tel`:`email`}function Wh({onSignedIn:e,useAsModel:t=!1,cta:n,autoFocus:r=!0}){let a=s(),o=(0,L.useId)(),c=Ce(),[l,u]=(0,L.useState)(`code`),[d,f]=(0,L.useState)(``),[p,m]=(0,L.useState)(``),[h,g]=(0,L.useState)(``),[_,v]=(0,L.useState)(!1),[y,b]=(0,L.useState)(null),[x,S]=(0,L.useState)(null),[C,w]=(0,L.useState)(``),[T,E]=(0,L.useState)(!1);(0,L.useEffect)(()=>{let e=Vh();e&&(w(e),E(!0))},[]);let D=async()=>{if(t){b(`model`);try{await N.cloudUseAsModel()}catch{}}await e()},O=async()=>{let e=d.trim();if(e){b(`code`),S(null);try{await N.cloudCode(e),v(!0)}catch(e){S(a(e.message))}finally{b(null)}}},k=async()=>{let e=d.trim();if(!(!e||p.trim().length<4)){b(`verify`),S(null);try{(await N.cloudVerify(e,p.trim(),C.trim())).created&&Vf(),m(``),v(!1);try{localStorage.removeItem(Bh)}catch{}await D()}catch(e){S(a(e.message))}finally{b(null)}}},ee=async()=>{let e=d.trim();if(e&&h){b(`login`),S(null);try{await N.cloudLogin(e,h),g(``),await D()}catch(e){S(a(e.message))}finally{b(null)}}},j=()=>void(l===`password`?ee():_?k():O()),M=n??a(t?`Sign in and use its model`:`Sign in`);return(0,R.jsxs)(`form`,{className:`space-y-3`,onSubmit:e=>{e.preventDefault(),j()},children:[(0,R.jsxs)(`div`,{className:`grid grid-cols-2 gap-1 rounded-2xl bg-surface-2/70 p-1 text-[13px] font-medium`,children:[(0,R.jsx)(Gh,{active:l===`code`,onClick:()=>u(`code`),icon:(0,R.jsx)(Mt,{size:14}),label:a(`With a code`)}),(0,R.jsx)(Gh,{active:l===`password`,onClick:()=>u(`password`),icon:(0,R.jsx)(xt,{size:14}),label:a(`With a password`)})]}),(0,R.jsxs)(`div`,{children:[(0,R.jsx)(`label`,{htmlFor:`${o}-id`,className:`text-[12px] text-muted`,children:se()?a(`Mainland China phone number or e-mail`):a(`E-mail (or a mainland China phone number)`)}),(0,R.jsx)(`input`,{id:`${o}-id`,value:d,onChange:e=>{f(e.target.value),v(!1)},inputMode:Uh(d),autoComplete:`username`,autoFocus:r,placeholder:a(`138 0000 0000 or you@example.com`),className:i(Ie,`mt-1`)}),l===`code`&&!_&&(!se()||oe(d))&&(0,R.jsx)(`p`,{className:`mt-1.5 text-[12px] text-muted`,children:a(`Text-message codes reach mainland-China numbers only. Use an e-mail address instead.`)})]}),l===`password`?(0,R.jsxs)(`div`,{children:[(0,R.jsx)(`label`,{htmlFor:`${o}-password`,className:`text-[12px] text-muted`,children:a(`Password`)}),(0,R.jsx)(`input`,{id:`${o}-password`,type:`password`,value:h,onChange:e=>g(e.target.value),autoComplete:`current-password`,className:i(Ie,`mt-1`)}),(0,R.jsx)(`p`,{className:`mt-1.5 text-[12px] text-muted`,children:a(`No password yet? Use a code first; set one under Account.`)})]}):(0,R.jsxs)(R.Fragment,{children:[_&&(0,R.jsxs)(`div`,{children:[(0,R.jsx)(`label`,{htmlFor:`${o}-code`,className:`text-[12px] text-muted`,children:a(`The code you received`)}),(0,R.jsx)(`input`,{id:`${o}-code`,value:p,onChange:e=>m(e.target.value.replace(/\D/g,``).slice(0,8)),inputMode:`numeric`,autoComplete:`one-time-code`,placeholder:`123456`,autoFocus:!0,className:i(`w-full rounded-2xl bg-surface-2 px-3.5 py-2.5 text-[14.5px] outline-none focus:ring-2 focus:ring-accent/40`,`mt-1 tracking-[0.3em]`)})]}),T?(0,R.jsxs)(`div`,{children:[(0,R.jsx)(`label`,{htmlFor:`${o}-invite`,className:`text-[12px] text-muted`,children:a(`Invite code (optional)`)}),(0,R.jsx)(`input`,{id:`${o}-invite`,value:C,onChange:e=>w(Hh(e.target.value)),autoComplete:`off`,placeholder:`ABCD2345`,className:i(Ie,`mt-1 tracking-[0.2em] uppercase`)}),(0,R.jsx)(`p`,{className:`mt-1.5 text-[12px] text-muted`,children:a(`A friend's code counts for a new account: you both get ¥{invite} more allowance.`,{invite:(c.invite_bonus_cny??5).toFixed(0)})})]}):(0,R.jsx)(`button`,{type:`button`,onClick:()=>E(!0),className:`text-[12px] text-muted underline-offset-2 hover:underline`,children:a(`Have an invite code?`)})]}),x&&(0,R.jsx)(`div`,{className:`rounded-2xl bg-rose-500/12 px-3 py-2 text-[12.5px] text-rose-700 dark:text-rose-300`,children:x}),(0,R.jsx)(`div`,{className:`flex gap-2`,children:l===`code`&&_?(0,R.jsxs)(R.Fragment,{children:[(0,R.jsx)(`button`,{type:`button`,disabled:y!==null,onClick:()=>void O(),className:je,children:a(`Send again`)}),(0,R.jsxs)(`button`,{type:`submit`,disabled:y!==null||p.trim().length<4,className:i(Ne,`flex-1 py-3`),children:[y?(0,R.jsx)(A,{size:15,className:`animate-spin`}):null,` `,M]})]}):l===`code`?(0,R.jsxs)(`button`,{type:`submit`,disabled:y!==null||!d.trim(),className:i(Ne,`flex-1 py-3`),children:[y===`code`?(0,R.jsx)(A,{size:15,className:`animate-spin`}):null,` `,a(`Send me a code`)]}):(0,R.jsxs)(`button`,{type:`submit`,disabled:y!==null||!d.trim()||!h,className:i(Ne,`flex-1 py-3`),children:[y?(0,R.jsx)(A,{size:15,className:`animate-spin`}):null,` `,M]})})]})}function Gh({active:e,onClick:t,icon:n,label:r}){return(0,R.jsxs)(`button`,{type:`button`,onClick:t,"aria-pressed":e,className:i(`flex items-center justify-center gap-1.5 rounded-xl px-2 py-2 transition`,e?`bg-surface text-fg shadow-sm`:`text-muted hover:text-fg`),children:[n,` `,r]})}function Kh(){let{state:e,refreshSettings:t,refreshHub:n,toast:r,skipSignIn:i}=E(),a=s(),o=e.profile?.name??`nanoMuse`,c=(0,R.jsxs)(`ul`,{className:`grid grid-cols-2 gap-2 text-[12.5px] wide:grid-cols-1 wide:gap-1.5 wide:text-[13.5px]`,children:[(0,R.jsx)(qh,{icon:(0,R.jsx)(It,{size:15}),text:a(`Every device of yours, one nanoMuse`)}),(0,R.jsx)(qh,{icon:(0,R.jsx)(st,{size:15}),text:a(`A model with a free allowance, or your own key`)}),(0,R.jsx)(qh,{icon:(0,R.jsx)(vt,{size:15}),text:a(`It uses your phone and computers for you`)}),(0,R.jsx)(qh,{icon:(0,R.jsx)(Qt,{size:15}),text:a(`Keys in your vault; nothing you say is kept on the relay`)})]});return(0,R.jsxs)(`div`,{className:`relative mx-auto flex h-[100dvh] w-full max-w-[760px] flex-col overflow-hidden bg-bg sm:border-x sm:border-border wide:max-w-none wide:border-0`,children:[(0,R.jsx)(`div`,{className:`pointer-events-none absolute inset-x-0 top-0 h-[46vh] bg-[radial-gradient(ellipse_at_top,rgba(0,100,212,0.14),transparent_65%)] dark:bg-[radial-gradient(ellipse_at_top,rgba(23,147,255,0.2),transparent_65%)] wide:inset-y-0 wide:h-auto wide:bg-[radial-gradient(ellipse_at_left,rgba(0,100,212,0.12),transparent_60%)] wide:dark:bg-[radial-gradient(ellipse_at_left,rgba(23,147,255,0.16),transparent_60%)]`}),(0,R.jsx)(`div`,{className:`titlebar-room relative`}),(0,R.jsx)(`div`,{className:`relative flex-1 overflow-y-auto px-6 pb-8 wide:flex wide:items-center wide:px-12`,children:(0,R.jsxs)(`div`,{className:`mx-auto w-full wide:grid wide:max-w-[980px] wide:grid-cols-[1.1fr_1fr] wide:items-center wide:gap-16`,children:[(0,R.jsxs)(`div`,{className:`safe-top flex flex-col items-center pt-14 text-center wide:items-start wide:pt-0 wide:text-left`,children:[(0,R.jsx)(xn,{size:88,className:`drop-shadow-[0_20px_40px_rgba(0,100,212,0.28)]`}),(0,R.jsx)(`h1`,{className:`mt-6 text-[28px] font-bold tracking-tight wide:text-[34px]`,children:a(`Sign in to {name}`,{name:o})}),(0,R.jsx)(`p`,{className:`mt-2 max-w-sm text-[14.5px] leading-relaxed text-muted wide:max-w-md wide:text-[15.5px]`,children:a(`One free account. It is what lets your phone and computers work as one and brings a model to start with.`)}),(0,R.jsx)(`div`,{className:`mt-7 hidden w-full wide:block`,children:c}),(0,R.jsx)(Te,{compact:!0,className:`mt-6 hidden w-full wide:block`})]}),(0,R.jsxs)(`div`,{children:[(0,R.jsx)(`div`,{className:`mt-8 rounded-[28px] border border-border/70 bg-surface p-5 shadow-sm wide:mt-0 wide:p-7`,children:(0,R.jsx)(Wh,{onSignedIn:async()=>{r(a(`Signed in to nanoMuse Cloud.`)),await Promise.all([t(),n()])}})}),(0,R.jsx)(`button`,{type:`button`,onClick:i,className:`mt-4 w-full rounded-2xl border border-border/70 px-4 py-2.5 text-[13.5px] text-fg/80 hover:bg-surface-2`,"data-testid":`sign-in-skip`,children:a(`Use your own API key instead`)}),(0,R.jsx)(`p`,{className:`mt-2 text-center text-[11.5px] leading-relaxed text-muted`,children:a(`You can sign in later under Connections, for sync and your devices.`)}),(0,R.jsx)(`div`,{className:`mt-6 wide:hidden`,children:c}),(0,R.jsx)(Te,{compact:!0,className:`mt-6 wide:hidden`}),(0,R.jsxs)(`p`,{className:`mt-4 text-center text-[11.5px] leading-relaxed text-muted wide:mt-5`,children:[a(`The relay keeps an account id, a masked identifier, usage counts and your agent's name and look; what else, and what is yours to switch off, is in the`),` `,(0,R.jsx)(`a`,{href:Lh,target:`_blank`,rel:`noopener noreferrer`,className:`underline decoration-dotted underline-offset-2 hover:text-fg`,children:a(`privacy policy`)}),`.`]})]})]})})]})}function qh({icon:e,text:t}){return(0,R.jsxs)(`li`,{className:`flex items-start gap-2 rounded-2xl bg-surface-2/60 px-3 py-2.5 text-fg/80 wide:bg-transparent wide:px-0 wide:py-1`,children:[(0,R.jsx)(`span`,{className:`mt-0.5 text-accent`,children:e}),(0,R.jsx)(`span`,{className:`leading-snug`,children:t})]})}function Jh(e,t,n){return!e||!e.account.required||e.account.signed_in||t?.llm_ready?!1:!n}var Yh=`modulepreload`,Xh=function(e){return`/`+e},Zh={},Qh=function(e){return e.pathname.endsWith(`.css`)},$h=function(e,t,n){let r=Promise.resolve();if(t&&t.length>0){let e,i=document.querySelector(`meta[property=csp-nonce]`),a=i?.nonce||i?.getAttribute(`nonce`);function o(e){return Promise.all(e.map(e=>Promise.resolve(e).then(e=>({status:`fulfilled`,value:e}),e=>({status:`rejected`,reason:e}))))}function s(e){return import.meta.resolve?new URL(import.meta.resolve(e)):new URL(e,import.meta.url)}r=o(t.map(t=>{t=Xh(t,n);let r=s(t);if(r.href in Zh)return;Zh[r.href]=!0;let i=Qh(r);if(e===void 0){e={all:new Set,styles:new Set};let t=document.getElementsByTagName(`link`);for(let n=t.length-1;n>=0;n--){let r=t[n];e.all.add(r.href),r.rel===`stylesheet`&&e.styles.add(r.href)}}if((i?e.styles:e.all).has(r.href))return;let o=document.createElement(`link`);if(o.rel=i?`stylesheet`:Yh,i||(o.as=`script`),o.crossOrigin=``,o.href=r.href,a&&o.setAttribute(`nonce`,a),document.head.appendChild(o),i)return new Promise((e,t)=>{o.addEventListener(`load`,e),o.addEventListener(`error`,()=>t(Error(`Unable to preload CSS for ${r}`)))})}).filter(e=>e!==void 0))}function i(e){let t=new Event(`vite:preloadError`,{cancelable:!0});if(t.payload=e,window.dispatchEvent(t),!t.defaultPrevented)throw e}return r.then(t=>{for(let e of t||[])e.status===`rejected`&&i(e.reason);return e().catch(i)})},eg=(0,L.lazy)(()=>$h(()=>import(`./AccountScreen-CfcZ3emY.js`).then(e=>({default:e.AccountScreen})),__vite__mapDeps([0,1,2,3,4,5,6,7,8]))),tg=(0,L.lazy)(()=>$h(()=>import(`./AvatarStudioScreen-DuBIZ1Gf.js`).then(e=>({default:e.AvatarStudioScreen})),__vite__mapDeps([9,1,2,3,4,10,8,11]))),ng=(0,L.lazy)(()=>$h(()=>import(`./ChannelsScreen-DGK7O7Nz.js`).then(e=>({default:e.ChannelsScreen})),__vite__mapDeps([12,1,3,4,10,8]))),rg=(0,L.lazy)(()=>$h(()=>import(`./CodingScreen-DAGGlv2e.js`).then(e=>({default:e.CodingScreen})),__vite__mapDeps([13,1,4,10,8]))),ig=(0,L.lazy)(()=>$h(()=>import(`./ConnectionsScreen-DIFZneZ_.js`).then(e=>({default:e.ConnectionsScreen})),__vite__mapDeps([14,1,2,3,4,5,7,15,10,8,16]))),ag=(0,L.lazy)(()=>$h(()=>import(`./DevicesScreen-BLIuBnuO.js`).then(e=>({default:e.DevicesScreen})),__vite__mapDeps([17,1,3,4,10,8,16]))),og=(0,L.lazy)(()=>$h(()=>import(`./GoalsScreen-DgatXriG.js`).then(e=>({default:e.GoalsScreen})),__vite__mapDeps([18,1,2,3,4]))),sg=(0,L.lazy)(()=>$h(()=>import(`./IdeasScreen-Bwp6l7Xs.js`).then(e=>({default:e.IdeasScreen})),__vite__mapDeps([19,1,10]))),cg=(0,L.lazy)(()=>$h(()=>import(`./LibraryScreen-BclDd8-A.js`).then(e=>({default:e.LibraryScreen})),__vite__mapDeps([20,1]))),lg=(0,L.lazy)(()=>$h(()=>import(`./MemoryScreen-6ZrrpUSE.js`).then(e=>({default:e.MemoryScreen})),__vite__mapDeps([21,1,8]))),ug=(0,L.lazy)(()=>$h(()=>import(`./Onboarding-B0JPnst7.js`).then(e=>({default:e.Onboarding})),__vite__mapDeps([22,1,2,3,4,23,11,14,5,7,15,10,8,16]))),dg=(0,L.lazy)(()=>$h(()=>import(`./SettingsScreen-CJQ-5PSy.js`).then(e=>({default:e.SettingsScreen})),__vite__mapDeps([24,1,2,3,4,5,6,15,23,11,8]))),fg=(0,L.lazy)(()=>$h(()=>import(`./SkillsScreen-ZetN1PPI.js`).then(e=>({default:e.SkillsScreen})),__vite__mapDeps([25,1,8])));function pg(){return(0,R.jsx)(`div`,{className:`flex h-full min-h-[40vh] items-center justify-center text-muted`,children:(0,R.jsx)(A,{className:`animate-spin`,size:20})})}var mg=e=>({size:26,strokeWidth:e?2:1.7,fill:e?`currentColor`:`none`,fillOpacity:e?.18:0}),hg=[{id:`chat`,label:`Chat`,icon:e=>(0,R.jsx)(At,{...mg(e)})},{id:`feed`,label:`Feed`,icon:e=>(0,R.jsx)(Bt,{...mg(e)})},{id:`ideas`,label:`Ideas`,icon:e=>(0,R.jsx)(Ct,{...mg(e)})},{id:`goals`,label:`Goals`,icon:e=>(0,R.jsx)(rn,{...mg(e)})},{id:`library`,label:`Library`,icon:e=>(0,R.jsx)(St,{...mg(e)})}];function gg(){let{state:e,setTab:t,openFile:n}=E(),r=Wf(),a=s();(0,L.useEffect)(()=>{let t=e.profile?.name?.trim();document.title=t&&t.toLowerCase()!==`nanomuse`?`${t} · nanoMuse`:`nanoMuse`},[e.profile?.name]),(0,L.useEffect)(()=>{let e=Sn()?.onQuickChat?.(()=>{t(`chat`),requestAnimationFrame(()=>window.dispatchEvent(new Event(`nanomuse:quick-chat`)))});return()=>{typeof e==`function`&&e()}},[t]),(0,L.useEffect)(()=>{let e=()=>{let e=window.location.hash.slice(1);(e&&hg.some(t=>t.id===e)||e===`devices`||e===`you`||e===`memory`||e===`connections`||e===`channels`||e===`skills`||e===`account`||e===`coding`||e===`avatar`)&&t(e)};return e(),window.addEventListener(`hashchange`,e),()=>window.removeEventListener(`hashchange`,e)},[t]);let o=r&&e.hub?.account.signed_in?(0,R.jsx)(Gf,{}):null,c=e.lite&&e.settings!==null&&!e.settings.onboarded;if((0,L.useEffect)(()=>{c&&N.onboarded(!0).catch(()=>void 0)},[c]),e.authError)return(0,R.jsx)(vg,{});if(!e.loaded)return(0,R.jsx)(_g,{error:e.error});if(Jh(e.hub,e.settings,e.signInSkipped))return(0,R.jsx)(Kh,{});if(!e.lite&&e.settings&&!e.settings.onboarded&&!e.onboardingDismissed&&!e.threads.some(e=>e.events>0))return(0,R.jsxs)(L.Suspense,{fallback:(0,R.jsx)(pg,{}),children:[(0,R.jsx)(ug,{}),o]});let l=e.pendingApprovals.length,u=e.goals.filter(e=>e.proposal&&e.status!==`cancelled`).length,d=e.pendingApprovals.filter(t=>t.ts>e.feedSeenAt).length;return(0,R.jsxs)(`div`,{className:i(`mx-auto flex h-[100dvh] max-w-[760px] flex-col bg-bg sm:border-x sm:border-border`,!e.lite&&`wide:max-w-none wide:flex-row wide:border-x-0`),children:[!e.lite&&(0,R.jsx)(`div`,{className:`hidden wide:block wide:h-full`,children:(0,R.jsx)(uh,{})}),(0,R.jsxs)(`div`,{className:`relative flex min-h-0 min-w-0 flex-1 flex-col`,children:[e.gone&&(0,R.jsxs)(`div`,{className:`flex items-center justify-center gap-2 bg-surface-2 text-muted text-[12.5px] py-1`,children:[(0,R.jsx)(vn,{size:14}),` `,a(e.lite?`This demo has ended.`:`This nanoMuse has stopped. Reload the page once it is running again.`)]}),!e.gone&&!e.connected&&e.loaded&&(0,R.jsxs)(`div`,{className:`flex items-center justify-center gap-2 bg-amber-500/15 text-amber-700 dark:text-amber-300 text-[12.5px] py-1`,children:[(0,R.jsx)(vn,{size:14}),` `,a(`Reconnecting to your nanoMuse…`)]}),!e.lite&&(0,R.jsx)(En,{}),(0,R.jsx)(`main`,{className:i(`tabbar-room mx-auto min-h-0 w-full flex-1 wide:max-w-[900px]`,!e.lite&&`wide:pb-0`),children:(0,R.jsxs)(L.Suspense,{fallback:(0,R.jsx)(pg,{}),children:[e.tab===`chat`&&(0,R.jsx)(Wm,{}),e.tab===`feed`&&(0,R.jsx)(dh,{}),e.tab===`ideas`&&(0,R.jsx)(sg,{}),e.tab===`goals`&&(0,R.jsx)(og,{}),e.tab===`library`&&(0,R.jsx)(cg,{}),e.tab===`memory`&&(0,R.jsx)(lg,{}),e.tab===`skills`&&(0,R.jsx)(fg,{}),e.tab===`connections`&&(0,R.jsx)(ig,{}),e.tab===`channels`&&(0,R.jsx)(ng,{}),e.tab===`devices`&&(0,R.jsx)(ag,{}),e.tab===`you`&&(0,R.jsx)(dg,{}),e.tab===`account`&&(0,R.jsx)(eg,{}),e.tab===`coding`&&(0,R.jsx)(rg,{}),e.tab===`avatar`&&(0,R.jsx)(tg,{})]})}),(0,R.jsx)(`nav`,{className:i(`tabbar-float pointer-events-none absolute inset-x-0 z-20 flex justify-center px-3`,!e.lite&&`wide:hidden`),children:(0,R.jsx)(`ul`,{className:`pointer-events-auto flex w-full max-w-[420px] items-center gap-0.5 rounded-full bg-surface-2/55 px-3.5 py-1.5 ring-1 ring-border/50 backdrop-blur-2xl`,children:hg.map(n=>{let r=e.tab===n.id,o=n.id===`chat`?l:n.id===`feed`?d:n.id===`goals`?u:0;return(0,R.jsx)(`li`,{className:`min-w-0 flex-1`,children:(0,R.jsx)(`button`,{type:`button`,onClick:()=>t(n.id),"aria-label":a(n.label),"aria-current":r?`page`:void 0,className:i(`flex h-[46px] w-full items-center justify-center`,r?`text-ink-fg`:`text-muted hover:text-fg`),children:(0,R.jsxs)(`span`,{className:i(`relative flex h-[46px] w-full max-w-[60px] items-center justify-center rounded-full transition-colors duration-300`,r&&`bg-ink`),children:[n.icon(r),o>0&&(0,R.jsx)(`span`,{className:`absolute right-2.5 top-1 flex h-[17px] min-w-[17px] items-center justify-center rounded-full bg-rose-500 px-1 text-[10px] font-bold text-white`,children:o})]})})},n.id)})})})]}),(0,R.jsx)(kn,{}),(0,R.jsx)(gf,{path:e.viewer,onClose:()=>n(null)}),o,e.toast&&(0,R.jsx)(`div`,{className:`pointer-events-none fixed inset-x-0 bottom-[calc(6rem+env(safe-area-inset-bottom))] z-[70] flex justify-center px-4`,children:(0,R.jsx)(`div`,{role:`status`,className:`rise rounded-2xl bg-fg text-bg px-4 py-2 text-[13.5px] shadow-lg max-w-sm text-center`,children:e.toast})})]})}function _g({error:e}){let t=s();return(0,R.jsxs)(`div`,{className:`mx-auto flex h-[100dvh] max-w-sm flex-col items-center justify-center px-6 text-center`,children:[(0,R.jsx)(xn,{size:72}),e?(0,R.jsxs)(R.Fragment,{children:[(0,R.jsx)(`p`,{className:`mt-6 text-[15px] font-medium`,children:t(`Could not reach your nanoMuse.`)}),(0,R.jsx)(`p`,{className:`mt-1.5 text-[13px] text-muted`,children:t(e)}),(0,R.jsx)(`button`,{type:`button`,onClick:()=>window.location.reload(),className:`mt-5 rounded-full bg-fg px-5 py-2 text-[14px] font-medium text-bg`,children:t(`Try again`)})]}):(0,R.jsxs)(`p`,{className:`mt-6 flex items-center gap-2 text-[14px] text-muted`,children:[(0,R.jsx)(A,{className:`animate-spin`,size:16}),` `,t(`Connecting to your nanoMuse…`)]})]})}function vg(){let[e,t]=(0,L.useState)(``),n=s();return(0,R.jsxs)(`div`,{className:`mx-auto flex h-[100dvh] max-w-md flex-col items-center justify-center px-6 text-center`,children:[(0,R.jsx)(xn,{size:88}),(0,R.jsx)(`h1`,{className:`mt-4 text-[22px] font-bold`,children:n(`Connect to your nanoMuse`)}),(0,R.jsxs)(`p`,{className:`mt-2 text-[14px] text-muted`,children:[n(`This app talks to the nanoMuse server you run yourself. Scan the QR code printed by`),` `,(0,R.jsx)(`code`,{className:`rounded bg-surface-2 px-1`,children:`nanomuse serve`}),n(`, or paste the access token below.`)]}),(0,R.jsxs)(`form`,{className:`mt-5 w-full flex gap-2`,onSubmit:t=>{t.preventDefault(),e.trim()&&(g(e.trim()),window.location.reload())},children:[(0,R.jsx)(`input`,{value:e,onChange:e=>t(e.target.value),"aria-label":n(`Access token`),placeholder:n(`Access token`),className:`flex-1 rounded-2xl bg-surface-2 px-4 py-2.5 text-[15px] outline-none focus:ring-2 focus:ring-accent/40`}),(0,R.jsx)(`button`,{type:`submit`,className:`rounded-2xl bg-accent text-accent-fg px-4 font-medium`,children:n(`Connect`)})]})]})}a(),ee(),wn(),bn.createRoot(document.getElementById(`root`)).render((0,R.jsx)(L.StrictMode,{children:(0,R.jsx)(T,{children:(0,R.jsx)(gg,{})})}));export{Ut as $,Ff as A,gn as B,Jp as C,Ze as Ct,rp as D,Ke as Dt,ip as E,qe as Et,hf as F,tn as G,sn as H,Mn as I,Xt as J,Qt as K,Sn as L,Nf as M,Pf as N,Zf as O,Af as P,Gt as Q,Cn as R,tm as S,Qe as St,op as T,Je as Tt,on as U,fn as V,nn as W,qt as X,Jt as Y,I as Z,nm as _,ct as _t,Ah as a,Nt as at,rm as b,rt as bt,Ih as c,Tt as ct,Um as d,F as dt,Ht as et,Em as f,vt as ft,Xp as g,ut as gt,Qp as h,pt as ht,Fh as i,It as it,jf as j,$f as k,Nh as l,wt as lt,Yp as m,mt,Rh as n,Rt as nt,jh as o,At as ot,Zp as p,gt as pt,Zt as q,Lh as r,Lt as rt,Mh as s,Et as st,Wh as t,Vt as tt,Vm as u,xt as ut,im as v,st as vt,Op as w,Xe as wt,$p as x,tt as xt,em as y,at as yt,yn as z}; \ No newline at end of file diff --git a/nanomuse/server/static/assets/plug-u8jLJjTk.js b/nanomuse/server/static/assets/plug-DV_c5_Ny.js similarity index 77% rename from nanomuse/server/static/assets/plug-u8jLJjTk.js rename to nanomuse/server/static/assets/plug-DV_c5_Ny.js index b20c651a8..83b4ef1fc 100644 --- a/nanomuse/server/static/assets/plug-u8jLJjTk.js +++ b/nanomuse/server/static/assets/plug-DV_c5_Ny.js @@ -1 +1 @@ -import{J as e}from"./MuseHeader-BvAlmxiL.js";var t=e(`plug`,[[`path`,{d:`M12 22v-5`,key:`1ega77`}],[`path`,{d:`M15 8V2`,key:`18g5xt`}],[`path`,{d:`M17 8a1 1 0 0 1 1 1v4a4 4 0 0 1-4 4h-4a4 4 0 0 1-4-4V9a1 1 0 0 1 1-1z`,key:`1xoxul`}],[`path`,{d:`M9 8V2`,key:`14iosj`}]]);export{t}; \ No newline at end of file +import{J as e}from"./MuseHeader-RC--uR8o.js";var t=e(`plug`,[[`path`,{d:`M12 22v-5`,key:`1ega77`}],[`path`,{d:`M15 8V2`,key:`18g5xt`}],[`path`,{d:`M17 8a1 1 0 0 1 1 1v4a4 4 0 0 1-4 4h-4a4 4 0 0 1-4-4V9a1 1 0 0 1 1-1z`,key:`1xoxul`}],[`path`,{d:`M9 8V2`,key:`14iosj`}]]);export{t}; \ No newline at end of file diff --git a/nanomuse/server/static/assets/refresh-cw-BMLOGb5p.js b/nanomuse/server/static/assets/refresh-cw-CxZ3ZdI3.js similarity index 79% rename from nanomuse/server/static/assets/refresh-cw-BMLOGb5p.js rename to nanomuse/server/static/assets/refresh-cw-CxZ3ZdI3.js index d925472fe..b384a6405 100644 --- a/nanomuse/server/static/assets/refresh-cw-BMLOGb5p.js +++ b/nanomuse/server/static/assets/refresh-cw-CxZ3ZdI3.js @@ -1 +1 @@ -import{J as e}from"./MuseHeader-BvAlmxiL.js";var t=e(`refresh-cw`,[[`path`,{d:`M3 12a9 9 0 0 1 9-9 9.75 9.75 0 0 1 6.74 2.74L21 8`,key:`v9h5vc`}],[`path`,{d:`M21 3v5h-5`,key:`1q7to0`}],[`path`,{d:`M21 12a9 9 0 0 1-9 9 9.75 9.75 0 0 1-6.74-2.74L3 16`,key:`3uifl3`}],[`path`,{d:`M8 16H3v5`,key:`1cv678`}]]);export{t}; \ No newline at end of file +import{J as e}from"./MuseHeader-RC--uR8o.js";var t=e(`refresh-cw`,[[`path`,{d:`M3 12a9 9 0 0 1 9-9 9.75 9.75 0 0 1 6.74 2.74L21 8`,key:`v9h5vc`}],[`path`,{d:`M21 3v5h-5`,key:`1q7to0`}],[`path`,{d:`M21 12a9 9 0 0 1-9 9 9.75 9.75 0 0 1-6.74-2.74L3 16`,key:`3uifl3`}],[`path`,{d:`M8 16H3v5`,key:`1cv678`}]]);export{t}; \ No newline at end of file diff --git a/nanomuse/server/static/index.html b/nanomuse/server/static/index.html index 38c83e849..af240a70c 100644 --- a/nanomuse/server/static/index.html +++ b/nanomuse/server/static/index.html @@ -25,12 +25,12 @@ nanoMuse - - - - - - + + + + + + From f38a067f851a0b27acdee564ded7e40efb45fab1 Mon Sep 17 00:00:00 2001 From: Zeeshan Haque Date: Sun, 11 Oct 2026 23:24:40 -0700 Subject: [PATCH 92/98] test(sync): keep the fork's expectations on two tests upstream 1.0.3 rewrote Both files arrive from upstream 1.0.3 with assertions that assume upstream's own configuration, so they fail against the fork's sanitization contract rather than against the merged code: - `tests/test_readme_contributors.py` asserts the badge is `hits.sh/github.com/nano-muse/nanoMuse.svg?`. That URL embeds an upstream repo reference, which `tests/test_fork_docs_sanitization.py` forbids, so the ten READMEs carry the fork's komarev badge. Restores the fork's assertion (it was already this way at `fork/main` and the merge overwrote it). - `tests/test_endpoints_api.py` is new to the fork and adds `settings.cloud.base_url + "/v1"` as a custom endpoint, expecting the "it is the account, not an endpoint" refusal. With the fork's empty relay default that address is the relative `/v1`, refused earlier as malformed. The test now asserts the fork's behaviour for an unconfigured relay and then sets a relay on the live `Settings` to keep upstream's coverage of the account guard. Signed-off-by: Zeeshan Haque --- tests/test_endpoints_api.py | 12 ++++++++++++ tests/test_readme_contributors.py | 5 ++++- 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/tests/test_endpoints_api.py b/tests/test_endpoints_api.py index 5fdf6129d..ffab51597 100644 --- a/tests/test_endpoints_api.py +++ b/tests/test_endpoints_api.py @@ -84,10 +84,22 @@ def test_add_lists_the_models_and_keeps_the_key_in_the_vault(server, listed, set ).status_code == 400 ) + # Fork: no relay is configured by default (`cloud.base_url == ""`), so `/v1` + # is the relative address `/v1` and is refused as malformed before the account check. + assert settings.cloud.base_url == "" + assert ( + client.post( + "/api/connections/endpoints", json={"base_url": settings.cloud.base_url + "/v1"} + ).status_code + == 400 + ) + # With a relay configured the upstream contract holds: it is the account, not an endpoint. + settings.cloud.base_url = "https://relay.example.net" relay = client.post( "/api/connections/endpoints", json={"base_url": settings.cloud.base_url + "/v1"} ) assert relay.status_code == 400 and "nanoMuse Cloud" in relay.json()["detail"] + settings.cloud.base_url = "" added = client.post( "/api/connections/endpoints", json={"base_url": "gateway.example/v1", "api_key": "sk-gateway-1", "models": "my-typed"}, diff --git a/tests/test_readme_contributors.py b/tests/test_readme_contributors.py index b8b681d44..41d2872cb 100644 --- a/tests/test_readme_contributors.py +++ b/tests/test_readme_contributors.py @@ -108,5 +108,8 @@ def test_the_ten_readmes_carry_the_block_and_the_maintainer_card(script: ModuleT assert text.index(script.START) < text.index(script.END), path.name assert 'href="https://github.com/lgy0404"' in text, path.name # The same badge URL twice (badge row and footer): one camo URL, one view per visit. - assert text.count("hits.sh/github.com/nano-muse/nanoMuse.svg?") == 2, path.name + # Fork: the badge is the fork's own counter. Upstream's hits.sh URL embeds + # `github.com/nano-muse/nanoMuse`, which this fork's sanitization contract forbids + # (tests/test_fork_docs_sanitization.py), so the ten READMEs use komarev instead. + assert text.count("komarev.com/ghpvc/?username=nano-muse-nanomuse") == 2, path.name assert "lgy0404" not in text[text.index(script.START) : text.index(script.END)], path.name From e7f645ae8e9dade08f61eb5249dcbef2992104cd Mon Sep 17 00:00:00 2001 From: Zeeshan Haque Date: Sun, 11 Oct 2026 23:28:31 -0700 Subject: [PATCH 93/98] docs(evidence): add the 2026-10-11 sync PR body The PR body for the v1.0.3 (Helm) sanitized sync: provenance, the canonical backend scan and its 18-file classified remainder, the fork-only features the merge had to preserve, the two upstream tests that needed a fork-aware expectation, and every check actually run. Signed-off-by: Zeeshan Haque --- .../run-2026-10-11/pr-body.md | 172 ++++++++++++++++++ 1 file changed, 172 insertions(+) create mode 100644 maintenance-evidence/run-2026-10-11/pr-body.md diff --git a/maintenance-evidence/run-2026-10-11/pr-body.md b/maintenance-evidence/run-2026-10-11/pr-body.md new file mode 100644 index 000000000..68cd03392 --- /dev/null +++ b/maintenance-evidence/run-2026-10-11/pr-body.md @@ -0,0 +1,172 @@ +# Sync upstream nanoMuse v1.0.3 (Helm) into the fork (sanitized) + +Merges the published upstream release `v1.0.3` into the fork without losing any fork-only +feature, and keeps every `.cn` cloud-backend reference out of the shipped tree. + +## Provenance + +| | | +|---|---| +| Upstream repository (read-only) | `nano-muse/nanoMuse` | +| Upstream tip merged | `189621240d7efd6a99debc45a4cc1a55edb6b141` (`upstream/main`) | +| Published upstream releases discovered | `v1.0.3` (Helm) — the only release newer than the fork's previous integration point | +| Upstream release commit | `34a950c82977f20006d19d87d2241fe1f7071e7c` (`refs/tags/v1.0.3`) — **an ancestor of `upstream/main`**, 67 commits behind it, so no separate release-commit integration was needed | +| Fork baseline before this run | `f3237f9b697e0fd6c988c1fafcd2bfce830d54fc` (`fork/main`) | +| Previous merge base | `5379e97a5e6d8c68c6f1fc4da3b4649692b94f82` | +| Commits integrated | 180 (`git rev-list --count fork/main..upstream/main`) | +| **Tested head** | `f38a067f851a0b27acdee564ded7e40efb45fab1` (branch `sync/upstream-1.0.3-sanitize`) | +| Diff | 330 files changed, 11,891 insertions(+), 2,298 deletions(−) | + +Three commits, each with a DCO `Signed-off-by` line: + +``` +f38a067f85 test(sync): keep the fork's expectations on two tests upstream 1.0.3 rewrote +df23dbb031 build(web): regenerate committed static from the merged source (Node 22) +c7bd659949 chore(sync): merge sanitized upstream through v1.0.3 (Helm) +``` + +Releases are discovered independently of whether `upstream/main` moved. Fork releases +already present (`v1.0.0-fork.1`, `v1.0.1-fork.1`, `v1.0.2-fork.1`, `v0.1.41-fork.1`, …) +were deduplicated by upstream tag; `v1.0.3-fork.1` did not exist. + +## Sanitization — the scan of record + +Post-merge, the canonical scan (this exact command is the evidence of record in +`maintenance/RUNBOOK.md`): + +``` +git grep -l 'nanomuse\.cn' -- . \ + ':(exclude)CHANGELOG.md' ':(exclude)docs/releases/**' ':(exclude)cloud/deploy/**' \ + ':(exclude)demo/**' ':(exclude)docs/privacy.md' ':(exclude)docs/roadmap.md' \ + ':(exclude)docs/readme/**' ':(exclude)site/README.md' \ + ':(exclude)docs/release-notes-template.md' ':(exclude)nanomuse/server/static/**' +``` + +Remainder — **18 files**, every one classified, none a new active reference: + +``` +cloud/README.md the deploy artifact name cloud.nanomuse.cn.caddy (cloud/deploy/** is preserved) +docs/zh/cloud.md attribution prose for upstream's public relay +docs/zh/every-device.md attribution prose for upstream's showcase site +docs/zh/privacy.md legal text (in the sanitization test's ALLOWED set) +maintenance-evidence/run-2026-10-05/* immutable prior-run evidence (5 files) +maintenance-evidence/run-2026-10-10/* immutable prior-run evidence (5 files) +maintenance-evidence/run-2026-10-11/* this run's evidence — it quotes the scan command (3 files) +maintenance/RUNBOOK.md this runbook's own literal scan commands +tests/test_fork_relay_defaults.py absence assertion +tests/test_fork_upstream_037_sanitization.py absence assertion +tests/test_nudges_runtime.py absence assertion +``` + +(The runbook's "as of the 0.1.41 sync" list is 13 files; the extra five are this run's own +evidence files, which necessarily quote `nanomuse\.cn` — the same reason the +`run-2026-10-05` and `run-2026-10-10` files are in the remainder.) + +Active-surface scan of the areas the command does not exclude is **empty**: + +``` +git grep -nI 'nanomuse\.cn|demo\.nanomuse\.dev|nano-muse\.github\.io' -- \ + nanomuse web/src cloud/nanomuse_cloud harness desktop android/src \ + ':(exclude)nanomuse/server/static/**' # no hits +grep -rl 'nanomuse\.cn' nanomuse/server/static/ # empty +``` + +### Contract held + +- `NANOMUSE_CLOUD_BASE_URL` / `cloud.base_url` is still the only relay seam. +- `cloud/nanomuse_cloud/config.py`: `invite_url`, `own_key_docs`, `privacy_url`, `repo_url` + all default to `""`; `openrouter_url` keeps its documented third-party default. +- Empty relay still raises `relay_unconfigured` before any network I/O + (`nanomuse/cloud.py:46,108`), and the Android path still calls `requireBaseUrl(context)` + before building a request (`NanoMuseCloud.kt:1129`). +- Upstream's 1.0.3 rewording turned the Chinese docs' relay mentions into bare hostnames + (`在 \`cloud.nanomuse.cn\` 上`). The fork's "upstream's public relay" attribution was + re-applied so the text never reads as this fork's own relay, matching `fork/main`. + +### Preserved, not rewritten + +`CHANGELOG.md` (byte-identical to `upstream/main`), `docs/releases/**`, `docs/privacy.md`, +`docs/roadmap.md`, `docs/readme/**`, `site/README.md`, `docs/release-notes-template.md`, +`cloud/deploy/nanomuse-hk/**`, `demo/showcase/**`, and unrelated third-party `.cn` +citations (`open.bigmodel.cn`, `api.moonshot.cn`, `api.siliconflow.cn`, `open.feishu.cn`, +`pypi.tuna.tsinghua.edu.cn`, `goproxy.cn`, …). + +### Generated assets + +`nanomuse/server/static/**` is never merged by hand. Commit 1 takes upstream's tree +unchanged; commit 2 replaces it with the output of the merged source built on Node 22 +(`vite.config.ts` writes `outDir: "../nanomuse/server/static"`, `emptyOutDir: true`). + +## Fork-only features preserved + +| Feature | Where | State | +|---|---|---| +| Google Calendar over OAuth | `nanomuse/calendar/feeds.py` | fork's `_refresh_feeds` / `_refresh_google` split kept **and** upstream's `_error_text` URL redaction taken (private feed links are secrets) | +| `relay_unconfigured` before network I/O | `NanoMuseCloud.kt` | `requireBaseUrl(context)` kept inside upstream's refactored `request()` | +| Configurable relay hosting / signed-out relay editing | `nanomuse/server/*`, `web/src/**` | kept | +| Bundled desktop Playwright/Chromium | `scripts/desktop-app/*`, `harness/desktop` | kept | +| Update check: GitHub only, mirror opt-in | `nanomuse/server/update.py` | `INDEX_URL = os.environ.get("NANOMUSE_UPDATE_INDEX_URL", "")`, no default, no fallback | +| `source: 'github' \| 'mirror' \| 'none'` | `harness/dsh-nanomuse/src/desk.ts` | kept | +| Fork badge (no upstream repo ref in the READMEs) | `README.md`, `docs/readme/**` | kept — see the test note below | + +No source file present at `fork/main` is missing from this branch. The only 28 files that +disappear are regenerated `nanomuse/server/static/assets/*` bundles. + +## Two upstream tests needed a fork-aware expectation + +Both arrive with 1.0.3 and fail against the fork's configuration rather than against the +merged code. They are fixed in commit 3, not papered over: + +- `tests/test_readme_contributors.py` asserted the badge is + `hits.sh/github.com/nano-muse/nanoMuse.svg?`. That URL embeds an upstream repository + reference, which `tests/test_fork_docs_sanitization.py` forbids; the ten READMEs carry + the fork's komarev badge. The fork's assertion (already present at `fork/main`) is + restored. +- `tests/test_endpoints_api.py` is new to the fork and posts + `settings.cloud.base_url + "/v1"` as a custom endpoint, expecting the *"it is the + account, not an endpoint"* refusal. With the fork's empty relay default that address is + the relative `/v1`, refused earlier as malformed. The test now asserts the fork's + behaviour for an unconfigured relay, then sets a relay on the live `Settings` and keeps + upstream's coverage of the account guard. + +## Checks actually run + +| Check | Result | +|---|---| +| `pytest -q -m "not live"` (runtime, py3.12 CI venv) | **954 passed, 5 skipped, 1 deselected, 0 failed** | +| Same command at the `fork/main` baseline (`/tmp/nm_base`, `f3237f9b69`) | **854 passed, 5 skipped, 1 deselected, 0 failed** | +| Fork contract tests (3 files) | 143 passed | +| `cloud/` pytest | 178 passed | +| `demo/showcase/gateway` pytest | 44 passed | +| `ruff check nanomuse tests scripts demo cloud` | All checks passed | +| `ruff format --check nanomuse tests scripts` | 229 files already formatted | +| `mypy` (py3.12 venv, `[tool.mypy] files = ["nanomuse"]`) | Success: no issues found in 140 source files | +| `python -m compileall -q demo cloud nanomuse scripts` | clean | +| `web` `npm run check` (lint + tsc + vitest) | exit 0, 105 vitest tests passed | +| `harness/dsh-nanomuse` build + typecheck + test | 313 tests pass, 0 fail | +| `harness/desktop` typecheck + test | 59 tests pass, 0 fail | +| `node scripts/connectors-json.mjs --check` | clean | +| `node scripts/providers-json.mjs --check` | clean | +| End-to-end smoke proof | see below | + +The merge adds **100** passing runtime tests and no new failure. + +### End-to-end smoke proof (before any expensive build) + +`nanomuse serve` v1.0.3 booted on `127.0.0.1:8791` from the merged tree: + +- `/api/state` with the Bearer token → **HTTP 200**, `version: "1.0.3"` +- `/api/state` without a token → **HTTP 401** `invalid or missing token` +- all 7 content-hashed assets referenced by `index.html` → **HTTP 200**, including the + entry chunk `assets/index-tYqPtwPX.js` produced by the regenerated bundle +- a real browser (`chrome-headless-shell`, Chrome for Testing 153.0.8010.12) navigated + `http://127.0.0.1:8791/#token=…`: the SPA mounted into `
` and rendered the + onboarding copy (*"nanoMuse · Skip setup · Meet your nanoMuse …"*). The only stderr line + is the known non-GUI-session `CVDisplayLinkCreateWithCGDisplay failed` noise. + +## Not verified here + +- Windows and Linux desktop installers, the iOS build, and the Android release APK are CI + and release-time artifacts, not verified in this PR. +- The adversarial review's findings and their disposition are recorded in + `maintenance-evidence/run-2026-10-11/completion.md` once it has run. From 204633f98838b773ee4b47f92b4ccc63e33705e2 Mon Sep 17 00:00:00 2001 From: Zeeshan Haque Date: Sun, 11 Oct 2026 23:32:17 -0700 Subject: [PATCH 94/98] style(sync): apply ruff format to the three files an earlier sanitization left unformatted MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit CI runs `ruff format --check` over more of the tree than the local commands in `AGENTS.md` do (`demo/` and `cloud/` are checked by their own jobs, with the repository's own ruff). Three files fail that gate, all of them fork-caused: - `cloud/nanomuse_cloud/config.py`: the comment above the emptied `invite_url` default lost its indentation when the default became `""`, so it sits at column 0 inside the class body. - `cloud/tests/test_cloud.py`: the same damage on one dict entry, plus two expressions that were laid out for upstream's longer `nanomuse.cn` URLs and no longer need the wrapping now that the example host is `relay.test` and `own_key_docs` was added. - `demo/showcase/mirror/traffic.py`: `OWN_HOSTS` kept the multi-line comprehension upstream needed for its long `TRAFFIC_HOSTS` default; with the sanitized empty default the formatter joins it to one line. Measured before this commit: `ruff format --check demo cloud` reported 11 files at `fork/main` and 3 here (the merge already took upstream's formatted versions of the other 8). After: 0, with `ruff check` and both pytest suites unchanged (178 relay, 44 gateway). No behaviour changes — whitespace and indentation only. Signed-off-by: Zeeshan Haque --- cloud/nanomuse_cloud/config.py | 2 +- cloud/tests/test_cloud.py | 12 +++++++----- demo/showcase/mirror/traffic.py | 4 +--- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/cloud/nanomuse_cloud/config.py b/cloud/nanomuse_cloud/config.py index ab835d2b3..c29e8b938 100644 --- a/cloud/nanomuse_cloud/config.py +++ b/cloud/nanomuse_cloud/config.py @@ -490,7 +490,7 @@ class Settings: # INVITE_URL is the link the apps offer to share; the code is appended. # OWN_KEY_DOCS is the guide the apps open when the allowance is used up and # the person wants to bring their own model key. -# No default: the operator configures the relay's own URLs (empty hides the link). + # No default: the operator configures the relay's own URLs (empty hides the link). invite_url: str = field(default_factory=lambda: _env("INVITE_URL", "")) own_key_docs: str = field(default_factory=lambda: _env("OWN_KEY_DOCS", "")) # OPENROUTER_URL is where someone outside mainland China gets a key (0.17): Alibaba diff --git a/cloud/tests/test_cloud.py b/cloud/tests/test_cloud.py index 5a0c084e4..cd99f1f10 100644 --- a/cloud/tests/test_cloud.py +++ b/cloud/tests/test_cloud.py @@ -691,7 +691,7 @@ async def test_open_signup_members_unlimited_everyone_else_has_one_allowance(): # the 0.5 co-creation bonus is gone; the names stay for the apps of the time "contribute_bonus_cny": 0, "contribute_bonus_available": False, -"own_key_docs": "https://relay.test/own-key", + "own_key_docs": "https://relay.test/own-key", "openrouter_url": "https://openrouter.ai/keys", # 0.17: a mainland phone account is pointed to Bailian first, then OpenRouter, then an invite; # 0.21 adds the catalogue's facts to the two key ways (additive) and the whole card as `guidance` @@ -2272,7 +2272,11 @@ async def test_me_says_where_the_person_is_and_orders_the_ways_on_by_it(tmp_path ) ) app, client, sender, up, cloud = make_stack( - geoip_db=str(db), catalog_probe=False, allowance_cny=0.002, invite_url="https://relay.test/web/?invite=", own_key_docs="https://relay.test/own-key" + geoip_db=str(db), + catalog_probe=False, + allowance_cny=0.002, + invite_url="https://relay.test/web/?invite=", + own_key_docs="https://relay.test/own-key", ) assert app.state.geo.ready @@ -2303,9 +2307,7 @@ def auth(data, ip): assert [w["id"] for w in cn_ways] == ["bailian", "openrouter", "invite"] assert cn_ways[0] == {"id": "bailian", "url": "https://relay.test/own-key", "mainland_only": True, **WAY_FACTS["bailian"]} assert cn_ways[1] == {"id": "openrouter", "url": "https://openrouter.ai/keys", "mainland_only": False, **WAY_FACTS["openrouter"]} - assert ( - cn_ways[2]["id"] == "invite" and cn_ways[2]["url"].startswith("https://relay.test/web/?invite=") and cn_ways[2]["bonus_cny"] == 5 - ) + assert cn_ways[2]["id"] == "invite" and cn_ways[2]["url"].startswith("https://relay.test/web/?invite=") and cn_ways[2]["bonus_cny"] == 5 for who, ip in ((us, "8.8.8.8"), (nowhere, "9.9.9.9")): ways = (await client.get("/v1/me", headers=auth(who, ip))).json()["spend"]["ways"] assert [w["id"] for w in ways] == ["openrouter", "bailian", "invite"], who["region"] diff --git a/demo/showcase/mirror/traffic.py b/demo/showcase/mirror/traffic.py index 0b809d40c..24cb81c2a 100755 --- a/demo/showcase/mirror/traffic.py +++ b/demo/showcase/mirror/traffic.py @@ -51,9 +51,7 @@ # this mirror is not deployed by this fork, so the operator sets TRAFFIC_HOSTS for the # names their own box serves. Empty means "no known own hosts". OWN_HOSTS = { - h.strip().lower() - for h in (os.environ.get("TRAFFIC_HOSTS") or "").split(",") - if h.strip() + h.strip().lower() for h in (os.environ.get("TRAFFIC_HOSTS") or "").split(",") if h.strip() } DAY_OFFSET_S = int(os.environ.get("TRAFFIC_DAY_OFFSET_H") or "8") * 3600 TOKEN = os.environ.get("GITHUB_TOKEN", "") From cc4b552a040c53d78d05e57ef88c75c63fb0827d Mon Sep 17 00:00:00 2001 From: Zeeshan Haque Date: Sun, 11 Oct 2026 23:39:29 -0700 Subject: [PATCH 95/98] fix(docs): restore the sentence period the mirror-clause removal ate, and guard it Review found a real scar from this run's sanitization: dropping upstream's download-mirror clause also swallowed the joining `;` and the sentence's own `.`, so six READMEs read ".../releases/latest) Open the app" with the two sentences glued together. `README.md:65` plus `docs/readme/README_{es,fr,id,ru,vi}.md:63` now end the sentence properly, matching the wording already on `fork/main` (`README_fr.md` also had a double space). The zh, zh-TW, ja and ko readmes were never affected: the CJK ones have no space after `)` and the ja/ko ones continue with a particle. `tests/test_fork_docs_sanitization.py` grows a regression test for the whole class: a `releases/latest)` link followed by whitespace and a word is the signature, which no correct README produces. Signed-off-by: Zeeshan Haque --- README.md | 2 +- docs/readme/README_es.md | 2 +- docs/readme/README_fr.md | 2 +- docs/readme/README_id.md | 2 +- docs/readme/README_ru.md | 2 +- docs/readme/README_vi.md | 2 +- tests/test_fork_docs_sanitization.py | 21 +++++++++++++++++++++ 7 files changed, 27 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 13a7d60b5..ce3b0cf83 100644 --- a/README.md +++ b/README.md @@ -62,7 +62,7 @@ Every version: [releases](https://github.com/zeeshanhaque21/nanoMuse/releases). | **Linux** x64 | [AppImage](https://github.com/zeeshanhaque21/nanoMuse/releases/download/v1.0.3-fork.1/nanoMuse-Desktop-1.0.3-linux-x64.AppImage) · [.deb](https://github.com/zeeshanhaque21/nanoMuse/releases/download/v1.0.3-fork.1/nanoMuse-Desktop-1.0.3-linux-x64.deb) · [tar.gz](https://github.com/zeeshanhaque21/nanoMuse/releases/download/v1.0.3-fork.1/nanoMuse-Desktop-1.0.3-linux-x64.tar.gz) | | **Docker** | `bash scripts/self-host.sh --local` for your own relay; `docker compose up -d app` for the web app on a server of yours; see [self-hosting](docs/self-hosting.md) | -All downloads come from the [latest release](https://github.com/zeeshanhaque21/nanoMuse/releases/latest) Open the app, sign in with an e-mail or a mainland-China phone number, and it has a model to think with. The phone, the desktop and the web share one account and show the same conversations. +All downloads come from the [latest release](https://github.com/zeeshanhaque21/nanoMuse/releases/latest). Open the app, sign in with an e-mail or a mainland-China phone number, and it has a model to think with. The phone, the desktop and the web share one account and show the same conversations. ## What it does diff --git a/docs/readme/README_es.md b/docs/readme/README_es.md index bc5f5c3c7..d45829443 100644 --- a/docs/readme/README_es.md +++ b/docs/readme/README_es.md @@ -60,7 +60,7 @@ Todas las versiones: [releases](https://github.com/zeeshanhaque21/nanoMuse/relea | **Linux** x64 | [AppImage](https://github.com/zeeshanhaque21/nanoMuse/releases/download/v1.0.3-fork.1/nanoMuse-Desktop-1.0.3-linux-x64.AppImage) · [.deb](https://github.com/zeeshanhaque21/nanoMuse/releases/download/v1.0.3-fork.1/nanoMuse-Desktop-1.0.3-linux-x64.deb) · [tar.gz](https://github.com/zeeshanhaque21/nanoMuse/releases/download/v1.0.3-fork.1/nanoMuse-Desktop-1.0.3-linux-x64.tar.gz) | | **Docker** | `bash scripts/self-host.sh --local` para tu propio relay; `docker compose up -d app` para la app web en un servidor tuyo; véase [autoalojamiento](../self-hosting.md) | -Todas las descargas vienen de la [última versión](https://github.com/zeeshanhaque21/nanoMuse/releases/latest) Abre la app, inicia sesión con un correo o un número de teléfono de China continental, y el agente ya tiene un modelo con el que pensar. El teléfono, el escritorio y la web comparten una cuenta y muestran las mismas conversaciones. +Todas las descargas vienen de la [última versión](https://github.com/zeeshanhaque21/nanoMuse/releases/latest). Abre la app, inicia sesión con un correo o un número de teléfono de China continental, y el agente ya tiene un modelo con el que pensar. El teléfono, el escritorio y la web comparten una cuenta y muestran las mismas conversaciones. ## Qué hace diff --git a/docs/readme/README_fr.md b/docs/readme/README_fr.md index f8304d258..977af7443 100644 --- a/docs/readme/README_fr.md +++ b/docs/readme/README_fr.md @@ -60,7 +60,7 @@ Toutes les versions : [releases](https://github.com/zeeshanhaque21/nanoMuse/rele | **Linux** x64 | [AppImage](https://github.com/zeeshanhaque21/nanoMuse/releases/download/v1.0.3-fork.1/nanoMuse-Desktop-1.0.3-linux-x64.AppImage) · [.deb](https://github.com/zeeshanhaque21/nanoMuse/releases/download/v1.0.3-fork.1/nanoMuse-Desktop-1.0.3-linux-x64.deb) · [tar.gz](https://github.com/zeeshanhaque21/nanoMuse/releases/download/v1.0.3-fork.1/nanoMuse-Desktop-1.0.3-linux-x64.tar.gz) | | **Docker** | `bash scripts/self-host.sh --local` pour votre propre relais ; `docker compose up -d app` pour l'app web sur un serveur à vous ; voir [auto-hébergement](../self-hosting.md) | -Tous les téléchargements viennent de la [dernière version](https://github.com/zeeshanhaque21/nanoMuse/releases/latest) Ouvrez l'app, connectez-vous avec une adresse e-mail ou un numéro de téléphone de Chine continentale, et l'agent a un modèle pour réfléchir. Le téléphone, le bureau et le web partagent un compte et montrent les mêmes conversations. +Tous les téléchargements viennent de la [dernière version](https://github.com/zeeshanhaque21/nanoMuse/releases/latest). Ouvrez l'app, connectez-vous avec une adresse e-mail ou un numéro de téléphone de Chine continentale, et l'agent a un modèle pour réfléchir. Le téléphone, le bureau et le web partagent un compte et montrent les mêmes conversations. ## Ce qu'il fait diff --git a/docs/readme/README_id.md b/docs/readme/README_id.md index 03bc1e175..cd56bd227 100644 --- a/docs/readme/README_id.md +++ b/docs/readme/README_id.md @@ -60,7 +60,7 @@ Semua versi: [releases](https://github.com/zeeshanhaque21/nanoMuse/releases). | **Linux** x64 | [AppImage](https://github.com/zeeshanhaque21/nanoMuse/releases/download/v1.0.3-fork.1/nanoMuse-Desktop-1.0.3-linux-x64.AppImage) · [.deb](https://github.com/zeeshanhaque21/nanoMuse/releases/download/v1.0.3-fork.1/nanoMuse-Desktop-1.0.3-linux-x64.deb) · [tar.gz](https://github.com/zeeshanhaque21/nanoMuse/releases/download/v1.0.3-fork.1/nanoMuse-Desktop-1.0.3-linux-x64.tar.gz) | | **Docker** | `bash scripts/self-host.sh --local` untuk relay sendiri; `docker compose up -d app` untuk aplikasi web di servermu; lihat [self-hosting](../self-hosting.md) | -Semua unduhan berasal dari [rilis terbaru](https://github.com/zeeshanhaque21/nanoMuse/releases/latest) Buka aplikasinya, masuk dengan e-mail atau nomor ponsel Tiongkok daratan, dan agen langsung punya model untuk berpikir. Ponsel, desktop, dan web memakai satu akun dan menampilkan percakapan yang sama. +Semua unduhan berasal dari [rilis terbaru](https://github.com/zeeshanhaque21/nanoMuse/releases/latest). Buka aplikasinya, masuk dengan e-mail atau nomor ponsel Tiongkok daratan, dan agen langsung punya model untuk berpikir. Ponsel, desktop, dan web memakai satu akun dan menampilkan percakapan yang sama. ## Apa yang dilakukannya diff --git a/docs/readme/README_ru.md b/docs/readme/README_ru.md index a7097ebe1..62e6a8a72 100644 --- a/docs/readme/README_ru.md +++ b/docs/readme/README_ru.md @@ -60,7 +60,7 @@ https://github.com/user-attachments/assets/c7694d5a-9450-4f99-9254-5d70560d7565 | **Linux** x64 | [AppImage](https://github.com/zeeshanhaque21/nanoMuse/releases/download/v1.0.3-fork.1/nanoMuse-Desktop-1.0.3-linux-x64.AppImage) · [.deb](https://github.com/zeeshanhaque21/nanoMuse/releases/download/v1.0.3-fork.1/nanoMuse-Desktop-1.0.3-linux-x64.deb) · [tar.gz](https://github.com/zeeshanhaque21/nanoMuse/releases/download/v1.0.3-fork.1/nanoMuse-Desktop-1.0.3-linux-x64.tar.gz) | | **Docker** | `bash scripts/self-host.sh --local` для своего реле; `docker compose up -d app` для веб-приложения на своём сервере; см. [самостоятельный хостинг](../self-hosting.md) | -Все загрузки — из [последнего выпуска на GitHub](https://github.com/zeeshanhaque21/nanoMuse/releases/latest) Откройте приложение, войдите по e-mail или по номеру телефона материкового Китая, и у агента есть модель, чтобы думать. Телефон, компьютер и веб делят один аккаунт и показывают одни и те же разговоры. +Все загрузки — из [последнего выпуска на GitHub](https://github.com/zeeshanhaque21/nanoMuse/releases/latest). Откройте приложение, войдите по e-mail или по номеру телефона материкового Китая, и у агента есть модель, чтобы думать. Телефон, компьютер и веб делят один аккаунт и показывают одни и те же разговоры. ## Что он умеет diff --git a/docs/readme/README_vi.md b/docs/readme/README_vi.md index 442176144..a5c0eb0ad 100644 --- a/docs/readme/README_vi.md +++ b/docs/readme/README_vi.md @@ -60,7 +60,7 @@ Mọi phiên bản: [releases](https://github.com/zeeshanhaque21/nanoMuse/releas | **Linux** x64 | [AppImage](https://github.com/zeeshanhaque21/nanoMuse/releases/download/v1.0.3-fork.1/nanoMuse-Desktop-1.0.3-linux-x64.AppImage) · [.deb](https://github.com/zeeshanhaque21/nanoMuse/releases/download/v1.0.3-fork.1/nanoMuse-Desktop-1.0.3-linux-x64.deb) · [tar.gz](https://github.com/zeeshanhaque21/nanoMuse/releases/download/v1.0.3-fork.1/nanoMuse-Desktop-1.0.3-linux-x64.tar.gz) | | **Docker** | `bash scripts/self-host.sh --local` để có relay của riêng bạn; `docker compose up -d app` để chạy ứng dụng web trên máy chủ của bạn; xem [tự lưu trữ](../self-hosting.md) | -Mọi bản tải đều từ [bản phát hành mới nhất trên GitHub](https://github.com/zeeshanhaque21/nanoMuse/releases/latest) Mở ứng dụng, đăng nhập bằng e-mail hoặc số điện thoại Trung Quốc đại lục, và trợ lý đã có sẵn một mô hình để làm việc. Điện thoại, máy tính và web dùng chung một tài khoản và hiển thị cùng những cuộc trò chuyện. +Mọi bản tải đều từ [bản phát hành mới nhất trên GitHub](https://github.com/zeeshanhaque21/nanoMuse/releases/latest). Mở ứng dụng, đăng nhập bằng e-mail hoặc số điện thoại Trung Quốc đại lục, và trợ lý đã có sẵn một mô hình để làm việc. Điện thoại, máy tính và web dùng chung một tài khoản và hiển thị cùng những cuộc trò chuyện. ## Nó làm được gì diff --git a/tests/test_fork_docs_sanitization.py b/tests/test_fork_docs_sanitization.py index 9717853ab..a88c883af 100644 --- a/tests/test_fork_docs_sanitization.py +++ b/tests/test_fork_docs_sanitization.py @@ -76,3 +76,24 @@ def test_the_scan_sees_the_active_docs() -> None: "website/.vitepress/config.mts", "site/legacy.html", } <= names + + +# Removing upstream's download-mirror clause from the ten READMEs swallowed the +# joining ";" and the sentence's own "." along with the clause, leaving +# ".../releases/latest) Open the app" -- a scar review found on 2026-10-11. +# The signature is a release link followed by whitespace and a word, which only +# the Latin-script readmes can produce: the ja/ko ones continue with a particle +# straight after ")" and the zh/zh-TW ones have no space there at all. +RELEASE_LINK_GLUED = re.compile(r"releases/latest\)\s+[^\s.。!?!?]") + + +def test_no_readme_glues_a_sentence_onto_the_release_link() -> None: + hits = [ + f"{path.relative_to(ROOT).as_posix()}:{n}" + for pattern in ("README.md", "docs/readme/*.md") + for path in ROOT.glob(pattern) + if path.is_file() + for n, line in enumerate(path.read_text(encoding="utf-8").splitlines(), 1) + if RELEASE_LINK_GLUED.search(line) + ] + assert not hits, "missing sentence terminator after the release link: " + ", ".join(hits) From 33161f53c7392f25381c926e5f1c378f22d437ce Mon Sep 17 00:00:00 2001 From: Zeeshan Haque Date: Sun, 11 Oct 2026 23:41:12 -0700 Subject: [PATCH 96/98] docs(evidence): correct the PR body's counts, tested head, and preservation claims The adversarial review fact-checked the body and found five wrong or overstated claims: the sanitization remainder is 19 files not 18, this run's evidence directory held one file not three, the stated tested head was stale and had two red CI jobs, and "preserved, not rewritten" was asserted over several paths that are in fact edited relative to upstream/main. Separate what is genuinely byte-identical to upstream from what was edited and why, restate the counts from a fresh scan, and record the review's findings. Signed-off-by: Zeeshan Haque --- .../run-2026-10-11/pr-body.md | 151 ++++++++++++------ 1 file changed, 106 insertions(+), 45 deletions(-) diff --git a/maintenance-evidence/run-2026-10-11/pr-body.md b/maintenance-evidence/run-2026-10-11/pr-body.md index 68cd03392..83a550e32 100644 --- a/maintenance-evidence/run-2026-10-11/pr-body.md +++ b/maintenance-evidence/run-2026-10-11/pr-body.md @@ -14,12 +14,16 @@ feature, and keeps every `.cn` cloud-backend reference out of the shipped tree. | Fork baseline before this run | `f3237f9b697e0fd6c988c1fafcd2bfce830d54fc` (`fork/main`) | | Previous merge base | `5379e97a5e6d8c68c6f1fc4da3b4649692b94f82` | | Commits integrated | 180 (`git rev-list --count fork/main..upstream/main`) | -| **Tested head** | `f38a067f851a0b27acdee564ded7e40efb45fab1` (branch `sync/upstream-1.0.3-sanitize`) | -| Diff | 330 files changed, 11,891 insertions(+), 2,298 deletions(−) | +| **Tested content head** | `cc4b552a040c53d78d05e57ef88c75c63fb0827d` (branch `sync/upstream-1.0.3-sanitize`) | +| Diff | 334 files changed, 12,087 insertions(+), 2,301 deletions(−) | -Three commits, each with a DCO `Signed-off-by` line: +Five commits, each with a DCO `Signed-off-by` line. The first four carry all the content; +the only commits after the tested content head are evidence-only edits under +`maintenance-evidence/run-2026-10-11/`, which touch no code: ``` +cc4b552a04 fix(docs): restore the sentence period the mirror-clause removal ate, and guard it +204633f988 style(sync): apply ruff format to the three files an earlier sanitization left unformatted f38a067f85 test(sync): keep the fork's expectations on two tests upstream 1.0.3 rewrote df23dbb031 build(web): regenerate committed static from the merged source (Node 22) c7bd659949 chore(sync): merge sanitized upstream through v1.0.3 (Helm) @@ -42,30 +46,30 @@ git grep -l 'nanomuse\.cn' -- . \ ':(exclude)docs/release-notes-template.md' ':(exclude)nanomuse/server/static/**' ``` -Remainder — **18 files**, every one classified, none a new active reference: +Remainder — **19 files**, every one classified, none a new active reference: ``` -cloud/README.md the deploy artifact name cloud.nanomuse.cn.caddy (cloud/deploy/** is preserved) -docs/zh/cloud.md attribution prose for upstream's public relay -docs/zh/every-device.md attribution prose for upstream's showcase site -docs/zh/privacy.md legal text (in the sanitization test's ALLOWED set) -maintenance-evidence/run-2026-10-05/* immutable prior-run evidence (5 files) -maintenance-evidence/run-2026-10-10/* immutable prior-run evidence (5 files) -maintenance-evidence/run-2026-10-11/* this run's evidence — it quotes the scan command (3 files) -maintenance/RUNBOOK.md this runbook's own literal scan commands -tests/test_fork_relay_defaults.py absence assertion -tests/test_fork_upstream_037_sanitization.py absence assertion -tests/test_nudges_runtime.py absence assertion +cloud/README.md 1 the deploy artifact name cloud.nanomuse.cn.caddy +docs/zh/cloud.md 3 attribution prose for upstream's public relay +docs/zh/every-device.md and upstream's showcase site +docs/zh/privacy.md legal text (in the sanitization test's ALLOWED set) +maintenance/RUNBOOK.md 1 the runbook's own literal scan commands +tests/test_fork_relay_defaults.py 3 absence assertions +tests/test_fork_upstream_037_sanitization.py +tests/test_nudges_runtime.py +maintenance-evidence/run-2026-10-05/* 5 immutable prior-run evidence +maintenance-evidence/run-2026-10-10/* 5 immutable prior-run evidence +maintenance-evidence/run-2026-10-11/pr-body.md 1 this run's PR body — it quotes the scan command ``` -(The runbook's "as of the 0.1.41 sync" list is 13 files; the extra five are this run's own -evidence files, which necessarily quote `nanomuse\.cn` — the same reason the -`run-2026-10-05` and `run-2026-10-10` files are in the remainder.) +(The runbook's "as of the 0.1.41 sync" list is 13 files; the extra six are prior runs' +evidence files plus this run's own, which necessarily quote `nanomuse\.cn`. This run's +`completion.md` will be a 20th once the run finishes.) Active-surface scan of the areas the command does not exclude is **empty**: ``` -git grep -nI 'nanomuse\.cn|demo\.nanomuse\.dev|nano-muse\.github\.io' -- \ +git grep -nI 'nanomuse\.cn\|demo\.nanomuse\.dev\|nano-muse\.github\.io' -- \ nanomuse web/src cloud/nanomuse_cloud harness desktop android/src \ ':(exclude)nanomuse/server/static/**' # no hits grep -rl 'nanomuse\.cn' nanomuse/server/static/ # empty @@ -77,25 +81,40 @@ grep -rl 'nanomuse\.cn' nanomuse/server/static/ # empty - `cloud/nanomuse_cloud/config.py`: `invite_url`, `own_key_docs`, `privacy_url`, `repo_url` all default to `""`; `openrouter_url` keeps its documented third-party default. - Empty relay still raises `relay_unconfigured` before any network I/O - (`nanomuse/cloud.py:46,108`), and the Android path still calls `requireBaseUrl(context)` - before building a request (`NanoMuseCloud.kt:1129`). + (`nanomuse/cloud.py`), and the Android path still calls `requireBaseUrl(context)` before + building a request (`NanoMuseCloud.kt:1129`). - Upstream's 1.0.3 rewording turned the Chinese docs' relay mentions into bare hostnames (`在 \`cloud.nanomuse.cn\` 上`). The fork's "upstream's public relay" attribution was re-applied so the text never reads as this fork's own relay, matching `fork/main`. -### Preserved, not rewritten +### Historical and attribution material -`CHANGELOG.md` (byte-identical to `upstream/main`), `docs/releases/**`, `docs/privacy.md`, -`docs/roadmap.md`, `docs/readme/**`, `site/README.md`, `docs/release-notes-template.md`, -`cloud/deploy/nanomuse-hk/**`, `demo/showcase/**`, and unrelated third-party `.cn` -citations (`open.bigmodel.cn`, `api.moonshot.cn`, `api.siliconflow.cn`, `open.feishu.cn`, -`pypi.tuna.tsinghua.edu.cn`, `goproxy.cn`, …). +Untouched relative to `upstream/main` — no active reference was removed from them: + +- `CHANGELOG.md` — byte-identical to `upstream/main` +- `docs/releases/**` — relative to `fork/main` upstream added only its own + `docs/releases/v1.0.3.md`; the directory carries no fork edit +- `docs/privacy.md`, `site/README.md` — byte-identical to `upstream/main` + +Edited relative to `upstream/main` **only** to rename the repository, drop the hosted-demo +and download-mirror references, and bump the version. Their history and their upstream +attribution are kept, not rewritten: + +- `docs/readme/README_*.md` (all ten), `docs/release-notes-template.md`, `docs/roadmap.md` +- `cloud/deploy/nanomuse-hk/deploy.sh` +- `demo/showcase/**` (`gateway/showcase_gateway/{config,logs,webpage}.py`, `mirror/traffic.py`) + +Unrelated third-party `.cn` citations are untouched: `open.bigmodel.cn`, `api.moonshot.cn`, +`api.siliconflow.cn`, `open.feishu.cn`, `iat-api.xfyun.cn`, `pypi.tuna.tsinghua.edu.cn`, +`goproxy.cn`, and the rest. ### Generated assets -`nanomuse/server/static/**` is never merged by hand. Commit 1 takes upstream's tree -unchanged; commit 2 replaces it with the output of the merged source built on Node 22 -(`vite.config.ts` writes `outDir: "../nanomuse/server/static"`, `emptyOutDir: true`). +`nanomuse/server/static/**` is never merged by hand. Commit `c7bd659949` takes upstream's +tree unchanged; commit `df23dbb031` replaces it with the output of the merged source built +on Node 22 (`vite.config.ts` writes `outDir: "../nanomuse/server/static"`, +`emptyOutDir: true`). CI's `web app build` job re-runs `npm run build` and fails if the +committed bundle is stale — it is green. ## Fork-only features preserved @@ -109,13 +128,13 @@ unchanged; commit 2 replaces it with the output of the merged source built on No | `source: 'github' \| 'mirror' \| 'none'` | `harness/dsh-nanomuse/src/desk.ts` | kept | | Fork badge (no upstream repo ref in the READMEs) | `README.md`, `docs/readme/**` | kept — see the test note below | -No source file present at `fork/main` is missing from this branch. The only 28 files that -disappear are regenerated `nanomuse/server/static/assets/*` bundles. +No file present at `fork/main` is missing from this branch except regenerated +`nanomuse/server/static/assets/*` bundles; zero non-static files were dropped. -## Two upstream tests needed a fork-aware expectation +## Three upstream tests needed a fork-aware expectation -Both arrive with 1.0.3 and fail against the fork's configuration rather than against the -merged code. They are fixed in commit 3, not papered over: +These arrive with 1.0.3 and fail against the fork's configuration rather than against the +merged code. They are fixed, not papered over: - `tests/test_readme_contributors.py` asserted the badge is `hits.sh/github.com/nano-muse/nanoMuse.svg?`. That URL embeds an upstream repository @@ -128,29 +147,47 @@ merged code. They are fixed in commit 3, not papered over: the relative `/v1`, refused earlier as malformed. The test now asserts the fork's behaviour for an unconfigured relay, then sets a relay on the live `Settings` and keeps upstream's coverage of the account guard. +- `tests/test_fork_docs_sanitization.py` grows a regression test for the sentence-gluing + scar described under *Review* below. ## Checks actually run +### Local + | Check | Result | |---|---| | `pytest -q -m "not live"` (runtime, py3.12 CI venv) | **954 passed, 5 skipped, 1 deselected, 0 failed** | | Same command at the `fork/main` baseline (`/tmp/nm_base`, `f3237f9b69`) | **854 passed, 5 skipped, 1 deselected, 0 failed** | -| Fork contract tests (3 files) | 143 passed | -| `cloud/` pytest | 178 passed | -| `demo/showcase/gateway` pytest | 44 passed | -| `ruff check nanomuse tests scripts demo cloud` | All checks passed | -| `ruff format --check nanomuse tests scripts` | 229 files already formatted | +| Fork contract tests (3 files) | 144 passed | +| `cloud/` `ruff check . && ruff format --check . && pytest -q` | clean; 178 passed | +| `demo` `ruff check && ruff format --check`; gateway `pytest -q` | clean; 44 passed | +| `ruff check nanomuse tests scripts` / `ruff format --check nanomuse tests scripts` | clean / 229 formatted | | `mypy` (py3.12 venv, `[tool.mypy] files = ["nanomuse"]`) | Success: no issues found in 140 source files | | `python -m compileall -q demo cloud nanomuse scripts` | clean | | `web` `npm run check` (lint + tsc + vitest) | exit 0, 105 vitest tests passed | | `harness/dsh-nanomuse` build + typecheck + test | 313 tests pass, 0 fail | | `harness/desktop` typecheck + test | 59 tests pass, 0 fail | -| `node scripts/connectors-json.mjs --check` | clean | -| `node scripts/providers-json.mjs --check` | clean | -| End-to-end smoke proof | see below | +| `node scripts/connectors-json.mjs --check` / `providers-json.mjs --check` | clean | The merge adds **100** passing runtime tests and no new failure. +### CI + +The first pushed head (`f38a067f85`) had **two red jobs**, both `ruff format --check` +failures the fork's own earlier sanitization had left behind and which the local commands +in `AGENTS.md` do not cover (`demo/` and `cloud/` are checked by their own jobs): + +- `gateway tests` — `demo/showcase/mirror/traffic.py` +- `relay · ruff and pytest` — `cloud/nanomuse_cloud/config.py:493`, + `cloud/tests/test_cloud.py:694` (an indentation scar and two expressions laid out for + upstream's longer URLs) + +`ruff format --check demo cloud` reported **11** unformatted files at `fork/main` and **3** +here — the merge already took upstream's formatted versions of the other eight. Commit +`204633f988` applies the repository's own formatter to the remaining three; both jobs are +now green at the current head, as are `Signed-off-by on every commit`, `web app build`, +`build · test · pack` and `build · test (Windows)`. + ### End-to-end smoke proof (before any expensive build) `nanomuse serve` v1.0.3 booted on `127.0.0.1:8791` from the merged tree: @@ -164,9 +201,33 @@ The merge adds **100** passing runtime tests and no new failure. onboarding copy (*"nanoMuse · Skip setup · Meet your nanoMuse …"*). The only stderr line is the known non-GUI-session `CVDisplayLinkCreateWithCGDisplay failed` noise. +## Review + +A separate fresh-context read-only subagent reviewed the diff, independently re-ran the +backend scan and both pytest suites, re-checked the baseline comparison, audited credential +handling and release provenance, and fact-checked this body. **Verdict: safe to merge, no +blockers.** + +Its findings, all corrected before the merge: + +1. **A real scar** — the mirror-clause removal swallowed a sentence's `.` and the joining + `;` in `README.md` and five translated readmes, gluing two sentences together. Fixed in + `cc4b552a04`, with a regression test. (Review listed four readmes; `README_ru.md` had + the same scar and is fixed too.) +2. **This body's counts were wrong** — the remainder is 19 files, not 18, and this run's + evidence directory held one file, not three. Corrected above. +3. **The stated tested head was stale and had two red CI jobs.** Corrected above. +4. **"Preserved, not rewritten" was overstated** — several listed paths *are* edited + relative to `upstream/main`. The section above now separates what is genuinely + untouched from what was edited, and says why. +5. **The diff stat and tested head were stale.** Both corrected. + ## Not verified here - Windows and Linux desktop installers, the iOS build, and the Android release APK are CI and release-time artifacts, not verified in this PR. -- The adversarial review's findings and their disposition are recorded in - `maintenance-evidence/run-2026-10-11/completion.md` once it has run. +- The committed static bundle was structurally checked (every `index.html` asset reference + exists on disk, no `.cn` strings, no upstream repo refs) and CI rebuilds it, but it was + not byte-compared against a fresh build in this session. +- The adversarial reviewer did not reproduce the end-to-end smoke proof itself; it verified + the surrounding evidence instead. From 80ce8589e50de496603b71c43e92ba1f321a9ff7 Mon Sep 17 00:00:00 2001 From: Zeeshan Haque Date: Sun, 11 Oct 2026 23:46:52 -0700 Subject: [PATCH 97/98] docs(evidence): restate the runtime counts and the commit list from fresh runs The suite is 955 passed at the current head, not 954 -- the 954 reading predates the regression test added in cc4b552a04 -- so the delta against the fork/main baseline (854) is 101, not 100. The branch also carries seven commits, not five: an evidence commit sat between the ruff-format and README fixes. Pin the diff stat to the content head so it cannot drift as evidence is edited, and record the merge-time tip SHA in completion.md rather than here. Signed-off-by: Zeeshan Haque --- .../run-2026-10-11/pr-body.md | 31 ++++++++++++------- 1 file changed, 20 insertions(+), 11 deletions(-) diff --git a/maintenance-evidence/run-2026-10-11/pr-body.md b/maintenance-evidence/run-2026-10-11/pr-body.md index 83a550e32..dee5a384c 100644 --- a/maintenance-evidence/run-2026-10-11/pr-body.md +++ b/maintenance-evidence/run-2026-10-11/pr-body.md @@ -14,21 +14,29 @@ feature, and keeps every `.cn` cloud-backend reference out of the shipped tree. | Fork baseline before this run | `f3237f9b697e0fd6c988c1fafcd2bfce830d54fc` (`fork/main`) | | Previous merge base | `5379e97a5e6d8c68c6f1fc4da3b4649692b94f82` | | Commits integrated | 180 (`git rev-list --count fork/main..upstream/main`) | -| **Tested content head** | `cc4b552a040c53d78d05e57ef88c75c63fb0827d` (branch `sync/upstream-1.0.3-sanitize`) | -| Diff | 334 files changed, 12,087 insertions(+), 2,301 deletions(−) | +| Content head (all code) | `cc4b552a040c53d78d05e57ef88c75c63fb0827d` | +| Tested head | the branch tip — every commit after the content head changes only `maintenance-evidence/run-2026-10-11/`, so tip and content head have identical code | +| Diff (`fork/main..cc4b552a04`, content only) | 334 files changed, 12,087 insertions(+), 2,301 deletions(−) | -Five commits, each with a DCO `Signed-off-by` line. The first four carry all the content; -the only commits after the tested content head are evidence-only edits under -`maintenance-evidence/run-2026-10-11/`, which touch no code: +Seven commits sit on `fork/main`: the sanitizing merge, three follow-up content commits, and +two evidence commits. Each carries a DCO `Signed-off-by` line. The evidence commits touch +only `maintenance-evidence/run-2026-10-11/`: ``` -cc4b552a04 fix(docs): restore the sentence period the mirror-clause removal ate, and guard it -204633f988 style(sync): apply ruff format to the three files an earlier sanitization left unformatted -f38a067f85 test(sync): keep the fork's expectations on two tests upstream 1.0.3 rewrote -df23dbb031 build(web): regenerate committed static from the merged source (Node 22) c7bd659949 chore(sync): merge sanitized upstream through v1.0.3 (Helm) +df23dbb031 build(web): regenerate committed static from the merged source (Node 22) +f38a067f85 test(sync): keep the fork's expectations on two tests upstream 1.0.3 rewrote +e7f645ae8e docs(evidence): add the 2026-10-11 sync PR body +204633f988 style(sync): apply ruff format to the three files an earlier sanitization left unformatted +cc4b552a04 fix(docs): restore the sentence period the mirror-clause removal ate, and guard it +33161f53c7 docs(evidence): correct the PR body's counts, tested head, and preservation claims ``` +The full runtime suite was re-run at the branch tip as well as at the content head, so the +numbers below describe the code that would merge rather than an earlier revision. Because +each further evidence edit moves the tip without touching code, the exact tip SHA at merge +time is recorded in `maintenance-evidence/run-2026-10-11/completion.md` instead of here. + Releases are discovered independently of whether `upstream/main` moved. Fork releases already present (`v1.0.0-fork.1`, `v1.0.1-fork.1`, `v1.0.2-fork.1`, `v0.1.41-fork.1`, …) were deduplicated by upstream tag; `v1.0.3-fork.1` did not exist. @@ -156,7 +164,7 @@ merged code. They are fixed, not papered over: | Check | Result | |---|---| -| `pytest -q -m "not live"` (runtime, py3.12 CI venv) | **954 passed, 5 skipped, 1 deselected, 0 failed** | +| `pytest -q -m "not live"` (runtime, py3.12 CI venv) | **955 passed, 5 skipped, 1 deselected, 0 failed** | | Same command at the `fork/main` baseline (`/tmp/nm_base`, `f3237f9b69`) | **854 passed, 5 skipped, 1 deselected, 0 failed** | | Fork contract tests (3 files) | 144 passed | | `cloud/` `ruff check . && ruff format --check . && pytest -q` | clean; 178 passed | @@ -169,7 +177,8 @@ merged code. They are fixed, not papered over: | `harness/desktop` typecheck + test | 59 tests pass, 0 fail | | `node scripts/connectors-json.mjs --check` / `providers-json.mjs --check` | clean | -The merge adds **100** passing runtime tests and no new failure. +The merge adds **101** passing runtime tests and no new failure (the count rose from 854 at +`fork/main` to 955 here; the last one is the regression test for the scar below). ### CI From b1cec00a58d949c404e4f1b9604bbf029b9a506f Mon Sep 17 00:00:00 2001 From: Zeeshan Haque Date: Sun, 11 Oct 2026 23:47:03 -0700 Subject: [PATCH 98/98] docs(evidence): enumerate only the stable content commits in the PR body A list of commits cannot contain the commit that writes it, so enumerating the evidence commits made the list stale on every edit. List the five content commits, which are fixed, and describe the evidence commits without counting them. Signed-off-by: Zeeshan Haque --- maintenance-evidence/run-2026-10-11/pr-body.md | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/maintenance-evidence/run-2026-10-11/pr-body.md b/maintenance-evidence/run-2026-10-11/pr-body.md index dee5a384c..1f204324d 100644 --- a/maintenance-evidence/run-2026-10-11/pr-body.md +++ b/maintenance-evidence/run-2026-10-11/pr-body.md @@ -18,18 +18,15 @@ feature, and keeps every `.cn` cloud-backend reference out of the shipped tree. | Tested head | the branch tip — every commit after the content head changes only `maintenance-evidence/run-2026-10-11/`, so tip and content head have identical code | | Diff (`fork/main..cc4b552a04`, content only) | 334 files changed, 12,087 insertions(+), 2,301 deletions(−) | -Seven commits sit on `fork/main`: the sanitizing merge, three follow-up content commits, and -two evidence commits. Each carries a DCO `Signed-off-by` line. The evidence commits touch -only `maintenance-evidence/run-2026-10-11/`: +Five content commits sit on `fork/main`, each with a DCO `Signed-off-by` line. Everything +after `cc4b552a04` is evidence-only, touching nothing but `maintenance-evidence/run-2026-10-11/`: ``` c7bd659949 chore(sync): merge sanitized upstream through v1.0.3 (Helm) df23dbb031 build(web): regenerate committed static from the merged source (Node 22) f38a067f85 test(sync): keep the fork's expectations on two tests upstream 1.0.3 rewrote -e7f645ae8e docs(evidence): add the 2026-10-11 sync PR body 204633f988 style(sync): apply ruff format to the three files an earlier sanitization left unformatted cc4b552a04 fix(docs): restore the sentence period the mirror-clause removal ate, and guard it -33161f53c7 docs(evidence): correct the PR body's counts, tested head, and preservation claims ``` The full runtime suite was re-run at the branch tip as well as at the content head, so the