refactor(web): split Shell.tsx into shell components and hooks (#129)
* chore: remove legacy orchestrator, trading and one-off script leftovers The repository still carried the pre-evOo prototype: a Python orchestrator, the old HTML "evoo-platform" cockpit (whose test ran in the root unit suite), an apex-trading package, the hot-reload deploy.sh for it, a permissions manifest, an architecture note with local file links, agent handoff notes, a Steve Jobs persona template and about ninety one-off scripts that probe a developer database with hard-coded local URLs. None of it is used by the product, CI or the real deploy in ops/evo-deploy. Delete those files, drop the evoo-platform test glob from the root vitest config, the Cockpit section from .env.example and the dead biome and gitignore entries, and update the docs that listed the removed tools. scripts/start-tmux.sh no longer starts the removed sentinel and resolves the checkout from its own location instead of a machine-specific path; scripts/seed-ollama.ts requires DATABASE_URL instead of falling back to a local URL with a username. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MRtGG9ARfqqhma3t85Ro2u * feat(media): add media contracts, schema and provider interfaces Groundwork for image and video generation, video editing and transcription. Nothing calls it yet; the media runner, providers, tools and UI build on it. - Contracts: video, audio and subtitle MIME types, per-kind size caps for streamed and generated artifacts, video/audio message blocks and the live media card block, media operations, job statuses and output presets (9:16, 16:9, 1:1, 4:5, 4:3, 21:9). - Core: attachment kinds include video and audio, artifacts become video or audio blocks, and agent history keeps media artifact ids so later turns can refer to them. - Schema: artifacts record width, height, duration and the artifact they were made from; media_jobs tracks generations, edits and transcriptions. - Adapter kit: provider-neutral image generation, video generation and transcription interfaces, the media job context operations run in, and the MediaRuntime that tools use to start jobs. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MRtGG9ARfqqhma3t85Ro2u * fix(web): drop trading and persona prompts from the conversation shell The web shell still showed leftovers from the trading prototype: composer chips with German trading and "Steve Jobs" prompts, trading suggestion chips under the empty conversation line, a German trading hero for the empty transcript, and a German "data protection" status panel in the sidebar. They suggested actions the product does not have and added persistent chrome. Remove the composer chips and their helper, the empty-state chips and the hero (the empty conversation keeps its existing one-line start hint), the sidebar trading indicator and the data trust panel. The new-bot E2E now asserts the plain empty state; the sidebar spec no longer expects the trading status, and the placeholder Steve Jobs spec with no assertions is gone. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MRtGG9ARfqqhma3t85Ro2u * refactor: remove the trading bot status integration With the sidebar trading indicator gone, the only remaining consumer of the trading bot status was a banner in General settings that reused the same component. evOo is a personal assistant; a status proxy and poller for one external trading service, configured through service-specific TRADING_BOT_URL and VITE_TRADING_BOT_URL variables, does not belong in the core product. Remove the settings banner and its prop plumbing, the web poller, the indicator component, the /api/trading-bot/status proxy, the shared core contract, the env loading and both variables from .env.example, together with their tests. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MRtGG9ARfqqhma3t85Ro2u * chore: remove one-off database scripts and a stale review note packages/db carried four hand-run scripts outside the package build that query or seed a developer database with a hard-coded connection string, one of them for a specific account. docs/VOICE-FIRST-REVIEW.md was a one-time verification note for a workflow that no longer exists and named private machines and local paths. Nothing references them. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MRtGG9ARfqqhma3t85Ro2u * feat(memory): remember appends dated notes instead of replacing memory The remember tool rewrote the bot's whole MEMORY.md with each call, so every new fact erased the earlier ones unless the model re-sent the full document. - MemoryCommitRequest gains mode "append" (the store joins the note onto the current content inside the same serializable transaction and still writes a revision row) and every commit is capped at 16 KB per document. - remember appends a dated bullet ("- YYYY-MM-DD: ...", the user's local date) by default and rewrites only with mode "replace"; a full document returns an error that tells the bot to condense it. Retries of the same tool call stay single appends through the existing effect record. - Scripted runtime memory entries can append too; the scripted "remember" script now appends instead of overwriting the bot's memory. - When memory does not fit the run's 32 KB budget, the prompt keeps a document's newest lines instead of its oldest. - memory.update maps an oversized save to BAD_REQUEST. - docs/PRODUCT.md records that UserFact is the cross-space user model and the space MEMORY.md stays space notes (no migration). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MRtGG9ARfqqhma3t85Ro2u * feat(coach): goals, habits, check-ins, daily briefs and check-in rhythm The main agent should coach the user, but nothing stored what the user wants to achieve or keep doing, and no routine ever checked in. This adds the data model and the interfaces the onboarding intake and the coach tools build on. - Schema: UserGoal, Habit, CheckIn (one per habit, goal or day and date) and DailyBrief, all keyed to the user's local calendar date, plus a coachKey on Routine that marks the main bot's coach check-ins. - Contracts (coach.ts): CoachRhythm, Goal, Habit, CheckIn, DailyBrief and CoachToday DTOs and the RPC inputs. - Repository (@rakazo/db coach.ts): goal, habit and check-in CRUD with per-user limits, upsertDailyBrief and loadCoachToday with streaks in the user's time zone. - coach-rhythm.ts: setCoachRhythm/getCoachRhythm keep up to three main bot routines (morning brief, evening check-in, weekly review) in the main conversation in step with the user's chosen times. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MRtGG9ARfqqhma3t85Ro2u * feat(notifications): add push subscriptions, notification settings and web push interfaces Push could only reach one mobile device per user (a token file), quiet hours did not exist, and the web app had no service worker, so a closed tab never heard about finished work. This lands the shared interfaces first so onboarding can build on them: - push_subscriptions (web push endpoints and Expo tokens, one row per device) and user_notification_settings (quiet hours as minutes in the profile time zone, nudges, a per-day nudge counter), with CHECK constraints. - NotificationSettingsSchema and web push contracts, notifications.settings.get/update and notifications.webPush.config/subscribe/unsubscribe (owner-scoped, https endpoints only). - getNotificationSettings/updateNotificationSettings plus the policy and nudge-cap helpers. - VAPID keys from VAPID_PUBLIC_KEY/VAPID_PRIVATE_KEY or generated once and stored encrypted, and an SSRF-guarded web push sender built on the web-push package. - The web app links its manifest, registers a push-only service worker where supported (secure context, not the desktop app) and exposes webPushSupported/webPushEnabled/enableWebPush/ disableWebPush. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MRtGG9ARfqqhma3t85Ro2u * chore: replace machine-specific paths and addresses with placeholders ORIGIN.md pinned the intended checkout to an absolute path under a personal home directory, docs/LOCAL-SETUP.md listed folders on one developer's machine, and two tests used what looks like a real tailnet address. Use a home-relative path, drop the machine-specific folder list, and use 100.100.100.100 in the tests; it is still inside 100.64.0.0/10, so both tests check the same thing as before. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MRtGG9ARfqqhma3t85Ro2u * test(coach): repository, streak and rhythm suites Covers what the coach interfaces promise before anything builds on them: goal and habit ownership and limits, one check-in per habit, goal and day dated in the user's time zone, streaks across weekends and weeks, and a rhythm that keeps exactly one main-bot routine per check-in and is idempotent when set again. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MRtGG9ARfqqhma3t85Ro2u * refactor(contracts): share one clock-time schema The coach rhythm and the quiet hours both parse "HH:MM" wall-clock times and each defined its own ClockTimeSchema, which the contracts index cannot export twice. Both now import it from one module. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MRtGG9ARfqqhma3t85Ro2u * feat(onboarding): ask the onboarding questions in the main conversation The wizard asked for the account name again and a "Tell us about yourself" form, and the focus answer in the main conversation was never saved. The main bot now gets to know the user in the main conversation instead, one card after each answer. - UserOnboarding keeps the pending step, the focus and when onboarding finished. - onboarding-intake.ts declares the steps (focus, goal, rhythm, quiet hours, notifications) as cards plus what their answers change; onboarding.ts commits an answer, the focus app suggestions and the next card or the closing line in one transaction. - The choice block gains a step, an optional text input and the typed answer; choose takes the step, the text and whether the device can still turn push on. - The focus answer becomes a goals fact; the goal, rhythm and quiet-hours effects and the push seam are placeholders until the coach and notification modules are merged. - The wizard drops the preferences step and fills time zone, locale and language from the browser; the main bot's prompt notes open onboarding cards; agent history shows a card's question and answer. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MRtGG9ARfqqhma3t85Ro2u * feat(media): transcribe speech on any OpenAI-compatible server and write subtitles Transcription has to run on the user's own hardware, and the only speech-to-text path so far was the OpenAI voice key. Self-hosted whisper servers (whisper.cpp, faster-whisper based servers, vLLM) all speak the OpenAI transcriptions protocol, so one provider covers them. - createOpenAiCompatibleTranscriptionProvider posts a multipart upload to {base}/audio/transcriptions asking for timed segments, falls back to plain JSON for servers that reject verbose_json, reads text/plain bodies, and reports failures in words. It reuses the address-checked fetch and URL guards of the other OpenAI-compatible adapters, caps uploads at 25 MiB and responses at 8 MiB, and builds the multipart body by hand because the undici fetch behind the address checks does not serialize the global FormData class. - An in-process server emulator (OpenAI/whisper.cpp, plain-JSON-only and text-only flavours) and an in-process provider back an offline conformance suite, plus one loopback test through the real fetch. - toSrt/toVtt in core turn segments into SubRip and WebVTT, wrapping long segments into cues of at most two 42-character lines that share the segment's time, and escaping WebVTT cue text. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MRtGG9ARfqqhma3t85Ro2u * feat(notifications): fan push out to every device, honour quiet hours, add notify_user Run notifications reached at most one phone and nothing could hold them back at night. - PushNotificationProvider sends each notification to all of the user's registered devices (web push and Expo), skips everything during quiet hours in the profile time zone, drops devices the push service reports gone (404/410, DeviceNotRegistered), records lastUsedAt and links each push to its conversation. - Expo tokens move from DATA_DIR/push-tokens files into push_subscriptions: the API imports and deletes the legacy files at start; notifications.registerPush/unregisterPush keep their contract for the mobile app (tokens must look like Expo tokens). - NotificationMessage gains the nudge kind, and the main bot gets notify_user: a short push to the main conversation that respects the nudge switch, quiet hours and a cap of three per day. It is withheld from shared messaging channels and from runs answering another owner's agent. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MRtGG9ARfqqhma3t85Ro2u * feat(coach): main-bot coach tools and goals in its prompt The main agent had no way to record what the user wants to achieve or how their day went, and its prompt never showed their goals or habits. - update_goal, update_habit, log_check_in and write_daily_brief, main-bot only and, like update_user_profile, withheld from shared channels and from runs that answer another owner's agent. Goals and habits can be named by id or exact title. - The main bot's own runs list active goals and habits (with ids, done state and streak) in the <user> block; the basics-only block and every other bot never see them. The main agent role adds a short coaching stance and names each coach tool only when the run has it, so the check-in routine prompts stay tool-agnostic. - The scripted runtime understands a few coach commands and the morning check-in, so tests can drive the tools end to end. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MRtGG9ARfqqhma3t85Ro2u * feat(media): add the Studio specialist the main bot hands media work to Media work (cutting for a format, subtitles, exports) needs editing judgement and a focused tool set, so the main bot should be able to delegate it to a visible specialist instead of doing it itself. - ensureStudioBot creates "Studio" once per user, next to the main bot so it can join the main conversation and read its media, tagged media, with editor instructions (hook first, tight pacing, 9:16 safe areas, subtitles for muted playback) and a restricted builtin allowlist: every media operation plus files, questions, memory and web lookup. It has a thread, so the main bot's specialist directory lists it. The spawn key carries the user id so members of a shared space each get their own. - A Studio the user archived or deleted stays gone. Deleted bots now record their spawn key in bot_deletions so idempotent creation can tell. - Postgres suite for concurrency, shared spaces, archive and delete. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MRtGG9ARfqqhma3t85Ro2u * fix(web): use English Lingui sources for German UI text Several web surfaces hard-coded German (the project card, roster and activity status labels, the sidebar "Heute" label) or used German text as the Lingui source message (sidebar sections, project timeline, bot picker, voice entry, group stage, copy and read-aloud buttons). English users saw German, and because production builds keep only message ids, none of these strings could be translated per locale. Convert them to English source messages, keeping the meaning: - ProjectCreatedCard: Lingui Trans/Plural instead of literals. - agent-activity: labels go through i18n._ with literal ids so the module stays importable from plain unit tests; the extractor still collects them. - Shell, ProjectSessionTimeline, bot-picker, StageVoiceEntry, OoStage: English sources, reusing existing messages where one already fit ("just now", "{n}m ago", "Search", "No bots match", "Set up voice", "Group conversation", "Transcript"). - The conversation picker matches its create entry against the translated label instead of a fixed German string. The German wording returns through the de catalog in the next commit. Unit and E2E tests now assert the English labels. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MRtGG9ARfqqhma3t85Ro2u * feat(web): keep Lingui catalogs complete and in sync The committed catalogs were last extracted weeks ago: about 330 source messages were missing from every locale, and production builds keep only message ids, so those strings rendered as hash ids (sidebar sections, privacy settings, profile, timeline, ...). German also had 226 empty entries, and every extraction rewrote the files because references carried line numbers. - lingui.config.ts: po references without line numbers, and a stable sort that breaks Lingui's ordering ties (explicit ids, equal text) by id, so the output no longer depends on file-system order. - Re-extract all catalogs with --clean (drops 25-44 obsolete entries per locale; no existing translation changed). - Translate every German entry (du form, consistent with the existing catalog). Other locales keep empty entries and fall back to English. - i18n-catalog-sync.test.ts extracts into a copy of the catalogs and fails when the committed files differ or a German entry is empty, so stale catalogs fail the unit test job (offline, about 5 s). Adds @lingui/format-po (already installed through @lingui/cli) as a direct dev dependency to configure the formatter. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MRtGG9ARfqqhma3t85Ro2u * feat(media): add the ComfyUI provider, default workflows and emulator Image and video generation run on the user's own GPU server. ComfyUI is the common self-hosted backend, so this adds a provider for its HTTP API that the generation operations can call. - Core: API-format workflow templates with a small placeholder format ({{prompt}}, {{width}}, {{seed}}, ...) that is validated and filled without evaluating anything. Defaults: text-to-image and image-to-image on core nodes for any SD-family checkpoint, and text/image-to-video on ComfyUI's core LTX-Video nodes; a README lists the placeholders and model files. - Adapters: createComfyUiProvider submits a workflow, polls its history, uploads input images and downloads outputs through the address-checked fetch used for other self-hosted model servers, with timeouts, capped reads and readable errors. A custom workflow from settings replaces the default it matches. Cancelling dequeues or interrupts only its own prompt. GPU status counts memory ComfyUI can free for itself as available. - Contracts: input schemas for generate_image, generate_video and edit_image. - Tests: an in-process ComfyUI emulator, a provider-neutral generation conformance suite and provider tests, all offline. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MRtGG9ARfqqhma3t85Ro2u * refactor(memory): derive the run's memory budget from the document limit The prompt budget was a separate 32 KB constant; it is now twice the per-document limit, so a full bot document and a full space document keep fitting if either number changes. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MRtGG9ARfqqhma3t85Ro2u * feat(profile): edit facts in place in About you About you could only confirm or delete what the bots know about the user, so a fact that was slightly wrong or filed under the wrong category had to be deleted and taught again, and a fact could not be limited to some spaces from the app even though the profile supports it. - Each fact gets an Edit button that turns its row into an inline editor: wording, category, and (when the user has more than one space, or the fact is already limited) which spaces it shows in. Escape or Cancel leaves it unchanged; only changed fields are sent through profile.update editFacts. - A limited fact names its spaces next to its source. - The repository validates edits like new facts: a wording whose normalized form is empty or equals another fact of the user is refused, all edits of one update apply atomically, and the stored embedding is only dropped when the wording really changes. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MRtGG9ARfqqhma3t85Ro2u * feat(inbox): list and answer items from all of the user's spaces The inbox in the main conversation only showed asks, approvals, takeovers and unread threads of the current space. The main conversation lives in the home space, so anything a bot needed in a project space never reached it. - inbox.list now covers every space the user belongs to (except spaces being deleted), still only the user's own bots, runs and threads. Items from another space carry that space's id and name. - The web inbox shows the space name next to the bot for those items, answers them with that space's header so the existing thread procedures check membership and ownership for that space, and opens their thread in it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MRtGG9ARfqqhma3t85Ro2u * feat(coach): coach RPCs for goals, habits, check-ins, today and rhythm The web app needs to show and change the user's coach data, and the check-in times need a way to change after onboarding. - coach.today, coach.goals.*, coach.habits.*, coach.checkIns.* and coach.rhythm.get/set, owner-only and not space-scoped; another user's ids read as not found, invalid input as a bad request. - coach-rhythm reuses the shared clock-time helpers. - Tests: an API suite covering ownership and validation for every procedure, the coach tools driven through the main bot (and refused for a specialist), and a morning check-in routine that fires in the main conversation and writes today's brief; the unauthenticated authorization sweep lists the new procedures. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MRtGG9ARfqqhma3t85Ro2u * feat(onboarding): save goal, check-in rhythm, quiet hours and push from the cards With the coach and notification modules merged, the onboarding answers now take effect: - the goal card creates a goal (source onboarding) through createGoal; - the rhythm card sets the main bot's check-in routines through setCoachRhythm, and the closing line names the first check-in from the routines that were saved; - the quiet-hours card updates the notification settings; - the choice card tells the server whether this browser can still turn push on, so the notifications card is offered only there, and "Turn on" subscribes before answering. The thread lock becomes NO KEY UPDATE so a rhythm routine, which references the thread, can be written while the answer holds the lock. The goal answer is capped at the coach title length. A Postgres suite walks the questions end to end: answers, skips, a dismissed card, a stale and a doubled answer, another bot's focus card, and another user's access. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MRtGG9ARfqqhma3t85Ro2u * feat(media): stream artifacts over HTTP with Range support Videos and audio can be hundreds of megabytes. Artifacts only travelled as base64 inside RPC calls, capped at 10 MiB and held whole in memory, so media could neither be uploaded, played with seeking nor produced by media jobs. - ArtifactStore gains stat, createReadStream (inclusive byte ranges), putStream (size cap enforced while writing, real SHA-256) and an optional localPath so ffmpeg can read stored files in place. LocalArtifactStore implements them with the same safety as before (O_EXCL, O_NOFOLLOW, 0600) and now validates space ids and keys before building paths. - storeArtifactStream / storeArtifactFromFile store a stream or a job's output file as an artifact row, with width, height, duration and parent, and remove the blob again if the row cannot be written. - GET /api/artifacts/:id serves an artifact with Range/206/416, ETag, inline disposition for media and attachment otherwise (safe RFC 6266 filenames), nosniff and same-origin CORP. Authorization matches artifacts.get: the owner's artifact of an active bot thread or group, with membership of the artifact's space (media elements cannot send the space header; an explicit header must name the same space). - POST /api/artifacts takes a raw streamed body with the target and name in the query, authorized like artifacts.create, with the MIME allowlist and the per-kind caps checked from Content-Length and again while writing. - The API CSP allows media from the app origin and blob URLs. - Web: artifactUrl(artifactId) and uploadArtifactFile for the UI. Tests cover the streaming store, range parsing, filename sanitizing, the file helper, and a Postgres suite for both routes: ranges, caching, other users, shared-space members, other spaces, archived threads, signed-out requests and upload limits including chunked bodies. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MRtGG9ARfqqhma3t85Ro2u * feat(media): media job runtime, media queue and media settings Media operations (generation, edits, transcription) need a runner that works outside the agent turn, keeps a card in the conversation current and never lets two processes put work on one GPU. Operations land in later commits; this is the runtime they register with. - Background job `media.run { jobId }` on a named `media` queue. Jobs carry an optional queue: the Graphile publisher passes it as queueName and the in-memory driver runs each queue one job at a time, in order. - `createMediaRuntime` implements MediaRuntime (capabilities, start, get, cancel) over a list of `MediaOperationRegistration`s and runs jobs: start validates the input, creates the job and posts the bot's media card in one transaction (idempotent per tool call through an operation key), then enqueues it. The runner claims a fenced lease (an advisory lock keeps one live lease at a time, so the GPU stays single even when the queue is bypassed), renews it while polling for cancellation, writes progress and outputs into the card, defers with backoff when the GPU is short of memory or the operation asks to wait, bounds deferrals, crash restarts and run time, always cleans the job's temp directory and always ends the card in a terminal state. With continue_after the starting bot is woken in the same transaction that ends the job (new run trigger `media`). - The reconciler re-enqueues jobs whose enqueue was lost, whose runner died or whose wait is over; a job stuck behind a dead worker's queue lock runs outside the queue. - Media backends are deployment-wide settings stored encrypted as the `media` IntegrationProviderConfig row: `loadMediaSettings` and `saveMediaSettings` with the same address policy as OpenAI-compatible servers (no metadata hosts, public hosts only when allowed, HTTPS when a key is sent), a saved key never follows the settings to another server, and the view never returns keys. Contract in contracts/media-settings.ts. - `createMediaOperations` is the one list both the API and the worker build their runtime from (empty until the operations land), and media-tools.ts has the shared `continue_after` schema helper for the tool definitions. - Migration: lease, deferral, operation key and continueAfter columns. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MRtGG9ARfqqhma3t85Ro2u * test(notifications): cover quiet hours, delivery, nudges and the notification RPCs The quiet-hours CHECK accepted a row with only one bound set, because a NULL comparison made the whole condition NULL; it now requires both bounds explicitly. The migration has not shipped yet, so it is corrected in place. - Unit: quiet-hours math across midnight, time zones and daylight saving; VAPID key handling (configured, generated once and shared, invalid); the web push sender (encrypted VAPID-signed request, gone on 404/410, no private or non-https endpoints); the fan-out with fake senders. - PostgreSQL: settings and subscription repositories (constraints, per-user removal, endpoint hand-over, device cap, concurrent nudge cap, cascade on account deletion), delivery and notify_user against a real main conversation, and every notification RPC through the API including cross-user isolation and endpoint validation. - .env.example documents the optional VAPID keys and VAPID_SUBJECT. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MRtGG9ARfqqhma3t85Ro2u * feat(web): notification settings, and sign-out stops this browser's push Users had no way to turn on push for a browser, set quiet hours or opt out of nudges. Settings gains a compact Notifications section: a switch for push on this device (only where web push works: a secure context outside the desktop app), quiet hours with from/to times (22:00-07:00 when first turned on) and a switch for nudges. Changes save in order as they are made. A browser that blocked notifications says so instead of offering a dead switch. Logging out unregisters the browser first, so a shared computer stops receiving the account's pushes. The E2E stubs the Push API (headless Chromium has no push service), walks all three controls, checks they survive a reload and captures the notification-settings screenshot. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MRtGG9ARfqqhma3t85Ro2u * feat(media): transcription input, chunked transcripts and the Studio trigger Groundwork for the transcribe operation and for creating Studio when it is first needed. - Contracts: TranscribeInputSchema (artifact id, optional language code). - transcribeChunks uploads audio chunks in order and stitches them into one transcript on the original timeline; transcriptionChunkSeconds sizes 16 kHz mono WAV chunks below the server's upload limit; transcriptSummary hands the bot the transcript, cut at a word. - ensureStudioWhenMediaConfigured creates Studio once a media server (generation or transcription) is configured. Local edits alone do not count, because ffmpeg and image tools are present on most installs and a specialist nobody asked for would appear for everyone. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MRtGG9ARfqqhma3t85Ro2u * feat(web): show media jobs as a live card in the conversation Media jobs report progress and results through the media block, which the web app did not render. - MediaCard renders the block: operation icon, title, status (reusing the task card's labels, plus "Waiting for GPU" for jobs queued behind the GPU), a progress bar while active, the error when failed, and outputs: images as thumbnails with the existing lightbox, video and audio in the media player, subtitle and text files as file cards. Finished video and audio get a download link, "Export" with presets labelled by aspect ratio (the video's own shape left out) and "Transcribe", offered only when the space can run them; running jobs get "Cancel". - MessageView renders it with one branch. - An E2E seeds the card on a thread snapshot with real uploaded artifacts. - artifact-url.ts and MediaPlayer.tsx are minimal stand-ins for the pipeline workstream's files and give way to them on merge. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MRtGG9ARfqqhma3t85Ro2u * feat(media): edit and export video with ffmpeg Bots can now cut, reframe and export videos for every common format without a hosted service: ffmpeg and ffprobe from PATH do the work on the server. - ffmpeg wrapper: PATH detection, ffprobe JSON probing (rotation, pixel aspect, frame rate, audio, packet scan when the container has no duration), runs with -progress parsing, abort and stall kills, an output size cap, partial-output cleanup and short errors without temp paths. Inputs go through the file protocol with the demuxer forced from the MIME type, so a crafted upload cannot be probed as a playlist that reads other files or URLs. extractAudio (16 kHz mono WAV) and renderPoster for transcription and media cards. - A pure planner turns edit steps (trim, keep, concat, reframe, speed, volume, mute, subtitles, extract_audio, poster) into one filter_complex pass: leading cuts seek the input, appended clips are normalized to the frame, fps and 48 kHz stereo (silence where a clip has none), reframes crop, pad or blur to the presets, speed chains atempo, subtitles burn in from generated file names with a readable style that stays clear of the controls on 9:16 frames. H.264/AAC MP4 with yuv420p and faststart; location metadata is stripped. - edit_video and export_video operations and tool definitions; the inputs are shared contracts so the media card can start exports. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MRtGG9ARfqqhma3t85Ro2u * feat(media): stream job inputs and outputs, cover the job lifecycle on Postgres Media files can be hundreds of megabytes, so the runner no longer buffers them: inputs are cloned from the local artifact file when the store has one and streamed otherwise, outputs go through storeArtifactFromFile (per-kind size cap and MIME check while streaming; an oversized result fails the job with a short card error). A Postgres suite runs the runtime with fake operations: success with outputs, posters and parent versions; input, availability, artifact and thread checks before a job exists; tool-call replay; failure with temp-dir cleanup; outputs outside the temp dir and sources of another user; deferral with backoff and its budget; the GPU memory guard; cancel of a queued job and of a job running in another process; one job per lease and one job on the GPU at a time; crash recovery and its restart limit; reconciliation inside and outside the queue; the continue_after wake; a cleared conversation; the run time limit; and capabilities. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MRtGG9ARfqqhma3t85Ro2u * fix(profile): keep the fact editor's Save label visible Small buttons in ui-web merge their text-ui-label size over the default variant's text color, so the small Save button rendered ink on ink. The editor now uses default-size controls, with the category select at the same height. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MRtGG9ARfqqhma3t85Ro2u * feat(media): generate images and video on ComfyUI and edit images Bots can now make images and short clips on the user's own GPU server and rework images locally, through the media job runtime. - generate_image: prompt, aspect preset or exact size, up to 4 images, optional source image for image-to-image. Sizes target what the default models are tuned for, and sources are fitted to that size before upload, so large photos cannot exhaust GPU memory. - generate_video: prompt, aspect, duration up to 10 s, optional start frame. - edit_image: crop, rotate, flip, resize to a size or format (crop, pad or blurred background), extend, convert, in that order, with sharp; an optional prompt repaints the result on ComfyUI. Edits keep the source as parent. - Registrations declare the input artifacts so jobs refuse ones the user cannot read, and generation declares a fixed GPU memory floor (6 GB images, 12 GB video) that a custom workflow cannot lower. - Tool definitions reuse the operation input schemas plus continue_after. - Saving media settings rejects custom workflows the provider could not fill. - Tests: sharp edits on generated fixtures, handlers against the ComfyUI emulator, and a PostgreSQL suite running the operations through the media runtime (card outputs, artifact versions, foreign artifacts, GPU wait). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MRtGG9ARfqqhma3t85Ro2u * refactor(media): share the ComfyUI JSON request helpers Queue, interrupt and prompt requests now go through one JSON helper, so the cancel path reads like the rest of the client. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MRtGG9ARfqqhma3t85Ro2u * feat(media): register video operations with the media runtime edit_video and export_video now run as media jobs: both registrations join the shared operation list the API and the worker build their runtime from, name every artifact they read (source, appended clips, subtitle files) so starting a job refuses artifacts the user cannot read, and their tool schemas use the runtime's continue_after helper. Container deployments get ffmpeg, ffprobe and the subtitle font in the API/worker image. Tests cover the handlers against a fake job context: cuts, blurred 9:16 reframes with subtitles, appended silent clips, audio extraction, single frames, batch exports with posters and progress, rotated phone video, clear input errors and cancellation. They skip where ffmpeg is not installed; the planner and parser tests always run. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MRtGG9ARfqqhma3t85Ro2u * fix(media): describe media tools by what the model can rely on The image server is the deployment's, not necessarily the user's, and repainting an edit only works when generation is available. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MRtGG9ARfqqhma3t85Ro2u * feat(media): media tools, media RPCs and owner-only media settings API Bots and users need to start and follow media jobs, and the deployment owner needs to point the deployment at their GPU and transcription servers. - Media tools are named like their operations. A run sees one only when the space can run that operation (MediaRuntime.capabilities); the per-bot allowlist still applies. applyTool hands every media tool to one dispatcher (media-tools.ts) that splits off continue_after, starts the job under the tool call's effect key (a replay returns the same job) and returns at once; refusals (invalid input, unknown artifact, unavailable) go back to the model as tool errors. - media.jobs.start starts an export, transcription or image edit from a card: the conversation is resolved like every thread procedure, the card's bot (or the group's lead) posts the new card, and the runtime refuses source artifacts outside the actor's space. media.jobs.get and media.jobs.cancel only see the actor's own jobs. - media.settings.get/update are deployment-owner only, never return keys and answer invalid URLs with a 400 that says what is wrong. - createApp accepts media operations as a test seam. - Tests: a Postgres suite over the RPCs (owner-only settings, encryption, key retention per server, URL policy, start/get/cancel isolation between users, card jobs end to end) and unit tests for tool exposure and dispatch. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MRtGG9ARfqqhma3t85Ro2u * feat(media): transcribe audio and video into subtitles as a media job With the media runtime in place, transcription becomes an operation like the others: bots call the transcribe tool, the job runs in the background and the card shows the subtitle files. - createTranscriptionOperations registers transcribe: available when a transcription server is configured, refuses artifacts the user cannot read before the job exists, and writes <name>.srt and <name>.vtt next to the source (a .txt when the server returns no timings). With ffmpeg the audio is converted to 16 kHz mono WAV and long media is transcribed in upload-sized ranges on one timeline; without it audio is sent as stored and video is refused with a clear message. A server that is down or busy (unreachable, 429, 502, 503) defers the job instead of failing it, since nothing has been stored yet. The bot gets the transcript, cut at a word. - The transcribe tool definition uses the shared media schema helper and continue_after; dispatch stays generic. - The main bot's run creates Studio once a media server is configured, right before the specialist directory is built. - Dictation: when the user's voice provider cannot transcribe (or there is none), /api/voice/transcribe uses the self-hosted transcription server, and the voice status reports server dictation so the web app uses it instead of the browser's speech recognition. A voice provider that transcribes keeps being used as before. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MRtGG9ARfqqhma3t85Ro2u * refactor(notifications): keep the push sender contract next to the fan-out The payload, target and outcome types are shared by the Expo and web push senders, so they now live with PushSender in push-notifications.ts instead of in the web push adapter. The settings E2E also stubs the Notification permission (headless Chromium reports it as denied even when granted), and the quiet-hours inputs are wide enough for 12-hour times. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MRtGG9ARfqqhma3t85Ro2u * feat(web): play video and audio inline and stream uploads and downloads Media sent in a conversation had nowhere to go: the composer capped every file at 10 MiB and pushed it through a base64 RPC, video and audio blocks did not render, and downloads decoded whole files in the page. - Video and audio blocks play inline through MediaPlayer, which loads nothing until the player is near the viewport, sizes the frame from the block's dimensions (vertical clips stay within the column) and uses the poster when one exists. Files the browser cannot play fall back to their name with a download action. - Images load straight from the artifact route; the lightbox gains a download action. - File cards, the Markdown preview and downloads read from the artifact route instead of decoding base64. - The composer accepts each kind up to its cap and names the computed limit when it skips a file; video, audio and anything above the inline cap upload as a raw stream, small files keep the inline RPC. - MediaPlayer and artifactUrl are what the media card builds on. Tests: MediaPlayer laziness, sizing and fallback, the upload helper, and an E2E that uploads a tiny MP4 fixture (VP9, since Playwright's Chromium has no H.264 decoder), plays it from the artifact route and captures media-video-block, plus the image lightbox download. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MRtGG9ARfqqhma3t85Ro2u * test(media): run transcribe through the media runtime on Postgres Covers what the unit tests fake: the job starts from validated input with the "Transcript" card, runs against the transcription emulator, stores the .srt and .vtt as artifacts next to the source and lists them on the card, and an artifact of another user is refused before a job exists. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MRtGG9ARfqqhma3t85Ro2u * feat(media): disclose media servers in AI data sharing Media tools and card actions send prompts, images, video and audio to the deployment owner's ComfyUI and transcription servers. Like the embeddings server behind built-in memory, those self-hosted endpoints are recipients in the AI data-sharing disclosure: they appear with the model uses ("ComfyUI (<origin>)", "Transcription (<origin>)", keyed by the full endpoint so a new server asks again), and starting a card job asks for model consent on clients that run the foreground check. Also adds unit tests for the media settings store: URL normalization and refusals, encryption, the key-free view, one decryption per saved version, key retention per server and removing empty settings. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MRtGG9ARfqqhma3t85Ro2u * refactor(media): trim unused ffmpeg wrapper options Binary paths, the ffmpeg version, the probe's container name and a configurable stall timeout had no caller; detection is cached per process, so every helper looks the binaries up itself. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MRtGG9ARfqqhma3t85Ro2u * fix(media): hand the transcript to the bot as quoted speech A transcript is whatever was said in the recording, so the summary the bot is woken with quotes it and says it is not instructions. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MRtGG9ARfqqhma3t85Ro2u * feat(web): media settings section for the deployment owner (wip) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MRtGG9ARfqqhma3t85Ro2u * feat(media): give agents attached media and larger bot files Agents only received the documents of a turn on their computer and could attach workspace files up to 10 MiB, so they could neither cut a clip a user sent nor post the video they rendered. - Current-turn images, video and audio are copied into the bot's workspace (Team Computers under bots/<botId>/) like documents. Remote computers move files as base64 JSON, so anything above their 12 MiB transfer cap stays in storage and the agent is told it by artifact id instead of failing the turn; local computers copy up to the kind cap. - attach_file accepts video and audio by extension and attaches up to the kind cap when the store streams (still bounded by the transfer cap of a remote computer), stored through the shared artifact helper with a real SHA-256. - The render_plot fallback that attaches a chart PNG now records the group, so the chart opens in group conversations. - Agent history names image artifacts by id, like video and audio, so a later turn can refer to them. - artifacts.get refuses files above 25 MiB: base64 reads hold the whole file in memory, and larger media is served by the artifact route. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MRtGG9ARfqqhma3t85Ro2u * fix(mobile): show video, audio and media cards as plain rows Mobile has no media UI yet, so video, audio and media-card blocks rendered as empty bubbles or fell out of previews. - Thread text and reply previews describe video and audio files and the media card's title and status. - The bubble lists video, audio and a finished card's outputs as tappable rows that open the file like other attachments. - Opening video or audio downloads it from the artifact route to the cache instead of a base64 RPC, so long recordings open without the server holding them in memory. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MRtGG9ARfqqhma3t85Ro2u * fix(web): download media outputs with the forced-download artifact URL The media card's download link uses artifactUrl's download option so a video or audio output is saved rather than opened inline, and the E2E seeds the thread snapshot with fresh response headers so the patched body is read. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MRtGG9ARfqqhma3t85Ro2u * fix(api): refuse artifact uploads from untrusted origins Uploads with a text/plain, text/csv or text/markdown body are CORS "simple" requests that a browser sends cross-site without a preflight. The session cookie's SameSite default already keeps it off such requests, but a deployment that relaxes it would accept uploads from any page. The route now applies the same origin rule as CORS before reading the session. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MRtGG9ARfqqhma3t85Ro2u * fix(core): load child_process normally in the git checkout reader readGitCheckout loaded node:child_process through require(), which does not exist in the ESM API runtime. Linking a project space to a folder that is a git checkout therefore failed after the space was created. The lazy load is no longer needed: the reader is only reachable through the server-only "@rakazo/core/git-checkout" subpath, never through the package entry the web app bundles. Import spawn at the top instead. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MRtGG9ARfqqhma3t85Ro2u * feat(onboarding): ask before discovering projects and let the user choose The onboarding scan started on its own, discarded what it found, claimed to read email and calendars, simulated progress for everyone who could not scan, and its project creation always failed (wrong Space fields and a space lookup by title across tenants). Discovery now asks first and creates nothing without a choice: - The scan step appears only for the deployment owner when ONBOARDING_SCAN_HOME is set; everyone else skips it. The simulated scan is gone. - It shows the folder and asks. Only directory listings are read: git projects up to four levels deep, their languages and a few tools (Docker, GitHub Actions, Terraform). Symlinks are never followed and each chosen folder is resolved again before use, so nothing outside the folder is reached. Results stay with the account that scanned. - Found projects are a checklist (none preselected); found languages and tools are facts (preselected). "Add" creates one project space per chosen project with createSpaceForMember and wireProjectWorkspace in the user's own organization, reusing the user's own space already linked to that folder, and saves the chosen facts as onboarding facts under the profile lock and fact limit. - When a connection becomes connected (direct connect, authorization round trip, or catalog reconciliation), "Uses <App>" is remembered as a tools fact from the connector. Revoking keeps it. The E2E harness now points ONBOARDING_SCAN_HOME at a fixture folder and starts without a deployment owner, so owner-only onboarding steps appear only in specs that take the seat through /__e2e/deployment-owner. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MRtGG9ARfqqhma3t85Ro2u * feat(web): start exports, transcriptions and cancels from the media card The card's follow-ups now reach the media job RPCs, and it only offers what the space can run. - media.capabilities answers which operations the actor's space can run (booleans only). The card asks once per minute per space, and only when it shows finished video or audio, so other cards cost nothing. - Export and Transcribe call media.jobs.start with the card's message, so the same bot posts the new card; Cancel calls media.jobs.cancel. A refused start shows the server's message under the card. - New files use top-level import type. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MRtGG9ARfqqhma3t85Ro2u * fix(media): GPU guard for smaller cards, top-level type imports - The GPU guard waited for free VRAM at the operation's floor even on a card whose total memory is below it (an 8 GB card and a 12 GB video floor), so such jobs deferred until their budget ran out. The requirement is now capped at 90% of the card's total; a card with less than half the floor fails at once with "The GPU does not have enough memory for this job." - Tests pin that media tools reach a run only through the space's capabilities and within the bot's allowlist now that the image tool definitions exist. - Type-only imports are top-level `import type` in the media runtime, tools, RPCs and tests (AGENTS.md). - The ComfyUI settings test gives saveMediaSettings a store with nothing saved, since the save reads the previous settings before validating. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MRtGG9ARfqqhma3t85Ro2u * test(media): run video edits and exports through the media runtime A Postgres suite starts edit_video and export_video through the real runtime and local artifact store: outputs become linked versions with posters on the card, exports store one version per preset, appended clips and subtitle files of another user are refused at start, and an out-of-range cut fails the job with a readable error. It skips without Postgres or ffmpeg. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MRtGG9ARfqqhma3t85Ro2u * fix(media): abandoned handlers cannot crash the worker, sweep stale temp dirs - A handler that ignores its abort is left behind after the grace period; a late rejection from it (or from the grace timer after the job settled) was unobserved, and the worker exits on unhandled rejections. Both sides of the race are now observed and the grace timer is cleared with the job. - Ending a job removes its temp directory when no runner in this process holds it (leftovers of a runner that died here), and reconciliation sweeps directories of jobs that no longer run. - An executor test runs a media tool end to end through applyTool: shown only for operations the space can run, started with the run's scope and effect key, continue_after split off, refused when not exposed. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MRtGG9ARfqqhma3t85Ro2u * fix(web): offer media card follow-ups on any settled job Failed or cancelled jobs can still carry finished outputs, so the card asks for the space's capabilities whenever a settled job shows video or audio. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MRtGG9ARfqqhma3t85Ro2u * feat(web): coach on the Heute page Heute only listed runs and linked to a hard-coded local Mission Control address, so the coach's work had nowhere to show. - Today's brief at the top, habits with a check-off and their streak, and active goals, each only when there is something to show; then the existing needs-you, doing and done lists. - One icon button opens the check-in times (morning, evening, weekly), loaded when opened and saved on every change. - The page reads coach.today, refreshes it when a run finishes or the tab becomes visible, and checks habits off optimistically; the date header uses the user's time zone from the profile. - Removes the Mission Control link and its constant. - Tests: helper unit tests and a web E2E that writes the brief through the main bot, checks a habit off across a reload and sets check-in times (screenshots heute-coach and heute-rhythm). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MRtGG9ARfqqhma3t85Ro2u * test(onboarding): walk the onboarding questions end to end; mobile reads cards as text - onboarding-intake.spec walks focus, goal (after typing into the composer, which still works), check-ins, quiet hours and the notifications card when the browser offers it, with the onboarding-intake-goal, -rhythm and -done screenshots. - completeOnboarding and the wizard specs drop the preferences step; the scan step is optional (skipped when it asks, otherwise it advances by itself). - The user-profile spec now checks the browser-filled profile and the focus fact; the conversation spec checks the shorter app suggestion and the following goal question. - The hover spec measures a reply that fills its row (a bot row's rail sits at the row's end, so the old long onboarding line was what made it pass) and scopes Send to the composer, since an open goal card has its own. - Mobile shows a choice card as its question and answer instead of an empty bubble. - The focus options drop their unused summary. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MRtGG9ARfqqhma3t85Ro2u * test(web): stub the Notification permission without a static-only class Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MRtGG9ARfqqhma3t85Ro2u * fix(media): let bots title image edits in the user's language Edit cards showed English words such as "crop · flip · extend" to every user. edit_image now takes an optional title written by the bot in the user's language, used for the card and the file name like edit_video. Without one, the card falls back to the repaint prompt or to language-neutral tokens only: sizes, ratios, degrees, arrows and format names. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MRtGG9ARfqqhma3t85Ro2u * test(media): transcribe real clips through ffmpeg Generated clips (nothing binary committed) go through extractAudio: a video's audio reaches the server as 16 kHz mono WAV, a 12-second recording is uploaded in two ranges under a small limit, and a video without sound is refused before anything is uploaded. Skipped where ffmpeg is missing, which may include CI runners. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MRtGG9ARfqqhma3t85Ro2u * test(web): cover group uploads in the main conversation The image E2E now runs in the main conversation, which is a group thread, so the browser test covers group uploads and reads from the artifact route as well as bot threads. Bot file attachments keep their run's operation id for tracing, and the non-streaming attach cap is the inline cap directly. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MRtGG9ARfqqhma3t85Ro2u * feat(media): title transcription cards with what they transcribe A card that only says "Transcript" does not tell two transcriptions apart, and it is English whatever the user's language. - transcribe takes an optional title like the video operations, so a bot names the card in the user's language; "Transcript" stays the default. - Transcribe on a media card passes the source file name as the title. - The E2E seeds the card through bootstrap as well as threads/get, since the bot thread's first snapshot arrives with bootstrap. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MRtGG9ARfqqhma3t85Ro2u * refactor(web): match the media player stand-in to the pipeline's props The pipeline workstream's MediaPlayer takes artifactId, kind, name, poster and size, without a MIME type; the card and the stand-in now use exactly that, so its file replaces the stand-in without other changes. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MRtGG9ARfqqhma3t85Ro2u * test(web): media settings E2E with the media-settings screenshot The Media settings section (added in the previous web commit) lets the deployment owner point media at their own servers: ComfyUI URL and optional key, with the image model and custom image/video workflows folded under Advanced, and a transcription URL with optional model and key. Saved keys are never shown again; the key field says one is saved and offers to remove it. Members who do not own the deployment do not see the section. The spec fills both servers, captures `media-settings`, saves and checks the exact update the server receives, then removes the saved key and the transcription server; a second spec checks a member has no Media section. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MRtGG9ARfqqhma3t85Ro2u * fix(web): size uploaded videos from their own frame Uploaded videos carry no dimensions, so a vertical clip sat letterboxed in a 16:9 frame. The player now takes the frame size from the file's metadata when the block has none. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MRtGG9ARfqqhma3t85Ro2u * fix(media): disclose the transcription server before dictation uses it Dictation falls back to the owner's transcription server when the voice provider cannot transcribe, so that server is a voice recipient too: it is listed for voice use (as "Transcription (<origin>)") whenever it would take the recording, and not when the voice provider transcribes itself. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MRtGG9ARfqqhma3t85Ro2u * fix(web): render media card outputs with the URL-based previews The media pipeline moved image and file previews to the artifact route, so they no longer take a bot or group target. The media card still passed one, which no longer type-checks; only its follow-up actions need the target. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MRtGG9ARfqqhma3t85Ro2u * fix(api): let large uploads finish and abort stalled ones Node's default 5-minute requestTimeout cut off a 500 MiB video upload on any uplink slower than about 14 Mbit/s, so the video cap was unusable over ordinary connections. - The API server's requestTimeout is 30 minutes, enough for the largest upload at about 2.5 Mbit/s. headersTimeout keeps its 60-second default. - Each streamed upload aborts when the client sends no bytes for 60 seconds: the route answers 408, the partial file is deleted and no row is written, so a slow-drip client cannot hold a connection for the full request timeout. Time spent writing to disk does not count. - The store and the upload guard no longer wait for a body to confirm its cancellation, which a stalled or hostile client may never do. - A guard test checks that every file the executor attaches records the thread's group, which the render_plot chart fallback once dropped. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MRtGG9ARfqqhma3t85Ro2u * fix(media): use snake_case keys in every media tool input The model saw edit_video and export_video with artifact_id next to generate_image, generate_video, edit_image and transcribe with artifactId, sourceArtifactId and negativePrompt. Mixed conventions in one tool list invite wrong calls, so all media inputs now use snake_case like continue_after and the other builtin tools: artifact_id, source_artifact_id, negative_prompt, duration_seconds. Handlers, artifact checks, the media card's transcribe action and the tests follow. Nothing has shipped, so stored job inputs need no migration. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MRtGG9ARfqqhma3t85Ro2u * fix(media): act on media cards in their own space, not the selected one The main conversation lives in the home space, but the user can have another space selected while it is on screen, and the card's actions sent that space: media.jobs.start resolved the conversation in the selected space and failed, and media.jobs.get/cancel only found jobs of the selected space. The server now takes the space from the card itself. start finds the card's message in one of the actor's own threads (the conversation named by botId or groupId), requires the actor to still be a member of that thread's space, and resolves the conversation and the source artifacts there. get and cancel find the actor's job by id and require membership of the job's space. media.capabilities takes an optional job id and answers for that job's space; the card asks through its job and shares the answer per conversation. Every other case is a 404, as before. A Postgres test runs a card in the home-space main conversation while another space is selected (start, get, capabilities, cancel) and checks that another user and a user who left the card's space get 404 on every procedure. This also completes the media settings section committed earlier as work in progress (01eea83); its code was final, only that commit message said otherwise. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MRtGG9ARfqqhma3t85Ro2u * test(web): find the sidebar Today button by its English label The shell contrast test added on main looks up the sidebar button by the old German source text, which this branch replaces with "Today". Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MRtGG9ARfqqhma3t85Ro2u * style: use top-level type imports in the media changes AGENTS.md asks for top-level `import type` instead of inline `type` specifiers; this applies it to the import statements the media work added or changed. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MRtGG9ARfqqhma3t85Ro2u * chore(web): extract catalogs and translate the media strings to German Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MRtGG9ARfqqhma3t85Ro2u * feat(onboarding): show the onboarding cards and check-in names in the user's language The onboarding cards, the closing line and the coach routine names were English server text for every user. The server keeps the state and an English fallback; the web now words them through Lingui, so there is one translation source. - Choice cards: the web says the question, the option labels and the placeholder from the step and option ids, and keeps the server text for anything it does not know (quiet-hour ranges are already written in the user's locale). Another bot's focus card is recognized by its option ids. Mobile and agent history keep the server text. - The "Got it. … are a good place to start." line is gone: the app cards speak for themselves, and with no cards nothing is said. - The closing line becomes an intake_note block (note "done", nextCheckInAt, English text). The web words it with the first check-in in the user's clock; mobile blockText and blocksToAgentHistoryText read its text through their generic fallback. - Routines carry coachKey. The routine list and editor show a check-in under its label in the UI language until the user renames it; saving an untouched label keeps the stored name. The English names move to contracts (COACH_ROUTINE_NAMES); prompts stay English. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MRtGG9ARfqqhma3t85Ro2u * style: use top-level type imports in the coach changes AGENTS.md asks for top-level `import type` instead of inline `type` specifiers; this applies it to the import statements the coach work added or changed. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MRtGG9ARfqqhma3t85Ro2u * chore(web): extract catalogs and translate the coach strings to German Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MRtGG9ARfqqhma3t85Ro2u * test(web): look for the bot reply in the transcript only The main conversation's sidebar row now previews the latest reply, so the unscoped text lookup matched the sidebar too and failed in strict mode. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MRtGG9ARfqqhma3t85Ro2u * test(web): drop the trading status from the shell contrast test main's contrast test now waits for the sidebar trading status before measuring; this branch removes that status. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MRtGG9ARfqqhma3t85Ro2u * test(onboarding): link the foreign folder while its tenant owns the deployment Since #112 only the deployment owner can link a host folder, so the discovery test creates the other tenant's linked space while that tenant holds the deployment, then hands the deployment to the scanning owner. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MRtGG9ARfqqhma3t85Ro2u * chore(web): extract catalogs and translate the in-app browser strings Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MRtGG9ARfqqhma3t85Ro2u * fix(media): write poster frames as full-range JPEG Newer ffmpeg releases refuse to encode JPEG from limited-range video frames, so poster frames failed on CI's ffmpeg while older versions accepted the same command. The poster is converted to full-range yuvj420p before encoding, which every supported ffmpeg version takes. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MRtGG9ARfqqhma3t85Ro2u * test: look up the home main conversation in the scheduling journey Since every project has its own main conversation, the journey that schedules for a specialist found the user's main conversation with findFirst over all of them. With the Lab project's conversation also matching, it picked either one, so the check failed about one run in three. The lookup now names the home space, where the specialist joined and the routine is created. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MRtGG9ARfqqhma3t85Ro2u * test: look up the home main conversation in the scheduling journey Since every project has its own main conversation, the journey that schedules for a specialist found the user's main conversation with findFirst over all of them. With the Lab project's conversation also matching, it picked either one, so the check failed about one run in three. The lookup now names the home space, where the specialist joined and the routine is created. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MRtGG9ARfqqhma3t85Ro2u * test: expect the home main conversation's ask in another space's inbox Every project now has a main conversation of its own, so an ask waiting in the home main conversation is not visible from a project and its inbox lists it, answered in the home space. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MRtGG9ARfqqhma3t85Ro2u * fix(coach): move check-ins when the user's time zone changes The coach check-ins are main-bot routines scheduled in the profile time zone, but a later zone change (About you, onboarding, the main bot's update_user_profile tool, or forgetting the whole profile) left them in the old zone until the rhythm was saved again, so they fired at the wrong local time. syncCoachTimeZone, next to the rhythm code, moves the main bot's coach routines that are not in the current profile zone into it, recomputes the next run of armed ones and re-arms their wakeup. Paused check-ins move but stay paused, routines the user made are never touched, users without check-ins get none, and a save that leaves the zone as it is changes nothing. The profile update and forget RPCs and the profile tool call it whenever they write the zone. Quiet hours, the daily nudge cap and coach dates are evaluated in the profile zone when they are used, so they need no migration. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MRtGG9ARfqqhma3t85Ro2u * fix(web): word the main conversation preview in the user's language during onboarding While onboarding wrote the main conversation, its sidebar row, project rows and Heute showed the server preview: nothing for a pending card (a card has no text of its own, so the row fell back to "Ready") and the English fallback of the closing note, even for a German user. Groups now carry `previewBlock` next to `preview`: the latest message when it is an onboarding card or note, validated with the same block schemas the messages use (now named exports). The web words it with the helpers that render the card and the note, so no copy is duplicated: the question while a card waits, the answer once given, and the closing note in the user's language and clock. A dismissed card keeps the plain preview, as the conversation no longer shows it. The field is left out for every other message, and mobile keeps using the plain `preview`. The chosen-answer lookup moves from the card into onboarding-copy so the card and the preview share it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MRtGG9ARfqqhma3t85Ro2u * fix(media): stream large media between the store and local computers Attachments copied into a local computer's workspace were read whole from the artifact store first, so a 500 MiB video sat in memory before it was written to disk. attach_file did the same in the other direction: a large file on a local computer was read whole before it was stored. SandboxProvider gains optional readFileStream/writeFileStream. The desktop (host workspace) provider implements them with the same path confinement as its byte methods, one chunk in memory at a time, and removes a file whose write fails or is aborted, including one that replaced an earlier copy. The host-aware wrapper routes them, and providers without them (remote computers, still capped at 12 MiB) receive the collected bytes. Current-turn staging and attach_file now go through these helpers, and unread streams are cancelled so the stored file is released. Media job inputs stop copying when the job is cancelled. The stream helpers move from the local artifact store into a shared module so both use one implementation. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MRtGG9ARfqqhma3t85Ro2u * feat(media): live ComfyUI progress over its websocket A video generation runs a single ComfyUI prompt for minutes, and the media card only advanced after each prompt finished, so it sat still until the clip was done. The ComfyUI provider now follows ComfyUI's standard /ws stream while its prompts run and maps step progress to the job's overall fraction across all prompts: never backwards, and short of each prompt's share until its outputs are downloaded. The history poll stays the source of truth for completion and errors; a socket that cannot connect, drops, or stays silent leaves generation exactly as before, and it is closed on finish, failure, cancel and abort. Each generation uses its own client id, so concurrent jobs do not take over each other's messages. The socket goes through a new createOpenAiCompatibleWebSocket next to the guarded fetch: same URL and key checks, same resolved-address lookup, ws/wss derived from http/https, the same Authorization header, a message size cap, and a hard drop when a server never finishes the closing handshake. It uses the undici package's WebSocket, so no dependency was added. A provider given a replaced fetch without a matching socket opens none, so tests and emulators never reach the network. The ComfyUI emulator now serves the websocket and reports progress for running prompts; provider, guard and conformance tests cover ordering, multi-prompt mapping, unavailable and failing sockets, stray messages, closing on cancel, and the address checks against a loopback server. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MRtGG9ARfqqhma3t85Ro2u * test(web): look for the focus question in the conversation, not the sidebar The main conversation's sidebar row now shows the pending intake question, so a page-wide text match finds it twice (strict mode) or never reaches zero. The specs mean the card in the open conversation, so they look there. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MRtGG9ARfqqhma3t85Ro2u * refactor(web): move Shell.tsx module-level code into pages/shell modules Shell.tsx had grown to about 8,000 lines, roughly 2,200 of them module-level components and helpers below ShellPage. That made the page hard to navigate and review and turned every chat change into an edit of one hot file. This is a move-only refactor: code is moved verbatim and only imports and exports change. No renames, no JSX or memo boundary changes. - shell/transcript.tsx: Transcript, QuoteSelectionButton, MessageHoverActions, MessageView - shell/composer.tsx: Composer, slashActionLabel, MentionOptionIcon, MentionChipIcon, ATTACHMENT_ACCEPT - shell/computer-screen.tsx: ComputerReleaseActions, embeddableScreenUrl, screenIframeSandbox, DesktopKindEmptyState, computerPlaceholder, computerLabel (all used by the computer pane) - shell/thread-state.ts: threadSnapshotSignal, firstThreadRoute, applyThreadEvent, newClientNonce - shell/roster-format.ts: stripSpaceTitlePrefix, formatRosterTime, cleanRosterPreview - shell/message-preview.ts: previewMessageText (shared by composer and transcript) - shell/collapsed-sidebar-sections.ts: collapsed sidebar storage helpers - shell/shell-types.ts: PendingAttachment and FALLBACK_BOT_COLOR, shared by Shell.tsx, composer and transcript Types, constants and one-off helpers used only by ShellPage stay in Shell.tsx. The Lingui catalogs only change their file-reference comments; message ids and translations are unchanged. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MRtGG9ARfqqhma3t85Ro2u * refactor(web): extract sidebar model and space search hooks from ShellPage ShellPage mixes the sidebar's derived roster with thread orchestration in one 3,000-line body, which makes both hard to review. Behaviour-preserving move: - useSpaceSearch owns the sidebar query, the debounced space search and jumpToSearchHit. - useSidebarModel owns the sidebar memos (roster groups, conversations, projects, main conversation entry) and the project drag-and-drop order. Both are called where the sidebar memos were, so the search effect keeps its place among ShellPage's effects; bodies and dependency arrays move verbatim. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MRtGG9ARfqqhma3t85Ro2u * refactor(web): extract sound, Today count and browser notification hooks Behaviour-preserving move of ShellPage side effects into named hooks: - useShellSounds: audio ducking, the app-start sound and the sounds for bots that need the user, finished work, run errors, handoffs and group sparks. - useHeuteActionCount: the 15-second Today brief poll behind the sidebar badge. - useBrowserNotifications: pending and delivered browser notification bookkeeping plus notifyBrowserForEvent / flushPendingBrowserNotifications. The hooks run where the code was. The Today poll effect sat between the app-start sound and the bot status sound; it now runs just before the sound hook, ahead of the two mount-only audio effects it does not interact with. Effect bodies, refs and dependency arrays move verbatim. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MRtGG9ARfqqhma3t85Ro2u * refactor(web): extract mobile sidebar, bots sidebar and computer viewport hooks Behaviour-preserving move of layout state out of ShellPage: - useMobileSidebar: the mobile navigation open state, closing it at the desktop breakpoint, and the edge-swipe touch handlers that were inline on the shell root. - useBotsSidebarCollapse: the per-user collapsed preference and the edge-drag pointer handlers that were inline on the sidebar edge button. - useComputerViewport: the on-screen-keyboard viewport tracking for the full-screen computer. Each hook is called where its effect was, so effect order is unchanged. The inline JSX handlers become named functions with identical bodies, still recreated on every render as before. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MRtGG9ARfqqhma3t85Ro2u * refactor(web): extract messaging status, agent skills and mention target hooks Behaviour-preserving move of ShellPage data loaders into named hooks: - useMessagingStatus: the messaging surface flag and providers, loaded once a session user exists. - useAgentSkills: the agent skill catalog for slash commands, its refresh, and the setter bot settings use after editing skills. - useMentionTargets: composer mention options built from bots, group members, routines and connectors, including the routine/connector loader. Each hook is called where its effect was, so effect order is unchanged, and the hooks take the same objects the effects read so bodies and dependency arrays move verbatim. The mention loader's bots ref stays private to the hook; nothing else read it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MRtGG9ARfqqhma3t85Ro2u * refactor(web): extract ShellPage sidebar JSX into components ShellPage's JSX carried the whole sidebar inline, including two near-copies of the group header and of the main header's sidebar toggles, which made the render hard to follow and easy to change in one place only. Move-only: the sidebar header, group header (one component for the conversation and project variants), the team and project roster rows, the archived section, the user menu and the sidebar toggle buttons now live in pages/shell. DOM, classNames, test ids, aria attributes, handlers and messages are unchanged; the catalogs only update their file references, and the desktop source checks for the header toggles now read the file they moved to. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MRtGG9ARfqqhma3t85Ro2u * refactor(web): extract ShellPage side panel and computer JSX into components The side panel header, the computer preview and the full-window computer overlay were large inline blocks in ShellPage's render. Move-only: they are now SidePanelHeader, ComputerPanelPreview and FullscreenComputerOverlay in pages/shell, each with explicit props. The booting screen, the routine list and the create-bot modal stay where they are. DOM, classNames, test ids, aria attributes, handlers and messages are unchanged; the catalogs only update their file references. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MRtGG9ARfqqhma3t85Ro2u * refactor(web): share one PointerMenu for the space and section menus The space and section context menus repeated the same dropdown with an invisible trigger anchored at the pointer; only their label and items differ. Move-only: PointerMenu in pages/shell renders that dropdown and both menus pass their label, close handler and items. DOM, attributes and handlers are unchanged, and the labels stay in ShellPage, so the catalogs do not change. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MRtGG9ARfqqhma3t85Ro2u --------- Co-authored-by: Claude <noreply@anthropic.com>
This commit is contained in:
parent
dda03bff9e
commit
f395ed9a23
@ -63,6 +63,7 @@ describe("window chrome", () => {
|
|||||||
it("keeps conversation header controls clickable", () => {
|
it("keeps conversation header controls clickable", () => {
|
||||||
const root = path.join(path.dirname(fileURLToPath(import.meta.url)), "../pages");
|
const root = path.join(path.dirname(fileURLToPath(import.meta.url)), "../pages");
|
||||||
const shell = readFileSync(path.join(root, "Shell.tsx"), "utf8");
|
const shell = readFileSync(path.join(root, "Shell.tsx"), "utf8");
|
||||||
|
const toggles = readFileSync(path.join(root, "shell/sidebar-toggle-buttons.tsx"), "utf8");
|
||||||
expect(shell).toContain(
|
expect(shell).toContain(
|
||||||
'className="app-drag flex items-center justify-between border-b border-sidebar-border',
|
'className="app-drag flex items-center justify-between border-b border-sidebar-border',
|
||||||
);
|
);
|
||||||
@ -70,14 +71,16 @@ describe("window chrome", () => {
|
|||||||
expect(shell).toContain('className="app-no-drag flex min-w-0 items-center gap-3"');
|
expect(shell).toContain('className="app-no-drag flex min-w-0 items-center gap-3"');
|
||||||
// Ensure header sidebar toggle controls stay clickable (not part of drag region)
|
// Ensure header sidebar toggle controls stay clickable (not part of drag region)
|
||||||
expect(
|
expect(
|
||||||
shell.match(/app-no-drag .* size-control-lg .* place-items-center/g)?.length ?? 0,
|
toggles.match(/app-no-drag .* size-control-lg .* place-items-center/g)?.length ?? 0,
|
||||||
).toBeGreaterThanOrEqual(2);
|
).toBeGreaterThanOrEqual(2);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("moves window chrome into the conversation header when the bots sidebar is collapsed", () => {
|
it("moves window chrome into the conversation header when the bots sidebar is collapsed", () => {
|
||||||
const root = path.join(path.dirname(fileURLToPath(import.meta.url)), "../pages");
|
const root = path.join(path.dirname(fileURLToPath(import.meta.url)), "../pages");
|
||||||
const shell = readFileSync(path.join(root, "Shell.tsx"), "utf8");
|
const shell = readFileSync(path.join(root, "Shell.tsx"), "utf8");
|
||||||
expect(shell).toContain("{botsSidebarCollapsed && desktopBridge() ? <WindowChrome /> : null}");
|
const toggles = readFileSync(path.join(root, "shell/sidebar-toggle-buttons.tsx"), "utf8");
|
||||||
|
expect(shell).toContain("collapsed={botsSidebarCollapsed}");
|
||||||
|
expect(toggles).toContain("{collapsed && desktopBridge() ? <WindowChrome /> : null}");
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@ -14,7 +14,7 @@ msgstr ""
|
|||||||
"Plural-Forms: \n"
|
"Plural-Forms: \n"
|
||||||
"X-Generator: @lingui/cli\n"
|
"X-Generator: @lingui/cli\n"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/roster-rows.tsx
|
||||||
msgid " (unread)"
|
msgid " (unread)"
|
||||||
msgstr " (ungelesen)"
|
msgstr " (ungelesen)"
|
||||||
|
|
||||||
@ -126,22 +126,22 @@ msgid "{0}, {label}"
|
|||||||
msgstr "{0}, {label}"
|
msgstr "{0}, {label}"
|
||||||
|
|
||||||
#. placeholder {0}: item.chat.name
|
#. placeholder {0}: item.chat.name
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/roster-rows.tsx
|
||||||
msgid "{0}, 1:1 conversation"
|
msgid "{0}, 1:1 conversation"
|
||||||
msgstr "{0}, 1:1-Unterhaltung"
|
msgstr "{0}, 1:1-Unterhaltung"
|
||||||
|
|
||||||
#. placeholder {0}: item.chat.name
|
#. placeholder {0}: item.chat.name
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/roster-rows.tsx
|
||||||
msgid "{0}, group conversation"
|
msgid "{0}, group conversation"
|
||||||
msgstr "{0}, Gruppenunterhaltung"
|
msgstr "{0}, Gruppenunterhaltung"
|
||||||
|
|
||||||
#. placeholder {0}: item.chat.name
|
#. placeholder {0}: item.chat.name
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/roster-rows.tsx
|
||||||
msgid "{0}, main conversation"
|
msgid "{0}, main conversation"
|
||||||
msgstr "{0}, Hauptunterhaltung"
|
msgstr "{0}, Hauptunterhaltung"
|
||||||
|
|
||||||
#. placeholder {0}: active.name
|
#. placeholder {0}: active.name
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/computer-panel-preview.tsx
|
||||||
msgid "{0}'s screen"
|
msgid "{0}'s screen"
|
||||||
msgstr "{0}s Bildschirm"
|
msgstr "{0}s Bildschirm"
|
||||||
|
|
||||||
@ -210,7 +210,7 @@ msgstr "{botName} verfolgt den Fehler…"
|
|||||||
msgid "{botName} watches the tape…"
|
msgid "{botName} watches the tape…"
|
||||||
msgstr "{botName} beobachtet den Markt…"
|
msgstr "{botName} beobachtet den Markt…"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/computer-screen.tsx
|
||||||
msgid "{botName}’s computer"
|
msgid "{botName}’s computer"
|
||||||
msgstr "Computer von {botName}"
|
msgstr "Computer von {botName}"
|
||||||
|
|
||||||
@ -277,7 +277,7 @@ msgstr "{title}, {label}"
|
|||||||
msgid "{toolCount, plural, one {# tool} other {# tools}}"
|
msgid "{toolCount, plural, one {# tool} other {# tools}}"
|
||||||
msgstr "{toolCount, plural, one {# Tool} other {# Tools}}"
|
msgstr "{toolCount, plural, one {# Tool} other {# Tools}}"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "{workingBotName} is working"
|
msgid "{workingBotName} is working"
|
||||||
msgstr "{workingBotName} arbeitet"
|
msgstr "{workingBotName} arbeitet"
|
||||||
|
|
||||||
@ -339,6 +339,7 @@ msgstr "Aktionsbestätigungen"
|
|||||||
#. placeholder {0}: sectionMenu.section.name
|
#. placeholder {0}: sectionMenu.section.name
|
||||||
#: src/pages/BotContextMenu.tsx
|
#: src/pages/BotContextMenu.tsx
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/Shell.tsx
|
||||||
|
#: src/pages/shell/sidebar-group-header.tsx
|
||||||
msgid "Actions for {0}"
|
msgid "Actions for {0}"
|
||||||
msgstr "Aktionen für {0}"
|
msgstr "Aktionen für {0}"
|
||||||
|
|
||||||
@ -354,7 +355,7 @@ msgstr "Aktiv"
|
|||||||
msgid "Active model"
|
msgid "Active model"
|
||||||
msgstr "Aktives Modell"
|
msgstr "Aktives Modell"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/sidebar-header.tsx
|
||||||
msgid "Activity"
|
msgid "Activity"
|
||||||
msgstr "Aktivität"
|
msgstr "Aktivität"
|
||||||
|
|
||||||
@ -643,15 +644,15 @@ msgstr "Genehmige diesen Server, damit dein Agent seine Tools verwenden kann."
|
|||||||
msgid "Archive"
|
msgid "Archive"
|
||||||
msgstr "Archivieren"
|
msgstr "Archivieren"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "archived"
|
msgid "archived"
|
||||||
msgstr "archiviert"
|
msgstr "archiviert"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/archived-section.tsx
|
||||||
msgid "Archived"
|
msgid "Archived"
|
||||||
msgstr "Archiviert"
|
msgstr "Archiviert"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "Archived. Chat, memory, and files kept."
|
msgid "Archived. Chat, memory, and files kept."
|
||||||
msgstr "Archiviert. Chat, Erinnerungen und Dateien bleiben erhalten."
|
msgstr "Archiviert. Chat, Erinnerungen und Dateien bleiben erhalten."
|
||||||
|
|
||||||
@ -711,11 +712,11 @@ msgstr "um {0}"
|
|||||||
msgid "at {timeSelect}"
|
msgid "at {timeSelect}"
|
||||||
msgstr "um {timeSelect}"
|
msgstr "um {timeSelect}"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/composer.tsx
|
||||||
msgid "Attach file"
|
msgid "Attach file"
|
||||||
msgstr "Datei anhängen"
|
msgstr "Datei anhängen"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/message-preview.ts
|
||||||
msgid "Attachment"
|
msgid "Attachment"
|
||||||
msgstr "Anhang"
|
msgstr "Anhang"
|
||||||
|
|
||||||
@ -788,7 +789,7 @@ msgstr "Bearer-Token"
|
|||||||
msgid "Blocked in your browser settings"
|
msgid "Blocked in your browser settings"
|
||||||
msgstr "In deinen Browser-Einstellungen blockiert"
|
msgstr "In deinen Browser-Einstellungen blockiert"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/computer-screen.tsx
|
||||||
msgid "Booting live desktop…"
|
msgid "Booting live desktop…"
|
||||||
msgstr "Live-Desktop wird gestartet…"
|
msgstr "Live-Desktop wird gestartet…"
|
||||||
|
|
||||||
@ -797,7 +798,7 @@ msgstr "Live-Desktop wird gestartet…"
|
|||||||
msgid "Booting up {0}’s computer"
|
msgid "Booting up {0}’s computer"
|
||||||
msgstr "Computer von {0} wird gestartet"
|
msgstr "Computer von {0} wird gestartet"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "bot"
|
msgid "bot"
|
||||||
msgstr "Bot"
|
msgstr "Bot"
|
||||||
|
|
||||||
@ -812,11 +813,11 @@ msgstr "Bot"
|
|||||||
msgid "Bot"
|
msgid "Bot"
|
||||||
msgstr "Bot"
|
msgstr "Bot"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/fullscreen-computer-overlay.tsx
|
||||||
msgid "Bot screen"
|
msgid "Bot screen"
|
||||||
msgstr "Bot-Bildschirm"
|
msgstr "Bot-Bildschirm"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/computer-panel-preview.tsx
|
||||||
msgid "Bot screen preview"
|
msgid "Bot screen preview"
|
||||||
msgstr "Bot-Bildschirmvorschau"
|
msgstr "Bot-Bildschirmvorschau"
|
||||||
|
|
||||||
@ -828,7 +829,7 @@ msgstr "Zu verknüpfender Bot"
|
|||||||
msgid "Bots act without asking by default. Add an exception only when you want to review a type of action first."
|
msgid "Bots act without asking by default. Add an exception only when you want to review a type of action first."
|
||||||
msgstr "Bots handeln standardmäßig ohne Nachfrage. Füge nur dann eine Ausnahme hinzu, wenn du eine Aktionsart zuerst prüfen möchtest."
|
msgstr "Bots handeln standardmäßig ohne Nachfrage. Füge nur dann eine Ausnahme hinzu, wenn du eine Aktionsart zuerst prüfen möchtest."
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "Bots are working"
|
msgid "Bots are working"
|
||||||
msgstr "Bots arbeiten"
|
msgstr "Bots arbeiten"
|
||||||
|
|
||||||
@ -889,7 +890,7 @@ msgstr "Neuen Bot abbrechen"
|
|||||||
msgid "Cancel new group"
|
msgid "Cancel new group"
|
||||||
msgstr "Neue Gruppe abbrechen"
|
msgstr "Neue Gruppe abbrechen"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/composer.tsx
|
||||||
msgid "Cancel reply"
|
msgid "Cancel reply"
|
||||||
msgstr "Antwort abbrechen"
|
msgstr "Antwort abbrechen"
|
||||||
|
|
||||||
@ -946,7 +947,7 @@ msgstr "Chat-Apps, Gruppenkanäle und Agent-Verbindungen."
|
|||||||
msgid "Chat history"
|
msgid "Chat history"
|
||||||
msgstr "Chatverlauf"
|
msgstr "Chatverlauf"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/composer.tsx
|
||||||
msgid "Chat Settings"
|
msgid "Chat Settings"
|
||||||
msgstr "Chat-Einstellungen"
|
msgstr "Chat-Einstellungen"
|
||||||
|
|
||||||
@ -1088,7 +1089,7 @@ msgstr "Schließen"
|
|||||||
msgid "Close chart"
|
msgid "Close chart"
|
||||||
msgstr "Diagramm schließen"
|
msgstr "Diagramm schließen"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/fullscreen-computer-overlay.tsx
|
||||||
msgid "Close computer"
|
msgid "Close computer"
|
||||||
msgstr "Computer schließen"
|
msgstr "Computer schließen"
|
||||||
|
|
||||||
@ -1128,7 +1129,7 @@ msgstr "Navigation schließen"
|
|||||||
|
|
||||||
#: src/components/ArtifactPane.tsx
|
#: src/components/ArtifactPane.tsx
|
||||||
#: src/components/browser/InAppBrowser.tsx
|
#: src/components/browser/InAppBrowser.tsx
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/side-panel-header.tsx
|
||||||
msgid "Close panel"
|
msgid "Close panel"
|
||||||
msgstr "Panel schließen"
|
msgstr "Panel schließen"
|
||||||
|
|
||||||
@ -1159,7 +1160,7 @@ msgid "Coder"
|
|||||||
msgstr "Coder"
|
msgstr "Coder"
|
||||||
|
|
||||||
#. placeholder {0}: group.title
|
#. placeholder {0}: group.title
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/sidebar-group-header.tsx
|
||||||
msgid "Collapse {0}"
|
msgid "Collapse {0}"
|
||||||
msgstr "{0} einklappen"
|
msgstr "{0} einklappen"
|
||||||
|
|
||||||
@ -1192,24 +1193,24 @@ msgid "Composing a reply…"
|
|||||||
msgstr "Schreibt eine Antwort…"
|
msgstr "Schreibt eine Antwort…"
|
||||||
|
|
||||||
#: src/pages/SettingsOverlay.tsx
|
#: src/pages/SettingsOverlay.tsx
|
||||||
#: src/pages/Shell.tsx
|
|
||||||
#: src/pages/shell/bot-panel.tsx
|
#: src/pages/shell/bot-panel.tsx
|
||||||
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "Computer"
|
msgid "Computer"
|
||||||
msgstr "Computer"
|
msgstr "Computer"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/computer-screen.tsx
|
||||||
msgid "Computer failed to boot"
|
msgid "Computer failed to boot"
|
||||||
msgstr "Computer konnte nicht gestartet werden"
|
msgstr "Computer konnte nicht gestartet werden"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/fullscreen-computer-overlay.tsx
|
||||||
msgid "Computer is asleep"
|
msgid "Computer is asleep"
|
||||||
msgstr "Computer ist im Ruhezustand"
|
msgstr "Computer ist im Ruhezustand"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/computer-screen.tsx
|
||||||
msgid "Computer is asleep. Open it to wake."
|
msgid "Computer is asleep. Open it to wake."
|
||||||
msgstr "Computer ist im Ruhezustand. Öffne ihn, um ihn aufzuwecken."
|
msgstr "Computer ist im Ruhezustand. Öffne ihn, um ihn aufzuwecken."
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/computer-screen.tsx
|
||||||
msgid "Computer is stopped"
|
msgid "Computer is stopped"
|
||||||
msgstr "Computer ist gestoppt"
|
msgstr "Computer ist gestoppt"
|
||||||
|
|
||||||
@ -1353,7 +1354,7 @@ msgstr "Im Hintergrund fortsetzen"
|
|||||||
msgid "Continue with email"
|
msgid "Continue with email"
|
||||||
msgstr "Mit E-Mail fortfahren"
|
msgstr "Mit E-Mail fortfahren"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "Conversation record"
|
msgid "Conversation record"
|
||||||
msgstr "Gesprächsverlauf"
|
msgstr "Gesprächsverlauf"
|
||||||
|
|
||||||
@ -1361,11 +1362,11 @@ msgstr "Gesprächsverlauf"
|
|||||||
msgid "Conversations"
|
msgid "Conversations"
|
||||||
msgstr "Unterhaltungen"
|
msgstr "Unterhaltungen"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "Copy"
|
msgid "Copy"
|
||||||
msgstr "Kopieren"
|
msgstr "Kopieren"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "Copy reply"
|
msgid "Copy reply"
|
||||||
msgstr "Antwort kopieren"
|
msgstr "Antwort kopieren"
|
||||||
|
|
||||||
@ -1747,9 +1748,9 @@ msgstr "Avatare konnten nicht aktualisiert werden"
|
|||||||
msgid "Couldn't update messaging settings"
|
msgid "Couldn't update messaging settings"
|
||||||
msgstr "Messaging-Einstellungen konnten nicht aktualisiert werden"
|
msgstr "Messaging-Einstellungen konnten nicht aktualisiert werden"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
|
||||||
#: src/pages/shell/bot-panel.tsx
|
#: src/pages/shell/bot-panel.tsx
|
||||||
#: src/pages/shell/dialogs.tsx
|
#: src/pages/shell/dialogs.tsx
|
||||||
|
#: src/pages/shell/sidebar-header.tsx
|
||||||
msgid "Create"
|
msgid "Create"
|
||||||
msgstr "Erstellen"
|
msgstr "Erstellen"
|
||||||
|
|
||||||
@ -1906,14 +1907,14 @@ msgstr "Standardbereich"
|
|||||||
#: src/pages/KnowledgeSection.tsx
|
#: src/pages/KnowledgeSection.tsx
|
||||||
#: src/pages/McpServersOverlay.tsx
|
#: src/pages/McpServersOverlay.tsx
|
||||||
#: src/pages/RoutineEditor.tsx
|
#: src/pages/RoutineEditor.tsx
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/archived-section.tsx
|
||||||
#: src/pages/shell/dialogs.tsx
|
#: src/pages/shell/dialogs.tsx
|
||||||
msgid "Delete"
|
msgid "Delete"
|
||||||
msgstr "Löschen"
|
msgstr "Löschen"
|
||||||
|
|
||||||
#. placeholder {0}: bot.name
|
#. placeholder {0}: bot.name
|
||||||
#. placeholder {0}: group.name
|
#. placeholder {0}: group.name
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/archived-section.tsx
|
||||||
msgid "Delete {0}"
|
msgid "Delete {0}"
|
||||||
msgstr "{0} löschen"
|
msgstr "{0} löschen"
|
||||||
|
|
||||||
@ -1943,7 +1944,7 @@ msgstr "Mein Konto löschen"
|
|||||||
msgid "Delete space"
|
msgid "Delete space"
|
||||||
msgstr "Space löschen"
|
msgstr "Space löschen"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "deleted"
|
msgid "deleted"
|
||||||
msgstr "gelöscht"
|
msgstr "gelöscht"
|
||||||
|
|
||||||
@ -2013,7 +2014,7 @@ msgstr "Verbindung wird getrennt…"
|
|||||||
msgid "Dismiss"
|
msgid "Dismiss"
|
||||||
msgstr "Ausblenden"
|
msgstr "Ausblenden"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/composer.tsx
|
||||||
msgid "Dismiss error"
|
msgid "Dismiss error"
|
||||||
msgstr "Fehler ausblenden"
|
msgstr "Fehler ausblenden"
|
||||||
|
|
||||||
@ -2111,7 +2112,7 @@ msgstr "Duplizieren"
|
|||||||
msgid "e.g. Hivenet Agent, Presales, Timesheets bot"
|
msgid "e.g. Hivenet Agent, Presales, Timesheets bot"
|
||||||
msgstr "z. B. Hivenet Agent, Presales, Zeiterfassungs-Bot"
|
msgstr "z. B. Hivenet Agent, Presales, Zeiterfassungs-Bot"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "Earlier message"
|
msgid "Earlier message"
|
||||||
msgstr "Frühere Nachricht"
|
msgstr "Frühere Nachricht"
|
||||||
|
|
||||||
@ -2222,7 +2223,7 @@ msgid "Expand"
|
|||||||
msgstr "Erweitern"
|
msgstr "Erweitern"
|
||||||
|
|
||||||
#. placeholder {0}: group.title
|
#. placeholder {0}: group.title
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/sidebar-group-header.tsx
|
||||||
msgid "Expand {0}"
|
msgid "Expand {0}"
|
||||||
msgstr "{0} ausklappen"
|
msgstr "{0} ausklappen"
|
||||||
|
|
||||||
@ -2404,6 +2405,7 @@ msgstr "Ziele für dieses Projekt, unabhängig von Chat-Nachrichten. Unterhaltun
|
|||||||
#: src/components/stage/OoStage.tsx
|
#: src/components/stage/OoStage.tsx
|
||||||
#: src/pages/MessagingSettingsOverlay.tsx
|
#: src/pages/MessagingSettingsOverlay.tsx
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/Shell.tsx
|
||||||
|
#: src/pages/shell/side-panel-header.tsx
|
||||||
msgid "Group"
|
msgid "Group"
|
||||||
msgstr "Gruppe"
|
msgstr "Gruppe"
|
||||||
|
|
||||||
@ -2528,7 +2530,7 @@ msgstr "Wie soll dein Oo klingen, wenn es Antworten vorliest?"
|
|||||||
msgid "How to check"
|
msgid "How to check"
|
||||||
msgstr "So wird geprüft"
|
msgstr "So wird geprüft"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/computer-screen.tsx
|
||||||
msgid "I’m done"
|
msgid "I’m done"
|
||||||
msgstr "Ich bin fertig"
|
msgstr "Ich bin fertig"
|
||||||
|
|
||||||
@ -2635,11 +2637,11 @@ msgstr "Isoliert"
|
|||||||
msgid "Its conversation, files, and routines will be permanently deleted. Bots it created stay in your list."
|
msgid "Its conversation, files, and routines will be permanently deleted. Bots it created stay in your list."
|
||||||
msgstr "Seine Unterhaltung, Dateien und Routinen werden dauerhaft gelöscht. Von ihm erstellte Bots bleiben in deiner Liste."
|
msgstr "Seine Unterhaltung, Dateien und Routinen werden dauerhaft gelöscht. Von ihm erstellte Bots bleiben in deiner Liste."
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "Jump to latest"
|
msgid "Jump to latest"
|
||||||
msgstr "Zur neuesten Nachricht springen"
|
msgstr "Zur neuesten Nachricht springen"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "Jump to replied message"
|
msgid "Jump to replied message"
|
||||||
msgstr "Zur beantworteten Nachricht springen"
|
msgstr "Zur beantworteten Nachricht springen"
|
||||||
|
|
||||||
@ -2726,7 +2728,7 @@ msgstr "Ich höre zu — was ist kaputt oder langsam?"
|
|||||||
msgid "Listening — what's the story?"
|
msgid "Listening — what's the story?"
|
||||||
msgstr "Ich höre zu — was ist die Geschichte?"
|
msgstr "Ich höre zu — was ist die Geschichte?"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "Load earlier messages"
|
msgid "Load earlier messages"
|
||||||
msgstr "Frühere Nachrichten laden"
|
msgstr "Frühere Nachrichten laden"
|
||||||
|
|
||||||
@ -2779,7 +2781,7 @@ msgstr "Stimmen werden geladen…"
|
|||||||
#: src/pages/HeuteBrief.tsx
|
#: src/pages/HeuteBrief.tsx
|
||||||
#: src/pages/IntegrationSetup.tsx
|
#: src/pages/IntegrationSetup.tsx
|
||||||
#: src/pages/PeerMessagesOverlay.tsx
|
#: src/pages/PeerMessagesOverlay.tsx
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "Loading…"
|
msgid "Loading…"
|
||||||
msgstr "Wird geladen…"
|
msgstr "Wird geladen…"
|
||||||
|
|
||||||
@ -2799,7 +2801,7 @@ msgstr "Lokales Docker"
|
|||||||
msgid "Local Server Settings"
|
msgid "Local Server Settings"
|
||||||
msgstr "Einstellungen des lokalen Servers"
|
msgstr "Einstellungen des lokalen Servers"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/user-menu.tsx
|
||||||
msgid "Log out"
|
msgid "Log out"
|
||||||
msgstr "Abmelden"
|
msgstr "Abmelden"
|
||||||
|
|
||||||
@ -2926,7 +2928,7 @@ msgstr "Erinnerungen"
|
|||||||
msgid "Memory scope"
|
msgid "Memory scope"
|
||||||
msgstr "Erinnerungsbereich"
|
msgstr "Erinnerungsbereich"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/composer.tsx
|
||||||
msgid "Mentions"
|
msgid "Mentions"
|
||||||
msgstr "Erwähnungen"
|
msgstr "Erwähnungen"
|
||||||
|
|
||||||
@ -2939,11 +2941,12 @@ msgstr "Nur Erwähnungen"
|
|||||||
msgid "Message"
|
msgid "Message"
|
||||||
msgstr "Nachricht"
|
msgstr "Nachricht"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/composer.tsx
|
||||||
|
#: src/pages/shell/message-preview.ts
|
||||||
msgid "Message"
|
msgid "Message"
|
||||||
msgstr "Nachricht"
|
msgstr "Nachricht"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/composer.tsx
|
||||||
msgid "Message composer"
|
msgid "Message composer"
|
||||||
msgstr "Nachrichteneingabe"
|
msgstr "Nachrichteneingabe"
|
||||||
|
|
||||||
@ -2951,11 +2954,11 @@ msgstr "Nachrichteneingabe"
|
|||||||
msgid "Message event"
|
msgid "Message event"
|
||||||
msgstr "Nachrichtenereignis"
|
msgstr "Nachrichtenereignis"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "Message from {peer}"
|
msgid "Message from {peer}"
|
||||||
msgstr "Nachricht von {peer}"
|
msgstr "Nachricht von {peer}"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/composer.tsx
|
||||||
msgid "Message…"
|
msgid "Message…"
|
||||||
msgstr "Nachricht…"
|
msgstr "Nachricht…"
|
||||||
|
|
||||||
@ -2981,7 +2984,7 @@ msgstr "Minimal"
|
|||||||
msgid "Minimize"
|
msgid "Minimize"
|
||||||
msgstr "Minimieren"
|
msgstr "Minimieren"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/sidebar-toggle-buttons.tsx
|
||||||
msgid "Minimize bots"
|
msgid "Minimize bots"
|
||||||
msgstr "Bots minimieren"
|
msgstr "Bots minimieren"
|
||||||
|
|
||||||
@ -3038,7 +3041,7 @@ msgstr "Modelle vom Server"
|
|||||||
msgid "Monthly"
|
msgid "Monthly"
|
||||||
msgstr "Monatlich"
|
msgstr "Monatlich"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "More"
|
msgid "More"
|
||||||
msgstr "Mehr"
|
msgstr "Mehr"
|
||||||
|
|
||||||
@ -3104,7 +3107,8 @@ msgstr "Braucht dich"
|
|||||||
#: src/components/MainInbox.tsx
|
#: src/components/MainInbox.tsx
|
||||||
#: src/pages/ActivityList.tsx
|
#: src/pages/ActivityList.tsx
|
||||||
#: src/pages/HeuteBrief.tsx
|
#: src/pages/HeuteBrief.tsx
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/fullscreen-computer-overlay.tsx
|
||||||
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "Needs you"
|
msgid "Needs you"
|
||||||
msgstr "Braucht dich"
|
msgstr "Braucht dich"
|
||||||
|
|
||||||
@ -3397,12 +3401,12 @@ msgid "Only file and folder names are read."
|
|||||||
msgstr "Gelesen werden nur Datei- und Ordnernamen."
|
msgstr "Gelesen werden nur Datei- und Ordnernamen."
|
||||||
|
|
||||||
#: src/pages/ScratchpadSection.tsx
|
#: src/pages/ScratchpadSection.tsx
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/computer-panel-preview.tsx
|
||||||
msgid "Open"
|
msgid "Open"
|
||||||
msgstr "Öffnen"
|
msgstr "Öffnen"
|
||||||
|
|
||||||
#. placeholder {0}: group.title
|
#. placeholder {0}: group.title
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/sidebar-group-header.tsx
|
||||||
msgid "Open {0}"
|
msgid "Open {0}"
|
||||||
msgstr "{0} öffnen"
|
msgstr "{0} öffnen"
|
||||||
|
|
||||||
@ -3418,11 +3422,11 @@ msgstr "Unterhaltung öffnen"
|
|||||||
msgid "Open in browser"
|
msgid "Open in browser"
|
||||||
msgstr "Im Browser öffnen"
|
msgstr "Im Browser öffnen"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/computer-panel-preview.tsx
|
||||||
msgid "Open in full window"
|
msgid "Open in full window"
|
||||||
msgstr "In vollständigem Fenster öffnen"
|
msgstr "In vollständigem Fenster öffnen"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/sidebar-toggle-buttons.tsx
|
||||||
msgid "Open navigation"
|
msgid "Open navigation"
|
||||||
msgstr "Navigation öffnen"
|
msgstr "Navigation öffnen"
|
||||||
|
|
||||||
@ -3438,7 +3442,7 @@ msgstr "Offene Arbeit"
|
|||||||
msgid "OpenAI-compatible server URL"
|
msgid "OpenAI-compatible server URL"
|
||||||
msgstr "URL eines OpenAI-kompatiblen Servers"
|
msgstr "URL eines OpenAI-kompatiblen Servers"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "Opened its thread."
|
msgid "Opened its thread."
|
||||||
msgstr "Thread geöffnet."
|
msgstr "Thread geöffnet."
|
||||||
|
|
||||||
@ -3679,19 +3683,19 @@ msgstr "Ende der Ruhezeiten"
|
|||||||
msgid "Quiet hours start"
|
msgid "Quiet hours start"
|
||||||
msgstr "Beginn der Ruhezeiten"
|
msgstr "Beginn der Ruhezeiten"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "Quote"
|
msgid "Quote"
|
||||||
msgstr "Zitieren"
|
msgstr "Zitieren"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "React"
|
msgid "React"
|
||||||
msgstr "Reagieren"
|
msgstr "Reagieren"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "Reactions"
|
msgid "Reactions"
|
||||||
msgstr "Reaktionen"
|
msgstr "Reaktionen"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "Read aloud"
|
msgid "Read aloud"
|
||||||
msgstr "Vorlesen"
|
msgstr "Vorlesen"
|
||||||
|
|
||||||
@ -3796,7 +3800,7 @@ msgstr "Wird aktualisiert…"
|
|||||||
msgid "Region"
|
msgid "Region"
|
||||||
msgstr "Region"
|
msgstr "Region"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/computer-screen.tsx
|
||||||
msgid "Release"
|
msgid "Release"
|
||||||
msgstr "Freigeben"
|
msgstr "Freigeben"
|
||||||
|
|
||||||
@ -3820,7 +3824,7 @@ msgid "Remove"
|
|||||||
msgstr "Entfernen"
|
msgstr "Entfernen"
|
||||||
|
|
||||||
#. placeholder {0}: attachment.file.name
|
#. placeholder {0}: attachment.file.name
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/composer.tsx
|
||||||
msgid "Remove {0}"
|
msgid "Remove {0}"
|
||||||
msgstr "{0} entfernen"
|
msgstr "{0} entfernen"
|
||||||
|
|
||||||
@ -3829,7 +3833,7 @@ msgid "Remove Git event"
|
|||||||
msgstr "Git-Ereignis entfernen"
|
msgstr "Git-Ereignis entfernen"
|
||||||
|
|
||||||
#. placeholder {0}: mention.name
|
#. placeholder {0}: mention.name
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/composer.tsx
|
||||||
msgid "Remove mention {0}"
|
msgid "Remove mention {0}"
|
||||||
msgstr "Erwähnung von {0} entfernen"
|
msgstr "Erwähnung von {0} entfernen"
|
||||||
|
|
||||||
@ -3842,7 +3846,7 @@ msgid "Remove schedule"
|
|||||||
msgstr "Zeitplan entfernen"
|
msgstr "Zeitplan entfernen"
|
||||||
|
|
||||||
#. placeholder {0}: selectedSkill.name
|
#. placeholder {0}: selectedSkill.name
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/composer.tsx
|
||||||
msgid "Remove skill {0}"
|
msgid "Remove skill {0}"
|
||||||
msgstr "Skill {0} entfernen"
|
msgstr "Skill {0} entfernen"
|
||||||
|
|
||||||
@ -3850,7 +3854,7 @@ msgstr "Skill {0} entfernen"
|
|||||||
msgid "Remove webhook"
|
msgid "Remove webhook"
|
||||||
msgstr "Webhook entfernen"
|
msgstr "Webhook entfernen"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "Removed with chat, computer, and memory."
|
msgid "Removed with chat, computer, and memory."
|
||||||
msgstr "Zusammen mit Chat, Computer und Erinnerungen entfernt."
|
msgstr "Zusammen mit Chat, Computer und Erinnerungen entfernt."
|
||||||
|
|
||||||
@ -3883,15 +3887,15 @@ msgstr "API-Schlüssel ersetzen"
|
|||||||
msgid "Replace key"
|
msgid "Replace key"
|
||||||
msgstr "Schlüssel ersetzen"
|
msgstr "Schlüssel ersetzen"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "Reply"
|
msgid "Reply"
|
||||||
msgstr "Antworten"
|
msgstr "Antworten"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/composer.tsx
|
||||||
msgid "Replying to {replyName}"
|
msgid "Replying to {replyName}"
|
||||||
msgstr "Antwort an {replyName}"
|
msgstr "Antwort an {replyName}"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/composer.tsx
|
||||||
msgid "Replying to {replyName}: “{replyQuote}”"
|
msgid "Replying to {replyName}: “{replyQuote}”"
|
||||||
msgstr "Antwort an {replyName}: „{replyQuote}“"
|
msgstr "Antwort an {replyName}: „{replyQuote}“"
|
||||||
|
|
||||||
@ -3937,7 +3941,7 @@ msgstr "Wird zurückgesetzt…"
|
|||||||
msgid "Restart to update"
|
msgid "Restart to update"
|
||||||
msgstr "Zum Aktualisieren neu starten"
|
msgstr "Zum Aktualisieren neu starten"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/archived-section.tsx
|
||||||
msgid "Restore"
|
msgid "Restore"
|
||||||
msgstr "Wiederherstellen"
|
msgstr "Wiederherstellen"
|
||||||
|
|
||||||
@ -4142,7 +4146,7 @@ msgid "Searching…"
|
|||||||
msgstr "Suche…"
|
msgstr "Suche…"
|
||||||
|
|
||||||
#. placeholder {0}: group.title
|
#. placeholder {0}: group.title
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/sidebar-group-header.tsx
|
||||||
msgid "Select {0}"
|
msgid "Select {0}"
|
||||||
msgstr "{0} auswählen"
|
msgstr "{0} auswählen"
|
||||||
|
|
||||||
@ -4150,7 +4154,7 @@ msgstr "{0} auswählen"
|
|||||||
msgid "Self-hosted (better-auth)"
|
msgid "Self-hosted (better-auth)"
|
||||||
msgstr "Selbst gehostet (better-auth)"
|
msgstr "Selbst gehostet (better-auth)"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/composer.tsx
|
||||||
#: src/pages/shell/message-cards.tsx
|
#: src/pages/shell/message-cards.tsx
|
||||||
msgid "Send"
|
msgid "Send"
|
||||||
msgstr "Senden"
|
msgstr "Senden"
|
||||||
@ -4201,21 +4205,22 @@ msgid "Server URL"
|
|||||||
msgstr "Server-URL"
|
msgstr "Server-URL"
|
||||||
|
|
||||||
#: src/components/stage/StageVoiceEntry.tsx
|
#: src/components/stage/StageVoiceEntry.tsx
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/composer.tsx
|
||||||
msgid "Set up voice"
|
msgid "Set up voice"
|
||||||
msgstr "Stimme einrichten"
|
msgstr "Stimme einrichten"
|
||||||
|
|
||||||
#: src/pages/MessagingSettingsOverlay.tsx
|
#: src/pages/MessagingSettingsOverlay.tsx
|
||||||
#: src/pages/SettingsOverlay.tsx
|
#: src/pages/SettingsOverlay.tsx
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/side-panel-header.tsx
|
||||||
|
#: src/pages/shell/user-menu.tsx
|
||||||
msgid "Settings"
|
msgid "Settings"
|
||||||
msgstr "Einstellungen"
|
msgstr "Einstellungen"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/composer.tsx
|
||||||
msgid "Settings: General"
|
msgid "Settings: General"
|
||||||
msgstr "Einstellungen: Allgemein"
|
msgstr "Einstellungen: Allgemein"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/composer.tsx
|
||||||
msgid "Settings: Usage"
|
msgid "Settings: Usage"
|
||||||
msgstr "Einstellungen: Nutzung"
|
msgstr "Einstellungen: Nutzung"
|
||||||
|
|
||||||
@ -4259,10 +4264,11 @@ msgid "Show all {0}"
|
|||||||
msgstr "Alle {0} anzeigen"
|
msgstr "Alle {0} anzeigen"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/Shell.tsx
|
||||||
|
#: src/pages/shell/sidebar-toggle-buttons.tsx
|
||||||
msgid "Show bots"
|
msgid "Show bots"
|
||||||
msgstr "Bots anzeigen"
|
msgstr "Bots anzeigen"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/side-panel-header.tsx
|
||||||
msgid "Show computer"
|
msgid "Show computer"
|
||||||
msgstr "Computer anzeigen"
|
msgstr "Computer anzeigen"
|
||||||
|
|
||||||
@ -4278,7 +4284,7 @@ msgstr "Mehr anzeigen"
|
|||||||
msgid "Show password"
|
msgid "Show password"
|
||||||
msgstr "Passwort anzeigen"
|
msgstr "Passwort anzeigen"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/side-panel-header.tsx
|
||||||
msgid "Show settings"
|
msgid "Show settings"
|
||||||
msgstr "Einstellungen anzeigen"
|
msgstr "Einstellungen anzeigen"
|
||||||
|
|
||||||
@ -4307,7 +4313,7 @@ msgid "Sketching the blueprint…"
|
|||||||
msgstr "Skizziere den Bauplan…"
|
msgstr "Skizziere den Bauplan…"
|
||||||
|
|
||||||
#. placeholder {0}: skill.name
|
#. placeholder {0}: skill.name
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/composer.tsx
|
||||||
msgid "Skill {0}"
|
msgid "Skill {0}"
|
||||||
msgstr "Skill {0}"
|
msgstr "Skill {0}"
|
||||||
|
|
||||||
@ -4319,7 +4325,7 @@ msgstr "Skills"
|
|||||||
#: src/components/onboarding/OnboardingScanStep.tsx
|
#: src/components/onboarding/OnboardingScanStep.tsx
|
||||||
#: src/components/onboarding/OnboardingVoiceStep.tsx
|
#: src/components/onboarding/OnboardingVoiceStep.tsx
|
||||||
#: src/lib/onboarding-copy.ts
|
#: src/lib/onboarding-copy.ts
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/computer-screen.tsx
|
||||||
msgid "Skip"
|
msgid "Skip"
|
||||||
msgstr "Überspringen"
|
msgstr "Überspringen"
|
||||||
|
|
||||||
@ -4373,11 +4379,11 @@ msgstr "Space-Standard"
|
|||||||
msgid "Spaces"
|
msgid "Spaces"
|
||||||
msgstr "Spaces"
|
msgstr "Spaces"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "Speak"
|
msgid "Speak"
|
||||||
msgstr "Vorlesen"
|
msgstr "Vorlesen"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "Speak this reply"
|
msgid "Speak this reply"
|
||||||
msgstr "Diese Antwort vorlesen"
|
msgstr "Diese Antwort vorlesen"
|
||||||
|
|
||||||
@ -4431,15 +4437,15 @@ msgstr "Aufnahme starten"
|
|||||||
msgid "Start talking"
|
msgid "Start talking"
|
||||||
msgstr "Sprechen starten"
|
msgstr "Sprechen starten"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "Start the conversation — {activeName} is on stage above."
|
msgid "Start the conversation — {activeName} is on stage above."
|
||||||
msgstr "Starte die Unterhaltung — {activeName} steht oben auf der Bühne."
|
msgstr "Starte die Unterhaltung — {activeName} steht oben auf der Bühne."
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "Start the conversation."
|
msgid "Start the conversation."
|
||||||
msgstr "Starte die Unterhaltung."
|
msgstr "Starte die Unterhaltung."
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/composer.tsx
|
||||||
msgid "Start voice conversation"
|
msgid "Start voice conversation"
|
||||||
msgstr "Sprachunterhaltung starten"
|
msgstr "Sprachunterhaltung starten"
|
||||||
|
|
||||||
@ -4466,11 +4472,13 @@ msgid "Steps"
|
|||||||
msgstr "Schritte"
|
msgstr "Schritte"
|
||||||
|
|
||||||
#: src/components/browser/InAppBrowser.tsx
|
#: src/components/browser/InAppBrowser.tsx
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/composer.tsx
|
||||||
|
#: src/pages/shell/fullscreen-computer-overlay.tsx
|
||||||
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "Stop"
|
msgid "Stop"
|
||||||
msgstr "Stoppen"
|
msgstr "Stoppen"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "Stop speaking"
|
msgid "Stop speaking"
|
||||||
msgstr "Vorlesen stoppen"
|
msgstr "Vorlesen stoppen"
|
||||||
|
|
||||||
@ -4500,7 +4508,7 @@ msgstr "Stresstest fürs Portfolio…"
|
|||||||
msgid "Stronger together — {0} specialists"
|
msgid "Stronger together — {0} specialists"
|
||||||
msgstr "Stärker zusammen — {0} Spezialisten"
|
msgstr "Stärker zusammen — {0} Spezialisten"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "subagent"
|
msgid "subagent"
|
||||||
msgstr "Subagent"
|
msgstr "Subagent"
|
||||||
|
|
||||||
@ -4565,7 +4573,7 @@ msgstr "Aufgabe wird angelernt. Beende das Anlernen, bevor du eine neue Nachrich
|
|||||||
msgid "Team"
|
msgid "Team"
|
||||||
msgstr "Team"
|
msgstr "Team"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/computer-screen.tsx
|
||||||
msgid "Team Computer"
|
msgid "Team Computer"
|
||||||
msgstr "Team-Computer"
|
msgstr "Team-Computer"
|
||||||
|
|
||||||
@ -4606,7 +4614,7 @@ msgstr "Der ausgewählte Erinnerungsanbieter ist in diesem Build nicht verfügba
|
|||||||
msgid "Thinking"
|
msgid "Thinking"
|
||||||
msgstr "Denkmodus"
|
msgstr "Denkmodus"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/computer-screen.tsx
|
||||||
msgid "This bot runs on this computer, not a Linux desktop. Shell and files use your home folder."
|
msgid "This bot runs on this computer, not a Linux desktop. Shell and files use your home folder."
|
||||||
msgstr "Dieser Bot wird auf diesem Computer und nicht auf einem Linux-Desktop ausgeführt. Shell und Dateien verwenden deinen persönlichen Ordner."
|
msgstr "Dieser Bot wird auf diesem Computer und nicht auf einem Linux-Desktop ausgeführt. Shell und Dateien verwenden deinen persönlichen Ordner."
|
||||||
|
|
||||||
@ -4713,7 +4721,7 @@ msgid "Transcribe"
|
|||||||
msgstr "Transkribieren"
|
msgstr "Transkribieren"
|
||||||
|
|
||||||
#: src/components/voice/VoiceStage.tsx
|
#: src/components/voice/VoiceStage.tsx
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "Transcript"
|
msgid "Transcript"
|
||||||
msgstr "Transkript"
|
msgstr "Transkript"
|
||||||
|
|
||||||
@ -4836,7 +4844,7 @@ msgstr "Hochladen"
|
|||||||
|
|
||||||
#: src/pages/AccountSettingsOverlay.tsx
|
#: src/pages/AccountSettingsOverlay.tsx
|
||||||
#: src/pages/SettingsOverlay.tsx
|
#: src/pages/SettingsOverlay.tsx
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/user-menu.tsx
|
||||||
msgid "Usage"
|
msgid "Usage"
|
||||||
msgstr "Nutzung"
|
msgstr "Nutzung"
|
||||||
|
|
||||||
@ -4877,8 +4885,8 @@ msgid "Video workflow"
|
|||||||
msgstr "Video-Workflow"
|
msgstr "Video-Workflow"
|
||||||
|
|
||||||
#: src/pages/SettingsOverlay.tsx
|
#: src/pages/SettingsOverlay.tsx
|
||||||
#: src/pages/Shell.tsx
|
|
||||||
#: src/pages/shell/bot-panel.tsx
|
#: src/pages/shell/bot-panel.tsx
|
||||||
|
#: src/pages/shell/composer.tsx
|
||||||
#: src/pages/VoiceSettingsOverlay.tsx
|
#: src/pages/VoiceSettingsOverlay.tsx
|
||||||
msgid "Voice"
|
msgid "Voice"
|
||||||
msgstr "Stimme"
|
msgstr "Stimme"
|
||||||
@ -5074,7 +5082,7 @@ msgstr "Arbeitet…"
|
|||||||
msgid "Working…"
|
msgid "Working…"
|
||||||
msgstr "Wird verarbeitet…"
|
msgstr "Wird verarbeitet…"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/roster-format.ts
|
||||||
msgid "Yesterday"
|
msgid "Yesterday"
|
||||||
msgstr "Gestern"
|
msgstr "Gestern"
|
||||||
|
|
||||||
@ -5092,7 +5100,7 @@ msgstr "Du kannst diesen Tab schließen, wenn du nicht automatisch weitergeleite
|
|||||||
msgid "You can close this window."
|
msgid "You can close this window."
|
||||||
msgstr "Du kannst dieses Fenster schließen."
|
msgstr "Du kannst dieses Fenster schließen."
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/fullscreen-computer-overlay.tsx
|
||||||
msgid "You have control"
|
msgid "You have control"
|
||||||
msgstr "Du hast die Kontrolle"
|
msgstr "Du hast die Kontrolle"
|
||||||
|
|
||||||
|
|||||||
@ -14,7 +14,7 @@ msgstr ""
|
|||||||
"Plural-Forms: \n"
|
"Plural-Forms: \n"
|
||||||
"X-Generator: @lingui/cli\n"
|
"X-Generator: @lingui/cli\n"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/roster-rows.tsx
|
||||||
msgid " (unread)"
|
msgid " (unread)"
|
||||||
msgstr " (unread)"
|
msgstr " (unread)"
|
||||||
|
|
||||||
@ -126,22 +126,22 @@ msgid "{0}, {label}"
|
|||||||
msgstr "{0}, {label}"
|
msgstr "{0}, {label}"
|
||||||
|
|
||||||
#. placeholder {0}: item.chat.name
|
#. placeholder {0}: item.chat.name
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/roster-rows.tsx
|
||||||
msgid "{0}, 1:1 conversation"
|
msgid "{0}, 1:1 conversation"
|
||||||
msgstr "{0}, 1:1 conversation"
|
msgstr "{0}, 1:1 conversation"
|
||||||
|
|
||||||
#. placeholder {0}: item.chat.name
|
#. placeholder {0}: item.chat.name
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/roster-rows.tsx
|
||||||
msgid "{0}, group conversation"
|
msgid "{0}, group conversation"
|
||||||
msgstr "{0}, group conversation"
|
msgstr "{0}, group conversation"
|
||||||
|
|
||||||
#. placeholder {0}: item.chat.name
|
#. placeholder {0}: item.chat.name
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/roster-rows.tsx
|
||||||
msgid "{0}, main conversation"
|
msgid "{0}, main conversation"
|
||||||
msgstr "{0}, main conversation"
|
msgstr "{0}, main conversation"
|
||||||
|
|
||||||
#. placeholder {0}: active.name
|
#. placeholder {0}: active.name
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/computer-panel-preview.tsx
|
||||||
msgid "{0}'s screen"
|
msgid "{0}'s screen"
|
||||||
msgstr "{0}'s screen"
|
msgstr "{0}'s screen"
|
||||||
|
|
||||||
@ -210,7 +210,7 @@ msgstr "{botName} traces the failure…"
|
|||||||
msgid "{botName} watches the tape…"
|
msgid "{botName} watches the tape…"
|
||||||
msgstr "{botName} watches the tape…"
|
msgstr "{botName} watches the tape…"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/computer-screen.tsx
|
||||||
msgid "{botName}’s computer"
|
msgid "{botName}’s computer"
|
||||||
msgstr "{botName}’s computer"
|
msgstr "{botName}’s computer"
|
||||||
|
|
||||||
@ -277,7 +277,7 @@ msgstr "{title}, {label}"
|
|||||||
msgid "{toolCount, plural, one {# tool} other {# tools}}"
|
msgid "{toolCount, plural, one {# tool} other {# tools}}"
|
||||||
msgstr "{toolCount, plural, one {# tool} other {# tools}}"
|
msgstr "{toolCount, plural, one {# tool} other {# tools}}"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "{workingBotName} is working"
|
msgid "{workingBotName} is working"
|
||||||
msgstr "{workingBotName} is working"
|
msgstr "{workingBotName} is working"
|
||||||
|
|
||||||
@ -339,6 +339,7 @@ msgstr "Action confirmations"
|
|||||||
#. placeholder {0}: sectionMenu.section.name
|
#. placeholder {0}: sectionMenu.section.name
|
||||||
#: src/pages/BotContextMenu.tsx
|
#: src/pages/BotContextMenu.tsx
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/Shell.tsx
|
||||||
|
#: src/pages/shell/sidebar-group-header.tsx
|
||||||
msgid "Actions for {0}"
|
msgid "Actions for {0}"
|
||||||
msgstr "Actions for {0}"
|
msgstr "Actions for {0}"
|
||||||
|
|
||||||
@ -354,7 +355,7 @@ msgstr "Active"
|
|||||||
msgid "Active model"
|
msgid "Active model"
|
||||||
msgstr "Active model"
|
msgstr "Active model"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/sidebar-header.tsx
|
||||||
msgid "Activity"
|
msgid "Activity"
|
||||||
msgstr "Activity"
|
msgstr "Activity"
|
||||||
|
|
||||||
@ -643,15 +644,15 @@ msgstr "Approve this server to let your agent use its tools."
|
|||||||
msgid "Archive"
|
msgid "Archive"
|
||||||
msgstr "Archive"
|
msgstr "Archive"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "archived"
|
msgid "archived"
|
||||||
msgstr "archived"
|
msgstr "archived"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/archived-section.tsx
|
||||||
msgid "Archived"
|
msgid "Archived"
|
||||||
msgstr "Archived"
|
msgstr "Archived"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "Archived. Chat, memory, and files kept."
|
msgid "Archived. Chat, memory, and files kept."
|
||||||
msgstr "Archived. Chat, memory, and files kept."
|
msgstr "Archived. Chat, memory, and files kept."
|
||||||
|
|
||||||
@ -711,11 +712,11 @@ msgstr "at {0}"
|
|||||||
msgid "at {timeSelect}"
|
msgid "at {timeSelect}"
|
||||||
msgstr "at {timeSelect}"
|
msgstr "at {timeSelect}"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/composer.tsx
|
||||||
msgid "Attach file"
|
msgid "Attach file"
|
||||||
msgstr "Attach file"
|
msgstr "Attach file"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/message-preview.ts
|
||||||
msgid "Attachment"
|
msgid "Attachment"
|
||||||
msgstr "Attachment"
|
msgstr "Attachment"
|
||||||
|
|
||||||
@ -788,7 +789,7 @@ msgstr "Bearer token"
|
|||||||
msgid "Blocked in your browser settings"
|
msgid "Blocked in your browser settings"
|
||||||
msgstr "Blocked in your browser settings"
|
msgstr "Blocked in your browser settings"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/computer-screen.tsx
|
||||||
msgid "Booting live desktop…"
|
msgid "Booting live desktop…"
|
||||||
msgstr "Booting live desktop…"
|
msgstr "Booting live desktop…"
|
||||||
|
|
||||||
@ -797,7 +798,7 @@ msgstr "Booting live desktop…"
|
|||||||
msgid "Booting up {0}’s computer"
|
msgid "Booting up {0}’s computer"
|
||||||
msgstr "Booting up {0}’s computer"
|
msgstr "Booting up {0}’s computer"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "bot"
|
msgid "bot"
|
||||||
msgstr "bot"
|
msgstr "bot"
|
||||||
|
|
||||||
@ -812,11 +813,11 @@ msgstr "Bot"
|
|||||||
msgid "Bot"
|
msgid "Bot"
|
||||||
msgstr "Bot"
|
msgstr "Bot"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/fullscreen-computer-overlay.tsx
|
||||||
msgid "Bot screen"
|
msgid "Bot screen"
|
||||||
msgstr "Bot screen"
|
msgstr "Bot screen"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/computer-panel-preview.tsx
|
||||||
msgid "Bot screen preview"
|
msgid "Bot screen preview"
|
||||||
msgstr "Bot screen preview"
|
msgstr "Bot screen preview"
|
||||||
|
|
||||||
@ -828,7 +829,7 @@ msgstr "Bot to link"
|
|||||||
msgid "Bots act without asking by default. Add an exception only when you want to review a type of action first."
|
msgid "Bots act without asking by default. Add an exception only when you want to review a type of action first."
|
||||||
msgstr "Bots act without asking by default. Add an exception only when you want to review a type of action first."
|
msgstr "Bots act without asking by default. Add an exception only when you want to review a type of action first."
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "Bots are working"
|
msgid "Bots are working"
|
||||||
msgstr "Bots are working"
|
msgstr "Bots are working"
|
||||||
|
|
||||||
@ -889,7 +890,7 @@ msgstr "Cancel new bot"
|
|||||||
msgid "Cancel new group"
|
msgid "Cancel new group"
|
||||||
msgstr "Cancel new group"
|
msgstr "Cancel new group"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/composer.tsx
|
||||||
msgid "Cancel reply"
|
msgid "Cancel reply"
|
||||||
msgstr "Cancel reply"
|
msgstr "Cancel reply"
|
||||||
|
|
||||||
@ -946,7 +947,7 @@ msgstr "Chat apps, group channels, and agent connections."
|
|||||||
msgid "Chat history"
|
msgid "Chat history"
|
||||||
msgstr "Chat history"
|
msgstr "Chat history"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/composer.tsx
|
||||||
msgid "Chat Settings"
|
msgid "Chat Settings"
|
||||||
msgstr "Chat Settings"
|
msgstr "Chat Settings"
|
||||||
|
|
||||||
@ -1088,7 +1089,7 @@ msgstr "Close"
|
|||||||
msgid "Close chart"
|
msgid "Close chart"
|
||||||
msgstr "Close chart"
|
msgstr "Close chart"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/fullscreen-computer-overlay.tsx
|
||||||
msgid "Close computer"
|
msgid "Close computer"
|
||||||
msgstr "Close computer"
|
msgstr "Close computer"
|
||||||
|
|
||||||
@ -1128,7 +1129,7 @@ msgstr "Close navigation"
|
|||||||
|
|
||||||
#: src/components/ArtifactPane.tsx
|
#: src/components/ArtifactPane.tsx
|
||||||
#: src/components/browser/InAppBrowser.tsx
|
#: src/components/browser/InAppBrowser.tsx
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/side-panel-header.tsx
|
||||||
msgid "Close panel"
|
msgid "Close panel"
|
||||||
msgstr "Close panel"
|
msgstr "Close panel"
|
||||||
|
|
||||||
@ -1159,7 +1160,7 @@ msgid "Coder"
|
|||||||
msgstr "Coder"
|
msgstr "Coder"
|
||||||
|
|
||||||
#. placeholder {0}: group.title
|
#. placeholder {0}: group.title
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/sidebar-group-header.tsx
|
||||||
msgid "Collapse {0}"
|
msgid "Collapse {0}"
|
||||||
msgstr "Collapse {0}"
|
msgstr "Collapse {0}"
|
||||||
|
|
||||||
@ -1192,24 +1193,24 @@ msgid "Composing a reply…"
|
|||||||
msgstr "Composing a reply…"
|
msgstr "Composing a reply…"
|
||||||
|
|
||||||
#: src/pages/SettingsOverlay.tsx
|
#: src/pages/SettingsOverlay.tsx
|
||||||
#: src/pages/Shell.tsx
|
|
||||||
#: src/pages/shell/bot-panel.tsx
|
#: src/pages/shell/bot-panel.tsx
|
||||||
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "Computer"
|
msgid "Computer"
|
||||||
msgstr "Computer"
|
msgstr "Computer"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/computer-screen.tsx
|
||||||
msgid "Computer failed to boot"
|
msgid "Computer failed to boot"
|
||||||
msgstr "Computer failed to boot"
|
msgstr "Computer failed to boot"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/fullscreen-computer-overlay.tsx
|
||||||
msgid "Computer is asleep"
|
msgid "Computer is asleep"
|
||||||
msgstr "Computer is asleep"
|
msgstr "Computer is asleep"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/computer-screen.tsx
|
||||||
msgid "Computer is asleep. Open it to wake."
|
msgid "Computer is asleep. Open it to wake."
|
||||||
msgstr "Computer is asleep. Open it to wake."
|
msgstr "Computer is asleep. Open it to wake."
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/computer-screen.tsx
|
||||||
msgid "Computer is stopped"
|
msgid "Computer is stopped"
|
||||||
msgstr "Computer is stopped"
|
msgstr "Computer is stopped"
|
||||||
|
|
||||||
@ -1353,7 +1354,7 @@ msgstr "Continue in Background"
|
|||||||
msgid "Continue with email"
|
msgid "Continue with email"
|
||||||
msgstr "Continue with email"
|
msgstr "Continue with email"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "Conversation record"
|
msgid "Conversation record"
|
||||||
msgstr "Conversation record"
|
msgstr "Conversation record"
|
||||||
|
|
||||||
@ -1361,11 +1362,11 @@ msgstr "Conversation record"
|
|||||||
msgid "Conversations"
|
msgid "Conversations"
|
||||||
msgstr "Conversations"
|
msgstr "Conversations"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "Copy"
|
msgid "Copy"
|
||||||
msgstr "Copy"
|
msgstr "Copy"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "Copy reply"
|
msgid "Copy reply"
|
||||||
msgstr "Copy reply"
|
msgstr "Copy reply"
|
||||||
|
|
||||||
@ -1747,9 +1748,9 @@ msgstr "Couldn't update avatars"
|
|||||||
msgid "Couldn't update messaging settings"
|
msgid "Couldn't update messaging settings"
|
||||||
msgstr "Couldn't update messaging settings"
|
msgstr "Couldn't update messaging settings"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
|
||||||
#: src/pages/shell/bot-panel.tsx
|
#: src/pages/shell/bot-panel.tsx
|
||||||
#: src/pages/shell/dialogs.tsx
|
#: src/pages/shell/dialogs.tsx
|
||||||
|
#: src/pages/shell/sidebar-header.tsx
|
||||||
msgid "Create"
|
msgid "Create"
|
||||||
msgstr "Create"
|
msgstr "Create"
|
||||||
|
|
||||||
@ -1906,14 +1907,14 @@ msgstr "Default scope"
|
|||||||
#: src/pages/KnowledgeSection.tsx
|
#: src/pages/KnowledgeSection.tsx
|
||||||
#: src/pages/McpServersOverlay.tsx
|
#: src/pages/McpServersOverlay.tsx
|
||||||
#: src/pages/RoutineEditor.tsx
|
#: src/pages/RoutineEditor.tsx
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/archived-section.tsx
|
||||||
#: src/pages/shell/dialogs.tsx
|
#: src/pages/shell/dialogs.tsx
|
||||||
msgid "Delete"
|
msgid "Delete"
|
||||||
msgstr "Delete"
|
msgstr "Delete"
|
||||||
|
|
||||||
#. placeholder {0}: bot.name
|
#. placeholder {0}: bot.name
|
||||||
#. placeholder {0}: group.name
|
#. placeholder {0}: group.name
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/archived-section.tsx
|
||||||
msgid "Delete {0}"
|
msgid "Delete {0}"
|
||||||
msgstr "Delete {0}"
|
msgstr "Delete {0}"
|
||||||
|
|
||||||
@ -1943,7 +1944,7 @@ msgstr "Delete my account"
|
|||||||
msgid "Delete space"
|
msgid "Delete space"
|
||||||
msgstr "Delete space"
|
msgstr "Delete space"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "deleted"
|
msgid "deleted"
|
||||||
msgstr "deleted"
|
msgstr "deleted"
|
||||||
|
|
||||||
@ -2013,7 +2014,7 @@ msgstr "Disconnecting…"
|
|||||||
msgid "Dismiss"
|
msgid "Dismiss"
|
||||||
msgstr "Dismiss"
|
msgstr "Dismiss"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/composer.tsx
|
||||||
msgid "Dismiss error"
|
msgid "Dismiss error"
|
||||||
msgstr "Dismiss error"
|
msgstr "Dismiss error"
|
||||||
|
|
||||||
@ -2111,7 +2112,7 @@ msgstr "Duplicate"
|
|||||||
msgid "e.g. Hivenet Agent, Presales, Timesheets bot"
|
msgid "e.g. Hivenet Agent, Presales, Timesheets bot"
|
||||||
msgstr "e.g. Hivenet Agent, Presales, Timesheets bot"
|
msgstr "e.g. Hivenet Agent, Presales, Timesheets bot"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "Earlier message"
|
msgid "Earlier message"
|
||||||
msgstr "Earlier message"
|
msgstr "Earlier message"
|
||||||
|
|
||||||
@ -2222,7 +2223,7 @@ msgid "Expand"
|
|||||||
msgstr "Expand"
|
msgstr "Expand"
|
||||||
|
|
||||||
#. placeholder {0}: group.title
|
#. placeholder {0}: group.title
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/sidebar-group-header.tsx
|
||||||
msgid "Expand {0}"
|
msgid "Expand {0}"
|
||||||
msgstr "Expand {0}"
|
msgstr "Expand {0}"
|
||||||
|
|
||||||
@ -2404,6 +2405,7 @@ msgstr "Goals for this project, separate from chat messages. Conversations are b
|
|||||||
#: src/components/stage/OoStage.tsx
|
#: src/components/stage/OoStage.tsx
|
||||||
#: src/pages/MessagingSettingsOverlay.tsx
|
#: src/pages/MessagingSettingsOverlay.tsx
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/Shell.tsx
|
||||||
|
#: src/pages/shell/side-panel-header.tsx
|
||||||
msgid "Group"
|
msgid "Group"
|
||||||
msgstr "Group"
|
msgstr "Group"
|
||||||
|
|
||||||
@ -2528,7 +2530,7 @@ msgstr "How should your Oo sound when reading replies aloud?"
|
|||||||
msgid "How to check"
|
msgid "How to check"
|
||||||
msgstr "How to check"
|
msgstr "How to check"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/computer-screen.tsx
|
||||||
msgid "I’m done"
|
msgid "I’m done"
|
||||||
msgstr "I’m done"
|
msgstr "I’m done"
|
||||||
|
|
||||||
@ -2635,11 +2637,11 @@ msgstr "Isolated"
|
|||||||
msgid "Its conversation, files, and routines will be permanently deleted. Bots it created stay in your list."
|
msgid "Its conversation, files, and routines will be permanently deleted. Bots it created stay in your list."
|
||||||
msgstr "Its conversation, files, and routines will be permanently deleted. Bots it created stay in your list."
|
msgstr "Its conversation, files, and routines will be permanently deleted. Bots it created stay in your list."
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "Jump to latest"
|
msgid "Jump to latest"
|
||||||
msgstr "Jump to latest"
|
msgstr "Jump to latest"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "Jump to replied message"
|
msgid "Jump to replied message"
|
||||||
msgstr "Jump to replied message"
|
msgstr "Jump to replied message"
|
||||||
|
|
||||||
@ -2726,7 +2728,7 @@ msgstr "Listening — what's broken or slow?"
|
|||||||
msgid "Listening — what's the story?"
|
msgid "Listening — what's the story?"
|
||||||
msgstr "Listening — what's the story?"
|
msgstr "Listening — what's the story?"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "Load earlier messages"
|
msgid "Load earlier messages"
|
||||||
msgstr "Load earlier messages"
|
msgstr "Load earlier messages"
|
||||||
|
|
||||||
@ -2779,7 +2781,7 @@ msgstr "Loading voices…"
|
|||||||
#: src/pages/HeuteBrief.tsx
|
#: src/pages/HeuteBrief.tsx
|
||||||
#: src/pages/IntegrationSetup.tsx
|
#: src/pages/IntegrationSetup.tsx
|
||||||
#: src/pages/PeerMessagesOverlay.tsx
|
#: src/pages/PeerMessagesOverlay.tsx
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "Loading…"
|
msgid "Loading…"
|
||||||
msgstr "Loading…"
|
msgstr "Loading…"
|
||||||
|
|
||||||
@ -2799,7 +2801,7 @@ msgstr "Local Docker"
|
|||||||
msgid "Local Server Settings"
|
msgid "Local Server Settings"
|
||||||
msgstr "Local Server Settings"
|
msgstr "Local Server Settings"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/user-menu.tsx
|
||||||
msgid "Log out"
|
msgid "Log out"
|
||||||
msgstr "Log out"
|
msgstr "Log out"
|
||||||
|
|
||||||
@ -2926,7 +2928,7 @@ msgstr "Memory"
|
|||||||
msgid "Memory scope"
|
msgid "Memory scope"
|
||||||
msgstr "Memory scope"
|
msgstr "Memory scope"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/composer.tsx
|
||||||
msgid "Mentions"
|
msgid "Mentions"
|
||||||
msgstr "Mentions"
|
msgstr "Mentions"
|
||||||
|
|
||||||
@ -2939,11 +2941,12 @@ msgstr "Mentions only"
|
|||||||
msgid "Message"
|
msgid "Message"
|
||||||
msgstr "Message"
|
msgstr "Message"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/composer.tsx
|
||||||
|
#: src/pages/shell/message-preview.ts
|
||||||
msgid "Message"
|
msgid "Message"
|
||||||
msgstr "Message"
|
msgstr "Message"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/composer.tsx
|
||||||
msgid "Message composer"
|
msgid "Message composer"
|
||||||
msgstr "Message composer"
|
msgstr "Message composer"
|
||||||
|
|
||||||
@ -2951,11 +2954,11 @@ msgstr "Message composer"
|
|||||||
msgid "Message event"
|
msgid "Message event"
|
||||||
msgstr "Message event"
|
msgstr "Message event"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "Message from {peer}"
|
msgid "Message from {peer}"
|
||||||
msgstr "Message from {peer}"
|
msgstr "Message from {peer}"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/composer.tsx
|
||||||
msgid "Message…"
|
msgid "Message…"
|
||||||
msgstr "Message…"
|
msgstr "Message…"
|
||||||
|
|
||||||
@ -2981,7 +2984,7 @@ msgstr "Minimal"
|
|||||||
msgid "Minimize"
|
msgid "Minimize"
|
||||||
msgstr "Minimize"
|
msgstr "Minimize"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/sidebar-toggle-buttons.tsx
|
||||||
msgid "Minimize bots"
|
msgid "Minimize bots"
|
||||||
msgstr "Minimize bots"
|
msgstr "Minimize bots"
|
||||||
|
|
||||||
@ -3038,7 +3041,7 @@ msgstr "Models from server"
|
|||||||
msgid "Monthly"
|
msgid "Monthly"
|
||||||
msgstr "Monthly"
|
msgstr "Monthly"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "More"
|
msgid "More"
|
||||||
msgstr "More"
|
msgstr "More"
|
||||||
|
|
||||||
@ -3104,7 +3107,8 @@ msgstr "Needs you"
|
|||||||
#: src/components/MainInbox.tsx
|
#: src/components/MainInbox.tsx
|
||||||
#: src/pages/ActivityList.tsx
|
#: src/pages/ActivityList.tsx
|
||||||
#: src/pages/HeuteBrief.tsx
|
#: src/pages/HeuteBrief.tsx
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/fullscreen-computer-overlay.tsx
|
||||||
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "Needs you"
|
msgid "Needs you"
|
||||||
msgstr "Needs you"
|
msgstr "Needs you"
|
||||||
|
|
||||||
@ -3397,12 +3401,12 @@ msgid "Only file and folder names are read."
|
|||||||
msgstr "Only file and folder names are read."
|
msgstr "Only file and folder names are read."
|
||||||
|
|
||||||
#: src/pages/ScratchpadSection.tsx
|
#: src/pages/ScratchpadSection.tsx
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/computer-panel-preview.tsx
|
||||||
msgid "Open"
|
msgid "Open"
|
||||||
msgstr "Open"
|
msgstr "Open"
|
||||||
|
|
||||||
#. placeholder {0}: group.title
|
#. placeholder {0}: group.title
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/sidebar-group-header.tsx
|
||||||
msgid "Open {0}"
|
msgid "Open {0}"
|
||||||
msgstr "Open {0}"
|
msgstr "Open {0}"
|
||||||
|
|
||||||
@ -3418,11 +3422,11 @@ msgstr "Open conversation"
|
|||||||
msgid "Open in browser"
|
msgid "Open in browser"
|
||||||
msgstr "Open in browser"
|
msgstr "Open in browser"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/computer-panel-preview.tsx
|
||||||
msgid "Open in full window"
|
msgid "Open in full window"
|
||||||
msgstr "Open in full window"
|
msgstr "Open in full window"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/sidebar-toggle-buttons.tsx
|
||||||
msgid "Open navigation"
|
msgid "Open navigation"
|
||||||
msgstr "Open navigation"
|
msgstr "Open navigation"
|
||||||
|
|
||||||
@ -3438,7 +3442,7 @@ msgstr "Open work"
|
|||||||
msgid "OpenAI-compatible server URL"
|
msgid "OpenAI-compatible server URL"
|
||||||
msgstr "OpenAI-compatible server URL"
|
msgstr "OpenAI-compatible server URL"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "Opened its thread."
|
msgid "Opened its thread."
|
||||||
msgstr "Opened its thread."
|
msgstr "Opened its thread."
|
||||||
|
|
||||||
@ -3679,19 +3683,19 @@ msgstr "Quiet hours end"
|
|||||||
msgid "Quiet hours start"
|
msgid "Quiet hours start"
|
||||||
msgstr "Quiet hours start"
|
msgstr "Quiet hours start"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "Quote"
|
msgid "Quote"
|
||||||
msgstr "Quote"
|
msgstr "Quote"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "React"
|
msgid "React"
|
||||||
msgstr "React"
|
msgstr "React"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "Reactions"
|
msgid "Reactions"
|
||||||
msgstr "Reactions"
|
msgstr "Reactions"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "Read aloud"
|
msgid "Read aloud"
|
||||||
msgstr "Read aloud"
|
msgstr "Read aloud"
|
||||||
|
|
||||||
@ -3796,7 +3800,7 @@ msgstr "Refreshing…"
|
|||||||
msgid "Region"
|
msgid "Region"
|
||||||
msgstr "Region"
|
msgstr "Region"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/computer-screen.tsx
|
||||||
msgid "Release"
|
msgid "Release"
|
||||||
msgstr "Release"
|
msgstr "Release"
|
||||||
|
|
||||||
@ -3820,7 +3824,7 @@ msgid "Remove"
|
|||||||
msgstr "Remove"
|
msgstr "Remove"
|
||||||
|
|
||||||
#. placeholder {0}: attachment.file.name
|
#. placeholder {0}: attachment.file.name
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/composer.tsx
|
||||||
msgid "Remove {0}"
|
msgid "Remove {0}"
|
||||||
msgstr "Remove {0}"
|
msgstr "Remove {0}"
|
||||||
|
|
||||||
@ -3829,7 +3833,7 @@ msgid "Remove Git event"
|
|||||||
msgstr "Remove Git event"
|
msgstr "Remove Git event"
|
||||||
|
|
||||||
#. placeholder {0}: mention.name
|
#. placeholder {0}: mention.name
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/composer.tsx
|
||||||
msgid "Remove mention {0}"
|
msgid "Remove mention {0}"
|
||||||
msgstr "Remove mention {0}"
|
msgstr "Remove mention {0}"
|
||||||
|
|
||||||
@ -3842,7 +3846,7 @@ msgid "Remove schedule"
|
|||||||
msgstr "Remove schedule"
|
msgstr "Remove schedule"
|
||||||
|
|
||||||
#. placeholder {0}: selectedSkill.name
|
#. placeholder {0}: selectedSkill.name
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/composer.tsx
|
||||||
msgid "Remove skill {0}"
|
msgid "Remove skill {0}"
|
||||||
msgstr "Remove skill {0}"
|
msgstr "Remove skill {0}"
|
||||||
|
|
||||||
@ -3850,7 +3854,7 @@ msgstr "Remove skill {0}"
|
|||||||
msgid "Remove webhook"
|
msgid "Remove webhook"
|
||||||
msgstr "Remove webhook"
|
msgstr "Remove webhook"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "Removed with chat, computer, and memory."
|
msgid "Removed with chat, computer, and memory."
|
||||||
msgstr "Removed with chat, computer, and memory."
|
msgstr "Removed with chat, computer, and memory."
|
||||||
|
|
||||||
@ -3883,15 +3887,15 @@ msgstr "Replace API key"
|
|||||||
msgid "Replace key"
|
msgid "Replace key"
|
||||||
msgstr "Replace key"
|
msgstr "Replace key"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "Reply"
|
msgid "Reply"
|
||||||
msgstr "Reply"
|
msgstr "Reply"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/composer.tsx
|
||||||
msgid "Replying to {replyName}"
|
msgid "Replying to {replyName}"
|
||||||
msgstr "Replying to {replyName}"
|
msgstr "Replying to {replyName}"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/composer.tsx
|
||||||
msgid "Replying to {replyName}: “{replyQuote}”"
|
msgid "Replying to {replyName}: “{replyQuote}”"
|
||||||
msgstr "Replying to {replyName}: “{replyQuote}”"
|
msgstr "Replying to {replyName}: “{replyQuote}”"
|
||||||
|
|
||||||
@ -3937,7 +3941,7 @@ msgstr "Resetting…"
|
|||||||
msgid "Restart to update"
|
msgid "Restart to update"
|
||||||
msgstr "Restart to update"
|
msgstr "Restart to update"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/archived-section.tsx
|
||||||
msgid "Restore"
|
msgid "Restore"
|
||||||
msgstr "Restore"
|
msgstr "Restore"
|
||||||
|
|
||||||
@ -4142,7 +4146,7 @@ msgid "Searching…"
|
|||||||
msgstr "Searching…"
|
msgstr "Searching…"
|
||||||
|
|
||||||
#. placeholder {0}: group.title
|
#. placeholder {0}: group.title
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/sidebar-group-header.tsx
|
||||||
msgid "Select {0}"
|
msgid "Select {0}"
|
||||||
msgstr "Select {0}"
|
msgstr "Select {0}"
|
||||||
|
|
||||||
@ -4150,7 +4154,7 @@ msgstr "Select {0}"
|
|||||||
msgid "Self-hosted (better-auth)"
|
msgid "Self-hosted (better-auth)"
|
||||||
msgstr "Self-hosted (better-auth)"
|
msgstr "Self-hosted (better-auth)"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/composer.tsx
|
||||||
#: src/pages/shell/message-cards.tsx
|
#: src/pages/shell/message-cards.tsx
|
||||||
msgid "Send"
|
msgid "Send"
|
||||||
msgstr "Send"
|
msgstr "Send"
|
||||||
@ -4201,21 +4205,22 @@ msgid "Server URL"
|
|||||||
msgstr "Server URL"
|
msgstr "Server URL"
|
||||||
|
|
||||||
#: src/components/stage/StageVoiceEntry.tsx
|
#: src/components/stage/StageVoiceEntry.tsx
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/composer.tsx
|
||||||
msgid "Set up voice"
|
msgid "Set up voice"
|
||||||
msgstr "Set up voice"
|
msgstr "Set up voice"
|
||||||
|
|
||||||
#: src/pages/MessagingSettingsOverlay.tsx
|
#: src/pages/MessagingSettingsOverlay.tsx
|
||||||
#: src/pages/SettingsOverlay.tsx
|
#: src/pages/SettingsOverlay.tsx
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/side-panel-header.tsx
|
||||||
|
#: src/pages/shell/user-menu.tsx
|
||||||
msgid "Settings"
|
msgid "Settings"
|
||||||
msgstr "Settings"
|
msgstr "Settings"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/composer.tsx
|
||||||
msgid "Settings: General"
|
msgid "Settings: General"
|
||||||
msgstr "Settings: General"
|
msgstr "Settings: General"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/composer.tsx
|
||||||
msgid "Settings: Usage"
|
msgid "Settings: Usage"
|
||||||
msgstr "Settings: Usage"
|
msgstr "Settings: Usage"
|
||||||
|
|
||||||
@ -4259,10 +4264,11 @@ msgid "Show all {0}"
|
|||||||
msgstr "Show all {0}"
|
msgstr "Show all {0}"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/Shell.tsx
|
||||||
|
#: src/pages/shell/sidebar-toggle-buttons.tsx
|
||||||
msgid "Show bots"
|
msgid "Show bots"
|
||||||
msgstr "Show bots"
|
msgstr "Show bots"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/side-panel-header.tsx
|
||||||
msgid "Show computer"
|
msgid "Show computer"
|
||||||
msgstr "Show computer"
|
msgstr "Show computer"
|
||||||
|
|
||||||
@ -4278,7 +4284,7 @@ msgstr "Show more"
|
|||||||
msgid "Show password"
|
msgid "Show password"
|
||||||
msgstr "Show password"
|
msgstr "Show password"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/side-panel-header.tsx
|
||||||
msgid "Show settings"
|
msgid "Show settings"
|
||||||
msgstr "Show settings"
|
msgstr "Show settings"
|
||||||
|
|
||||||
@ -4307,7 +4313,7 @@ msgid "Sketching the blueprint…"
|
|||||||
msgstr "Sketching the blueprint…"
|
msgstr "Sketching the blueprint…"
|
||||||
|
|
||||||
#. placeholder {0}: skill.name
|
#. placeholder {0}: skill.name
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/composer.tsx
|
||||||
msgid "Skill {0}"
|
msgid "Skill {0}"
|
||||||
msgstr "Skill {0}"
|
msgstr "Skill {0}"
|
||||||
|
|
||||||
@ -4319,7 +4325,7 @@ msgstr "Skills"
|
|||||||
#: src/components/onboarding/OnboardingScanStep.tsx
|
#: src/components/onboarding/OnboardingScanStep.tsx
|
||||||
#: src/components/onboarding/OnboardingVoiceStep.tsx
|
#: src/components/onboarding/OnboardingVoiceStep.tsx
|
||||||
#: src/lib/onboarding-copy.ts
|
#: src/lib/onboarding-copy.ts
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/computer-screen.tsx
|
||||||
msgid "Skip"
|
msgid "Skip"
|
||||||
msgstr "Skip"
|
msgstr "Skip"
|
||||||
|
|
||||||
@ -4373,11 +4379,11 @@ msgstr "Space default"
|
|||||||
msgid "Spaces"
|
msgid "Spaces"
|
||||||
msgstr "Spaces"
|
msgstr "Spaces"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "Speak"
|
msgid "Speak"
|
||||||
msgstr "Speak"
|
msgstr "Speak"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "Speak this reply"
|
msgid "Speak this reply"
|
||||||
msgstr "Speak this reply"
|
msgstr "Speak this reply"
|
||||||
|
|
||||||
@ -4431,15 +4437,15 @@ msgstr "Start recording"
|
|||||||
msgid "Start talking"
|
msgid "Start talking"
|
||||||
msgstr "Start talking"
|
msgstr "Start talking"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "Start the conversation — {activeName} is on stage above."
|
msgid "Start the conversation — {activeName} is on stage above."
|
||||||
msgstr "Start the conversation — {activeName} is on stage above."
|
msgstr "Start the conversation — {activeName} is on stage above."
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "Start the conversation."
|
msgid "Start the conversation."
|
||||||
msgstr "Start the conversation."
|
msgstr "Start the conversation."
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/composer.tsx
|
||||||
msgid "Start voice conversation"
|
msgid "Start voice conversation"
|
||||||
msgstr "Start voice conversation"
|
msgstr "Start voice conversation"
|
||||||
|
|
||||||
@ -4466,11 +4472,13 @@ msgid "Steps"
|
|||||||
msgstr "Steps"
|
msgstr "Steps"
|
||||||
|
|
||||||
#: src/components/browser/InAppBrowser.tsx
|
#: src/components/browser/InAppBrowser.tsx
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/composer.tsx
|
||||||
|
#: src/pages/shell/fullscreen-computer-overlay.tsx
|
||||||
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "Stop"
|
msgid "Stop"
|
||||||
msgstr "Stop"
|
msgstr "Stop"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "Stop speaking"
|
msgid "Stop speaking"
|
||||||
msgstr "Stop speaking"
|
msgstr "Stop speaking"
|
||||||
|
|
||||||
@ -4500,7 +4508,7 @@ msgstr "Stress-testing the book…"
|
|||||||
msgid "Stronger together — {0} specialists"
|
msgid "Stronger together — {0} specialists"
|
||||||
msgstr "Stronger together — {0} specialists"
|
msgstr "Stronger together — {0} specialists"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "subagent"
|
msgid "subagent"
|
||||||
msgstr "subagent"
|
msgstr "subagent"
|
||||||
|
|
||||||
@ -4565,7 +4573,7 @@ msgstr "Teaching in progress. Stop teaching before sending a new message."
|
|||||||
msgid "Team"
|
msgid "Team"
|
||||||
msgstr "Team"
|
msgstr "Team"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/computer-screen.tsx
|
||||||
msgid "Team Computer"
|
msgid "Team Computer"
|
||||||
msgstr "Team Computer"
|
msgstr "Team Computer"
|
||||||
|
|
||||||
@ -4606,7 +4614,7 @@ msgstr "The selected memory provider is not available in this build."
|
|||||||
msgid "Thinking"
|
msgid "Thinking"
|
||||||
msgstr "Thinking"
|
msgstr "Thinking"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/computer-screen.tsx
|
||||||
msgid "This bot runs on this computer, not a Linux desktop. Shell and files use your home folder."
|
msgid "This bot runs on this computer, not a Linux desktop. Shell and files use your home folder."
|
||||||
msgstr "This bot runs on this computer, not a Linux desktop. Shell and files use your home folder."
|
msgstr "This bot runs on this computer, not a Linux desktop. Shell and files use your home folder."
|
||||||
|
|
||||||
@ -4713,7 +4721,7 @@ msgid "Transcribe"
|
|||||||
msgstr "Transcribe"
|
msgstr "Transcribe"
|
||||||
|
|
||||||
#: src/components/voice/VoiceStage.tsx
|
#: src/components/voice/VoiceStage.tsx
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "Transcript"
|
msgid "Transcript"
|
||||||
msgstr "Transcript"
|
msgstr "Transcript"
|
||||||
|
|
||||||
@ -4836,7 +4844,7 @@ msgstr "Upload"
|
|||||||
|
|
||||||
#: src/pages/AccountSettingsOverlay.tsx
|
#: src/pages/AccountSettingsOverlay.tsx
|
||||||
#: src/pages/SettingsOverlay.tsx
|
#: src/pages/SettingsOverlay.tsx
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/user-menu.tsx
|
||||||
msgid "Usage"
|
msgid "Usage"
|
||||||
msgstr "Usage"
|
msgstr "Usage"
|
||||||
|
|
||||||
@ -4877,8 +4885,8 @@ msgid "Video workflow"
|
|||||||
msgstr "Video workflow"
|
msgstr "Video workflow"
|
||||||
|
|
||||||
#: src/pages/SettingsOverlay.tsx
|
#: src/pages/SettingsOverlay.tsx
|
||||||
#: src/pages/Shell.tsx
|
|
||||||
#: src/pages/shell/bot-panel.tsx
|
#: src/pages/shell/bot-panel.tsx
|
||||||
|
#: src/pages/shell/composer.tsx
|
||||||
#: src/pages/VoiceSettingsOverlay.tsx
|
#: src/pages/VoiceSettingsOverlay.tsx
|
||||||
msgid "Voice"
|
msgid "Voice"
|
||||||
msgstr "Voice"
|
msgstr "Voice"
|
||||||
@ -5074,7 +5082,7 @@ msgstr "Working…"
|
|||||||
msgid "Working…"
|
msgid "Working…"
|
||||||
msgstr "Working…"
|
msgstr "Working…"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/roster-format.ts
|
||||||
msgid "Yesterday"
|
msgid "Yesterday"
|
||||||
msgstr "Yesterday"
|
msgstr "Yesterday"
|
||||||
|
|
||||||
@ -5092,7 +5100,7 @@ msgstr "You can close this tab if it does not redirect automatically."
|
|||||||
msgid "You can close this window."
|
msgid "You can close this window."
|
||||||
msgstr "You can close this window."
|
msgstr "You can close this window."
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/fullscreen-computer-overlay.tsx
|
||||||
msgid "You have control"
|
msgid "You have control"
|
||||||
msgstr "You have control"
|
msgstr "You have control"
|
||||||
|
|
||||||
|
|||||||
@ -14,7 +14,7 @@ msgstr ""
|
|||||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||||
"X-Generator: @lingui/cli\n"
|
"X-Generator: @lingui/cli\n"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/roster-rows.tsx
|
||||||
msgid " (unread)"
|
msgid " (unread)"
|
||||||
msgstr " (sin leer)"
|
msgstr " (sin leer)"
|
||||||
|
|
||||||
@ -126,22 +126,22 @@ msgid "{0}, {label}"
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#. placeholder {0}: item.chat.name
|
#. placeholder {0}: item.chat.name
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/roster-rows.tsx
|
||||||
msgid "{0}, 1:1 conversation"
|
msgid "{0}, 1:1 conversation"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#. placeholder {0}: item.chat.name
|
#. placeholder {0}: item.chat.name
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/roster-rows.tsx
|
||||||
msgid "{0}, group conversation"
|
msgid "{0}, group conversation"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#. placeholder {0}: item.chat.name
|
#. placeholder {0}: item.chat.name
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/roster-rows.tsx
|
||||||
msgid "{0}, main conversation"
|
msgid "{0}, main conversation"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#. placeholder {0}: active.name
|
#. placeholder {0}: active.name
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/computer-panel-preview.tsx
|
||||||
msgid "{0}'s screen"
|
msgid "{0}'s screen"
|
||||||
msgstr "Pantalla de {0}"
|
msgstr "Pantalla de {0}"
|
||||||
|
|
||||||
@ -210,7 +210,7 @@ msgstr ""
|
|||||||
msgid "{botName} watches the tape…"
|
msgid "{botName} watches the tape…"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/computer-screen.tsx
|
||||||
msgid "{botName}’s computer"
|
msgid "{botName}’s computer"
|
||||||
msgstr "Computadora de {botName}"
|
msgstr "Computadora de {botName}"
|
||||||
|
|
||||||
@ -277,7 +277,7 @@ msgstr "{title}, {label}"
|
|||||||
msgid "{toolCount, plural, one {# tool} other {# tools}}"
|
msgid "{toolCount, plural, one {# tool} other {# tools}}"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "{workingBotName} is working"
|
msgid "{workingBotName} is working"
|
||||||
msgstr "{workingBotName} está trabajando"
|
msgstr "{workingBotName} está trabajando"
|
||||||
|
|
||||||
@ -339,6 +339,7 @@ msgstr "Confirmaciones de acción"
|
|||||||
#. placeholder {0}: sectionMenu.section.name
|
#. placeholder {0}: sectionMenu.section.name
|
||||||
#: src/pages/BotContextMenu.tsx
|
#: src/pages/BotContextMenu.tsx
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/Shell.tsx
|
||||||
|
#: src/pages/shell/sidebar-group-header.tsx
|
||||||
msgid "Actions for {0}"
|
msgid "Actions for {0}"
|
||||||
msgstr "Acciones para {0}"
|
msgstr "Acciones para {0}"
|
||||||
|
|
||||||
@ -354,7 +355,7 @@ msgstr "Activo"
|
|||||||
msgid "Active model"
|
msgid "Active model"
|
||||||
msgstr "Modelo activo"
|
msgstr "Modelo activo"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/sidebar-header.tsx
|
||||||
msgid "Activity"
|
msgid "Activity"
|
||||||
msgstr "Actividad"
|
msgstr "Actividad"
|
||||||
|
|
||||||
@ -643,15 +644,15 @@ msgstr "Aprueba este servidor para que tu agente use sus herramientas."
|
|||||||
msgid "Archive"
|
msgid "Archive"
|
||||||
msgstr "Archivar"
|
msgstr "Archivar"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "archived"
|
msgid "archived"
|
||||||
msgstr "archivado"
|
msgstr "archivado"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/archived-section.tsx
|
||||||
msgid "Archived"
|
msgid "Archived"
|
||||||
msgstr "Archivado"
|
msgstr "Archivado"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "Archived. Chat, memory, and files kept."
|
msgid "Archived. Chat, memory, and files kept."
|
||||||
msgstr "Archivado. Se conservan el chat, la memoria y los archivos."
|
msgstr "Archivado. Se conservan el chat, la memoria y los archivos."
|
||||||
|
|
||||||
@ -711,11 +712,11 @@ msgstr "a las {0}"
|
|||||||
msgid "at {timeSelect}"
|
msgid "at {timeSelect}"
|
||||||
msgstr "a las {timeSelect}"
|
msgstr "a las {timeSelect}"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/composer.tsx
|
||||||
msgid "Attach file"
|
msgid "Attach file"
|
||||||
msgstr "Adjuntar archivo"
|
msgstr "Adjuntar archivo"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/message-preview.ts
|
||||||
msgid "Attachment"
|
msgid "Attachment"
|
||||||
msgstr "Archivo adjunto"
|
msgstr "Archivo adjunto"
|
||||||
|
|
||||||
@ -788,7 +789,7 @@ msgstr "Token Bearer"
|
|||||||
msgid "Blocked in your browser settings"
|
msgid "Blocked in your browser settings"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/computer-screen.tsx
|
||||||
msgid "Booting live desktop…"
|
msgid "Booting live desktop…"
|
||||||
msgstr "Iniciando escritorio en vivo…"
|
msgstr "Iniciando escritorio en vivo…"
|
||||||
|
|
||||||
@ -797,7 +798,7 @@ msgstr "Iniciando escritorio en vivo…"
|
|||||||
msgid "Booting up {0}’s computer"
|
msgid "Booting up {0}’s computer"
|
||||||
msgstr "Iniciando la computadora de {0}"
|
msgstr "Iniciando la computadora de {0}"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "bot"
|
msgid "bot"
|
||||||
msgstr "bot"
|
msgstr "bot"
|
||||||
|
|
||||||
@ -812,11 +813,11 @@ msgstr "Bot"
|
|||||||
msgid "Bot"
|
msgid "Bot"
|
||||||
msgstr "Bot"
|
msgstr "Bot"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/fullscreen-computer-overlay.tsx
|
||||||
msgid "Bot screen"
|
msgid "Bot screen"
|
||||||
msgstr "Pantalla del bot"
|
msgstr "Pantalla del bot"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/computer-panel-preview.tsx
|
||||||
msgid "Bot screen preview"
|
msgid "Bot screen preview"
|
||||||
msgstr "Vista previa de la pantalla del bot"
|
msgstr "Vista previa de la pantalla del bot"
|
||||||
|
|
||||||
@ -828,7 +829,7 @@ msgstr "Bot a vincular"
|
|||||||
msgid "Bots act without asking by default. Add an exception only when you want to review a type of action first."
|
msgid "Bots act without asking by default. Add an exception only when you want to review a type of action first."
|
||||||
msgstr "Los bots actúan sin preguntar de forma predeterminada. Agrega una excepción solo cuando quieras revisar primero un tipo de acción."
|
msgstr "Los bots actúan sin preguntar de forma predeterminada. Agrega una excepción solo cuando quieras revisar primero un tipo de acción."
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "Bots are working"
|
msgid "Bots are working"
|
||||||
msgstr "Los bots están trabajando"
|
msgstr "Los bots están trabajando"
|
||||||
|
|
||||||
@ -889,7 +890,7 @@ msgstr "Cancelar nuevo bot"
|
|||||||
msgid "Cancel new group"
|
msgid "Cancel new group"
|
||||||
msgstr "Cancelar nuevo grupo"
|
msgstr "Cancelar nuevo grupo"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/composer.tsx
|
||||||
msgid "Cancel reply"
|
msgid "Cancel reply"
|
||||||
msgstr "Cancelar respuesta"
|
msgstr "Cancelar respuesta"
|
||||||
|
|
||||||
@ -946,7 +947,7 @@ msgstr "Apps de chat, canales de grupo y conexiones de agentes."
|
|||||||
msgid "Chat history"
|
msgid "Chat history"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/composer.tsx
|
||||||
msgid "Chat Settings"
|
msgid "Chat Settings"
|
||||||
msgstr "Configuración del chat"
|
msgstr "Configuración del chat"
|
||||||
|
|
||||||
@ -1088,7 +1089,7 @@ msgstr "Cerrar"
|
|||||||
msgid "Close chart"
|
msgid "Close chart"
|
||||||
msgstr "Cerrar gráfico"
|
msgstr "Cerrar gráfico"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/fullscreen-computer-overlay.tsx
|
||||||
msgid "Close computer"
|
msgid "Close computer"
|
||||||
msgstr "Cerrar computadora"
|
msgstr "Cerrar computadora"
|
||||||
|
|
||||||
@ -1128,7 +1129,7 @@ msgstr "Cerrar navegación"
|
|||||||
|
|
||||||
#: src/components/ArtifactPane.tsx
|
#: src/components/ArtifactPane.tsx
|
||||||
#: src/components/browser/InAppBrowser.tsx
|
#: src/components/browser/InAppBrowser.tsx
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/side-panel-header.tsx
|
||||||
msgid "Close panel"
|
msgid "Close panel"
|
||||||
msgstr "Cerrar panel"
|
msgstr "Cerrar panel"
|
||||||
|
|
||||||
@ -1159,7 +1160,7 @@ msgid "Coder"
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#. placeholder {0}: group.title
|
#. placeholder {0}: group.title
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/sidebar-group-header.tsx
|
||||||
msgid "Collapse {0}"
|
msgid "Collapse {0}"
|
||||||
msgstr "Contraer {0}"
|
msgstr "Contraer {0}"
|
||||||
|
|
||||||
@ -1192,24 +1193,24 @@ msgid "Composing a reply…"
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/SettingsOverlay.tsx
|
#: src/pages/SettingsOverlay.tsx
|
||||||
#: src/pages/Shell.tsx
|
|
||||||
#: src/pages/shell/bot-panel.tsx
|
#: src/pages/shell/bot-panel.tsx
|
||||||
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "Computer"
|
msgid "Computer"
|
||||||
msgstr "Computadora"
|
msgstr "Computadora"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/computer-screen.tsx
|
||||||
msgid "Computer failed to boot"
|
msgid "Computer failed to boot"
|
||||||
msgstr "La computadora no pudo iniciarse"
|
msgstr "La computadora no pudo iniciarse"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/fullscreen-computer-overlay.tsx
|
||||||
msgid "Computer is asleep"
|
msgid "Computer is asleep"
|
||||||
msgstr "La computadora está en reposo"
|
msgstr "La computadora está en reposo"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/computer-screen.tsx
|
||||||
msgid "Computer is asleep. Open it to wake."
|
msgid "Computer is asleep. Open it to wake."
|
||||||
msgstr "La computadora está en reposo. Ábrela para despertarla."
|
msgstr "La computadora está en reposo. Ábrela para despertarla."
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/computer-screen.tsx
|
||||||
msgid "Computer is stopped"
|
msgid "Computer is stopped"
|
||||||
msgstr "La computadora está detenida"
|
msgstr "La computadora está detenida"
|
||||||
|
|
||||||
@ -1353,7 +1354,7 @@ msgstr ""
|
|||||||
msgid "Continue with email"
|
msgid "Continue with email"
|
||||||
msgstr "Continuar con el correo"
|
msgstr "Continuar con el correo"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "Conversation record"
|
msgid "Conversation record"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@ -1361,11 +1362,11 @@ msgstr ""
|
|||||||
msgid "Conversations"
|
msgid "Conversations"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "Copy"
|
msgid "Copy"
|
||||||
msgstr "Copiar"
|
msgstr "Copiar"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "Copy reply"
|
msgid "Copy reply"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@ -1747,9 +1748,9 @@ msgstr "No se pudieron actualizar los avatares"
|
|||||||
msgid "Couldn't update messaging settings"
|
msgid "Couldn't update messaging settings"
|
||||||
msgstr "No se pudo actualizar la configuración de mensajería"
|
msgstr "No se pudo actualizar la configuración de mensajería"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
|
||||||
#: src/pages/shell/bot-panel.tsx
|
#: src/pages/shell/bot-panel.tsx
|
||||||
#: src/pages/shell/dialogs.tsx
|
#: src/pages/shell/dialogs.tsx
|
||||||
|
#: src/pages/shell/sidebar-header.tsx
|
||||||
msgid "Create"
|
msgid "Create"
|
||||||
msgstr "Crear"
|
msgstr "Crear"
|
||||||
|
|
||||||
@ -1906,14 +1907,14 @@ msgstr "Alcance predeterminado"
|
|||||||
#: src/pages/KnowledgeSection.tsx
|
#: src/pages/KnowledgeSection.tsx
|
||||||
#: src/pages/McpServersOverlay.tsx
|
#: src/pages/McpServersOverlay.tsx
|
||||||
#: src/pages/RoutineEditor.tsx
|
#: src/pages/RoutineEditor.tsx
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/archived-section.tsx
|
||||||
#: src/pages/shell/dialogs.tsx
|
#: src/pages/shell/dialogs.tsx
|
||||||
msgid "Delete"
|
msgid "Delete"
|
||||||
msgstr "Eliminar"
|
msgstr "Eliminar"
|
||||||
|
|
||||||
#. placeholder {0}: bot.name
|
#. placeholder {0}: bot.name
|
||||||
#. placeholder {0}: group.name
|
#. placeholder {0}: group.name
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/archived-section.tsx
|
||||||
msgid "Delete {0}"
|
msgid "Delete {0}"
|
||||||
msgstr "Eliminar {0}"
|
msgstr "Eliminar {0}"
|
||||||
|
|
||||||
@ -1943,7 +1944,7 @@ msgstr ""
|
|||||||
msgid "Delete space"
|
msgid "Delete space"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "deleted"
|
msgid "deleted"
|
||||||
msgstr "eliminado"
|
msgstr "eliminado"
|
||||||
|
|
||||||
@ -2013,7 +2014,7 @@ msgstr "Desconectando…"
|
|||||||
msgid "Dismiss"
|
msgid "Dismiss"
|
||||||
msgstr "Descartar"
|
msgstr "Descartar"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/composer.tsx
|
||||||
msgid "Dismiss error"
|
msgid "Dismiss error"
|
||||||
msgstr "Descartar error"
|
msgstr "Descartar error"
|
||||||
|
|
||||||
@ -2111,7 +2112,7 @@ msgstr "Duplicar"
|
|||||||
msgid "e.g. Hivenet Agent, Presales, Timesheets bot"
|
msgid "e.g. Hivenet Agent, Presales, Timesheets bot"
|
||||||
msgstr "p. ej. Hivenet Agent, Presales, bot de hojas de horas"
|
msgstr "p. ej. Hivenet Agent, Presales, bot de hojas de horas"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "Earlier message"
|
msgid "Earlier message"
|
||||||
msgstr "Mensaje anterior"
|
msgstr "Mensaje anterior"
|
||||||
|
|
||||||
@ -2222,7 +2223,7 @@ msgid "Expand"
|
|||||||
msgstr "Expandir"
|
msgstr "Expandir"
|
||||||
|
|
||||||
#. placeholder {0}: group.title
|
#. placeholder {0}: group.title
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/sidebar-group-header.tsx
|
||||||
msgid "Expand {0}"
|
msgid "Expand {0}"
|
||||||
msgstr "Expandir {0}"
|
msgstr "Expandir {0}"
|
||||||
|
|
||||||
@ -2404,6 +2405,7 @@ msgstr ""
|
|||||||
#: src/components/stage/OoStage.tsx
|
#: src/components/stage/OoStage.tsx
|
||||||
#: src/pages/MessagingSettingsOverlay.tsx
|
#: src/pages/MessagingSettingsOverlay.tsx
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/Shell.tsx
|
||||||
|
#: src/pages/shell/side-panel-header.tsx
|
||||||
msgid "Group"
|
msgid "Group"
|
||||||
msgstr "Grupo"
|
msgstr "Grupo"
|
||||||
|
|
||||||
@ -2528,7 +2530,7 @@ msgstr ""
|
|||||||
msgid "How to check"
|
msgid "How to check"
|
||||||
msgstr "Cómo comprobar"
|
msgstr "Cómo comprobar"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/computer-screen.tsx
|
||||||
msgid "I’m done"
|
msgid "I’m done"
|
||||||
msgstr "Listo"
|
msgstr "Listo"
|
||||||
|
|
||||||
@ -2635,11 +2637,11 @@ msgstr "Aislado"
|
|||||||
msgid "Its conversation, files, and routines will be permanently deleted. Bots it created stay in your list."
|
msgid "Its conversation, files, and routines will be permanently deleted. Bots it created stay in your list."
|
||||||
msgstr "Su conversación, archivos y rutinas se eliminarán de forma permanente. Los bots que creó permanecerán en tu lista."
|
msgstr "Su conversación, archivos y rutinas se eliminarán de forma permanente. Los bots que creó permanecerán en tu lista."
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "Jump to latest"
|
msgid "Jump to latest"
|
||||||
msgstr "Ir al más reciente"
|
msgstr "Ir al más reciente"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "Jump to replied message"
|
msgid "Jump to replied message"
|
||||||
msgstr "Ir al mensaje respondido"
|
msgstr "Ir al mensaje respondido"
|
||||||
|
|
||||||
@ -2726,7 +2728,7 @@ msgstr ""
|
|||||||
msgid "Listening — what's the story?"
|
msgid "Listening — what's the story?"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "Load earlier messages"
|
msgid "Load earlier messages"
|
||||||
msgstr "Cargar mensajes anteriores"
|
msgstr "Cargar mensajes anteriores"
|
||||||
|
|
||||||
@ -2779,7 +2781,7 @@ msgstr ""
|
|||||||
#: src/pages/HeuteBrief.tsx
|
#: src/pages/HeuteBrief.tsx
|
||||||
#: src/pages/IntegrationSetup.tsx
|
#: src/pages/IntegrationSetup.tsx
|
||||||
#: src/pages/PeerMessagesOverlay.tsx
|
#: src/pages/PeerMessagesOverlay.tsx
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "Loading…"
|
msgid "Loading…"
|
||||||
msgstr "Cargando…"
|
msgstr "Cargando…"
|
||||||
|
|
||||||
@ -2799,7 +2801,7 @@ msgstr ""
|
|||||||
msgid "Local Server Settings"
|
msgid "Local Server Settings"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/user-menu.tsx
|
||||||
msgid "Log out"
|
msgid "Log out"
|
||||||
msgstr "Cerrar sesión"
|
msgstr "Cerrar sesión"
|
||||||
|
|
||||||
@ -2926,7 +2928,7 @@ msgstr "Memoria"
|
|||||||
msgid "Memory scope"
|
msgid "Memory scope"
|
||||||
msgstr "Alcance de memoria"
|
msgstr "Alcance de memoria"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/composer.tsx
|
||||||
msgid "Mentions"
|
msgid "Mentions"
|
||||||
msgstr "Menciones"
|
msgstr "Menciones"
|
||||||
|
|
||||||
@ -2939,11 +2941,12 @@ msgstr ""
|
|||||||
msgid "Message"
|
msgid "Message"
|
||||||
msgstr "Mensaje"
|
msgstr "Mensaje"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/composer.tsx
|
||||||
|
#: src/pages/shell/message-preview.ts
|
||||||
msgid "Message"
|
msgid "Message"
|
||||||
msgstr "Mensaje"
|
msgstr "Mensaje"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/composer.tsx
|
||||||
msgid "Message composer"
|
msgid "Message composer"
|
||||||
msgstr "Redactor de mensajes"
|
msgstr "Redactor de mensajes"
|
||||||
|
|
||||||
@ -2951,11 +2954,11 @@ msgstr "Redactor de mensajes"
|
|||||||
msgid "Message event"
|
msgid "Message event"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "Message from {peer}"
|
msgid "Message from {peer}"
|
||||||
msgstr "Mensaje de {peer}"
|
msgstr "Mensaje de {peer}"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/composer.tsx
|
||||||
msgid "Message…"
|
msgid "Message…"
|
||||||
msgstr "Mensaje…"
|
msgstr "Mensaje…"
|
||||||
|
|
||||||
@ -2981,7 +2984,7 @@ msgstr "Mínimo"
|
|||||||
msgid "Minimize"
|
msgid "Minimize"
|
||||||
msgstr "Minimizar"
|
msgstr "Minimizar"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/sidebar-toggle-buttons.tsx
|
||||||
msgid "Minimize bots"
|
msgid "Minimize bots"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@ -3038,7 +3041,7 @@ msgstr "Modelos del servidor"
|
|||||||
msgid "Monthly"
|
msgid "Monthly"
|
||||||
msgstr "Mensual"
|
msgstr "Mensual"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "More"
|
msgid "More"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@ -3104,7 +3107,8 @@ msgstr ""
|
|||||||
#: src/components/MainInbox.tsx
|
#: src/components/MainInbox.tsx
|
||||||
#: src/pages/ActivityList.tsx
|
#: src/pages/ActivityList.tsx
|
||||||
#: src/pages/HeuteBrief.tsx
|
#: src/pages/HeuteBrief.tsx
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/fullscreen-computer-overlay.tsx
|
||||||
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "Needs you"
|
msgid "Needs you"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@ -3397,12 +3401,12 @@ msgid "Only file and folder names are read."
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/ScratchpadSection.tsx
|
#: src/pages/ScratchpadSection.tsx
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/computer-panel-preview.tsx
|
||||||
msgid "Open"
|
msgid "Open"
|
||||||
msgstr "Abrir"
|
msgstr "Abrir"
|
||||||
|
|
||||||
#. placeholder {0}: group.title
|
#. placeholder {0}: group.title
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/sidebar-group-header.tsx
|
||||||
msgid "Open {0}"
|
msgid "Open {0}"
|
||||||
msgstr "Abrir {0}"
|
msgstr "Abrir {0}"
|
||||||
|
|
||||||
@ -3418,11 +3422,11 @@ msgstr ""
|
|||||||
msgid "Open in browser"
|
msgid "Open in browser"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/computer-panel-preview.tsx
|
||||||
msgid "Open in full window"
|
msgid "Open in full window"
|
||||||
msgstr "Abrir en ventana completa"
|
msgstr "Abrir en ventana completa"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/sidebar-toggle-buttons.tsx
|
||||||
msgid "Open navigation"
|
msgid "Open navigation"
|
||||||
msgstr "Abrir navegación"
|
msgstr "Abrir navegación"
|
||||||
|
|
||||||
@ -3438,7 +3442,7 @@ msgstr "Trabajo abierto"
|
|||||||
msgid "OpenAI-compatible server URL"
|
msgid "OpenAI-compatible server URL"
|
||||||
msgstr "URL de servidor compatible con OpenAI"
|
msgstr "URL de servidor compatible con OpenAI"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "Opened its thread."
|
msgid "Opened its thread."
|
||||||
msgstr "Se abrió su hilo."
|
msgstr "Se abrió su hilo."
|
||||||
|
|
||||||
@ -3679,19 +3683,19 @@ msgstr ""
|
|||||||
msgid "Quiet hours start"
|
msgid "Quiet hours start"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "Quote"
|
msgid "Quote"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "React"
|
msgid "React"
|
||||||
msgstr "Reaccionar"
|
msgstr "Reaccionar"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "Reactions"
|
msgid "Reactions"
|
||||||
msgstr "Reacciones"
|
msgstr "Reacciones"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "Read aloud"
|
msgid "Read aloud"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@ -3796,7 +3800,7 @@ msgstr "Actualizando…"
|
|||||||
msgid "Region"
|
msgid "Region"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/computer-screen.tsx
|
||||||
msgid "Release"
|
msgid "Release"
|
||||||
msgstr "Liberar"
|
msgstr "Liberar"
|
||||||
|
|
||||||
@ -3820,7 +3824,7 @@ msgid "Remove"
|
|||||||
msgstr "Quitar"
|
msgstr "Quitar"
|
||||||
|
|
||||||
#. placeholder {0}: attachment.file.name
|
#. placeholder {0}: attachment.file.name
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/composer.tsx
|
||||||
msgid "Remove {0}"
|
msgid "Remove {0}"
|
||||||
msgstr "Quitar {0}"
|
msgstr "Quitar {0}"
|
||||||
|
|
||||||
@ -3829,7 +3833,7 @@ msgid "Remove Git event"
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#. placeholder {0}: mention.name
|
#. placeholder {0}: mention.name
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/composer.tsx
|
||||||
msgid "Remove mention {0}"
|
msgid "Remove mention {0}"
|
||||||
msgstr "Quitar mención {0}"
|
msgstr "Quitar mención {0}"
|
||||||
|
|
||||||
@ -3842,7 +3846,7 @@ msgid "Remove schedule"
|
|||||||
msgstr "Quitar horario"
|
msgstr "Quitar horario"
|
||||||
|
|
||||||
#. placeholder {0}: selectedSkill.name
|
#. placeholder {0}: selectedSkill.name
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/composer.tsx
|
||||||
msgid "Remove skill {0}"
|
msgid "Remove skill {0}"
|
||||||
msgstr "Quitar habilidad {0}"
|
msgstr "Quitar habilidad {0}"
|
||||||
|
|
||||||
@ -3850,7 +3854,7 @@ msgstr "Quitar habilidad {0}"
|
|||||||
msgid "Remove webhook"
|
msgid "Remove webhook"
|
||||||
msgstr "Quitar webhook"
|
msgstr "Quitar webhook"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "Removed with chat, computer, and memory."
|
msgid "Removed with chat, computer, and memory."
|
||||||
msgstr "Eliminado junto con el chat, la computadora y la memoria."
|
msgstr "Eliminado junto con el chat, la computadora y la memoria."
|
||||||
|
|
||||||
@ -3883,15 +3887,15 @@ msgstr "Reemplazar clave de API"
|
|||||||
msgid "Replace key"
|
msgid "Replace key"
|
||||||
msgstr "Reemplazar clave"
|
msgstr "Reemplazar clave"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "Reply"
|
msgid "Reply"
|
||||||
msgstr "Responder"
|
msgstr "Responder"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/composer.tsx
|
||||||
msgid "Replying to {replyName}"
|
msgid "Replying to {replyName}"
|
||||||
msgstr "Respondiendo a {replyName}"
|
msgstr "Respondiendo a {replyName}"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/composer.tsx
|
||||||
msgid "Replying to {replyName}: “{replyQuote}”"
|
msgid "Replying to {replyName}: “{replyQuote}”"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@ -3937,7 +3941,7 @@ msgstr "Restableciendo…"
|
|||||||
msgid "Restart to update"
|
msgid "Restart to update"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/archived-section.tsx
|
||||||
msgid "Restore"
|
msgid "Restore"
|
||||||
msgstr "Restaurar"
|
msgstr "Restaurar"
|
||||||
|
|
||||||
@ -4142,7 +4146,7 @@ msgid "Searching…"
|
|||||||
msgstr "Buscando…"
|
msgstr "Buscando…"
|
||||||
|
|
||||||
#. placeholder {0}: group.title
|
#. placeholder {0}: group.title
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/sidebar-group-header.tsx
|
||||||
msgid "Select {0}"
|
msgid "Select {0}"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@ -4150,7 +4154,7 @@ msgstr ""
|
|||||||
msgid "Self-hosted (better-auth)"
|
msgid "Self-hosted (better-auth)"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/composer.tsx
|
||||||
#: src/pages/shell/message-cards.tsx
|
#: src/pages/shell/message-cards.tsx
|
||||||
msgid "Send"
|
msgid "Send"
|
||||||
msgstr "Enviar"
|
msgstr "Enviar"
|
||||||
@ -4201,21 +4205,22 @@ msgid "Server URL"
|
|||||||
msgstr "URL del servidor"
|
msgstr "URL del servidor"
|
||||||
|
|
||||||
#: src/components/stage/StageVoiceEntry.tsx
|
#: src/components/stage/StageVoiceEntry.tsx
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/composer.tsx
|
||||||
msgid "Set up voice"
|
msgid "Set up voice"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/MessagingSettingsOverlay.tsx
|
#: src/pages/MessagingSettingsOverlay.tsx
|
||||||
#: src/pages/SettingsOverlay.tsx
|
#: src/pages/SettingsOverlay.tsx
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/side-panel-header.tsx
|
||||||
|
#: src/pages/shell/user-menu.tsx
|
||||||
msgid "Settings"
|
msgid "Settings"
|
||||||
msgstr "Configuración"
|
msgstr "Configuración"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/composer.tsx
|
||||||
msgid "Settings: General"
|
msgid "Settings: General"
|
||||||
msgstr "Configuración: General"
|
msgstr "Configuración: General"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/composer.tsx
|
||||||
msgid "Settings: Usage"
|
msgid "Settings: Usage"
|
||||||
msgstr "Configuración: Uso"
|
msgstr "Configuración: Uso"
|
||||||
|
|
||||||
@ -4259,10 +4264,11 @@ msgid "Show all {0}"
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/Shell.tsx
|
||||||
|
#: src/pages/shell/sidebar-toggle-buttons.tsx
|
||||||
msgid "Show bots"
|
msgid "Show bots"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/side-panel-header.tsx
|
||||||
msgid "Show computer"
|
msgid "Show computer"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@ -4278,7 +4284,7 @@ msgstr "Mostrar más"
|
|||||||
msgid "Show password"
|
msgid "Show password"
|
||||||
msgstr "Mostrar contraseña"
|
msgstr "Mostrar contraseña"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/side-panel-header.tsx
|
||||||
msgid "Show settings"
|
msgid "Show settings"
|
||||||
msgstr "Mostrar configuración"
|
msgstr "Mostrar configuración"
|
||||||
|
|
||||||
@ -4307,7 +4313,7 @@ msgid "Sketching the blueprint…"
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#. placeholder {0}: skill.name
|
#. placeholder {0}: skill.name
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/composer.tsx
|
||||||
msgid "Skill {0}"
|
msgid "Skill {0}"
|
||||||
msgstr "Habilidad {0}"
|
msgstr "Habilidad {0}"
|
||||||
|
|
||||||
@ -4319,7 +4325,7 @@ msgstr "Habilidades"
|
|||||||
#: src/components/onboarding/OnboardingScanStep.tsx
|
#: src/components/onboarding/OnboardingScanStep.tsx
|
||||||
#: src/components/onboarding/OnboardingVoiceStep.tsx
|
#: src/components/onboarding/OnboardingVoiceStep.tsx
|
||||||
#: src/lib/onboarding-copy.ts
|
#: src/lib/onboarding-copy.ts
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/computer-screen.tsx
|
||||||
msgid "Skip"
|
msgid "Skip"
|
||||||
msgstr "Omitir"
|
msgstr "Omitir"
|
||||||
|
|
||||||
@ -4373,11 +4379,11 @@ msgstr "Predeterminado del Space"
|
|||||||
msgid "Spaces"
|
msgid "Spaces"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "Speak"
|
msgid "Speak"
|
||||||
msgstr "Hablar"
|
msgstr "Hablar"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "Speak this reply"
|
msgid "Speak this reply"
|
||||||
msgstr "Leer esta respuesta"
|
msgstr "Leer esta respuesta"
|
||||||
|
|
||||||
@ -4431,15 +4437,15 @@ msgstr "Iniciar grabación"
|
|||||||
msgid "Start talking"
|
msgid "Start talking"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "Start the conversation — {activeName} is on stage above."
|
msgid "Start the conversation — {activeName} is on stage above."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "Start the conversation."
|
msgid "Start the conversation."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/composer.tsx
|
||||||
msgid "Start voice conversation"
|
msgid "Start voice conversation"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@ -4466,11 +4472,13 @@ msgid "Steps"
|
|||||||
msgstr "Pasos"
|
msgstr "Pasos"
|
||||||
|
|
||||||
#: src/components/browser/InAppBrowser.tsx
|
#: src/components/browser/InAppBrowser.tsx
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/composer.tsx
|
||||||
|
#: src/pages/shell/fullscreen-computer-overlay.tsx
|
||||||
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "Stop"
|
msgid "Stop"
|
||||||
msgstr "Detener"
|
msgstr "Detener"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "Stop speaking"
|
msgid "Stop speaking"
|
||||||
msgstr "Dejar de hablar"
|
msgstr "Dejar de hablar"
|
||||||
|
|
||||||
@ -4500,7 +4508,7 @@ msgstr ""
|
|||||||
msgid "Stronger together — {0} specialists"
|
msgid "Stronger together — {0} specialists"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "subagent"
|
msgid "subagent"
|
||||||
msgstr "subagente"
|
msgstr "subagente"
|
||||||
|
|
||||||
@ -4565,7 +4573,7 @@ msgstr "Enseñanza en curso: detén la enseñanza antes de enviar un nuevo mensa
|
|||||||
msgid "Team"
|
msgid "Team"
|
||||||
msgstr "Equipo"
|
msgstr "Equipo"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/computer-screen.tsx
|
||||||
msgid "Team Computer"
|
msgid "Team Computer"
|
||||||
msgstr "Team Computer"
|
msgstr "Team Computer"
|
||||||
|
|
||||||
@ -4606,7 +4614,7 @@ msgstr "El proveedor de memoria seleccionado no está disponible en esta build."
|
|||||||
msgid "Thinking"
|
msgid "Thinking"
|
||||||
msgstr "Pensando"
|
msgstr "Pensando"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/computer-screen.tsx
|
||||||
msgid "This bot runs on this computer, not a Linux desktop. Shell and files use your home folder."
|
msgid "This bot runs on this computer, not a Linux desktop. Shell and files use your home folder."
|
||||||
msgstr "Este bot se ejecuta en esta computadora, no en un escritorio Linux. El shell y los archivos usan tu carpeta de inicio."
|
msgstr "Este bot se ejecuta en esta computadora, no en un escritorio Linux. El shell y los archivos usan tu carpeta de inicio."
|
||||||
|
|
||||||
@ -4713,7 +4721,7 @@ msgid "Transcribe"
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/voice/VoiceStage.tsx
|
#: src/components/voice/VoiceStage.tsx
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "Transcript"
|
msgid "Transcript"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@ -4836,7 +4844,7 @@ msgstr "Subir"
|
|||||||
|
|
||||||
#: src/pages/AccountSettingsOverlay.tsx
|
#: src/pages/AccountSettingsOverlay.tsx
|
||||||
#: src/pages/SettingsOverlay.tsx
|
#: src/pages/SettingsOverlay.tsx
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/user-menu.tsx
|
||||||
msgid "Usage"
|
msgid "Usage"
|
||||||
msgstr "Uso"
|
msgstr "Uso"
|
||||||
|
|
||||||
@ -4877,8 +4885,8 @@ msgid "Video workflow"
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/SettingsOverlay.tsx
|
#: src/pages/SettingsOverlay.tsx
|
||||||
#: src/pages/Shell.tsx
|
|
||||||
#: src/pages/shell/bot-panel.tsx
|
#: src/pages/shell/bot-panel.tsx
|
||||||
|
#: src/pages/shell/composer.tsx
|
||||||
#: src/pages/VoiceSettingsOverlay.tsx
|
#: src/pages/VoiceSettingsOverlay.tsx
|
||||||
msgid "Voice"
|
msgid "Voice"
|
||||||
msgstr "Voz"
|
msgstr "Voz"
|
||||||
@ -5074,7 +5082,7 @@ msgstr "Trabajando…"
|
|||||||
msgid "Working…"
|
msgid "Working…"
|
||||||
msgstr "Trabajando…"
|
msgstr "Trabajando…"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/roster-format.ts
|
||||||
msgid "Yesterday"
|
msgid "Yesterday"
|
||||||
msgstr "Ayer"
|
msgstr "Ayer"
|
||||||
|
|
||||||
@ -5092,7 +5100,7 @@ msgstr "Puedes cerrar esta pestaña si no redirige automáticamente."
|
|||||||
msgid "You can close this window."
|
msgid "You can close this window."
|
||||||
msgstr "Puedes cerrar esta ventana."
|
msgstr "Puedes cerrar esta ventana."
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/fullscreen-computer-overlay.tsx
|
||||||
msgid "You have control"
|
msgid "You have control"
|
||||||
msgstr "Tienes el control"
|
msgstr "Tienes el control"
|
||||||
|
|
||||||
|
|||||||
@ -14,7 +14,7 @@ msgstr ""
|
|||||||
"Plural-Forms: \n"
|
"Plural-Forms: \n"
|
||||||
"X-Generator: @lingui/cli\n"
|
"X-Generator: @lingui/cli\n"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/roster-rows.tsx
|
||||||
msgid " (unread)"
|
msgid " (unread)"
|
||||||
msgstr " (अपठित)"
|
msgstr " (अपठित)"
|
||||||
|
|
||||||
@ -126,22 +126,22 @@ msgid "{0}, {label}"
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#. placeholder {0}: item.chat.name
|
#. placeholder {0}: item.chat.name
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/roster-rows.tsx
|
||||||
msgid "{0}, 1:1 conversation"
|
msgid "{0}, 1:1 conversation"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#. placeholder {0}: item.chat.name
|
#. placeholder {0}: item.chat.name
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/roster-rows.tsx
|
||||||
msgid "{0}, group conversation"
|
msgid "{0}, group conversation"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#. placeholder {0}: item.chat.name
|
#. placeholder {0}: item.chat.name
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/roster-rows.tsx
|
||||||
msgid "{0}, main conversation"
|
msgid "{0}, main conversation"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#. placeholder {0}: active.name
|
#. placeholder {0}: active.name
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/computer-panel-preview.tsx
|
||||||
msgid "{0}'s screen"
|
msgid "{0}'s screen"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@ -210,7 +210,7 @@ msgstr ""
|
|||||||
msgid "{botName} watches the tape…"
|
msgid "{botName} watches the tape…"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/computer-screen.tsx
|
||||||
msgid "{botName}’s computer"
|
msgid "{botName}’s computer"
|
||||||
msgstr "{botName} का कंप्यूटर"
|
msgstr "{botName} का कंप्यूटर"
|
||||||
|
|
||||||
@ -277,7 +277,7 @@ msgstr "{title}, {label}"
|
|||||||
msgid "{toolCount, plural, one {# tool} other {# tools}}"
|
msgid "{toolCount, plural, one {# tool} other {# tools}}"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "{workingBotName} is working"
|
msgid "{workingBotName} is working"
|
||||||
msgstr "{workingBotName} काम कर रहा है"
|
msgstr "{workingBotName} काम कर रहा है"
|
||||||
|
|
||||||
@ -339,6 +339,7 @@ msgstr "कार्रवाई की पुष्टि"
|
|||||||
#. placeholder {0}: sectionMenu.section.name
|
#. placeholder {0}: sectionMenu.section.name
|
||||||
#: src/pages/BotContextMenu.tsx
|
#: src/pages/BotContextMenu.tsx
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/Shell.tsx
|
||||||
|
#: src/pages/shell/sidebar-group-header.tsx
|
||||||
msgid "Actions for {0}"
|
msgid "Actions for {0}"
|
||||||
msgstr "{0} के लिए कार्रवाइयां"
|
msgstr "{0} के लिए कार्रवाइयां"
|
||||||
|
|
||||||
@ -354,7 +355,7 @@ msgstr ""
|
|||||||
msgid "Active model"
|
msgid "Active model"
|
||||||
msgstr "सक्रिय मॉडल"
|
msgstr "सक्रिय मॉडल"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/sidebar-header.tsx
|
||||||
msgid "Activity"
|
msgid "Activity"
|
||||||
msgstr "गतिविधि"
|
msgstr "गतिविधि"
|
||||||
|
|
||||||
@ -643,15 +644,15 @@ msgstr "अपने एजेंट को इसके टूल उपयो
|
|||||||
msgid "Archive"
|
msgid "Archive"
|
||||||
msgstr "आर्काइव करें"
|
msgstr "आर्काइव करें"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "archived"
|
msgid "archived"
|
||||||
msgstr "आर्काइव किया गया"
|
msgstr "आर्काइव किया गया"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/archived-section.tsx
|
||||||
msgid "Archived"
|
msgid "Archived"
|
||||||
msgstr "आर्काइव किया गया"
|
msgstr "आर्काइव किया गया"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "Archived. Chat, memory, and files kept."
|
msgid "Archived. Chat, memory, and files kept."
|
||||||
msgstr "आर्काइव किया गया। चैट, मेमोरी और फ़ाइलें सुरक्षित रखी गईं।"
|
msgstr "आर्काइव किया गया। चैट, मेमोरी और फ़ाइलें सुरक्षित रखी गईं।"
|
||||||
|
|
||||||
@ -711,11 +712,11 @@ msgstr "{0} बजे"
|
|||||||
msgid "at {timeSelect}"
|
msgid "at {timeSelect}"
|
||||||
msgstr "{timeSelect} बजे"
|
msgstr "{timeSelect} बजे"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/composer.tsx
|
||||||
msgid "Attach file"
|
msgid "Attach file"
|
||||||
msgstr "फ़ाइल संलग्न करें"
|
msgstr "फ़ाइल संलग्न करें"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/message-preview.ts
|
||||||
msgid "Attachment"
|
msgid "Attachment"
|
||||||
msgstr "अटैचमेंट"
|
msgstr "अटैचमेंट"
|
||||||
|
|
||||||
@ -788,7 +789,7 @@ msgstr "बियरर टोकन"
|
|||||||
msgid "Blocked in your browser settings"
|
msgid "Blocked in your browser settings"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/computer-screen.tsx
|
||||||
msgid "Booting live desktop…"
|
msgid "Booting live desktop…"
|
||||||
msgstr "लाइव डेस्कटॉप शुरू हो रहा है…"
|
msgstr "लाइव डेस्कटॉप शुरू हो रहा है…"
|
||||||
|
|
||||||
@ -797,7 +798,7 @@ msgstr "लाइव डेस्कटॉप शुरू हो रहा ह
|
|||||||
msgid "Booting up {0}’s computer"
|
msgid "Booting up {0}’s computer"
|
||||||
msgstr "{0} का कंप्यूटर शुरू हो रहा है"
|
msgstr "{0} का कंप्यूटर शुरू हो रहा है"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "bot"
|
msgid "bot"
|
||||||
msgstr "बॉट"
|
msgstr "बॉट"
|
||||||
|
|
||||||
@ -812,11 +813,11 @@ msgstr "बॉट"
|
|||||||
msgid "Bot"
|
msgid "Bot"
|
||||||
msgstr "बॉट"
|
msgstr "बॉट"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/fullscreen-computer-overlay.tsx
|
||||||
msgid "Bot screen"
|
msgid "Bot screen"
|
||||||
msgstr "बॉट स्क्रीन"
|
msgstr "बॉट स्क्रीन"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/computer-panel-preview.tsx
|
||||||
msgid "Bot screen preview"
|
msgid "Bot screen preview"
|
||||||
msgstr "बॉट स्क्रीन प्रीव्यू"
|
msgstr "बॉट स्क्रीन प्रीव्यू"
|
||||||
|
|
||||||
@ -828,7 +829,7 @@ msgstr ""
|
|||||||
msgid "Bots act without asking by default. Add an exception only when you want to review a type of action first."
|
msgid "Bots act without asking by default. Add an exception only when you want to review a type of action first."
|
||||||
msgstr "बॉट डिफ़ॉल्ट रूप से बिना पूछे कार्रवाई करते हैं। अपवाद तभी जोड़ें जब आप किसी प्रकार की कार्रवाई की पहले समीक्षा करना चाहते हों।"
|
msgstr "बॉट डिफ़ॉल्ट रूप से बिना पूछे कार्रवाई करते हैं। अपवाद तभी जोड़ें जब आप किसी प्रकार की कार्रवाई की पहले समीक्षा करना चाहते हों।"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "Bots are working"
|
msgid "Bots are working"
|
||||||
msgstr "बॉट काम कर रहे हैं"
|
msgstr "बॉट काम कर रहे हैं"
|
||||||
|
|
||||||
@ -889,7 +890,7 @@ msgstr "नया बॉट रद्द करें"
|
|||||||
msgid "Cancel new group"
|
msgid "Cancel new group"
|
||||||
msgstr "नया समूह रद्द करें"
|
msgstr "नया समूह रद्द करें"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/composer.tsx
|
||||||
msgid "Cancel reply"
|
msgid "Cancel reply"
|
||||||
msgstr "उत्तर रद्द करें"
|
msgstr "उत्तर रद्द करें"
|
||||||
|
|
||||||
@ -946,7 +947,7 @@ msgstr ""
|
|||||||
msgid "Chat history"
|
msgid "Chat history"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/composer.tsx
|
||||||
msgid "Chat Settings"
|
msgid "Chat Settings"
|
||||||
msgstr "चैट सेटिंग्स"
|
msgstr "चैट सेटिंग्स"
|
||||||
|
|
||||||
@ -1088,7 +1089,7 @@ msgstr "बंद करें"
|
|||||||
msgid "Close chart"
|
msgid "Close chart"
|
||||||
msgstr "चार्ट बंद करें"
|
msgstr "चार्ट बंद करें"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/fullscreen-computer-overlay.tsx
|
||||||
msgid "Close computer"
|
msgid "Close computer"
|
||||||
msgstr "कंप्यूटर बंद करें"
|
msgstr "कंप्यूटर बंद करें"
|
||||||
|
|
||||||
@ -1128,7 +1129,7 @@ msgstr "नेविगेशन बंद करें"
|
|||||||
|
|
||||||
#: src/components/ArtifactPane.tsx
|
#: src/components/ArtifactPane.tsx
|
||||||
#: src/components/browser/InAppBrowser.tsx
|
#: src/components/browser/InAppBrowser.tsx
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/side-panel-header.tsx
|
||||||
msgid "Close panel"
|
msgid "Close panel"
|
||||||
msgstr "पैनल बंद करें"
|
msgstr "पैनल बंद करें"
|
||||||
|
|
||||||
@ -1159,7 +1160,7 @@ msgid "Coder"
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#. placeholder {0}: group.title
|
#. placeholder {0}: group.title
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/sidebar-group-header.tsx
|
||||||
msgid "Collapse {0}"
|
msgid "Collapse {0}"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@ -1192,24 +1193,24 @@ msgid "Composing a reply…"
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/SettingsOverlay.tsx
|
#: src/pages/SettingsOverlay.tsx
|
||||||
#: src/pages/Shell.tsx
|
|
||||||
#: src/pages/shell/bot-panel.tsx
|
#: src/pages/shell/bot-panel.tsx
|
||||||
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "Computer"
|
msgid "Computer"
|
||||||
msgstr "कंप्यूटर"
|
msgstr "कंप्यूटर"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/computer-screen.tsx
|
||||||
msgid "Computer failed to boot"
|
msgid "Computer failed to boot"
|
||||||
msgstr "कंप्यूटर शुरू नहीं हो सका"
|
msgstr "कंप्यूटर शुरू नहीं हो सका"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/fullscreen-computer-overlay.tsx
|
||||||
msgid "Computer is asleep"
|
msgid "Computer is asleep"
|
||||||
msgstr "कंप्यूटर निष्क्रिय है"
|
msgstr "कंप्यूटर निष्क्रिय है"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/computer-screen.tsx
|
||||||
msgid "Computer is asleep. Open it to wake."
|
msgid "Computer is asleep. Open it to wake."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/computer-screen.tsx
|
||||||
msgid "Computer is stopped"
|
msgid "Computer is stopped"
|
||||||
msgstr "कंप्यूटर रुका हुआ है"
|
msgstr "कंप्यूटर रुका हुआ है"
|
||||||
|
|
||||||
@ -1353,7 +1354,7 @@ msgstr ""
|
|||||||
msgid "Continue with email"
|
msgid "Continue with email"
|
||||||
msgstr "ईमेल से जारी रखें"
|
msgstr "ईमेल से जारी रखें"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "Conversation record"
|
msgid "Conversation record"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@ -1361,11 +1362,11 @@ msgstr ""
|
|||||||
msgid "Conversations"
|
msgid "Conversations"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "Copy"
|
msgid "Copy"
|
||||||
msgstr "कॉपी करें"
|
msgstr "कॉपी करें"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "Copy reply"
|
msgid "Copy reply"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@ -1747,9 +1748,9 @@ msgstr ""
|
|||||||
msgid "Couldn't update messaging settings"
|
msgid "Couldn't update messaging settings"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
|
||||||
#: src/pages/shell/bot-panel.tsx
|
#: src/pages/shell/bot-panel.tsx
|
||||||
#: src/pages/shell/dialogs.tsx
|
#: src/pages/shell/dialogs.tsx
|
||||||
|
#: src/pages/shell/sidebar-header.tsx
|
||||||
msgid "Create"
|
msgid "Create"
|
||||||
msgstr "बनाएं"
|
msgstr "बनाएं"
|
||||||
|
|
||||||
@ -1906,14 +1907,14 @@ msgstr "डिफ़ॉल्ट स्कोप"
|
|||||||
#: src/pages/KnowledgeSection.tsx
|
#: src/pages/KnowledgeSection.tsx
|
||||||
#: src/pages/McpServersOverlay.tsx
|
#: src/pages/McpServersOverlay.tsx
|
||||||
#: src/pages/RoutineEditor.tsx
|
#: src/pages/RoutineEditor.tsx
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/archived-section.tsx
|
||||||
#: src/pages/shell/dialogs.tsx
|
#: src/pages/shell/dialogs.tsx
|
||||||
msgid "Delete"
|
msgid "Delete"
|
||||||
msgstr "डिलीट करें"
|
msgstr "डिलीट करें"
|
||||||
|
|
||||||
#. placeholder {0}: bot.name
|
#. placeholder {0}: bot.name
|
||||||
#. placeholder {0}: group.name
|
#. placeholder {0}: group.name
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/archived-section.tsx
|
||||||
msgid "Delete {0}"
|
msgid "Delete {0}"
|
||||||
msgstr "{0} डिलीट करें"
|
msgstr "{0} डिलीट करें"
|
||||||
|
|
||||||
@ -1943,7 +1944,7 @@ msgstr ""
|
|||||||
msgid "Delete space"
|
msgid "Delete space"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "deleted"
|
msgid "deleted"
|
||||||
msgstr "डिलीट किया गया"
|
msgstr "डिलीट किया गया"
|
||||||
|
|
||||||
@ -2013,7 +2014,7 @@ msgstr "डिस्कनेक्ट हो रहा है…"
|
|||||||
msgid "Dismiss"
|
msgid "Dismiss"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/composer.tsx
|
||||||
msgid "Dismiss error"
|
msgid "Dismiss error"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@ -2111,7 +2112,7 @@ msgstr "डुप्लिकेट"
|
|||||||
msgid "e.g. Hivenet Agent, Presales, Timesheets bot"
|
msgid "e.g. Hivenet Agent, Presales, Timesheets bot"
|
||||||
msgstr "उदा. Hivenet Agent, Presales, टाइमशीट बॉट"
|
msgstr "उदा. Hivenet Agent, Presales, टाइमशीट बॉट"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "Earlier message"
|
msgid "Earlier message"
|
||||||
msgstr "पुराना संदेश"
|
msgstr "पुराना संदेश"
|
||||||
|
|
||||||
@ -2222,7 +2223,7 @@ msgid "Expand"
|
|||||||
msgstr "विस्तृत करें"
|
msgstr "विस्तृत करें"
|
||||||
|
|
||||||
#. placeholder {0}: group.title
|
#. placeholder {0}: group.title
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/sidebar-group-header.tsx
|
||||||
msgid "Expand {0}"
|
msgid "Expand {0}"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@ -2404,6 +2405,7 @@ msgstr ""
|
|||||||
#: src/components/stage/OoStage.tsx
|
#: src/components/stage/OoStage.tsx
|
||||||
#: src/pages/MessagingSettingsOverlay.tsx
|
#: src/pages/MessagingSettingsOverlay.tsx
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/Shell.tsx
|
||||||
|
#: src/pages/shell/side-panel-header.tsx
|
||||||
msgid "Group"
|
msgid "Group"
|
||||||
msgstr "समूह"
|
msgstr "समूह"
|
||||||
|
|
||||||
@ -2528,7 +2530,7 @@ msgstr ""
|
|||||||
msgid "How to check"
|
msgid "How to check"
|
||||||
msgstr "जांच कैसे करें"
|
msgstr "जांच कैसे करें"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/computer-screen.tsx
|
||||||
msgid "I’m done"
|
msgid "I’m done"
|
||||||
msgstr "मेरा काम हो गया"
|
msgstr "मेरा काम हो गया"
|
||||||
|
|
||||||
@ -2635,11 +2637,11 @@ msgstr "पृथक"
|
|||||||
msgid "Its conversation, files, and routines will be permanently deleted. Bots it created stay in your list."
|
msgid "Its conversation, files, and routines will be permanently deleted. Bots it created stay in your list."
|
||||||
msgstr "इसकी बातचीत, फ़ाइलें और रूटीन स्थायी रूप से डिलीट कर दिए जाएंगे। इसके बनाए बॉट आपकी सूची में बने रहेंगे।"
|
msgstr "इसकी बातचीत, फ़ाइलें और रूटीन स्थायी रूप से डिलीट कर दिए जाएंगे। इसके बनाए बॉट आपकी सूची में बने रहेंगे।"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "Jump to latest"
|
msgid "Jump to latest"
|
||||||
msgstr "नवीनतम संदेश पर जाएँ"
|
msgstr "नवीनतम संदेश पर जाएँ"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "Jump to replied message"
|
msgid "Jump to replied message"
|
||||||
msgstr "जिस संदेश का उत्तर दिया गया उस पर जाएं"
|
msgstr "जिस संदेश का उत्तर दिया गया उस पर जाएं"
|
||||||
|
|
||||||
@ -2726,7 +2728,7 @@ msgstr ""
|
|||||||
msgid "Listening — what's the story?"
|
msgid "Listening — what's the story?"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "Load earlier messages"
|
msgid "Load earlier messages"
|
||||||
msgstr "पुराने संदेश लोड करें"
|
msgstr "पुराने संदेश लोड करें"
|
||||||
|
|
||||||
@ -2779,7 +2781,7 @@ msgstr ""
|
|||||||
#: src/pages/HeuteBrief.tsx
|
#: src/pages/HeuteBrief.tsx
|
||||||
#: src/pages/IntegrationSetup.tsx
|
#: src/pages/IntegrationSetup.tsx
|
||||||
#: src/pages/PeerMessagesOverlay.tsx
|
#: src/pages/PeerMessagesOverlay.tsx
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "Loading…"
|
msgid "Loading…"
|
||||||
msgstr "लोड हो रहा है…"
|
msgstr "लोड हो रहा है…"
|
||||||
|
|
||||||
@ -2799,7 +2801,7 @@ msgstr ""
|
|||||||
msgid "Local Server Settings"
|
msgid "Local Server Settings"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/user-menu.tsx
|
||||||
msgid "Log out"
|
msgid "Log out"
|
||||||
msgstr "लॉग आउट"
|
msgstr "लॉग आउट"
|
||||||
|
|
||||||
@ -2926,7 +2928,7 @@ msgstr "मेमोरी"
|
|||||||
msgid "Memory scope"
|
msgid "Memory scope"
|
||||||
msgstr "मेमोरी स्कोप"
|
msgstr "मेमोरी स्कोप"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/composer.tsx
|
||||||
msgid "Mentions"
|
msgid "Mentions"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@ -2939,11 +2941,12 @@ msgstr ""
|
|||||||
msgid "Message"
|
msgid "Message"
|
||||||
msgstr "संदेश"
|
msgstr "संदेश"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/composer.tsx
|
||||||
|
#: src/pages/shell/message-preview.ts
|
||||||
msgid "Message"
|
msgid "Message"
|
||||||
msgstr "संदेश"
|
msgstr "संदेश"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/composer.tsx
|
||||||
msgid "Message composer"
|
msgid "Message composer"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@ -2951,11 +2954,11 @@ msgstr ""
|
|||||||
msgid "Message event"
|
msgid "Message event"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "Message from {peer}"
|
msgid "Message from {peer}"
|
||||||
msgstr "{peer} का संदेश"
|
msgstr "{peer} का संदेश"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/composer.tsx
|
||||||
msgid "Message…"
|
msgid "Message…"
|
||||||
msgstr "संदेश…"
|
msgstr "संदेश…"
|
||||||
|
|
||||||
@ -2981,7 +2984,7 @@ msgstr "न्यूनतम"
|
|||||||
msgid "Minimize"
|
msgid "Minimize"
|
||||||
msgstr "छोटा करें"
|
msgstr "छोटा करें"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/sidebar-toggle-buttons.tsx
|
||||||
msgid "Minimize bots"
|
msgid "Minimize bots"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@ -3038,7 +3041,7 @@ msgstr "सर्वर से मॉडल"
|
|||||||
msgid "Monthly"
|
msgid "Monthly"
|
||||||
msgstr "मासिक"
|
msgstr "मासिक"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "More"
|
msgid "More"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@ -3104,7 +3107,8 @@ msgstr ""
|
|||||||
#: src/components/MainInbox.tsx
|
#: src/components/MainInbox.tsx
|
||||||
#: src/pages/ActivityList.tsx
|
#: src/pages/ActivityList.tsx
|
||||||
#: src/pages/HeuteBrief.tsx
|
#: src/pages/HeuteBrief.tsx
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/fullscreen-computer-overlay.tsx
|
||||||
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "Needs you"
|
msgid "Needs you"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@ -3397,12 +3401,12 @@ msgid "Only file and folder names are read."
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/ScratchpadSection.tsx
|
#: src/pages/ScratchpadSection.tsx
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/computer-panel-preview.tsx
|
||||||
msgid "Open"
|
msgid "Open"
|
||||||
msgstr "खोलें"
|
msgstr "खोलें"
|
||||||
|
|
||||||
#. placeholder {0}: group.title
|
#. placeholder {0}: group.title
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/sidebar-group-header.tsx
|
||||||
msgid "Open {0}"
|
msgid "Open {0}"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@ -3418,11 +3422,11 @@ msgstr ""
|
|||||||
msgid "Open in browser"
|
msgid "Open in browser"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/computer-panel-preview.tsx
|
||||||
msgid "Open in full window"
|
msgid "Open in full window"
|
||||||
msgstr "पूरी विंडो में खोलें"
|
msgstr "पूरी विंडो में खोलें"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/sidebar-toggle-buttons.tsx
|
||||||
msgid "Open navigation"
|
msgid "Open navigation"
|
||||||
msgstr "नेविगेशन खोलें"
|
msgstr "नेविगेशन खोलें"
|
||||||
|
|
||||||
@ -3438,7 +3442,7 @@ msgstr "खुला कार्य"
|
|||||||
msgid "OpenAI-compatible server URL"
|
msgid "OpenAI-compatible server URL"
|
||||||
msgstr "OpenAI-संगत सर्वर URL"
|
msgstr "OpenAI-संगत सर्वर URL"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "Opened its thread."
|
msgid "Opened its thread."
|
||||||
msgstr "इसका थ्रेड खोला।"
|
msgstr "इसका थ्रेड खोला।"
|
||||||
|
|
||||||
@ -3679,19 +3683,19 @@ msgstr ""
|
|||||||
msgid "Quiet hours start"
|
msgid "Quiet hours start"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "Quote"
|
msgid "Quote"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "React"
|
msgid "React"
|
||||||
msgstr "प्रतिक्रिया दें"
|
msgstr "प्रतिक्रिया दें"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "Reactions"
|
msgid "Reactions"
|
||||||
msgstr "प्रतिक्रियाएँ"
|
msgstr "प्रतिक्रियाएँ"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "Read aloud"
|
msgid "Read aloud"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@ -3796,7 +3800,7 @@ msgstr ""
|
|||||||
msgid "Region"
|
msgid "Region"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/computer-screen.tsx
|
||||||
msgid "Release"
|
msgid "Release"
|
||||||
msgstr "नियंत्रण छोड़ें"
|
msgstr "नियंत्रण छोड़ें"
|
||||||
|
|
||||||
@ -3820,7 +3824,7 @@ msgid "Remove"
|
|||||||
msgstr "हटाएं"
|
msgstr "हटाएं"
|
||||||
|
|
||||||
#. placeholder {0}: attachment.file.name
|
#. placeholder {0}: attachment.file.name
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/composer.tsx
|
||||||
msgid "Remove {0}"
|
msgid "Remove {0}"
|
||||||
msgstr "{0} हटाएं"
|
msgstr "{0} हटाएं"
|
||||||
|
|
||||||
@ -3829,7 +3833,7 @@ msgid "Remove Git event"
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#. placeholder {0}: mention.name
|
#. placeholder {0}: mention.name
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/composer.tsx
|
||||||
msgid "Remove mention {0}"
|
msgid "Remove mention {0}"
|
||||||
msgstr "उल्लेख {0} हटाएं"
|
msgstr "उल्लेख {0} हटाएं"
|
||||||
|
|
||||||
@ -3842,7 +3846,7 @@ msgid "Remove schedule"
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#. placeholder {0}: selectedSkill.name
|
#. placeholder {0}: selectedSkill.name
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/composer.tsx
|
||||||
msgid "Remove skill {0}"
|
msgid "Remove skill {0}"
|
||||||
msgstr "स्किल {0} हटाएं"
|
msgstr "स्किल {0} हटाएं"
|
||||||
|
|
||||||
@ -3850,7 +3854,7 @@ msgstr "स्किल {0} हटाएं"
|
|||||||
msgid "Remove webhook"
|
msgid "Remove webhook"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "Removed with chat, computer, and memory."
|
msgid "Removed with chat, computer, and memory."
|
||||||
msgstr "चैट, कंप्यूटर और मेमोरी सहित हटाया गया।"
|
msgstr "चैट, कंप्यूटर और मेमोरी सहित हटाया गया।"
|
||||||
|
|
||||||
@ -3883,15 +3887,15 @@ msgstr "API कुंजी बदलें"
|
|||||||
msgid "Replace key"
|
msgid "Replace key"
|
||||||
msgstr "कुंजी बदलें"
|
msgstr "कुंजी बदलें"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "Reply"
|
msgid "Reply"
|
||||||
msgstr "उत्तर दें"
|
msgstr "उत्तर दें"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/composer.tsx
|
||||||
msgid "Replying to {replyName}"
|
msgid "Replying to {replyName}"
|
||||||
msgstr "{replyName} को उत्तर दे रहे हैं"
|
msgstr "{replyName} को उत्तर दे रहे हैं"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/composer.tsx
|
||||||
msgid "Replying to {replyName}: “{replyQuote}”"
|
msgid "Replying to {replyName}: “{replyQuote}”"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@ -3937,7 +3941,7 @@ msgstr "रीसेट हो रहा है…"
|
|||||||
msgid "Restart to update"
|
msgid "Restart to update"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/archived-section.tsx
|
||||||
msgid "Restore"
|
msgid "Restore"
|
||||||
msgstr "बहाल करें"
|
msgstr "बहाल करें"
|
||||||
|
|
||||||
@ -4142,7 +4146,7 @@ msgid "Searching…"
|
|||||||
msgstr "खोजा जा रहा है…"
|
msgstr "खोजा जा रहा है…"
|
||||||
|
|
||||||
#. placeholder {0}: group.title
|
#. placeholder {0}: group.title
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/sidebar-group-header.tsx
|
||||||
msgid "Select {0}"
|
msgid "Select {0}"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@ -4150,7 +4154,7 @@ msgstr ""
|
|||||||
msgid "Self-hosted (better-auth)"
|
msgid "Self-hosted (better-auth)"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/composer.tsx
|
||||||
#: src/pages/shell/message-cards.tsx
|
#: src/pages/shell/message-cards.tsx
|
||||||
msgid "Send"
|
msgid "Send"
|
||||||
msgstr "भेजें"
|
msgstr "भेजें"
|
||||||
@ -4201,21 +4205,22 @@ msgid "Server URL"
|
|||||||
msgstr "सर्वर URL"
|
msgstr "सर्वर URL"
|
||||||
|
|
||||||
#: src/components/stage/StageVoiceEntry.tsx
|
#: src/components/stage/StageVoiceEntry.tsx
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/composer.tsx
|
||||||
msgid "Set up voice"
|
msgid "Set up voice"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/MessagingSettingsOverlay.tsx
|
#: src/pages/MessagingSettingsOverlay.tsx
|
||||||
#: src/pages/SettingsOverlay.tsx
|
#: src/pages/SettingsOverlay.tsx
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/side-panel-header.tsx
|
||||||
|
#: src/pages/shell/user-menu.tsx
|
||||||
msgid "Settings"
|
msgid "Settings"
|
||||||
msgstr "सेटिंग्स"
|
msgstr "सेटिंग्स"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/composer.tsx
|
||||||
msgid "Settings: General"
|
msgid "Settings: General"
|
||||||
msgstr "सेटिंग्स: सामान्य"
|
msgstr "सेटिंग्स: सामान्य"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/composer.tsx
|
||||||
msgid "Settings: Usage"
|
msgid "Settings: Usage"
|
||||||
msgstr "सेटिंग्स: उपयोग"
|
msgstr "सेटिंग्स: उपयोग"
|
||||||
|
|
||||||
@ -4259,10 +4264,11 @@ msgid "Show all {0}"
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/Shell.tsx
|
||||||
|
#: src/pages/shell/sidebar-toggle-buttons.tsx
|
||||||
msgid "Show bots"
|
msgid "Show bots"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/side-panel-header.tsx
|
||||||
msgid "Show computer"
|
msgid "Show computer"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@ -4278,7 +4284,7 @@ msgstr "और दिखाएँ"
|
|||||||
msgid "Show password"
|
msgid "Show password"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/side-panel-header.tsx
|
||||||
msgid "Show settings"
|
msgid "Show settings"
|
||||||
msgstr "सेटिंग्स दिखाएं"
|
msgstr "सेटिंग्स दिखाएं"
|
||||||
|
|
||||||
@ -4307,7 +4313,7 @@ msgid "Sketching the blueprint…"
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#. placeholder {0}: skill.name
|
#. placeholder {0}: skill.name
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/composer.tsx
|
||||||
msgid "Skill {0}"
|
msgid "Skill {0}"
|
||||||
msgstr "स्किल {0}"
|
msgstr "स्किल {0}"
|
||||||
|
|
||||||
@ -4319,7 +4325,7 @@ msgstr "स्किल्स"
|
|||||||
#: src/components/onboarding/OnboardingScanStep.tsx
|
#: src/components/onboarding/OnboardingScanStep.tsx
|
||||||
#: src/components/onboarding/OnboardingVoiceStep.tsx
|
#: src/components/onboarding/OnboardingVoiceStep.tsx
|
||||||
#: src/lib/onboarding-copy.ts
|
#: src/lib/onboarding-copy.ts
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/computer-screen.tsx
|
||||||
msgid "Skip"
|
msgid "Skip"
|
||||||
msgstr "छोड़ें"
|
msgstr "छोड़ें"
|
||||||
|
|
||||||
@ -4373,11 +4379,11 @@ msgstr "स्पेस डिफ़ॉल्ट"
|
|||||||
msgid "Spaces"
|
msgid "Spaces"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "Speak"
|
msgid "Speak"
|
||||||
msgstr "बोलें"
|
msgstr "बोलें"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "Speak this reply"
|
msgid "Speak this reply"
|
||||||
msgstr "यह उत्तर बोलकर सुनाएं"
|
msgstr "यह उत्तर बोलकर सुनाएं"
|
||||||
|
|
||||||
@ -4431,15 +4437,15 @@ msgstr "रिकॉर्डिंग शुरू करें"
|
|||||||
msgid "Start talking"
|
msgid "Start talking"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "Start the conversation — {activeName} is on stage above."
|
msgid "Start the conversation — {activeName} is on stage above."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "Start the conversation."
|
msgid "Start the conversation."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/composer.tsx
|
||||||
msgid "Start voice conversation"
|
msgid "Start voice conversation"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@ -4466,11 +4472,13 @@ msgid "Steps"
|
|||||||
msgstr "चरण"
|
msgstr "चरण"
|
||||||
|
|
||||||
#: src/components/browser/InAppBrowser.tsx
|
#: src/components/browser/InAppBrowser.tsx
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/composer.tsx
|
||||||
|
#: src/pages/shell/fullscreen-computer-overlay.tsx
|
||||||
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "Stop"
|
msgid "Stop"
|
||||||
msgstr "रोकें"
|
msgstr "रोकें"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "Stop speaking"
|
msgid "Stop speaking"
|
||||||
msgstr "बोलना रोकें"
|
msgstr "बोलना रोकें"
|
||||||
|
|
||||||
@ -4500,7 +4508,7 @@ msgstr ""
|
|||||||
msgid "Stronger together — {0} specialists"
|
msgid "Stronger together — {0} specialists"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "subagent"
|
msgid "subagent"
|
||||||
msgstr "सबएजेंट"
|
msgstr "सबएजेंट"
|
||||||
|
|
||||||
@ -4565,7 +4573,7 @@ msgstr "सिखाना जारी है। नया संदेश भ
|
|||||||
msgid "Team"
|
msgid "Team"
|
||||||
msgstr "टीम"
|
msgstr "टीम"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/computer-screen.tsx
|
||||||
msgid "Team Computer"
|
msgid "Team Computer"
|
||||||
msgstr "टीम कंप्यूटर"
|
msgstr "टीम कंप्यूटर"
|
||||||
|
|
||||||
@ -4606,7 +4614,7 @@ msgstr "चयनित मेमोरी प्रोवाइडर इस
|
|||||||
msgid "Thinking"
|
msgid "Thinking"
|
||||||
msgstr "सोच रहा है"
|
msgstr "सोच रहा है"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/computer-screen.tsx
|
||||||
msgid "This bot runs on this computer, not a Linux desktop. Shell and files use your home folder."
|
msgid "This bot runs on this computer, not a Linux desktop. Shell and files use your home folder."
|
||||||
msgstr "यह बॉट इसी कंप्यूटर पर चलता है, किसी Linux डेस्कटॉप पर नहीं। शेल और फ़ाइलें आपके होम फ़ोल्डर का उपयोग करती हैं।"
|
msgstr "यह बॉट इसी कंप्यूटर पर चलता है, किसी Linux डेस्कटॉप पर नहीं। शेल और फ़ाइलें आपके होम फ़ोल्डर का उपयोग करती हैं।"
|
||||||
|
|
||||||
@ -4713,7 +4721,7 @@ msgid "Transcribe"
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/voice/VoiceStage.tsx
|
#: src/components/voice/VoiceStage.tsx
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "Transcript"
|
msgid "Transcript"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@ -4836,7 +4844,7 @@ msgstr "अपलोड"
|
|||||||
|
|
||||||
#: src/pages/AccountSettingsOverlay.tsx
|
#: src/pages/AccountSettingsOverlay.tsx
|
||||||
#: src/pages/SettingsOverlay.tsx
|
#: src/pages/SettingsOverlay.tsx
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/user-menu.tsx
|
||||||
msgid "Usage"
|
msgid "Usage"
|
||||||
msgstr "उपयोग"
|
msgstr "उपयोग"
|
||||||
|
|
||||||
@ -4877,8 +4885,8 @@ msgid "Video workflow"
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/SettingsOverlay.tsx
|
#: src/pages/SettingsOverlay.tsx
|
||||||
#: src/pages/Shell.tsx
|
|
||||||
#: src/pages/shell/bot-panel.tsx
|
#: src/pages/shell/bot-panel.tsx
|
||||||
|
#: src/pages/shell/composer.tsx
|
||||||
#: src/pages/VoiceSettingsOverlay.tsx
|
#: src/pages/VoiceSettingsOverlay.tsx
|
||||||
msgid "Voice"
|
msgid "Voice"
|
||||||
msgstr "आवाज़"
|
msgstr "आवाज़"
|
||||||
@ -5074,7 +5082,7 @@ msgstr "काम चल रहा है…"
|
|||||||
msgid "Working…"
|
msgid "Working…"
|
||||||
msgstr "काम चल रहा है…"
|
msgstr "काम चल रहा है…"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/roster-format.ts
|
||||||
msgid "Yesterday"
|
msgid "Yesterday"
|
||||||
msgstr "कल"
|
msgstr "कल"
|
||||||
|
|
||||||
@ -5092,7 +5100,7 @@ msgstr "अगर यह अपने आप रीडायरेक्ट न
|
|||||||
msgid "You can close this window."
|
msgid "You can close this window."
|
||||||
msgstr "आप यह विंडो बंद कर सकते हैं।"
|
msgstr "आप यह विंडो बंद कर सकते हैं।"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/fullscreen-computer-overlay.tsx
|
||||||
msgid "You have control"
|
msgid "You have control"
|
||||||
msgstr "नियंत्रण आपके पास है"
|
msgstr "नियंत्रण आपके पास है"
|
||||||
|
|
||||||
|
|||||||
@ -14,7 +14,7 @@ msgstr ""
|
|||||||
"Plural-Forms: \n"
|
"Plural-Forms: \n"
|
||||||
"X-Generator: @lingui/cli\n"
|
"X-Generator: @lingui/cli\n"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/roster-rows.tsx
|
||||||
msgid " (unread)"
|
msgid " (unread)"
|
||||||
msgstr " (읽지 않음)"
|
msgstr " (읽지 않음)"
|
||||||
|
|
||||||
@ -126,22 +126,22 @@ msgid "{0}, {label}"
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#. placeholder {0}: item.chat.name
|
#. placeholder {0}: item.chat.name
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/roster-rows.tsx
|
||||||
msgid "{0}, 1:1 conversation"
|
msgid "{0}, 1:1 conversation"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#. placeholder {0}: item.chat.name
|
#. placeholder {0}: item.chat.name
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/roster-rows.tsx
|
||||||
msgid "{0}, group conversation"
|
msgid "{0}, group conversation"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#. placeholder {0}: item.chat.name
|
#. placeholder {0}: item.chat.name
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/roster-rows.tsx
|
||||||
msgid "{0}, main conversation"
|
msgid "{0}, main conversation"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#. placeholder {0}: active.name
|
#. placeholder {0}: active.name
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/computer-panel-preview.tsx
|
||||||
msgid "{0}'s screen"
|
msgid "{0}'s screen"
|
||||||
msgstr "{0}의 화면"
|
msgstr "{0}의 화면"
|
||||||
|
|
||||||
@ -210,7 +210,7 @@ msgstr ""
|
|||||||
msgid "{botName} watches the tape…"
|
msgid "{botName} watches the tape…"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/computer-screen.tsx
|
||||||
msgid "{botName}’s computer"
|
msgid "{botName}’s computer"
|
||||||
msgstr "{botName}의 컴퓨터"
|
msgstr "{botName}의 컴퓨터"
|
||||||
|
|
||||||
@ -277,7 +277,7 @@ msgstr "{title}, {label}"
|
|||||||
msgid "{toolCount, plural, one {# tool} other {# tools}}"
|
msgid "{toolCount, plural, one {# tool} other {# tools}}"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "{workingBotName} is working"
|
msgid "{workingBotName} is working"
|
||||||
msgstr "{workingBotName} 작업 중"
|
msgstr "{workingBotName} 작업 중"
|
||||||
|
|
||||||
@ -339,6 +339,7 @@ msgstr "작업 실행 전 확인"
|
|||||||
#. placeholder {0}: sectionMenu.section.name
|
#. placeholder {0}: sectionMenu.section.name
|
||||||
#: src/pages/BotContextMenu.tsx
|
#: src/pages/BotContextMenu.tsx
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/Shell.tsx
|
||||||
|
#: src/pages/shell/sidebar-group-header.tsx
|
||||||
msgid "Actions for {0}"
|
msgid "Actions for {0}"
|
||||||
msgstr "{0} 작업 메뉴"
|
msgstr "{0} 작업 메뉴"
|
||||||
|
|
||||||
@ -354,7 +355,7 @@ msgstr "활성"
|
|||||||
msgid "Active model"
|
msgid "Active model"
|
||||||
msgstr "현재 모델"
|
msgstr "현재 모델"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/sidebar-header.tsx
|
||||||
msgid "Activity"
|
msgid "Activity"
|
||||||
msgstr "활동"
|
msgstr "활동"
|
||||||
|
|
||||||
@ -643,15 +644,15 @@ msgstr "이 서버를 승인하면 Bot이 제공되는 도구를 사용할 수
|
|||||||
msgid "Archive"
|
msgid "Archive"
|
||||||
msgstr "보관"
|
msgstr "보관"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "archived"
|
msgid "archived"
|
||||||
msgstr "보관됨"
|
msgstr "보관됨"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/archived-section.tsx
|
||||||
msgid "Archived"
|
msgid "Archived"
|
||||||
msgstr "보관됨"
|
msgstr "보관됨"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "Archived. Chat, memory, and files kept."
|
msgid "Archived. Chat, memory, and files kept."
|
||||||
msgstr "보관되었습니다. 대화, 기억, 파일은 유지됩니다."
|
msgstr "보관되었습니다. 대화, 기억, 파일은 유지됩니다."
|
||||||
|
|
||||||
@ -711,11 +712,11 @@ msgstr "{0}에"
|
|||||||
msgid "at {timeSelect}"
|
msgid "at {timeSelect}"
|
||||||
msgstr "{timeSelect}에"
|
msgstr "{timeSelect}에"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/composer.tsx
|
||||||
msgid "Attach file"
|
msgid "Attach file"
|
||||||
msgstr "파일 첨부"
|
msgstr "파일 첨부"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/message-preview.ts
|
||||||
msgid "Attachment"
|
msgid "Attachment"
|
||||||
msgstr "첨부 파일"
|
msgstr "첨부 파일"
|
||||||
|
|
||||||
@ -788,7 +789,7 @@ msgstr "Bearer 토큰"
|
|||||||
msgid "Blocked in your browser settings"
|
msgid "Blocked in your browser settings"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/computer-screen.tsx
|
||||||
msgid "Booting live desktop…"
|
msgid "Booting live desktop…"
|
||||||
msgstr "라이브 데스크톱 시작 중…"
|
msgstr "라이브 데스크톱 시작 중…"
|
||||||
|
|
||||||
@ -797,7 +798,7 @@ msgstr "라이브 데스크톱 시작 중…"
|
|||||||
msgid "Booting up {0}’s computer"
|
msgid "Booting up {0}’s computer"
|
||||||
msgstr "{0}의 컴퓨터를 켜는 중"
|
msgstr "{0}의 컴퓨터를 켜는 중"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "bot"
|
msgid "bot"
|
||||||
msgstr "Bot"
|
msgstr "Bot"
|
||||||
|
|
||||||
@ -812,11 +813,11 @@ msgstr "Bot"
|
|||||||
msgid "Bot"
|
msgid "Bot"
|
||||||
msgstr "봇"
|
msgstr "봇"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/fullscreen-computer-overlay.tsx
|
||||||
msgid "Bot screen"
|
msgid "Bot screen"
|
||||||
msgstr "Bot 화면"
|
msgstr "Bot 화면"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/computer-panel-preview.tsx
|
||||||
msgid "Bot screen preview"
|
msgid "Bot screen preview"
|
||||||
msgstr "Bot 화면 미리보기"
|
msgstr "Bot 화면 미리보기"
|
||||||
|
|
||||||
@ -828,7 +829,7 @@ msgstr "연결할 Bot"
|
|||||||
msgid "Bots act without asking by default. Add an exception only when you want to review a type of action first."
|
msgid "Bots act without asking by default. Add an exception only when you want to review a type of action first."
|
||||||
msgstr "Bot은 기본적으로 묻지 않고 작업합니다. 먼저 확인하고 싶은 작업만 예외로 추가하세요."
|
msgstr "Bot은 기본적으로 묻지 않고 작업합니다. 먼저 확인하고 싶은 작업만 예외로 추가하세요."
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "Bots are working"
|
msgid "Bots are working"
|
||||||
msgstr "봇 작업 중"
|
msgstr "봇 작업 중"
|
||||||
|
|
||||||
@ -889,7 +890,7 @@ msgstr "새 Bot 만들기 취소"
|
|||||||
msgid "Cancel new group"
|
msgid "Cancel new group"
|
||||||
msgstr "새 그룹 만들기 취소"
|
msgstr "새 그룹 만들기 취소"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/composer.tsx
|
||||||
msgid "Cancel reply"
|
msgid "Cancel reply"
|
||||||
msgstr "답장 취소"
|
msgstr "답장 취소"
|
||||||
|
|
||||||
@ -946,7 +947,7 @@ msgstr "채팅 앱, 그룹 채널 및 Agent 연결을 관리합니다."
|
|||||||
msgid "Chat history"
|
msgid "Chat history"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/composer.tsx
|
||||||
msgid "Chat Settings"
|
msgid "Chat Settings"
|
||||||
msgstr "채팅 설정"
|
msgstr "채팅 설정"
|
||||||
|
|
||||||
@ -1088,7 +1089,7 @@ msgstr "닫기"
|
|||||||
msgid "Close chart"
|
msgid "Close chart"
|
||||||
msgstr "차트 닫기"
|
msgstr "차트 닫기"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/fullscreen-computer-overlay.tsx
|
||||||
msgid "Close computer"
|
msgid "Close computer"
|
||||||
msgstr "컴퓨터 닫기"
|
msgstr "컴퓨터 닫기"
|
||||||
|
|
||||||
@ -1128,7 +1129,7 @@ msgstr "메뉴 닫기"
|
|||||||
|
|
||||||
#: src/components/ArtifactPane.tsx
|
#: src/components/ArtifactPane.tsx
|
||||||
#: src/components/browser/InAppBrowser.tsx
|
#: src/components/browser/InAppBrowser.tsx
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/side-panel-header.tsx
|
||||||
msgid "Close panel"
|
msgid "Close panel"
|
||||||
msgstr "패널 닫기"
|
msgstr "패널 닫기"
|
||||||
|
|
||||||
@ -1159,7 +1160,7 @@ msgid "Coder"
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#. placeholder {0}: group.title
|
#. placeholder {0}: group.title
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/sidebar-group-header.tsx
|
||||||
msgid "Collapse {0}"
|
msgid "Collapse {0}"
|
||||||
msgstr "{0} 접기"
|
msgstr "{0} 접기"
|
||||||
|
|
||||||
@ -1192,24 +1193,24 @@ msgid "Composing a reply…"
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/SettingsOverlay.tsx
|
#: src/pages/SettingsOverlay.tsx
|
||||||
#: src/pages/Shell.tsx
|
|
||||||
#: src/pages/shell/bot-panel.tsx
|
#: src/pages/shell/bot-panel.tsx
|
||||||
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "Computer"
|
msgid "Computer"
|
||||||
msgstr "컴퓨터"
|
msgstr "컴퓨터"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/computer-screen.tsx
|
||||||
msgid "Computer failed to boot"
|
msgid "Computer failed to boot"
|
||||||
msgstr "컴퓨터를 시작하지 못했습니다"
|
msgstr "컴퓨터를 시작하지 못했습니다"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/fullscreen-computer-overlay.tsx
|
||||||
msgid "Computer is asleep"
|
msgid "Computer is asleep"
|
||||||
msgstr "컴퓨터가 절전 상태입니다"
|
msgstr "컴퓨터가 절전 상태입니다"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/computer-screen.tsx
|
||||||
msgid "Computer is asleep. Open it to wake."
|
msgid "Computer is asleep. Open it to wake."
|
||||||
msgstr "컴퓨터가 절전 상태입니다. 열어 깨우세요."
|
msgstr "컴퓨터가 절전 상태입니다. 열어 깨우세요."
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/computer-screen.tsx
|
||||||
msgid "Computer is stopped"
|
msgid "Computer is stopped"
|
||||||
msgstr "컴퓨터가 중지됨"
|
msgstr "컴퓨터가 중지됨"
|
||||||
|
|
||||||
@ -1353,7 +1354,7 @@ msgstr ""
|
|||||||
msgid "Continue with email"
|
msgid "Continue with email"
|
||||||
msgstr "이메일로 계속하기"
|
msgstr "이메일로 계속하기"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "Conversation record"
|
msgid "Conversation record"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@ -1361,11 +1362,11 @@ msgstr ""
|
|||||||
msgid "Conversations"
|
msgid "Conversations"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "Copy"
|
msgid "Copy"
|
||||||
msgstr "복사"
|
msgstr "복사"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "Copy reply"
|
msgid "Copy reply"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@ -1747,9 +1748,9 @@ msgstr "아바타를 업데이트할 수 없습니다"
|
|||||||
msgid "Couldn't update messaging settings"
|
msgid "Couldn't update messaging settings"
|
||||||
msgstr "메시징 설정을 업데이트할 수 없습니다"
|
msgstr "메시징 설정을 업데이트할 수 없습니다"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
|
||||||
#: src/pages/shell/bot-panel.tsx
|
#: src/pages/shell/bot-panel.tsx
|
||||||
#: src/pages/shell/dialogs.tsx
|
#: src/pages/shell/dialogs.tsx
|
||||||
|
#: src/pages/shell/sidebar-header.tsx
|
||||||
msgid "Create"
|
msgid "Create"
|
||||||
msgstr "만들기"
|
msgstr "만들기"
|
||||||
|
|
||||||
@ -1906,14 +1907,14 @@ msgstr "기본 기억 범위"
|
|||||||
#: src/pages/KnowledgeSection.tsx
|
#: src/pages/KnowledgeSection.tsx
|
||||||
#: src/pages/McpServersOverlay.tsx
|
#: src/pages/McpServersOverlay.tsx
|
||||||
#: src/pages/RoutineEditor.tsx
|
#: src/pages/RoutineEditor.tsx
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/archived-section.tsx
|
||||||
#: src/pages/shell/dialogs.tsx
|
#: src/pages/shell/dialogs.tsx
|
||||||
msgid "Delete"
|
msgid "Delete"
|
||||||
msgstr "삭제"
|
msgstr "삭제"
|
||||||
|
|
||||||
#. placeholder {0}: bot.name
|
#. placeholder {0}: bot.name
|
||||||
#. placeholder {0}: group.name
|
#. placeholder {0}: group.name
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/archived-section.tsx
|
||||||
msgid "Delete {0}"
|
msgid "Delete {0}"
|
||||||
msgstr "{0} 삭제"
|
msgstr "{0} 삭제"
|
||||||
|
|
||||||
@ -1943,7 +1944,7 @@ msgstr ""
|
|||||||
msgid "Delete space"
|
msgid "Delete space"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "deleted"
|
msgid "deleted"
|
||||||
msgstr "삭제됨"
|
msgstr "삭제됨"
|
||||||
|
|
||||||
@ -2013,7 +2014,7 @@ msgstr "연결 해제 중…"
|
|||||||
msgid "Dismiss"
|
msgid "Dismiss"
|
||||||
msgstr "닫기"
|
msgstr "닫기"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/composer.tsx
|
||||||
msgid "Dismiss error"
|
msgid "Dismiss error"
|
||||||
msgstr "오류 닫기"
|
msgstr "오류 닫기"
|
||||||
|
|
||||||
@ -2111,7 +2112,7 @@ msgstr "복제"
|
|||||||
msgid "e.g. Hivenet Agent, Presales, Timesheets bot"
|
msgid "e.g. Hivenet Agent, Presales, Timesheets bot"
|
||||||
msgstr "예: Hivenet Agent, Presales, 근무표 봇"
|
msgstr "예: Hivenet Agent, Presales, 근무표 봇"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "Earlier message"
|
msgid "Earlier message"
|
||||||
msgstr "이전 메시지"
|
msgstr "이전 메시지"
|
||||||
|
|
||||||
@ -2222,7 +2223,7 @@ msgid "Expand"
|
|||||||
msgstr "펼치기"
|
msgstr "펼치기"
|
||||||
|
|
||||||
#. placeholder {0}: group.title
|
#. placeholder {0}: group.title
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/sidebar-group-header.tsx
|
||||||
msgid "Expand {0}"
|
msgid "Expand {0}"
|
||||||
msgstr "{0} 펼치기"
|
msgstr "{0} 펼치기"
|
||||||
|
|
||||||
@ -2404,6 +2405,7 @@ msgstr ""
|
|||||||
#: src/components/stage/OoStage.tsx
|
#: src/components/stage/OoStage.tsx
|
||||||
#: src/pages/MessagingSettingsOverlay.tsx
|
#: src/pages/MessagingSettingsOverlay.tsx
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/Shell.tsx
|
||||||
|
#: src/pages/shell/side-panel-header.tsx
|
||||||
msgid "Group"
|
msgid "Group"
|
||||||
msgstr "그룹"
|
msgstr "그룹"
|
||||||
|
|
||||||
@ -2528,7 +2530,7 @@ msgstr ""
|
|||||||
msgid "How to check"
|
msgid "How to check"
|
||||||
msgstr "완료 확인 방법"
|
msgstr "완료 확인 방법"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/computer-screen.tsx
|
||||||
msgid "I’m done"
|
msgid "I’m done"
|
||||||
msgstr "조작 끝내기"
|
msgstr "조작 끝내기"
|
||||||
|
|
||||||
@ -2635,11 +2637,11 @@ msgstr "이 Bot만 사용"
|
|||||||
msgid "Its conversation, files, and routines will be permanently deleted. Bots it created stay in your list."
|
msgid "Its conversation, files, and routines will be permanently deleted. Bots it created stay in your list."
|
||||||
msgstr "대화, 파일, 자동 실행이 영구 삭제됩니다. 이 Bot이 만든 다른 Bot은 목록에 남습니다."
|
msgstr "대화, 파일, 자동 실행이 영구 삭제됩니다. 이 Bot이 만든 다른 Bot은 목록에 남습니다."
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "Jump to latest"
|
msgid "Jump to latest"
|
||||||
msgstr "최신 메시지로 이동"
|
msgstr "최신 메시지로 이동"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "Jump to replied message"
|
msgid "Jump to replied message"
|
||||||
msgstr "답장한 메시지로 이동"
|
msgstr "답장한 메시지로 이동"
|
||||||
|
|
||||||
@ -2726,7 +2728,7 @@ msgstr ""
|
|||||||
msgid "Listening — what's the story?"
|
msgid "Listening — what's the story?"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "Load earlier messages"
|
msgid "Load earlier messages"
|
||||||
msgstr "이전 메시지 불러오기"
|
msgstr "이전 메시지 불러오기"
|
||||||
|
|
||||||
@ -2779,7 +2781,7 @@ msgstr ""
|
|||||||
#: src/pages/HeuteBrief.tsx
|
#: src/pages/HeuteBrief.tsx
|
||||||
#: src/pages/IntegrationSetup.tsx
|
#: src/pages/IntegrationSetup.tsx
|
||||||
#: src/pages/PeerMessagesOverlay.tsx
|
#: src/pages/PeerMessagesOverlay.tsx
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "Loading…"
|
msgid "Loading…"
|
||||||
msgstr "불러오는 중…"
|
msgstr "불러오는 중…"
|
||||||
|
|
||||||
@ -2799,7 +2801,7 @@ msgstr ""
|
|||||||
msgid "Local Server Settings"
|
msgid "Local Server Settings"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/user-menu.tsx
|
||||||
msgid "Log out"
|
msgid "Log out"
|
||||||
msgstr "로그아웃"
|
msgstr "로그아웃"
|
||||||
|
|
||||||
@ -2926,7 +2928,7 @@ msgstr "기억"
|
|||||||
msgid "Memory scope"
|
msgid "Memory scope"
|
||||||
msgstr "기억 사용 범위"
|
msgstr "기억 사용 범위"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/composer.tsx
|
||||||
msgid "Mentions"
|
msgid "Mentions"
|
||||||
msgstr "멘션"
|
msgstr "멘션"
|
||||||
|
|
||||||
@ -2939,11 +2941,12 @@ msgstr ""
|
|||||||
msgid "Message"
|
msgid "Message"
|
||||||
msgstr "메시지"
|
msgstr "메시지"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/composer.tsx
|
||||||
|
#: src/pages/shell/message-preview.ts
|
||||||
msgid "Message"
|
msgid "Message"
|
||||||
msgstr "메시지"
|
msgstr "메시지"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/composer.tsx
|
||||||
msgid "Message composer"
|
msgid "Message composer"
|
||||||
msgstr "메시지 작성기"
|
msgstr "메시지 작성기"
|
||||||
|
|
||||||
@ -2951,11 +2954,11 @@ msgstr "메시지 작성기"
|
|||||||
msgid "Message event"
|
msgid "Message event"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "Message from {peer}"
|
msgid "Message from {peer}"
|
||||||
msgstr "{peer}의 메시지"
|
msgstr "{peer}의 메시지"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/composer.tsx
|
||||||
msgid "Message…"
|
msgid "Message…"
|
||||||
msgstr "메시지를 입력하세요"
|
msgstr "메시지를 입력하세요"
|
||||||
|
|
||||||
@ -2981,7 +2984,7 @@ msgstr "최소"
|
|||||||
msgid "Minimize"
|
msgid "Minimize"
|
||||||
msgstr "최소화"
|
msgstr "최소화"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/sidebar-toggle-buttons.tsx
|
||||||
msgid "Minimize bots"
|
msgid "Minimize bots"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@ -3038,7 +3041,7 @@ msgstr "서버에서 찾은 모델"
|
|||||||
msgid "Monthly"
|
msgid "Monthly"
|
||||||
msgstr "매월"
|
msgstr "매월"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "More"
|
msgid "More"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@ -3104,7 +3107,8 @@ msgstr ""
|
|||||||
#: src/components/MainInbox.tsx
|
#: src/components/MainInbox.tsx
|
||||||
#: src/pages/ActivityList.tsx
|
#: src/pages/ActivityList.tsx
|
||||||
#: src/pages/HeuteBrief.tsx
|
#: src/pages/HeuteBrief.tsx
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/fullscreen-computer-overlay.tsx
|
||||||
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "Needs you"
|
msgid "Needs you"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@ -3397,12 +3401,12 @@ msgid "Only file and folder names are read."
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/ScratchpadSection.tsx
|
#: src/pages/ScratchpadSection.tsx
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/computer-panel-preview.tsx
|
||||||
msgid "Open"
|
msgid "Open"
|
||||||
msgstr "열기"
|
msgstr "열기"
|
||||||
|
|
||||||
#. placeholder {0}: group.title
|
#. placeholder {0}: group.title
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/sidebar-group-header.tsx
|
||||||
msgid "Open {0}"
|
msgid "Open {0}"
|
||||||
msgstr "{0} 열기"
|
msgstr "{0} 열기"
|
||||||
|
|
||||||
@ -3418,11 +3422,11 @@ msgstr ""
|
|||||||
msgid "Open in browser"
|
msgid "Open in browser"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/computer-panel-preview.tsx
|
||||||
msgid "Open in full window"
|
msgid "Open in full window"
|
||||||
msgstr "전체 창으로 열기"
|
msgstr "전체 창으로 열기"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/sidebar-toggle-buttons.tsx
|
||||||
msgid "Open navigation"
|
msgid "Open navigation"
|
||||||
msgstr "메뉴 열기"
|
msgstr "메뉴 열기"
|
||||||
|
|
||||||
@ -3438,7 +3442,7 @@ msgstr "진행 중인 작업"
|
|||||||
msgid "OpenAI-compatible server URL"
|
msgid "OpenAI-compatible server URL"
|
||||||
msgstr "OpenAI 호환 서버 주소"
|
msgstr "OpenAI 호환 서버 주소"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "Opened its thread."
|
msgid "Opened its thread."
|
||||||
msgstr "대화가 만들어졌습니다."
|
msgstr "대화가 만들어졌습니다."
|
||||||
|
|
||||||
@ -3679,19 +3683,19 @@ msgstr ""
|
|||||||
msgid "Quiet hours start"
|
msgid "Quiet hours start"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "Quote"
|
msgid "Quote"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "React"
|
msgid "React"
|
||||||
msgstr "반응하기"
|
msgstr "반응하기"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "Reactions"
|
msgid "Reactions"
|
||||||
msgstr "반응"
|
msgstr "반응"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "Read aloud"
|
msgid "Read aloud"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@ -3796,7 +3800,7 @@ msgstr "새로고침 중…"
|
|||||||
msgid "Region"
|
msgid "Region"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/computer-screen.tsx
|
||||||
msgid "Release"
|
msgid "Release"
|
||||||
msgstr "제어권 돌려주기"
|
msgstr "제어권 돌려주기"
|
||||||
|
|
||||||
@ -3820,7 +3824,7 @@ msgid "Remove"
|
|||||||
msgstr "삭제"
|
msgstr "삭제"
|
||||||
|
|
||||||
#. placeholder {0}: attachment.file.name
|
#. placeholder {0}: attachment.file.name
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/composer.tsx
|
||||||
msgid "Remove {0}"
|
msgid "Remove {0}"
|
||||||
msgstr "{0} 삭제"
|
msgstr "{0} 삭제"
|
||||||
|
|
||||||
@ -3829,7 +3833,7 @@ msgid "Remove Git event"
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#. placeholder {0}: mention.name
|
#. placeholder {0}: mention.name
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/composer.tsx
|
||||||
msgid "Remove mention {0}"
|
msgid "Remove mention {0}"
|
||||||
msgstr "{0} 멘션 삭제"
|
msgstr "{0} 멘션 삭제"
|
||||||
|
|
||||||
@ -3842,7 +3846,7 @@ msgid "Remove schedule"
|
|||||||
msgstr "일정 제거"
|
msgstr "일정 제거"
|
||||||
|
|
||||||
#. placeholder {0}: selectedSkill.name
|
#. placeholder {0}: selectedSkill.name
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/composer.tsx
|
||||||
msgid "Remove skill {0}"
|
msgid "Remove skill {0}"
|
||||||
msgstr "작업 기술 {0} 삭제"
|
msgstr "작업 기술 {0} 삭제"
|
||||||
|
|
||||||
@ -3850,7 +3854,7 @@ msgstr "작업 기술 {0} 삭제"
|
|||||||
msgid "Remove webhook"
|
msgid "Remove webhook"
|
||||||
msgstr "웹훅 제거"
|
msgstr "웹훅 제거"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "Removed with chat, computer, and memory."
|
msgid "Removed with chat, computer, and memory."
|
||||||
msgstr "대화, 컴퓨터, 기억과 함께 삭제되었습니다."
|
msgstr "대화, 컴퓨터, 기억과 함께 삭제되었습니다."
|
||||||
|
|
||||||
@ -3883,15 +3887,15 @@ msgstr "API 키 교체"
|
|||||||
msgid "Replace key"
|
msgid "Replace key"
|
||||||
msgstr "키 교체"
|
msgstr "키 교체"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "Reply"
|
msgid "Reply"
|
||||||
msgstr "답장"
|
msgstr "답장"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/composer.tsx
|
||||||
msgid "Replying to {replyName}"
|
msgid "Replying to {replyName}"
|
||||||
msgstr "{replyName}에게 답장"
|
msgstr "{replyName}에게 답장"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/composer.tsx
|
||||||
msgid "Replying to {replyName}: “{replyQuote}”"
|
msgid "Replying to {replyName}: “{replyQuote}”"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@ -3937,7 +3941,7 @@ msgstr "재설정 중…"
|
|||||||
msgid "Restart to update"
|
msgid "Restart to update"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/archived-section.tsx
|
||||||
msgid "Restore"
|
msgid "Restore"
|
||||||
msgstr "복원"
|
msgstr "복원"
|
||||||
|
|
||||||
@ -4142,7 +4146,7 @@ msgid "Searching…"
|
|||||||
msgstr "검색 중…"
|
msgstr "검색 중…"
|
||||||
|
|
||||||
#. placeholder {0}: group.title
|
#. placeholder {0}: group.title
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/sidebar-group-header.tsx
|
||||||
msgid "Select {0}"
|
msgid "Select {0}"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@ -4150,7 +4154,7 @@ msgstr ""
|
|||||||
msgid "Self-hosted (better-auth)"
|
msgid "Self-hosted (better-auth)"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/composer.tsx
|
||||||
#: src/pages/shell/message-cards.tsx
|
#: src/pages/shell/message-cards.tsx
|
||||||
msgid "Send"
|
msgid "Send"
|
||||||
msgstr "보내기"
|
msgstr "보내기"
|
||||||
@ -4201,21 +4205,22 @@ msgid "Server URL"
|
|||||||
msgstr "서버 URL"
|
msgstr "서버 URL"
|
||||||
|
|
||||||
#: src/components/stage/StageVoiceEntry.tsx
|
#: src/components/stage/StageVoiceEntry.tsx
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/composer.tsx
|
||||||
msgid "Set up voice"
|
msgid "Set up voice"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/MessagingSettingsOverlay.tsx
|
#: src/pages/MessagingSettingsOverlay.tsx
|
||||||
#: src/pages/SettingsOverlay.tsx
|
#: src/pages/SettingsOverlay.tsx
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/side-panel-header.tsx
|
||||||
|
#: src/pages/shell/user-menu.tsx
|
||||||
msgid "Settings"
|
msgid "Settings"
|
||||||
msgstr "설정"
|
msgstr "설정"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/composer.tsx
|
||||||
msgid "Settings: General"
|
msgid "Settings: General"
|
||||||
msgstr "설정: 일반"
|
msgstr "설정: 일반"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/composer.tsx
|
||||||
msgid "Settings: Usage"
|
msgid "Settings: Usage"
|
||||||
msgstr "설정: 사용량"
|
msgstr "설정: 사용량"
|
||||||
|
|
||||||
@ -4259,10 +4264,11 @@ msgid "Show all {0}"
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/Shell.tsx
|
||||||
|
#: src/pages/shell/sidebar-toggle-buttons.tsx
|
||||||
msgid "Show bots"
|
msgid "Show bots"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/side-panel-header.tsx
|
||||||
msgid "Show computer"
|
msgid "Show computer"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@ -4278,7 +4284,7 @@ msgstr "더 보기"
|
|||||||
msgid "Show password"
|
msgid "Show password"
|
||||||
msgstr "비밀번호 표시"
|
msgstr "비밀번호 표시"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/side-panel-header.tsx
|
||||||
msgid "Show settings"
|
msgid "Show settings"
|
||||||
msgstr "설정 보기"
|
msgstr "설정 보기"
|
||||||
|
|
||||||
@ -4307,7 +4313,7 @@ msgid "Sketching the blueprint…"
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#. placeholder {0}: skill.name
|
#. placeholder {0}: skill.name
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/composer.tsx
|
||||||
msgid "Skill {0}"
|
msgid "Skill {0}"
|
||||||
msgstr "작업 기술 {0}"
|
msgstr "작업 기술 {0}"
|
||||||
|
|
||||||
@ -4319,7 +4325,7 @@ msgstr "스킬"
|
|||||||
#: src/components/onboarding/OnboardingScanStep.tsx
|
#: src/components/onboarding/OnboardingScanStep.tsx
|
||||||
#: src/components/onboarding/OnboardingVoiceStep.tsx
|
#: src/components/onboarding/OnboardingVoiceStep.tsx
|
||||||
#: src/lib/onboarding-copy.ts
|
#: src/lib/onboarding-copy.ts
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/computer-screen.tsx
|
||||||
msgid "Skip"
|
msgid "Skip"
|
||||||
msgstr "건너뛰기"
|
msgstr "건너뛰기"
|
||||||
|
|
||||||
@ -4373,11 +4379,11 @@ msgstr "스페이스 기본값"
|
|||||||
msgid "Spaces"
|
msgid "Spaces"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "Speak"
|
msgid "Speak"
|
||||||
msgstr "읽기"
|
msgstr "읽기"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "Speak this reply"
|
msgid "Speak this reply"
|
||||||
msgstr "이 답변 읽기"
|
msgstr "이 답변 읽기"
|
||||||
|
|
||||||
@ -4431,15 +4437,15 @@ msgstr "작업 녹화 시작"
|
|||||||
msgid "Start talking"
|
msgid "Start talking"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "Start the conversation — {activeName} is on stage above."
|
msgid "Start the conversation — {activeName} is on stage above."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "Start the conversation."
|
msgid "Start the conversation."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/composer.tsx
|
||||||
msgid "Start voice conversation"
|
msgid "Start voice conversation"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@ -4466,11 +4472,13 @@ msgid "Steps"
|
|||||||
msgstr "실행 단계"
|
msgstr "실행 단계"
|
||||||
|
|
||||||
#: src/components/browser/InAppBrowser.tsx
|
#: src/components/browser/InAppBrowser.tsx
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/composer.tsx
|
||||||
|
#: src/pages/shell/fullscreen-computer-overlay.tsx
|
||||||
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "Stop"
|
msgid "Stop"
|
||||||
msgstr "중지"
|
msgstr "중지"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "Stop speaking"
|
msgid "Stop speaking"
|
||||||
msgstr "읽기 중지"
|
msgstr "읽기 중지"
|
||||||
|
|
||||||
@ -4500,7 +4508,7 @@ msgstr ""
|
|||||||
msgid "Stronger together — {0} specialists"
|
msgid "Stronger together — {0} specialists"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "subagent"
|
msgid "subagent"
|
||||||
msgstr "보조 에이전트"
|
msgstr "보조 에이전트"
|
||||||
|
|
||||||
@ -4565,7 +4573,7 @@ msgstr "작업을 가르치는 중입니다. 새 메시지를 보내려면 먼
|
|||||||
msgid "Team"
|
msgid "Team"
|
||||||
msgstr "팀 공용"
|
msgstr "팀 공용"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/computer-screen.tsx
|
||||||
msgid "Team Computer"
|
msgid "Team Computer"
|
||||||
msgstr "팀 컴퓨터"
|
msgstr "팀 컴퓨터"
|
||||||
|
|
||||||
@ -4606,7 +4614,7 @@ msgstr "선택한 기억 서비스는 현재 빌드에서 사용할 수 없습
|
|||||||
msgid "Thinking"
|
msgid "Thinking"
|
||||||
msgstr "생각 깊이"
|
msgstr "생각 깊이"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/computer-screen.tsx
|
||||||
msgid "This bot runs on this computer, not a Linux desktop. Shell and files use your home folder."
|
msgid "This bot runs on this computer, not a Linux desktop. Shell and files use your home folder."
|
||||||
msgstr "이 Bot은 별도 Linux 화면이 아니라 현재 컴퓨터에서 실행됩니다. 터미널과 파일 작업은 홈 폴더를 사용합니다."
|
msgstr "이 Bot은 별도 Linux 화면이 아니라 현재 컴퓨터에서 실행됩니다. 터미널과 파일 작업은 홈 폴더를 사용합니다."
|
||||||
|
|
||||||
@ -4713,7 +4721,7 @@ msgid "Transcribe"
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/voice/VoiceStage.tsx
|
#: src/components/voice/VoiceStage.tsx
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "Transcript"
|
msgid "Transcript"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@ -4836,7 +4844,7 @@ msgstr "업로드"
|
|||||||
|
|
||||||
#: src/pages/AccountSettingsOverlay.tsx
|
#: src/pages/AccountSettingsOverlay.tsx
|
||||||
#: src/pages/SettingsOverlay.tsx
|
#: src/pages/SettingsOverlay.tsx
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/user-menu.tsx
|
||||||
msgid "Usage"
|
msgid "Usage"
|
||||||
msgstr "사용량"
|
msgstr "사용량"
|
||||||
|
|
||||||
@ -4877,8 +4885,8 @@ msgid "Video workflow"
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/SettingsOverlay.tsx
|
#: src/pages/SettingsOverlay.tsx
|
||||||
#: src/pages/Shell.tsx
|
|
||||||
#: src/pages/shell/bot-panel.tsx
|
#: src/pages/shell/bot-panel.tsx
|
||||||
|
#: src/pages/shell/composer.tsx
|
||||||
#: src/pages/VoiceSettingsOverlay.tsx
|
#: src/pages/VoiceSettingsOverlay.tsx
|
||||||
msgid "Voice"
|
msgid "Voice"
|
||||||
msgstr "음성"
|
msgstr "음성"
|
||||||
@ -5074,7 +5082,7 @@ msgstr "처리 중…"
|
|||||||
msgid "Working…"
|
msgid "Working…"
|
||||||
msgstr "처리 중…"
|
msgstr "처리 중…"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/roster-format.ts
|
||||||
msgid "Yesterday"
|
msgid "Yesterday"
|
||||||
msgstr "어제"
|
msgstr "어제"
|
||||||
|
|
||||||
@ -5092,7 +5100,7 @@ msgstr "자동으로 이동하지 않으면 이 탭을 닫아도 됩니다."
|
|||||||
msgid "You can close this window."
|
msgid "You can close this window."
|
||||||
msgstr "이 창을 닫아도 됩니다."
|
msgstr "이 창을 닫아도 됩니다."
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/fullscreen-computer-overlay.tsx
|
||||||
msgid "You have control"
|
msgid "You have control"
|
||||||
msgstr "직접 조작 중"
|
msgstr "직접 조작 중"
|
||||||
|
|
||||||
|
|||||||
@ -14,7 +14,7 @@ msgstr ""
|
|||||||
"Plural-Forms: nplurals=2; plural=(n > 1);\n"
|
"Plural-Forms: nplurals=2; plural=(n > 1);\n"
|
||||||
"X-Generator: @lingui/cli\n"
|
"X-Generator: @lingui/cli\n"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/roster-rows.tsx
|
||||||
msgid " (unread)"
|
msgid " (unread)"
|
||||||
msgstr " (não lido)"
|
msgstr " (não lido)"
|
||||||
|
|
||||||
@ -126,22 +126,22 @@ msgid "{0}, {label}"
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#. placeholder {0}: item.chat.name
|
#. placeholder {0}: item.chat.name
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/roster-rows.tsx
|
||||||
msgid "{0}, 1:1 conversation"
|
msgid "{0}, 1:1 conversation"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#. placeholder {0}: item.chat.name
|
#. placeholder {0}: item.chat.name
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/roster-rows.tsx
|
||||||
msgid "{0}, group conversation"
|
msgid "{0}, group conversation"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#. placeholder {0}: item.chat.name
|
#. placeholder {0}: item.chat.name
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/roster-rows.tsx
|
||||||
msgid "{0}, main conversation"
|
msgid "{0}, main conversation"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#. placeholder {0}: active.name
|
#. placeholder {0}: active.name
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/computer-panel-preview.tsx
|
||||||
msgid "{0}'s screen"
|
msgid "{0}'s screen"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@ -210,7 +210,7 @@ msgstr ""
|
|||||||
msgid "{botName} watches the tape…"
|
msgid "{botName} watches the tape…"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/computer-screen.tsx
|
||||||
msgid "{botName}’s computer"
|
msgid "{botName}’s computer"
|
||||||
msgstr "Computador do {botName}"
|
msgstr "Computador do {botName}"
|
||||||
|
|
||||||
@ -277,7 +277,7 @@ msgstr "{title}, {label}"
|
|||||||
msgid "{toolCount, plural, one {# tool} other {# tools}}"
|
msgid "{toolCount, plural, one {# tool} other {# tools}}"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "{workingBotName} is working"
|
msgid "{workingBotName} is working"
|
||||||
msgstr "{workingBotName} está trabalhando"
|
msgstr "{workingBotName} está trabalhando"
|
||||||
|
|
||||||
@ -339,6 +339,7 @@ msgstr "Confirmações de ação"
|
|||||||
#. placeholder {0}: sectionMenu.section.name
|
#. placeholder {0}: sectionMenu.section.name
|
||||||
#: src/pages/BotContextMenu.tsx
|
#: src/pages/BotContextMenu.tsx
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/Shell.tsx
|
||||||
|
#: src/pages/shell/sidebar-group-header.tsx
|
||||||
msgid "Actions for {0}"
|
msgid "Actions for {0}"
|
||||||
msgstr "Ações para {0}"
|
msgstr "Ações para {0}"
|
||||||
|
|
||||||
@ -354,7 +355,7 @@ msgstr ""
|
|||||||
msgid "Active model"
|
msgid "Active model"
|
||||||
msgstr "Modelo ativo"
|
msgstr "Modelo ativo"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/sidebar-header.tsx
|
||||||
msgid "Activity"
|
msgid "Activity"
|
||||||
msgstr "Atividade"
|
msgstr "Atividade"
|
||||||
|
|
||||||
@ -643,15 +644,15 @@ msgstr "Aprove este servidor para permitir que seu agente use suas ferramentas."
|
|||||||
msgid "Archive"
|
msgid "Archive"
|
||||||
msgstr "Arquivar"
|
msgstr "Arquivar"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "archived"
|
msgid "archived"
|
||||||
msgstr "arquivado"
|
msgstr "arquivado"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/archived-section.tsx
|
||||||
msgid "Archived"
|
msgid "Archived"
|
||||||
msgstr "Arquivado"
|
msgstr "Arquivado"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "Archived. Chat, memory, and files kept."
|
msgid "Archived. Chat, memory, and files kept."
|
||||||
msgstr "Arquivado. Chat, memória e arquivos mantidos."
|
msgstr "Arquivado. Chat, memória e arquivos mantidos."
|
||||||
|
|
||||||
@ -711,11 +712,11 @@ msgstr "em {0}"
|
|||||||
msgid "at {timeSelect}"
|
msgid "at {timeSelect}"
|
||||||
msgstr "em {timeSelect}"
|
msgstr "em {timeSelect}"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/composer.tsx
|
||||||
msgid "Attach file"
|
msgid "Attach file"
|
||||||
msgstr "Escolher arquivo"
|
msgstr "Escolher arquivo"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/message-preview.ts
|
||||||
msgid "Attachment"
|
msgid "Attachment"
|
||||||
msgstr "Anexo"
|
msgstr "Anexo"
|
||||||
|
|
||||||
@ -788,7 +789,7 @@ msgstr "Token portador"
|
|||||||
msgid "Blocked in your browser settings"
|
msgid "Blocked in your browser settings"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/computer-screen.tsx
|
||||||
msgid "Booting live desktop…"
|
msgid "Booting live desktop…"
|
||||||
msgstr "Iniciando a área de trabalho ao vivo..."
|
msgstr "Iniciando a área de trabalho ao vivo..."
|
||||||
|
|
||||||
@ -797,7 +798,7 @@ msgstr "Iniciando a área de trabalho ao vivo..."
|
|||||||
msgid "Booting up {0}’s computer"
|
msgid "Booting up {0}’s computer"
|
||||||
msgstr "Inicializando o computador do {0}"
|
msgstr "Inicializando o computador do {0}"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "bot"
|
msgid "bot"
|
||||||
msgstr "bot"
|
msgstr "bot"
|
||||||
|
|
||||||
@ -812,11 +813,11 @@ msgstr "Bot"
|
|||||||
msgid "Bot"
|
msgid "Bot"
|
||||||
msgstr "Bot"
|
msgstr "Bot"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/fullscreen-computer-overlay.tsx
|
||||||
msgid "Bot screen"
|
msgid "Bot screen"
|
||||||
msgstr "Tela do bot"
|
msgstr "Tela do bot"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/computer-panel-preview.tsx
|
||||||
msgid "Bot screen preview"
|
msgid "Bot screen preview"
|
||||||
msgstr "Pré-visualização da tela"
|
msgstr "Pré-visualização da tela"
|
||||||
|
|
||||||
@ -828,7 +829,7 @@ msgstr ""
|
|||||||
msgid "Bots act without asking by default. Add an exception only when you want to review a type of action first."
|
msgid "Bots act without asking by default. Add an exception only when you want to review a type of action first."
|
||||||
msgstr "Os bots agem sem perguntar por padrão. Adicione uma exceção apenas quando quiser analisar um tipo de ação primeiro."
|
msgstr "Os bots agem sem perguntar por padrão. Adicione uma exceção apenas quando quiser analisar um tipo de ação primeiro."
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "Bots are working"
|
msgid "Bots are working"
|
||||||
msgstr "Bots estão trabalhando"
|
msgstr "Bots estão trabalhando"
|
||||||
|
|
||||||
@ -889,7 +890,7 @@ msgstr "Cancelar novo bot"
|
|||||||
msgid "Cancel new group"
|
msgid "Cancel new group"
|
||||||
msgstr "Cancelar novo grupo"
|
msgstr "Cancelar novo grupo"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/composer.tsx
|
||||||
msgid "Cancel reply"
|
msgid "Cancel reply"
|
||||||
msgstr "cancelar resposta"
|
msgstr "cancelar resposta"
|
||||||
|
|
||||||
@ -946,7 +947,7 @@ msgstr ""
|
|||||||
msgid "Chat history"
|
msgid "Chat history"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/composer.tsx
|
||||||
msgid "Chat Settings"
|
msgid "Chat Settings"
|
||||||
msgstr "Configurações do chat"
|
msgstr "Configurações do chat"
|
||||||
|
|
||||||
@ -1088,7 +1089,7 @@ msgstr "Fechar"
|
|||||||
msgid "Close chart"
|
msgid "Close chart"
|
||||||
msgstr "Fechar gráfico"
|
msgstr "Fechar gráfico"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/fullscreen-computer-overlay.tsx
|
||||||
msgid "Close computer"
|
msgid "Close computer"
|
||||||
msgstr "Fechar computador"
|
msgstr "Fechar computador"
|
||||||
|
|
||||||
@ -1128,7 +1129,7 @@ msgstr "Fechar navegação"
|
|||||||
|
|
||||||
#: src/components/ArtifactPane.tsx
|
#: src/components/ArtifactPane.tsx
|
||||||
#: src/components/browser/InAppBrowser.tsx
|
#: src/components/browser/InAppBrowser.tsx
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/side-panel-header.tsx
|
||||||
msgid "Close panel"
|
msgid "Close panel"
|
||||||
msgstr "Fechar painel"
|
msgstr "Fechar painel"
|
||||||
|
|
||||||
@ -1159,7 +1160,7 @@ msgid "Coder"
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#. placeholder {0}: group.title
|
#. placeholder {0}: group.title
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/sidebar-group-header.tsx
|
||||||
msgid "Collapse {0}"
|
msgid "Collapse {0}"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@ -1192,24 +1193,24 @@ msgid "Composing a reply…"
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/SettingsOverlay.tsx
|
#: src/pages/SettingsOverlay.tsx
|
||||||
#: src/pages/Shell.tsx
|
|
||||||
#: src/pages/shell/bot-panel.tsx
|
#: src/pages/shell/bot-panel.tsx
|
||||||
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "Computer"
|
msgid "Computer"
|
||||||
msgstr "Computador"
|
msgstr "Computador"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/computer-screen.tsx
|
||||||
msgid "Computer failed to boot"
|
msgid "Computer failed to boot"
|
||||||
msgstr "Falha ao inicializar o computador"
|
msgstr "Falha ao inicializar o computador"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/fullscreen-computer-overlay.tsx
|
||||||
msgid "Computer is asleep"
|
msgid "Computer is asleep"
|
||||||
msgstr "O computador está dormindo"
|
msgstr "O computador está dormindo"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/computer-screen.tsx
|
||||||
msgid "Computer is asleep. Open it to wake."
|
msgid "Computer is asleep. Open it to wake."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/computer-screen.tsx
|
||||||
msgid "Computer is stopped"
|
msgid "Computer is stopped"
|
||||||
msgstr "O computador está parado"
|
msgstr "O computador está parado"
|
||||||
|
|
||||||
@ -1353,7 +1354,7 @@ msgstr ""
|
|||||||
msgid "Continue with email"
|
msgid "Continue with email"
|
||||||
msgstr "Continuar com e-mail"
|
msgstr "Continuar com e-mail"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "Conversation record"
|
msgid "Conversation record"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@ -1361,11 +1362,11 @@ msgstr ""
|
|||||||
msgid "Conversations"
|
msgid "Conversations"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "Copy"
|
msgid "Copy"
|
||||||
msgstr "Copiar"
|
msgstr "Copiar"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "Copy reply"
|
msgid "Copy reply"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@ -1747,9 +1748,9 @@ msgstr ""
|
|||||||
msgid "Couldn't update messaging settings"
|
msgid "Couldn't update messaging settings"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
|
||||||
#: src/pages/shell/bot-panel.tsx
|
#: src/pages/shell/bot-panel.tsx
|
||||||
#: src/pages/shell/dialogs.tsx
|
#: src/pages/shell/dialogs.tsx
|
||||||
|
#: src/pages/shell/sidebar-header.tsx
|
||||||
msgid "Create"
|
msgid "Create"
|
||||||
msgstr "Criar"
|
msgstr "Criar"
|
||||||
|
|
||||||
@ -1906,14 +1907,14 @@ msgstr "Escopo padrão"
|
|||||||
#: src/pages/KnowledgeSection.tsx
|
#: src/pages/KnowledgeSection.tsx
|
||||||
#: src/pages/McpServersOverlay.tsx
|
#: src/pages/McpServersOverlay.tsx
|
||||||
#: src/pages/RoutineEditor.tsx
|
#: src/pages/RoutineEditor.tsx
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/archived-section.tsx
|
||||||
#: src/pages/shell/dialogs.tsx
|
#: src/pages/shell/dialogs.tsx
|
||||||
msgid "Delete"
|
msgid "Delete"
|
||||||
msgstr "Excluir"
|
msgstr "Excluir"
|
||||||
|
|
||||||
#. placeholder {0}: bot.name
|
#. placeholder {0}: bot.name
|
||||||
#. placeholder {0}: group.name
|
#. placeholder {0}: group.name
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/archived-section.tsx
|
||||||
msgid "Delete {0}"
|
msgid "Delete {0}"
|
||||||
msgstr "Excluir {0}"
|
msgstr "Excluir {0}"
|
||||||
|
|
||||||
@ -1943,7 +1944,7 @@ msgstr ""
|
|||||||
msgid "Delete space"
|
msgid "Delete space"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "deleted"
|
msgid "deleted"
|
||||||
msgstr "excluído"
|
msgstr "excluído"
|
||||||
|
|
||||||
@ -2013,7 +2014,7 @@ msgstr "Desconectando…"
|
|||||||
msgid "Dismiss"
|
msgid "Dismiss"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/composer.tsx
|
||||||
msgid "Dismiss error"
|
msgid "Dismiss error"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@ -2111,7 +2112,7 @@ msgstr "Duplicar"
|
|||||||
msgid "e.g. Hivenet Agent, Presales, Timesheets bot"
|
msgid "e.g. Hivenet Agent, Presales, Timesheets bot"
|
||||||
msgstr "ex.: Hivenet Agent, Presales, bot de planilhas"
|
msgstr "ex.: Hivenet Agent, Presales, bot de planilhas"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "Earlier message"
|
msgid "Earlier message"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@ -2222,7 +2223,7 @@ msgid "Expand"
|
|||||||
msgstr "Expandir"
|
msgstr "Expandir"
|
||||||
|
|
||||||
#. placeholder {0}: group.title
|
#. placeholder {0}: group.title
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/sidebar-group-header.tsx
|
||||||
msgid "Expand {0}"
|
msgid "Expand {0}"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@ -2404,6 +2405,7 @@ msgstr ""
|
|||||||
#: src/components/stage/OoStage.tsx
|
#: src/components/stage/OoStage.tsx
|
||||||
#: src/pages/MessagingSettingsOverlay.tsx
|
#: src/pages/MessagingSettingsOverlay.tsx
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/Shell.tsx
|
||||||
|
#: src/pages/shell/side-panel-header.tsx
|
||||||
msgid "Group"
|
msgid "Group"
|
||||||
msgstr "Grupo"
|
msgstr "Grupo"
|
||||||
|
|
||||||
@ -2528,7 +2530,7 @@ msgstr ""
|
|||||||
msgid "How to check"
|
msgid "How to check"
|
||||||
msgstr "Como verificar"
|
msgstr "Como verificar"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/computer-screen.tsx
|
||||||
msgid "I’m done"
|
msgid "I’m done"
|
||||||
msgstr "Eu terminei."
|
msgstr "Eu terminei."
|
||||||
|
|
||||||
@ -2635,11 +2637,11 @@ msgstr "Isolado"
|
|||||||
msgid "Its conversation, files, and routines will be permanently deleted. Bots it created stay in your list."
|
msgid "Its conversation, files, and routines will be permanently deleted. Bots it created stay in your list."
|
||||||
msgstr "Suas conversas, arquivos e rotinas serão excluídos permanentemente. Os bots criados ficam na sua lista."
|
msgstr "Suas conversas, arquivos e rotinas serão excluídos permanentemente. Os bots criados ficam na sua lista."
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "Jump to latest"
|
msgid "Jump to latest"
|
||||||
msgstr "Ir para a mensagem mais recente"
|
msgstr "Ir para a mensagem mais recente"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "Jump to replied message"
|
msgid "Jump to replied message"
|
||||||
msgstr "Ir para a mensagem respondida"
|
msgstr "Ir para a mensagem respondida"
|
||||||
|
|
||||||
@ -2726,7 +2728,7 @@ msgstr ""
|
|||||||
msgid "Listening — what's the story?"
|
msgid "Listening — what's the story?"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "Load earlier messages"
|
msgid "Load earlier messages"
|
||||||
msgstr "Carregar mensagens anteriores..."
|
msgstr "Carregar mensagens anteriores..."
|
||||||
|
|
||||||
@ -2779,7 +2781,7 @@ msgstr ""
|
|||||||
#: src/pages/HeuteBrief.tsx
|
#: src/pages/HeuteBrief.tsx
|
||||||
#: src/pages/IntegrationSetup.tsx
|
#: src/pages/IntegrationSetup.tsx
|
||||||
#: src/pages/PeerMessagesOverlay.tsx
|
#: src/pages/PeerMessagesOverlay.tsx
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "Loading…"
|
msgid "Loading…"
|
||||||
msgstr "Carregando..."
|
msgstr "Carregando..."
|
||||||
|
|
||||||
@ -2799,7 +2801,7 @@ msgstr ""
|
|||||||
msgid "Local Server Settings"
|
msgid "Local Server Settings"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/user-menu.tsx
|
||||||
msgid "Log out"
|
msgid "Log out"
|
||||||
msgstr "Sair"
|
msgstr "Sair"
|
||||||
|
|
||||||
@ -2926,7 +2928,7 @@ msgstr "Memória"
|
|||||||
msgid "Memory scope"
|
msgid "Memory scope"
|
||||||
msgstr "Escopo de memória"
|
msgstr "Escopo de memória"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/composer.tsx
|
||||||
msgid "Mentions"
|
msgid "Mentions"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@ -2939,11 +2941,12 @@ msgstr ""
|
|||||||
msgid "Message"
|
msgid "Message"
|
||||||
msgstr "Mensagem"
|
msgstr "Mensagem"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/composer.tsx
|
||||||
|
#: src/pages/shell/message-preview.ts
|
||||||
msgid "Message"
|
msgid "Message"
|
||||||
msgstr "Mensagem"
|
msgstr "Mensagem"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/composer.tsx
|
||||||
msgid "Message composer"
|
msgid "Message composer"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@ -2951,11 +2954,11 @@ msgstr ""
|
|||||||
msgid "Message event"
|
msgid "Message event"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "Message from {peer}"
|
msgid "Message from {peer}"
|
||||||
msgstr "Mensagem de {peer}"
|
msgstr "Mensagem de {peer}"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/composer.tsx
|
||||||
msgid "Message…"
|
msgid "Message…"
|
||||||
msgstr "Mensagem…"
|
msgstr "Mensagem…"
|
||||||
|
|
||||||
@ -2981,7 +2984,7 @@ msgstr "Mínimo"
|
|||||||
msgid "Minimize"
|
msgid "Minimize"
|
||||||
msgstr "Minimizar"
|
msgstr "Minimizar"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/sidebar-toggle-buttons.tsx
|
||||||
msgid "Minimize bots"
|
msgid "Minimize bots"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@ -3038,7 +3041,7 @@ msgstr "Modelos do servidor"
|
|||||||
msgid "Monthly"
|
msgid "Monthly"
|
||||||
msgstr "Mensalmente"
|
msgstr "Mensalmente"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "More"
|
msgid "More"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@ -3104,7 +3107,8 @@ msgstr ""
|
|||||||
#: src/components/MainInbox.tsx
|
#: src/components/MainInbox.tsx
|
||||||
#: src/pages/ActivityList.tsx
|
#: src/pages/ActivityList.tsx
|
||||||
#: src/pages/HeuteBrief.tsx
|
#: src/pages/HeuteBrief.tsx
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/fullscreen-computer-overlay.tsx
|
||||||
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "Needs you"
|
msgid "Needs you"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@ -3397,12 +3401,12 @@ msgid "Only file and folder names are read."
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/ScratchpadSection.tsx
|
#: src/pages/ScratchpadSection.tsx
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/computer-panel-preview.tsx
|
||||||
msgid "Open"
|
msgid "Open"
|
||||||
msgstr "Abrir"
|
msgstr "Abrir"
|
||||||
|
|
||||||
#. placeholder {0}: group.title
|
#. placeholder {0}: group.title
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/sidebar-group-header.tsx
|
||||||
msgid "Open {0}"
|
msgid "Open {0}"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@ -3418,11 +3422,11 @@ msgstr ""
|
|||||||
msgid "Open in browser"
|
msgid "Open in browser"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/computer-panel-preview.tsx
|
||||||
msgid "Open in full window"
|
msgid "Open in full window"
|
||||||
msgstr "Abrir em janela cheia"
|
msgstr "Abrir em janela cheia"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/sidebar-toggle-buttons.tsx
|
||||||
msgid "Open navigation"
|
msgid "Open navigation"
|
||||||
msgstr "Abrir a navegação"
|
msgstr "Abrir a navegação"
|
||||||
|
|
||||||
@ -3438,7 +3442,7 @@ msgstr "Trabalho aberto"
|
|||||||
msgid "OpenAI-compatible server URL"
|
msgid "OpenAI-compatible server URL"
|
||||||
msgstr "URL do servidor compatível com OpenAI"
|
msgstr "URL do servidor compatível com OpenAI"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "Opened its thread."
|
msgid "Opened its thread."
|
||||||
msgstr "Abriu a conversa."
|
msgstr "Abriu a conversa."
|
||||||
|
|
||||||
@ -3679,19 +3683,19 @@ msgstr ""
|
|||||||
msgid "Quiet hours start"
|
msgid "Quiet hours start"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "Quote"
|
msgid "Quote"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "React"
|
msgid "React"
|
||||||
msgstr "Reagir"
|
msgstr "Reagir"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "Reactions"
|
msgid "Reactions"
|
||||||
msgstr "Reações"
|
msgstr "Reações"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "Read aloud"
|
msgid "Read aloud"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@ -3796,7 +3800,7 @@ msgstr ""
|
|||||||
msgid "Region"
|
msgid "Region"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/computer-screen.tsx
|
||||||
msgid "Release"
|
msgid "Release"
|
||||||
msgstr "Libere"
|
msgstr "Libere"
|
||||||
|
|
||||||
@ -3820,7 +3824,7 @@ msgid "Remove"
|
|||||||
msgstr "Remover"
|
msgstr "Remover"
|
||||||
|
|
||||||
#. placeholder {0}: attachment.file.name
|
#. placeholder {0}: attachment.file.name
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/composer.tsx
|
||||||
msgid "Remove {0}"
|
msgid "Remove {0}"
|
||||||
msgstr "Remover {0}"
|
msgstr "Remover {0}"
|
||||||
|
|
||||||
@ -3829,7 +3833,7 @@ msgid "Remove Git event"
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#. placeholder {0}: mention.name
|
#. placeholder {0}: mention.name
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/composer.tsx
|
||||||
msgid "Remove mention {0}"
|
msgid "Remove mention {0}"
|
||||||
msgstr "Remover menção {0}"
|
msgstr "Remover menção {0}"
|
||||||
|
|
||||||
@ -3842,7 +3846,7 @@ msgid "Remove schedule"
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#. placeholder {0}: selectedSkill.name
|
#. placeholder {0}: selectedSkill.name
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/composer.tsx
|
||||||
msgid "Remove skill {0}"
|
msgid "Remove skill {0}"
|
||||||
msgstr "Remover habilidade {0}"
|
msgstr "Remover habilidade {0}"
|
||||||
|
|
||||||
@ -3850,7 +3854,7 @@ msgstr "Remover habilidade {0}"
|
|||||||
msgid "Remove webhook"
|
msgid "Remove webhook"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "Removed with chat, computer, and memory."
|
msgid "Removed with chat, computer, and memory."
|
||||||
msgstr "Removido com chat, computador e memória."
|
msgstr "Removido com chat, computador e memória."
|
||||||
|
|
||||||
@ -3883,15 +3887,15 @@ msgstr "Substituir chave de API"
|
|||||||
msgid "Replace key"
|
msgid "Replace key"
|
||||||
msgstr "Substituir chave"
|
msgstr "Substituir chave"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "Reply"
|
msgid "Reply"
|
||||||
msgstr "Responder"
|
msgstr "Responder"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/composer.tsx
|
||||||
msgid "Replying to {replyName}"
|
msgid "Replying to {replyName}"
|
||||||
msgstr "Respondendo a {replyName}"
|
msgstr "Respondendo a {replyName}"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/composer.tsx
|
||||||
msgid "Replying to {replyName}: “{replyQuote}”"
|
msgid "Replying to {replyName}: “{replyQuote}”"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@ -3937,7 +3941,7 @@ msgstr "Redefinindo…"
|
|||||||
msgid "Restart to update"
|
msgid "Restart to update"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/archived-section.tsx
|
||||||
msgid "Restore"
|
msgid "Restore"
|
||||||
msgstr "Restaurar"
|
msgstr "Restaurar"
|
||||||
|
|
||||||
@ -4142,7 +4146,7 @@ msgid "Searching…"
|
|||||||
msgstr "Pesquisando…"
|
msgstr "Pesquisando…"
|
||||||
|
|
||||||
#. placeholder {0}: group.title
|
#. placeholder {0}: group.title
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/sidebar-group-header.tsx
|
||||||
msgid "Select {0}"
|
msgid "Select {0}"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@ -4150,7 +4154,7 @@ msgstr ""
|
|||||||
msgid "Self-hosted (better-auth)"
|
msgid "Self-hosted (better-auth)"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/composer.tsx
|
||||||
#: src/pages/shell/message-cards.tsx
|
#: src/pages/shell/message-cards.tsx
|
||||||
msgid "Send"
|
msgid "Send"
|
||||||
msgstr "Enviar"
|
msgstr "Enviar"
|
||||||
@ -4201,21 +4205,22 @@ msgid "Server URL"
|
|||||||
msgstr "URL do servidor"
|
msgstr "URL do servidor"
|
||||||
|
|
||||||
#: src/components/stage/StageVoiceEntry.tsx
|
#: src/components/stage/StageVoiceEntry.tsx
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/composer.tsx
|
||||||
msgid "Set up voice"
|
msgid "Set up voice"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/MessagingSettingsOverlay.tsx
|
#: src/pages/MessagingSettingsOverlay.tsx
|
||||||
#: src/pages/SettingsOverlay.tsx
|
#: src/pages/SettingsOverlay.tsx
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/side-panel-header.tsx
|
||||||
|
#: src/pages/shell/user-menu.tsx
|
||||||
msgid "Settings"
|
msgid "Settings"
|
||||||
msgstr "Configurações"
|
msgstr "Configurações"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/composer.tsx
|
||||||
msgid "Settings: General"
|
msgid "Settings: General"
|
||||||
msgstr "Opções > Geral"
|
msgstr "Opções > Geral"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/composer.tsx
|
||||||
msgid "Settings: Usage"
|
msgid "Settings: Usage"
|
||||||
msgstr "Configurações: Uso"
|
msgstr "Configurações: Uso"
|
||||||
|
|
||||||
@ -4259,10 +4264,11 @@ msgid "Show all {0}"
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/Shell.tsx
|
||||||
|
#: src/pages/shell/sidebar-toggle-buttons.tsx
|
||||||
msgid "Show bots"
|
msgid "Show bots"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/side-panel-header.tsx
|
||||||
msgid "Show computer"
|
msgid "Show computer"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@ -4278,7 +4284,7 @@ msgstr "Mostrar mais"
|
|||||||
msgid "Show password"
|
msgid "Show password"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/side-panel-header.tsx
|
||||||
msgid "Show settings"
|
msgid "Show settings"
|
||||||
msgstr "Mostrar configurações"
|
msgstr "Mostrar configurações"
|
||||||
|
|
||||||
@ -4307,7 +4313,7 @@ msgid "Sketching the blueprint…"
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#. placeholder {0}: skill.name
|
#. placeholder {0}: skill.name
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/composer.tsx
|
||||||
msgid "Skill {0}"
|
msgid "Skill {0}"
|
||||||
msgstr "Habilidade {0}"
|
msgstr "Habilidade {0}"
|
||||||
|
|
||||||
@ -4319,7 +4325,7 @@ msgstr "Habilidades"
|
|||||||
#: src/components/onboarding/OnboardingScanStep.tsx
|
#: src/components/onboarding/OnboardingScanStep.tsx
|
||||||
#: src/components/onboarding/OnboardingVoiceStep.tsx
|
#: src/components/onboarding/OnboardingVoiceStep.tsx
|
||||||
#: src/lib/onboarding-copy.ts
|
#: src/lib/onboarding-copy.ts
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/computer-screen.tsx
|
||||||
msgid "Skip"
|
msgid "Skip"
|
||||||
msgstr "Pular"
|
msgstr "Pular"
|
||||||
|
|
||||||
@ -4373,11 +4379,11 @@ msgstr "Padrão do espaço"
|
|||||||
msgid "Spaces"
|
msgid "Spaces"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "Speak"
|
msgid "Speak"
|
||||||
msgstr "Falar"
|
msgstr "Falar"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "Speak this reply"
|
msgid "Speak this reply"
|
||||||
msgstr "Fale esta resposta"
|
msgstr "Fale esta resposta"
|
||||||
|
|
||||||
@ -4431,15 +4437,15 @@ msgstr "Começar a gravar"
|
|||||||
msgid "Start talking"
|
msgid "Start talking"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "Start the conversation — {activeName} is on stage above."
|
msgid "Start the conversation — {activeName} is on stage above."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "Start the conversation."
|
msgid "Start the conversation."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/composer.tsx
|
||||||
msgid "Start voice conversation"
|
msgid "Start voice conversation"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@ -4466,11 +4472,13 @@ msgid "Steps"
|
|||||||
msgstr "Passos"
|
msgstr "Passos"
|
||||||
|
|
||||||
#: src/components/browser/InAppBrowser.tsx
|
#: src/components/browser/InAppBrowser.tsx
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/composer.tsx
|
||||||
|
#: src/pages/shell/fullscreen-computer-overlay.tsx
|
||||||
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "Stop"
|
msgid "Stop"
|
||||||
msgstr "Parar"
|
msgstr "Parar"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "Stop speaking"
|
msgid "Stop speaking"
|
||||||
msgstr "Pare de Falar"
|
msgstr "Pare de Falar"
|
||||||
|
|
||||||
@ -4500,7 +4508,7 @@ msgstr ""
|
|||||||
msgid "Stronger together — {0} specialists"
|
msgid "Stronger together — {0} specialists"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "subagent"
|
msgid "subagent"
|
||||||
msgstr "subagente"
|
msgstr "subagente"
|
||||||
|
|
||||||
@ -4565,7 +4573,7 @@ msgstr "Ensino em andamento. Pare de ensinar antes de enviar uma nova mensagem."
|
|||||||
msgid "Team"
|
msgid "Team"
|
||||||
msgstr "Equipe"
|
msgstr "Equipe"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/computer-screen.tsx
|
||||||
msgid "Team Computer"
|
msgid "Team Computer"
|
||||||
msgstr "Computador da equipe"
|
msgstr "Computador da equipe"
|
||||||
|
|
||||||
@ -4606,7 +4614,7 @@ msgstr "O provedor de memória selecionado não está disponível nesta compila
|
|||||||
msgid "Thinking"
|
msgid "Thinking"
|
||||||
msgstr "Pensando"
|
msgstr "Pensando"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/computer-screen.tsx
|
||||||
msgid "This bot runs on this computer, not a Linux desktop. Shell and files use your home folder."
|
msgid "This bot runs on this computer, not a Linux desktop. Shell and files use your home folder."
|
||||||
msgstr "Este bot é executado neste computador, não em um desktop Linux. Shell e arquivos usam sua pasta inicial."
|
msgstr "Este bot é executado neste computador, não em um desktop Linux. Shell e arquivos usam sua pasta inicial."
|
||||||
|
|
||||||
@ -4713,7 +4721,7 @@ msgid "Transcribe"
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/voice/VoiceStage.tsx
|
#: src/components/voice/VoiceStage.tsx
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "Transcript"
|
msgid "Transcript"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@ -4836,7 +4844,7 @@ msgstr "Enviar"
|
|||||||
|
|
||||||
#: src/pages/AccountSettingsOverlay.tsx
|
#: src/pages/AccountSettingsOverlay.tsx
|
||||||
#: src/pages/SettingsOverlay.tsx
|
#: src/pages/SettingsOverlay.tsx
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/user-menu.tsx
|
||||||
msgid "Usage"
|
msgid "Usage"
|
||||||
msgstr "Uso"
|
msgstr "Uso"
|
||||||
|
|
||||||
@ -4877,8 +4885,8 @@ msgid "Video workflow"
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/SettingsOverlay.tsx
|
#: src/pages/SettingsOverlay.tsx
|
||||||
#: src/pages/Shell.tsx
|
|
||||||
#: src/pages/shell/bot-panel.tsx
|
#: src/pages/shell/bot-panel.tsx
|
||||||
|
#: src/pages/shell/composer.tsx
|
||||||
#: src/pages/VoiceSettingsOverlay.tsx
|
#: src/pages/VoiceSettingsOverlay.tsx
|
||||||
msgid "Voice"
|
msgid "Voice"
|
||||||
msgstr "Voz"
|
msgstr "Voz"
|
||||||
@ -5074,7 +5082,7 @@ msgstr "Funcionando"
|
|||||||
msgid "Working…"
|
msgid "Working…"
|
||||||
msgstr "Funcionando"
|
msgstr "Funcionando"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/roster-format.ts
|
||||||
msgid "Yesterday"
|
msgid "Yesterday"
|
||||||
msgstr "Ontem"
|
msgstr "Ontem"
|
||||||
|
|
||||||
@ -5092,7 +5100,7 @@ msgstr "Você pode fechar esta guia se ela não for redirecionada automaticament
|
|||||||
msgid "You can close this window."
|
msgid "You can close this window."
|
||||||
msgstr "Você pode fechar esta janela."
|
msgstr "Você pode fechar esta janela."
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/fullscreen-computer-overlay.tsx
|
||||||
msgid "You have control"
|
msgid "You have control"
|
||||||
msgstr "Você tem o controle"
|
msgstr "Você tem o controle"
|
||||||
|
|
||||||
|
|||||||
@ -14,7 +14,7 @@ msgstr ""
|
|||||||
"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n"
|
"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n"
|
||||||
"X-Generator: @lingui/cli\n"
|
"X-Generator: @lingui/cli\n"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/roster-rows.tsx
|
||||||
msgid " (unread)"
|
msgid " (unread)"
|
||||||
msgstr " (непрочитано)"
|
msgstr " (непрочитано)"
|
||||||
|
|
||||||
@ -126,22 +126,22 @@ msgid "{0}, {label}"
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#. placeholder {0}: item.chat.name
|
#. placeholder {0}: item.chat.name
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/roster-rows.tsx
|
||||||
msgid "{0}, 1:1 conversation"
|
msgid "{0}, 1:1 conversation"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#. placeholder {0}: item.chat.name
|
#. placeholder {0}: item.chat.name
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/roster-rows.tsx
|
||||||
msgid "{0}, group conversation"
|
msgid "{0}, group conversation"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#. placeholder {0}: item.chat.name
|
#. placeholder {0}: item.chat.name
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/roster-rows.tsx
|
||||||
msgid "{0}, main conversation"
|
msgid "{0}, main conversation"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#. placeholder {0}: active.name
|
#. placeholder {0}: active.name
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/computer-panel-preview.tsx
|
||||||
msgid "{0}'s screen"
|
msgid "{0}'s screen"
|
||||||
msgstr "Экран {0}"
|
msgstr "Экран {0}"
|
||||||
|
|
||||||
@ -210,7 +210,7 @@ msgstr ""
|
|||||||
msgid "{botName} watches the tape…"
|
msgid "{botName} watches the tape…"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/computer-screen.tsx
|
||||||
msgid "{botName}’s computer"
|
msgid "{botName}’s computer"
|
||||||
msgstr "Компьютер {botName}"
|
msgstr "Компьютер {botName}"
|
||||||
|
|
||||||
@ -277,7 +277,7 @@ msgstr "{title}, {label}"
|
|||||||
msgid "{toolCount, plural, one {# tool} other {# tools}}"
|
msgid "{toolCount, plural, one {# tool} other {# tools}}"
|
||||||
msgstr "{toolCount, plural, one {# инструмент} few {# инструмента} many {# инструментов} other {# инструмента}}"
|
msgstr "{toolCount, plural, one {# инструмент} few {# инструмента} many {# инструментов} other {# инструмента}}"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "{workingBotName} is working"
|
msgid "{workingBotName} is working"
|
||||||
msgstr "{workingBotName} работает"
|
msgstr "{workingBotName} работает"
|
||||||
|
|
||||||
@ -339,6 +339,7 @@ msgstr "Подтверждения действий"
|
|||||||
#. placeholder {0}: sectionMenu.section.name
|
#. placeholder {0}: sectionMenu.section.name
|
||||||
#: src/pages/BotContextMenu.tsx
|
#: src/pages/BotContextMenu.tsx
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/Shell.tsx
|
||||||
|
#: src/pages/shell/sidebar-group-header.tsx
|
||||||
msgid "Actions for {0}"
|
msgid "Actions for {0}"
|
||||||
msgstr "Действия для {0}"
|
msgstr "Действия для {0}"
|
||||||
|
|
||||||
@ -354,7 +355,7 @@ msgstr "Активный"
|
|||||||
msgid "Active model"
|
msgid "Active model"
|
||||||
msgstr "Активная модель"
|
msgstr "Активная модель"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/sidebar-header.tsx
|
||||||
msgid "Activity"
|
msgid "Activity"
|
||||||
msgstr "Активность"
|
msgstr "Активность"
|
||||||
|
|
||||||
@ -643,15 +644,15 @@ msgstr "Одобрите этот сервер, чтобы ваш агент м
|
|||||||
msgid "Archive"
|
msgid "Archive"
|
||||||
msgstr "Архивировать"
|
msgstr "Архивировать"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "archived"
|
msgid "archived"
|
||||||
msgstr "в архиве"
|
msgstr "в архиве"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/archived-section.tsx
|
||||||
msgid "Archived"
|
msgid "Archived"
|
||||||
msgstr "В архиве"
|
msgstr "В архиве"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "Archived. Chat, memory, and files kept."
|
msgid "Archived. Chat, memory, and files kept."
|
||||||
msgstr "В архиве. Чат, память и файлы сохраняются."
|
msgstr "В архиве. Чат, память и файлы сохраняются."
|
||||||
|
|
||||||
@ -711,11 +712,11 @@ msgstr "в {0}"
|
|||||||
msgid "at {timeSelect}"
|
msgid "at {timeSelect}"
|
||||||
msgstr "в {timeSelect}"
|
msgstr "в {timeSelect}"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/composer.tsx
|
||||||
msgid "Attach file"
|
msgid "Attach file"
|
||||||
msgstr "Прикрепить файл"
|
msgstr "Прикрепить файл"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/message-preview.ts
|
||||||
msgid "Attachment"
|
msgid "Attachment"
|
||||||
msgstr "Вложение"
|
msgstr "Вложение"
|
||||||
|
|
||||||
@ -788,7 +789,7 @@ msgstr "Bearer-токен"
|
|||||||
msgid "Blocked in your browser settings"
|
msgid "Blocked in your browser settings"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/computer-screen.tsx
|
||||||
msgid "Booting live desktop…"
|
msgid "Booting live desktop…"
|
||||||
msgstr "Загрузка рабочего стола…"
|
msgstr "Загрузка рабочего стола…"
|
||||||
|
|
||||||
@ -797,7 +798,7 @@ msgstr "Загрузка рабочего стола…"
|
|||||||
msgid "Booting up {0}’s computer"
|
msgid "Booting up {0}’s computer"
|
||||||
msgstr "Загрузка компьютера {0}"
|
msgstr "Загрузка компьютера {0}"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "bot"
|
msgid "bot"
|
||||||
msgstr "бот"
|
msgstr "бот"
|
||||||
|
|
||||||
@ -812,11 +813,11 @@ msgstr "Бот"
|
|||||||
msgid "Bot"
|
msgid "Bot"
|
||||||
msgstr "Бот"
|
msgstr "Бот"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/fullscreen-computer-overlay.tsx
|
||||||
msgid "Bot screen"
|
msgid "Bot screen"
|
||||||
msgstr "Экран бота"
|
msgstr "Экран бота"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/computer-panel-preview.tsx
|
||||||
msgid "Bot screen preview"
|
msgid "Bot screen preview"
|
||||||
msgstr "Предварительный просмотр экрана бота"
|
msgstr "Предварительный просмотр экрана бота"
|
||||||
|
|
||||||
@ -828,7 +829,7 @@ msgstr "Бот для ссылки"
|
|||||||
msgid "Bots act without asking by default. Add an exception only when you want to review a type of action first."
|
msgid "Bots act without asking by default. Add an exception only when you want to review a type of action first."
|
||||||
msgstr "По умолчанию боты действуют, не спрашивая. Добавляйте исключение только в том случае, если вы хотите сначала просмотреть тип действия."
|
msgstr "По умолчанию боты действуют, не спрашивая. Добавляйте исключение только в том случае, если вы хотите сначала просмотреть тип действия."
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "Bots are working"
|
msgid "Bots are working"
|
||||||
msgstr "Боты работают"
|
msgstr "Боты работают"
|
||||||
|
|
||||||
@ -889,7 +890,7 @@ msgstr "Отменить создание бота"
|
|||||||
msgid "Cancel new group"
|
msgid "Cancel new group"
|
||||||
msgstr "Отменить создание группы"
|
msgstr "Отменить создание группы"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/composer.tsx
|
||||||
msgid "Cancel reply"
|
msgid "Cancel reply"
|
||||||
msgstr "Отменить ответ"
|
msgstr "Отменить ответ"
|
||||||
|
|
||||||
@ -946,7 +947,7 @@ msgstr "Приложения чата, групповые каналы и под
|
|||||||
msgid "Chat history"
|
msgid "Chat history"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/composer.tsx
|
||||||
msgid "Chat Settings"
|
msgid "Chat Settings"
|
||||||
msgstr "Настройки чата"
|
msgstr "Настройки чата"
|
||||||
|
|
||||||
@ -1088,7 +1089,7 @@ msgstr "Закрыть"
|
|||||||
msgid "Close chart"
|
msgid "Close chart"
|
||||||
msgstr "Закрыть график"
|
msgstr "Закрыть график"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/fullscreen-computer-overlay.tsx
|
||||||
msgid "Close computer"
|
msgid "Close computer"
|
||||||
msgstr "Закрыть компьютер"
|
msgstr "Закрыть компьютер"
|
||||||
|
|
||||||
@ -1128,7 +1129,7 @@ msgstr "Закрыть навигацию"
|
|||||||
|
|
||||||
#: src/components/ArtifactPane.tsx
|
#: src/components/ArtifactPane.tsx
|
||||||
#: src/components/browser/InAppBrowser.tsx
|
#: src/components/browser/InAppBrowser.tsx
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/side-panel-header.tsx
|
||||||
msgid "Close panel"
|
msgid "Close panel"
|
||||||
msgstr "Закрыть панель"
|
msgstr "Закрыть панель"
|
||||||
|
|
||||||
@ -1159,7 +1160,7 @@ msgid "Coder"
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#. placeholder {0}: group.title
|
#. placeholder {0}: group.title
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/sidebar-group-header.tsx
|
||||||
msgid "Collapse {0}"
|
msgid "Collapse {0}"
|
||||||
msgstr "Свернуть {0}"
|
msgstr "Свернуть {0}"
|
||||||
|
|
||||||
@ -1192,24 +1193,24 @@ msgid "Composing a reply…"
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/SettingsOverlay.tsx
|
#: src/pages/SettingsOverlay.tsx
|
||||||
#: src/pages/Shell.tsx
|
|
||||||
#: src/pages/shell/bot-panel.tsx
|
#: src/pages/shell/bot-panel.tsx
|
||||||
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "Computer"
|
msgid "Computer"
|
||||||
msgstr "Компьютер"
|
msgstr "Компьютер"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/computer-screen.tsx
|
||||||
msgid "Computer failed to boot"
|
msgid "Computer failed to boot"
|
||||||
msgstr "Компьютер не смог загрузиться"
|
msgstr "Компьютер не смог загрузиться"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/fullscreen-computer-overlay.tsx
|
||||||
msgid "Computer is asleep"
|
msgid "Computer is asleep"
|
||||||
msgstr "Компьютер спит"
|
msgstr "Компьютер спит"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/computer-screen.tsx
|
||||||
msgid "Computer is asleep. Open it to wake."
|
msgid "Computer is asleep. Open it to wake."
|
||||||
msgstr "Компьютер спит. Откройте его, чтобы разбудить."
|
msgstr "Компьютер спит. Откройте его, чтобы разбудить."
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/computer-screen.tsx
|
||||||
msgid "Computer is stopped"
|
msgid "Computer is stopped"
|
||||||
msgstr "Компьютер остановлен"
|
msgstr "Компьютер остановлен"
|
||||||
|
|
||||||
@ -1353,7 +1354,7 @@ msgstr "Продолжить в фоне"
|
|||||||
msgid "Continue with email"
|
msgid "Continue with email"
|
||||||
msgstr "Продолжить по электронной почте"
|
msgstr "Продолжить по электронной почте"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "Conversation record"
|
msgid "Conversation record"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@ -1361,11 +1362,11 @@ msgstr ""
|
|||||||
msgid "Conversations"
|
msgid "Conversations"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "Copy"
|
msgid "Copy"
|
||||||
msgstr "Копировать"
|
msgstr "Копировать"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "Copy reply"
|
msgid "Copy reply"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@ -1747,9 +1748,9 @@ msgstr "Не удалось обновить аватары"
|
|||||||
msgid "Couldn't update messaging settings"
|
msgid "Couldn't update messaging settings"
|
||||||
msgstr "Не удалось обновить настройки обмена сообщениями."
|
msgstr "Не удалось обновить настройки обмена сообщениями."
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
|
||||||
#: src/pages/shell/bot-panel.tsx
|
#: src/pages/shell/bot-panel.tsx
|
||||||
#: src/pages/shell/dialogs.tsx
|
#: src/pages/shell/dialogs.tsx
|
||||||
|
#: src/pages/shell/sidebar-header.tsx
|
||||||
msgid "Create"
|
msgid "Create"
|
||||||
msgstr "Создать"
|
msgstr "Создать"
|
||||||
|
|
||||||
@ -1906,14 +1907,14 @@ msgstr "Область действия по умолчанию"
|
|||||||
#: src/pages/KnowledgeSection.tsx
|
#: src/pages/KnowledgeSection.tsx
|
||||||
#: src/pages/McpServersOverlay.tsx
|
#: src/pages/McpServersOverlay.tsx
|
||||||
#: src/pages/RoutineEditor.tsx
|
#: src/pages/RoutineEditor.tsx
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/archived-section.tsx
|
||||||
#: src/pages/shell/dialogs.tsx
|
#: src/pages/shell/dialogs.tsx
|
||||||
msgid "Delete"
|
msgid "Delete"
|
||||||
msgstr "Удалить"
|
msgstr "Удалить"
|
||||||
|
|
||||||
#. placeholder {0}: bot.name
|
#. placeholder {0}: bot.name
|
||||||
#. placeholder {0}: group.name
|
#. placeholder {0}: group.name
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/archived-section.tsx
|
||||||
msgid "Delete {0}"
|
msgid "Delete {0}"
|
||||||
msgstr "Удалить {0}"
|
msgstr "Удалить {0}"
|
||||||
|
|
||||||
@ -1943,7 +1944,7 @@ msgstr ""
|
|||||||
msgid "Delete space"
|
msgid "Delete space"
|
||||||
msgstr "Удалить пространство"
|
msgstr "Удалить пространство"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "deleted"
|
msgid "deleted"
|
||||||
msgstr "удалено"
|
msgstr "удалено"
|
||||||
|
|
||||||
@ -2013,7 +2014,7 @@ msgstr "Отключение…"
|
|||||||
msgid "Dismiss"
|
msgid "Dismiss"
|
||||||
msgstr "Закрыть"
|
msgstr "Закрыть"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/composer.tsx
|
||||||
msgid "Dismiss error"
|
msgid "Dismiss error"
|
||||||
msgstr "Закрыть ошибку"
|
msgstr "Закрыть ошибку"
|
||||||
|
|
||||||
@ -2111,7 +2112,7 @@ msgstr "Дублировать"
|
|||||||
msgid "e.g. Hivenet Agent, Presales, Timesheets bot"
|
msgid "e.g. Hivenet Agent, Presales, Timesheets bot"
|
||||||
msgstr "напр. Hivenet Agent, Presales, бот табелей"
|
msgstr "напр. Hivenet Agent, Presales, бот табелей"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "Earlier message"
|
msgid "Earlier message"
|
||||||
msgstr "Предыдущее сообщение"
|
msgstr "Предыдущее сообщение"
|
||||||
|
|
||||||
@ -2222,7 +2223,7 @@ msgid "Expand"
|
|||||||
msgstr "Развернуть"
|
msgstr "Развернуть"
|
||||||
|
|
||||||
#. placeholder {0}: group.title
|
#. placeholder {0}: group.title
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/sidebar-group-header.tsx
|
||||||
msgid "Expand {0}"
|
msgid "Expand {0}"
|
||||||
msgstr "Развернуть {0}"
|
msgstr "Развернуть {0}"
|
||||||
|
|
||||||
@ -2404,6 +2405,7 @@ msgstr ""
|
|||||||
#: src/components/stage/OoStage.tsx
|
#: src/components/stage/OoStage.tsx
|
||||||
#: src/pages/MessagingSettingsOverlay.tsx
|
#: src/pages/MessagingSettingsOverlay.tsx
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/Shell.tsx
|
||||||
|
#: src/pages/shell/side-panel-header.tsx
|
||||||
msgid "Group"
|
msgid "Group"
|
||||||
msgstr "Группа"
|
msgstr "Группа"
|
||||||
|
|
||||||
@ -2528,7 +2530,7 @@ msgstr ""
|
|||||||
msgid "How to check"
|
msgid "How to check"
|
||||||
msgstr "Как проверить"
|
msgstr "Как проверить"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/computer-screen.tsx
|
||||||
msgid "I’m done"
|
msgid "I’m done"
|
||||||
msgstr "Готово"
|
msgstr "Готово"
|
||||||
|
|
||||||
@ -2635,11 +2637,11 @@ msgstr "изолированный"
|
|||||||
msgid "Its conversation, files, and routines will be permanently deleted. Bots it created stay in your list."
|
msgid "Its conversation, files, and routines will be permanently deleted. Bots it created stay in your list."
|
||||||
msgstr "Его диалог, файлы и задачи будут безвозвратно удалены. Созданные им боты останутся в вашем списке."
|
msgstr "Его диалог, файлы и задачи будут безвозвратно удалены. Созданные им боты останутся в вашем списке."
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "Jump to latest"
|
msgid "Jump to latest"
|
||||||
msgstr "Перейти к последнему"
|
msgstr "Перейти к последнему"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "Jump to replied message"
|
msgid "Jump to replied message"
|
||||||
msgstr "Перейти к ответному сообщению"
|
msgstr "Перейти к ответному сообщению"
|
||||||
|
|
||||||
@ -2726,7 +2728,7 @@ msgstr ""
|
|||||||
msgid "Listening — what's the story?"
|
msgid "Listening — what's the story?"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "Load earlier messages"
|
msgid "Load earlier messages"
|
||||||
msgstr "Загрузить более ранние сообщения"
|
msgstr "Загрузить более ранние сообщения"
|
||||||
|
|
||||||
@ -2779,7 +2781,7 @@ msgstr ""
|
|||||||
#: src/pages/HeuteBrief.tsx
|
#: src/pages/HeuteBrief.tsx
|
||||||
#: src/pages/IntegrationSetup.tsx
|
#: src/pages/IntegrationSetup.tsx
|
||||||
#: src/pages/PeerMessagesOverlay.tsx
|
#: src/pages/PeerMessagesOverlay.tsx
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "Loading…"
|
msgid "Loading…"
|
||||||
msgstr "Загрузка…"
|
msgstr "Загрузка…"
|
||||||
|
|
||||||
@ -2799,7 +2801,7 @@ msgstr ""
|
|||||||
msgid "Local Server Settings"
|
msgid "Local Server Settings"
|
||||||
msgstr "Настройки локального сервера"
|
msgstr "Настройки локального сервера"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/user-menu.tsx
|
||||||
msgid "Log out"
|
msgid "Log out"
|
||||||
msgstr "Выйти"
|
msgstr "Выйти"
|
||||||
|
|
||||||
@ -2926,7 +2928,7 @@ msgstr "Память"
|
|||||||
msgid "Memory scope"
|
msgid "Memory scope"
|
||||||
msgstr "Область памяти"
|
msgstr "Область памяти"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/composer.tsx
|
||||||
msgid "Mentions"
|
msgid "Mentions"
|
||||||
msgstr "Упоминания"
|
msgstr "Упоминания"
|
||||||
|
|
||||||
@ -2939,11 +2941,12 @@ msgstr "Только упоминания"
|
|||||||
msgid "Message"
|
msgid "Message"
|
||||||
msgstr "Сообщение"
|
msgstr "Сообщение"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/composer.tsx
|
||||||
|
#: src/pages/shell/message-preview.ts
|
||||||
msgid "Message"
|
msgid "Message"
|
||||||
msgstr "Сообщение"
|
msgstr "Сообщение"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/composer.tsx
|
||||||
msgid "Message composer"
|
msgid "Message composer"
|
||||||
msgstr "Поле сообщения"
|
msgstr "Поле сообщения"
|
||||||
|
|
||||||
@ -2951,11 +2954,11 @@ msgstr "Поле сообщения"
|
|||||||
msgid "Message event"
|
msgid "Message event"
|
||||||
msgstr "Событие сообщения"
|
msgstr "Событие сообщения"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "Message from {peer}"
|
msgid "Message from {peer}"
|
||||||
msgstr "Сообщение от {peer}"
|
msgstr "Сообщение от {peer}"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/composer.tsx
|
||||||
msgid "Message…"
|
msgid "Message…"
|
||||||
msgstr "Сообщение…"
|
msgstr "Сообщение…"
|
||||||
|
|
||||||
@ -2981,7 +2984,7 @@ msgstr "Минимальный"
|
|||||||
msgid "Minimize"
|
msgid "Minimize"
|
||||||
msgstr "Свернуть"
|
msgstr "Свернуть"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/sidebar-toggle-buttons.tsx
|
||||||
msgid "Minimize bots"
|
msgid "Minimize bots"
|
||||||
msgstr "Свернуть ботов"
|
msgstr "Свернуть ботов"
|
||||||
|
|
||||||
@ -3038,7 +3041,7 @@ msgstr "Модели с сервера"
|
|||||||
msgid "Monthly"
|
msgid "Monthly"
|
||||||
msgstr "Ежемесячно"
|
msgstr "Ежемесячно"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "More"
|
msgid "More"
|
||||||
msgstr "Ещё"
|
msgstr "Ещё"
|
||||||
|
|
||||||
@ -3104,7 +3107,8 @@ msgstr "Требуется ваше участие"
|
|||||||
#: src/components/MainInbox.tsx
|
#: src/components/MainInbox.tsx
|
||||||
#: src/pages/ActivityList.tsx
|
#: src/pages/ActivityList.tsx
|
||||||
#: src/pages/HeuteBrief.tsx
|
#: src/pages/HeuteBrief.tsx
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/fullscreen-computer-overlay.tsx
|
||||||
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "Needs you"
|
msgid "Needs you"
|
||||||
msgstr "Требуется ваше участие"
|
msgstr "Требуется ваше участие"
|
||||||
|
|
||||||
@ -3397,12 +3401,12 @@ msgid "Only file and folder names are read."
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/ScratchpadSection.tsx
|
#: src/pages/ScratchpadSection.tsx
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/computer-panel-preview.tsx
|
||||||
msgid "Open"
|
msgid "Open"
|
||||||
msgstr "Открыть"
|
msgstr "Открыть"
|
||||||
|
|
||||||
#. placeholder {0}: group.title
|
#. placeholder {0}: group.title
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/sidebar-group-header.tsx
|
||||||
msgid "Open {0}"
|
msgid "Open {0}"
|
||||||
msgstr "Открыть {0}"
|
msgstr "Открыть {0}"
|
||||||
|
|
||||||
@ -3418,11 +3422,11 @@ msgstr ""
|
|||||||
msgid "Open in browser"
|
msgid "Open in browser"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/computer-panel-preview.tsx
|
||||||
msgid "Open in full window"
|
msgid "Open in full window"
|
||||||
msgstr "Открыть в полном окне"
|
msgstr "Открыть в полном окне"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/sidebar-toggle-buttons.tsx
|
||||||
msgid "Open navigation"
|
msgid "Open navigation"
|
||||||
msgstr "Открыть навигацию"
|
msgstr "Открыть навигацию"
|
||||||
|
|
||||||
@ -3438,7 +3442,7 @@ msgstr "Открытые задачи"
|
|||||||
msgid "OpenAI-compatible server URL"
|
msgid "OpenAI-compatible server URL"
|
||||||
msgstr "URL-адрес сервера, совместимого с OpenAI"
|
msgstr "URL-адрес сервера, совместимого с OpenAI"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "Opened its thread."
|
msgid "Opened its thread."
|
||||||
msgstr "Диалог открыт."
|
msgstr "Диалог открыт."
|
||||||
|
|
||||||
@ -3679,19 +3683,19 @@ msgstr ""
|
|||||||
msgid "Quiet hours start"
|
msgid "Quiet hours start"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "Quote"
|
msgid "Quote"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "React"
|
msgid "React"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "Reactions"
|
msgid "Reactions"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "Read aloud"
|
msgid "Read aloud"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@ -3796,7 +3800,7 @@ msgstr "Обновление…"
|
|||||||
msgid "Region"
|
msgid "Region"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/computer-screen.tsx
|
||||||
msgid "Release"
|
msgid "Release"
|
||||||
msgstr "Освободить управление"
|
msgstr "Освободить управление"
|
||||||
|
|
||||||
@ -3820,7 +3824,7 @@ msgid "Remove"
|
|||||||
msgstr "Удалить"
|
msgstr "Удалить"
|
||||||
|
|
||||||
#. placeholder {0}: attachment.file.name
|
#. placeholder {0}: attachment.file.name
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/composer.tsx
|
||||||
msgid "Remove {0}"
|
msgid "Remove {0}"
|
||||||
msgstr "Удалить {0}"
|
msgstr "Удалить {0}"
|
||||||
|
|
||||||
@ -3829,7 +3833,7 @@ msgid "Remove Git event"
|
|||||||
msgstr "Удалить событие Git"
|
msgstr "Удалить событие Git"
|
||||||
|
|
||||||
#. placeholder {0}: mention.name
|
#. placeholder {0}: mention.name
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/composer.tsx
|
||||||
msgid "Remove mention {0}"
|
msgid "Remove mention {0}"
|
||||||
msgstr "Удалить упоминание {0}"
|
msgstr "Удалить упоминание {0}"
|
||||||
|
|
||||||
@ -3842,7 +3846,7 @@ msgid "Remove schedule"
|
|||||||
msgstr "Удалить расписание"
|
msgstr "Удалить расписание"
|
||||||
|
|
||||||
#. placeholder {0}: selectedSkill.name
|
#. placeholder {0}: selectedSkill.name
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/composer.tsx
|
||||||
msgid "Remove skill {0}"
|
msgid "Remove skill {0}"
|
||||||
msgstr "Удалить навык {0}"
|
msgstr "Удалить навык {0}"
|
||||||
|
|
||||||
@ -3850,7 +3854,7 @@ msgstr "Удалить навык {0}"
|
|||||||
msgid "Remove webhook"
|
msgid "Remove webhook"
|
||||||
msgstr "Удалить вебхук"
|
msgstr "Удалить вебхук"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "Removed with chat, computer, and memory."
|
msgid "Removed with chat, computer, and memory."
|
||||||
msgstr "Удалено вместе с чатом, компьютером и памятью."
|
msgstr "Удалено вместе с чатом, компьютером и памятью."
|
||||||
|
|
||||||
@ -3883,15 +3887,15 @@ msgstr "Заменить ключ API"
|
|||||||
msgid "Replace key"
|
msgid "Replace key"
|
||||||
msgstr "Заменить ключ"
|
msgstr "Заменить ключ"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "Reply"
|
msgid "Reply"
|
||||||
msgstr "Ответить"
|
msgstr "Ответить"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/composer.tsx
|
||||||
msgid "Replying to {replyName}"
|
msgid "Replying to {replyName}"
|
||||||
msgstr "Ответ на {replyName}"
|
msgstr "Ответ на {replyName}"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/composer.tsx
|
||||||
msgid "Replying to {replyName}: “{replyQuote}”"
|
msgid "Replying to {replyName}: “{replyQuote}”"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@ -3937,7 +3941,7 @@ msgstr "Сброс…"
|
|||||||
msgid "Restart to update"
|
msgid "Restart to update"
|
||||||
msgstr "Перезапустить для обновления"
|
msgstr "Перезапустить для обновления"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/archived-section.tsx
|
||||||
msgid "Restore"
|
msgid "Restore"
|
||||||
msgstr "Восстановить"
|
msgstr "Восстановить"
|
||||||
|
|
||||||
@ -4142,7 +4146,7 @@ msgid "Searching…"
|
|||||||
msgstr "Поиск…"
|
msgstr "Поиск…"
|
||||||
|
|
||||||
#. placeholder {0}: group.title
|
#. placeholder {0}: group.title
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/sidebar-group-header.tsx
|
||||||
msgid "Select {0}"
|
msgid "Select {0}"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@ -4150,7 +4154,7 @@ msgstr ""
|
|||||||
msgid "Self-hosted (better-auth)"
|
msgid "Self-hosted (better-auth)"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/composer.tsx
|
||||||
#: src/pages/shell/message-cards.tsx
|
#: src/pages/shell/message-cards.tsx
|
||||||
msgid "Send"
|
msgid "Send"
|
||||||
msgstr "Отправить"
|
msgstr "Отправить"
|
||||||
@ -4201,21 +4205,22 @@ msgid "Server URL"
|
|||||||
msgstr "URL-адрес сервера"
|
msgstr "URL-адрес сервера"
|
||||||
|
|
||||||
#: src/components/stage/StageVoiceEntry.tsx
|
#: src/components/stage/StageVoiceEntry.tsx
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/composer.tsx
|
||||||
msgid "Set up voice"
|
msgid "Set up voice"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/MessagingSettingsOverlay.tsx
|
#: src/pages/MessagingSettingsOverlay.tsx
|
||||||
#: src/pages/SettingsOverlay.tsx
|
#: src/pages/SettingsOverlay.tsx
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/side-panel-header.tsx
|
||||||
|
#: src/pages/shell/user-menu.tsx
|
||||||
msgid "Settings"
|
msgid "Settings"
|
||||||
msgstr "Настройки"
|
msgstr "Настройки"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/composer.tsx
|
||||||
msgid "Settings: General"
|
msgid "Settings: General"
|
||||||
msgstr "Настройки: Общие"
|
msgstr "Настройки: Общие"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/composer.tsx
|
||||||
msgid "Settings: Usage"
|
msgid "Settings: Usage"
|
||||||
msgstr "Настройки: Использование"
|
msgstr "Настройки: Использование"
|
||||||
|
|
||||||
@ -4259,10 +4264,11 @@ msgid "Show all {0}"
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/Shell.tsx
|
||||||
|
#: src/pages/shell/sidebar-toggle-buttons.tsx
|
||||||
msgid "Show bots"
|
msgid "Show bots"
|
||||||
msgstr "Показать ботов"
|
msgstr "Показать ботов"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/side-panel-header.tsx
|
||||||
msgid "Show computer"
|
msgid "Show computer"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@ -4278,7 +4284,7 @@ msgstr "Показать ещё"
|
|||||||
msgid "Show password"
|
msgid "Show password"
|
||||||
msgstr "Показать пароль"
|
msgstr "Показать пароль"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/side-panel-header.tsx
|
||||||
msgid "Show settings"
|
msgid "Show settings"
|
||||||
msgstr "Показать настройки"
|
msgstr "Показать настройки"
|
||||||
|
|
||||||
@ -4307,7 +4313,7 @@ msgid "Sketching the blueprint…"
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#. placeholder {0}: skill.name
|
#. placeholder {0}: skill.name
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/composer.tsx
|
||||||
msgid "Skill {0}"
|
msgid "Skill {0}"
|
||||||
msgstr "Навык {0}"
|
msgstr "Навык {0}"
|
||||||
|
|
||||||
@ -4319,7 +4325,7 @@ msgstr "Навыки"
|
|||||||
#: src/components/onboarding/OnboardingScanStep.tsx
|
#: src/components/onboarding/OnboardingScanStep.tsx
|
||||||
#: src/components/onboarding/OnboardingVoiceStep.tsx
|
#: src/components/onboarding/OnboardingVoiceStep.tsx
|
||||||
#: src/lib/onboarding-copy.ts
|
#: src/lib/onboarding-copy.ts
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/computer-screen.tsx
|
||||||
msgid "Skip"
|
msgid "Skip"
|
||||||
msgstr "Пропустить"
|
msgstr "Пропустить"
|
||||||
|
|
||||||
@ -4373,11 +4379,11 @@ msgstr "Пространство по умолчанию"
|
|||||||
msgid "Spaces"
|
msgid "Spaces"
|
||||||
msgstr "Пространства"
|
msgstr "Пространства"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "Speak"
|
msgid "Speak"
|
||||||
msgstr "Озвучить"
|
msgstr "Озвучить"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "Speak this reply"
|
msgid "Speak this reply"
|
||||||
msgstr "Озвучить этот ответ"
|
msgstr "Озвучить этот ответ"
|
||||||
|
|
||||||
@ -4431,15 +4437,15 @@ msgstr "Начать запись"
|
|||||||
msgid "Start talking"
|
msgid "Start talking"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "Start the conversation — {activeName} is on stage above."
|
msgid "Start the conversation — {activeName} is on stage above."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "Start the conversation."
|
msgid "Start the conversation."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/composer.tsx
|
||||||
msgid "Start voice conversation"
|
msgid "Start voice conversation"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@ -4466,11 +4472,13 @@ msgid "Steps"
|
|||||||
msgstr "Шаги"
|
msgstr "Шаги"
|
||||||
|
|
||||||
#: src/components/browser/InAppBrowser.tsx
|
#: src/components/browser/InAppBrowser.tsx
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/composer.tsx
|
||||||
|
#: src/pages/shell/fullscreen-computer-overlay.tsx
|
||||||
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "Stop"
|
msgid "Stop"
|
||||||
msgstr "Остановить"
|
msgstr "Остановить"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "Stop speaking"
|
msgid "Stop speaking"
|
||||||
msgstr "Остановить озвучивание"
|
msgstr "Остановить озвучивание"
|
||||||
|
|
||||||
@ -4500,7 +4508,7 @@ msgstr ""
|
|||||||
msgid "Stronger together — {0} specialists"
|
msgid "Stronger together — {0} specialists"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "subagent"
|
msgid "subagent"
|
||||||
msgstr "субагент"
|
msgstr "субагент"
|
||||||
|
|
||||||
@ -4565,7 +4573,7 @@ msgstr "Обучение в процессе. Прекратите обучен
|
|||||||
msgid "Team"
|
msgid "Team"
|
||||||
msgstr "Команда"
|
msgstr "Команда"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/computer-screen.tsx
|
||||||
msgid "Team Computer"
|
msgid "Team Computer"
|
||||||
msgstr "Командный компьютер"
|
msgstr "Командный компьютер"
|
||||||
|
|
||||||
@ -4606,7 +4614,7 @@ msgstr "Выбранный поставщик памяти недоступен
|
|||||||
msgid "Thinking"
|
msgid "Thinking"
|
||||||
msgstr "рассуждение"
|
msgstr "рассуждение"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/computer-screen.tsx
|
||||||
msgid "This bot runs on this computer, not a Linux desktop. Shell and files use your home folder."
|
msgid "This bot runs on this computer, not a Linux desktop. Shell and files use your home folder."
|
||||||
msgstr "Этот бот работает на этом компьютере, а не на рабочем столе Linux. Оболочка и файлы используют вашу домашнюю папку."
|
msgstr "Этот бот работает на этом компьютере, а не на рабочем столе Linux. Оболочка и файлы используют вашу домашнюю папку."
|
||||||
|
|
||||||
@ -4713,7 +4721,7 @@ msgid "Transcribe"
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/voice/VoiceStage.tsx
|
#: src/components/voice/VoiceStage.tsx
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "Transcript"
|
msgid "Transcript"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@ -4836,7 +4844,7 @@ msgstr "Загрузить"
|
|||||||
|
|
||||||
#: src/pages/AccountSettingsOverlay.tsx
|
#: src/pages/AccountSettingsOverlay.tsx
|
||||||
#: src/pages/SettingsOverlay.tsx
|
#: src/pages/SettingsOverlay.tsx
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/user-menu.tsx
|
||||||
msgid "Usage"
|
msgid "Usage"
|
||||||
msgstr "Использование"
|
msgstr "Использование"
|
||||||
|
|
||||||
@ -4877,8 +4885,8 @@ msgid "Video workflow"
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/SettingsOverlay.tsx
|
#: src/pages/SettingsOverlay.tsx
|
||||||
#: src/pages/Shell.tsx
|
|
||||||
#: src/pages/shell/bot-panel.tsx
|
#: src/pages/shell/bot-panel.tsx
|
||||||
|
#: src/pages/shell/composer.tsx
|
||||||
#: src/pages/VoiceSettingsOverlay.tsx
|
#: src/pages/VoiceSettingsOverlay.tsx
|
||||||
msgid "Voice"
|
msgid "Voice"
|
||||||
msgstr "Голос"
|
msgstr "Голос"
|
||||||
@ -5074,7 +5082,7 @@ msgstr "Выполняется…"
|
|||||||
msgid "Working…"
|
msgid "Working…"
|
||||||
msgstr "Выполняется…"
|
msgstr "Выполняется…"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/roster-format.ts
|
||||||
msgid "Yesterday"
|
msgid "Yesterday"
|
||||||
msgstr "Вчера"
|
msgstr "Вчера"
|
||||||
|
|
||||||
@ -5092,7 +5100,7 @@ msgstr "Вы можете закрыть эту вкладку, если она
|
|||||||
msgid "You can close this window."
|
msgid "You can close this window."
|
||||||
msgstr "Вы можете закрыть это окно."
|
msgstr "Вы можете закрыть это окно."
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/fullscreen-computer-overlay.tsx
|
||||||
msgid "You have control"
|
msgid "You have control"
|
||||||
msgstr "Вы управляете"
|
msgstr "Вы управляете"
|
||||||
|
|
||||||
|
|||||||
@ -14,7 +14,7 @@ msgstr ""
|
|||||||
"Plural-Forms: \n"
|
"Plural-Forms: \n"
|
||||||
"X-Generator: @lingui/cli\n"
|
"X-Generator: @lingui/cli\n"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/roster-rows.tsx
|
||||||
msgid " (unread)"
|
msgid " (unread)"
|
||||||
msgstr " (okunmadı)"
|
msgstr " (okunmadı)"
|
||||||
|
|
||||||
@ -126,22 +126,22 @@ msgid "{0}, {label}"
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#. placeholder {0}: item.chat.name
|
#. placeholder {0}: item.chat.name
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/roster-rows.tsx
|
||||||
msgid "{0}, 1:1 conversation"
|
msgid "{0}, 1:1 conversation"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#. placeholder {0}: item.chat.name
|
#. placeholder {0}: item.chat.name
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/roster-rows.tsx
|
||||||
msgid "{0}, group conversation"
|
msgid "{0}, group conversation"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#. placeholder {0}: item.chat.name
|
#. placeholder {0}: item.chat.name
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/roster-rows.tsx
|
||||||
msgid "{0}, main conversation"
|
msgid "{0}, main conversation"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#. placeholder {0}: active.name
|
#. placeholder {0}: active.name
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/computer-panel-preview.tsx
|
||||||
msgid "{0}'s screen"
|
msgid "{0}'s screen"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@ -210,7 +210,7 @@ msgstr ""
|
|||||||
msgid "{botName} watches the tape…"
|
msgid "{botName} watches the tape…"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/computer-screen.tsx
|
||||||
msgid "{botName}’s computer"
|
msgid "{botName}’s computer"
|
||||||
msgstr "{botName} adlı botun bilgisayarı"
|
msgstr "{botName} adlı botun bilgisayarı"
|
||||||
|
|
||||||
@ -277,7 +277,7 @@ msgstr "{title}, {label}"
|
|||||||
msgid "{toolCount, plural, one {# tool} other {# tools}}"
|
msgid "{toolCount, plural, one {# tool} other {# tools}}"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "{workingBotName} is working"
|
msgid "{workingBotName} is working"
|
||||||
msgstr "{workingBotName} çalışıyor"
|
msgstr "{workingBotName} çalışıyor"
|
||||||
|
|
||||||
@ -339,6 +339,7 @@ msgstr "İşlem onayları"
|
|||||||
#. placeholder {0}: sectionMenu.section.name
|
#. placeholder {0}: sectionMenu.section.name
|
||||||
#: src/pages/BotContextMenu.tsx
|
#: src/pages/BotContextMenu.tsx
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/Shell.tsx
|
||||||
|
#: src/pages/shell/sidebar-group-header.tsx
|
||||||
msgid "Actions for {0}"
|
msgid "Actions for {0}"
|
||||||
msgstr "{0} için işlemler"
|
msgstr "{0} için işlemler"
|
||||||
|
|
||||||
@ -354,7 +355,7 @@ msgstr ""
|
|||||||
msgid "Active model"
|
msgid "Active model"
|
||||||
msgstr "Etkin model"
|
msgstr "Etkin model"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/sidebar-header.tsx
|
||||||
msgid "Activity"
|
msgid "Activity"
|
||||||
msgstr "Etkinlik"
|
msgstr "Etkinlik"
|
||||||
|
|
||||||
@ -643,15 +644,15 @@ msgstr "Agent'ının bu sunucunun araçlarını kullanabilmesi için sunucuyu on
|
|||||||
msgid "Archive"
|
msgid "Archive"
|
||||||
msgstr "Arşivle"
|
msgstr "Arşivle"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "archived"
|
msgid "archived"
|
||||||
msgstr "arşivlendi"
|
msgstr "arşivlendi"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/archived-section.tsx
|
||||||
msgid "Archived"
|
msgid "Archived"
|
||||||
msgstr "Arşivlendi"
|
msgstr "Arşivlendi"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "Archived. Chat, memory, and files kept."
|
msgid "Archived. Chat, memory, and files kept."
|
||||||
msgstr "Arşivlendi. Sohbet, hafıza ve dosyalar korundu."
|
msgstr "Arşivlendi. Sohbet, hafıza ve dosyalar korundu."
|
||||||
|
|
||||||
@ -711,11 +712,11 @@ msgstr "saat {0}"
|
|||||||
msgid "at {timeSelect}"
|
msgid "at {timeSelect}"
|
||||||
msgstr "saat {timeSelect}"
|
msgstr "saat {timeSelect}"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/composer.tsx
|
||||||
msgid "Attach file"
|
msgid "Attach file"
|
||||||
msgstr "Dosya ekle"
|
msgstr "Dosya ekle"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/message-preview.ts
|
||||||
msgid "Attachment"
|
msgid "Attachment"
|
||||||
msgstr "Ek"
|
msgstr "Ek"
|
||||||
|
|
||||||
@ -788,7 +789,7 @@ msgstr "Bearer token"
|
|||||||
msgid "Blocked in your browser settings"
|
msgid "Blocked in your browser settings"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/computer-screen.tsx
|
||||||
msgid "Booting live desktop…"
|
msgid "Booting live desktop…"
|
||||||
msgstr "Canlı masaüstü başlatılıyor…"
|
msgstr "Canlı masaüstü başlatılıyor…"
|
||||||
|
|
||||||
@ -797,7 +798,7 @@ msgstr "Canlı masaüstü başlatılıyor…"
|
|||||||
msgid "Booting up {0}’s computer"
|
msgid "Booting up {0}’s computer"
|
||||||
msgstr "{0} adlı botun bilgisayarı başlatılıyor"
|
msgstr "{0} adlı botun bilgisayarı başlatılıyor"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "bot"
|
msgid "bot"
|
||||||
msgstr "bot"
|
msgstr "bot"
|
||||||
|
|
||||||
@ -812,11 +813,11 @@ msgstr "Bot"
|
|||||||
msgid "Bot"
|
msgid "Bot"
|
||||||
msgstr "Bot"
|
msgstr "Bot"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/fullscreen-computer-overlay.tsx
|
||||||
msgid "Bot screen"
|
msgid "Bot screen"
|
||||||
msgstr "Bot ekranı"
|
msgstr "Bot ekranı"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/computer-panel-preview.tsx
|
||||||
msgid "Bot screen preview"
|
msgid "Bot screen preview"
|
||||||
msgstr "Bot ekranı önizlemesi"
|
msgstr "Bot ekranı önizlemesi"
|
||||||
|
|
||||||
@ -828,7 +829,7 @@ msgstr ""
|
|||||||
msgid "Bots act without asking by default. Add an exception only when you want to review a type of action first."
|
msgid "Bots act without asking by default. Add an exception only when you want to review a type of action first."
|
||||||
msgstr "Botlar varsayılan olarak sormadan hareket eder. Yalnızca belirli bir işlem türünü önce incelemek istediğinde istisna ekle."
|
msgstr "Botlar varsayılan olarak sormadan hareket eder. Yalnızca belirli bir işlem türünü önce incelemek istediğinde istisna ekle."
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "Bots are working"
|
msgid "Bots are working"
|
||||||
msgstr "Botlar çalışıyor"
|
msgstr "Botlar çalışıyor"
|
||||||
|
|
||||||
@ -889,7 +890,7 @@ msgstr "Yeni botu iptal et"
|
|||||||
msgid "Cancel new group"
|
msgid "Cancel new group"
|
||||||
msgstr "Yeni grubu iptal et"
|
msgstr "Yeni grubu iptal et"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/composer.tsx
|
||||||
msgid "Cancel reply"
|
msgid "Cancel reply"
|
||||||
msgstr "Yanıtı iptal et"
|
msgstr "Yanıtı iptal et"
|
||||||
|
|
||||||
@ -946,7 +947,7 @@ msgstr ""
|
|||||||
msgid "Chat history"
|
msgid "Chat history"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/composer.tsx
|
||||||
msgid "Chat Settings"
|
msgid "Chat Settings"
|
||||||
msgstr "Sohbet Ayarları"
|
msgstr "Sohbet Ayarları"
|
||||||
|
|
||||||
@ -1088,7 +1089,7 @@ msgstr "Kapat"
|
|||||||
msgid "Close chart"
|
msgid "Close chart"
|
||||||
msgstr "Grafiği kapat"
|
msgstr "Grafiği kapat"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/fullscreen-computer-overlay.tsx
|
||||||
msgid "Close computer"
|
msgid "Close computer"
|
||||||
msgstr "Bilgisayarı kapat"
|
msgstr "Bilgisayarı kapat"
|
||||||
|
|
||||||
@ -1128,7 +1129,7 @@ msgstr "Gezinmeyi kapat"
|
|||||||
|
|
||||||
#: src/components/ArtifactPane.tsx
|
#: src/components/ArtifactPane.tsx
|
||||||
#: src/components/browser/InAppBrowser.tsx
|
#: src/components/browser/InAppBrowser.tsx
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/side-panel-header.tsx
|
||||||
msgid "Close panel"
|
msgid "Close panel"
|
||||||
msgstr "Paneli kapat"
|
msgstr "Paneli kapat"
|
||||||
|
|
||||||
@ -1159,7 +1160,7 @@ msgid "Coder"
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#. placeholder {0}: group.title
|
#. placeholder {0}: group.title
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/sidebar-group-header.tsx
|
||||||
msgid "Collapse {0}"
|
msgid "Collapse {0}"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@ -1192,24 +1193,24 @@ msgid "Composing a reply…"
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/SettingsOverlay.tsx
|
#: src/pages/SettingsOverlay.tsx
|
||||||
#: src/pages/Shell.tsx
|
|
||||||
#: src/pages/shell/bot-panel.tsx
|
#: src/pages/shell/bot-panel.tsx
|
||||||
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "Computer"
|
msgid "Computer"
|
||||||
msgstr "Bilgisayar"
|
msgstr "Bilgisayar"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/computer-screen.tsx
|
||||||
msgid "Computer failed to boot"
|
msgid "Computer failed to boot"
|
||||||
msgstr "Bilgisayar başlatılamadı"
|
msgstr "Bilgisayar başlatılamadı"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/fullscreen-computer-overlay.tsx
|
||||||
msgid "Computer is asleep"
|
msgid "Computer is asleep"
|
||||||
msgstr "Bilgisayar uykuda"
|
msgstr "Bilgisayar uykuda"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/computer-screen.tsx
|
||||||
msgid "Computer is asleep. Open it to wake."
|
msgid "Computer is asleep. Open it to wake."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/computer-screen.tsx
|
||||||
msgid "Computer is stopped"
|
msgid "Computer is stopped"
|
||||||
msgstr "Bilgisayar durduruldu"
|
msgstr "Bilgisayar durduruldu"
|
||||||
|
|
||||||
@ -1353,7 +1354,7 @@ msgstr ""
|
|||||||
msgid "Continue with email"
|
msgid "Continue with email"
|
||||||
msgstr "E-posta ile devam et"
|
msgstr "E-posta ile devam et"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "Conversation record"
|
msgid "Conversation record"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@ -1361,11 +1362,11 @@ msgstr ""
|
|||||||
msgid "Conversations"
|
msgid "Conversations"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "Copy"
|
msgid "Copy"
|
||||||
msgstr "Kopyala"
|
msgstr "Kopyala"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "Copy reply"
|
msgid "Copy reply"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@ -1747,9 +1748,9 @@ msgstr ""
|
|||||||
msgid "Couldn't update messaging settings"
|
msgid "Couldn't update messaging settings"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
|
||||||
#: src/pages/shell/bot-panel.tsx
|
#: src/pages/shell/bot-panel.tsx
|
||||||
#: src/pages/shell/dialogs.tsx
|
#: src/pages/shell/dialogs.tsx
|
||||||
|
#: src/pages/shell/sidebar-header.tsx
|
||||||
msgid "Create"
|
msgid "Create"
|
||||||
msgstr "Oluştur"
|
msgstr "Oluştur"
|
||||||
|
|
||||||
@ -1906,14 +1907,14 @@ msgstr "Varsayılan kapsam"
|
|||||||
#: src/pages/KnowledgeSection.tsx
|
#: src/pages/KnowledgeSection.tsx
|
||||||
#: src/pages/McpServersOverlay.tsx
|
#: src/pages/McpServersOverlay.tsx
|
||||||
#: src/pages/RoutineEditor.tsx
|
#: src/pages/RoutineEditor.tsx
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/archived-section.tsx
|
||||||
#: src/pages/shell/dialogs.tsx
|
#: src/pages/shell/dialogs.tsx
|
||||||
msgid "Delete"
|
msgid "Delete"
|
||||||
msgstr "Sil"
|
msgstr "Sil"
|
||||||
|
|
||||||
#. placeholder {0}: bot.name
|
#. placeholder {0}: bot.name
|
||||||
#. placeholder {0}: group.name
|
#. placeholder {0}: group.name
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/archived-section.tsx
|
||||||
msgid "Delete {0}"
|
msgid "Delete {0}"
|
||||||
msgstr "{0} sil"
|
msgstr "{0} sil"
|
||||||
|
|
||||||
@ -1943,7 +1944,7 @@ msgstr ""
|
|||||||
msgid "Delete space"
|
msgid "Delete space"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "deleted"
|
msgid "deleted"
|
||||||
msgstr "silindi"
|
msgstr "silindi"
|
||||||
|
|
||||||
@ -2013,7 +2014,7 @@ msgstr "Bağlantı kesiliyor…"
|
|||||||
msgid "Dismiss"
|
msgid "Dismiss"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/composer.tsx
|
||||||
msgid "Dismiss error"
|
msgid "Dismiss error"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@ -2111,7 +2112,7 @@ msgstr "Çoğalt"
|
|||||||
msgid "e.g. Hivenet Agent, Presales, Timesheets bot"
|
msgid "e.g. Hivenet Agent, Presales, Timesheets bot"
|
||||||
msgstr "örn. Hivenet Agent, Presales, puantaj botu"
|
msgstr "örn. Hivenet Agent, Presales, puantaj botu"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "Earlier message"
|
msgid "Earlier message"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@ -2222,7 +2223,7 @@ msgid "Expand"
|
|||||||
msgstr "Genişlet"
|
msgstr "Genişlet"
|
||||||
|
|
||||||
#. placeholder {0}: group.title
|
#. placeholder {0}: group.title
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/sidebar-group-header.tsx
|
||||||
msgid "Expand {0}"
|
msgid "Expand {0}"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@ -2404,6 +2405,7 @@ msgstr ""
|
|||||||
#: src/components/stage/OoStage.tsx
|
#: src/components/stage/OoStage.tsx
|
||||||
#: src/pages/MessagingSettingsOverlay.tsx
|
#: src/pages/MessagingSettingsOverlay.tsx
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/Shell.tsx
|
||||||
|
#: src/pages/shell/side-panel-header.tsx
|
||||||
msgid "Group"
|
msgid "Group"
|
||||||
msgstr "Grup"
|
msgstr "Grup"
|
||||||
|
|
||||||
@ -2528,7 +2530,7 @@ msgstr ""
|
|||||||
msgid "How to check"
|
msgid "How to check"
|
||||||
msgstr "Nasıl kontrol edilir"
|
msgstr "Nasıl kontrol edilir"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/computer-screen.tsx
|
||||||
msgid "I’m done"
|
msgid "I’m done"
|
||||||
msgstr "Bitirdim"
|
msgstr "Bitirdim"
|
||||||
|
|
||||||
@ -2635,11 +2637,11 @@ msgstr "Yalıtılmış"
|
|||||||
msgid "Its conversation, files, and routines will be permanently deleted. Bots it created stay in your list."
|
msgid "Its conversation, files, and routines will be permanently deleted. Bots it created stay in your list."
|
||||||
msgstr "Sohbeti, dosyaları ve rutinleri kalıcı olarak silinecek. Oluşturduğu botlar listende kalır."
|
msgstr "Sohbeti, dosyaları ve rutinleri kalıcı olarak silinecek. Oluşturduğu botlar listende kalır."
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "Jump to latest"
|
msgid "Jump to latest"
|
||||||
msgstr "En son mesaja git"
|
msgstr "En son mesaja git"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "Jump to replied message"
|
msgid "Jump to replied message"
|
||||||
msgstr "Yanıtlanan mesaja git"
|
msgstr "Yanıtlanan mesaja git"
|
||||||
|
|
||||||
@ -2726,7 +2728,7 @@ msgstr ""
|
|||||||
msgid "Listening — what's the story?"
|
msgid "Listening — what's the story?"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "Load earlier messages"
|
msgid "Load earlier messages"
|
||||||
msgstr "Önceki mesajları yükle"
|
msgstr "Önceki mesajları yükle"
|
||||||
|
|
||||||
@ -2779,7 +2781,7 @@ msgstr ""
|
|||||||
#: src/pages/HeuteBrief.tsx
|
#: src/pages/HeuteBrief.tsx
|
||||||
#: src/pages/IntegrationSetup.tsx
|
#: src/pages/IntegrationSetup.tsx
|
||||||
#: src/pages/PeerMessagesOverlay.tsx
|
#: src/pages/PeerMessagesOverlay.tsx
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "Loading…"
|
msgid "Loading…"
|
||||||
msgstr "Yükleniyor…"
|
msgstr "Yükleniyor…"
|
||||||
|
|
||||||
@ -2799,7 +2801,7 @@ msgstr ""
|
|||||||
msgid "Local Server Settings"
|
msgid "Local Server Settings"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/user-menu.tsx
|
||||||
msgid "Log out"
|
msgid "Log out"
|
||||||
msgstr "Çıkış yap"
|
msgstr "Çıkış yap"
|
||||||
|
|
||||||
@ -2926,7 +2928,7 @@ msgstr "Hafıza"
|
|||||||
msgid "Memory scope"
|
msgid "Memory scope"
|
||||||
msgstr "Hafıza kapsamı"
|
msgstr "Hafıza kapsamı"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/composer.tsx
|
||||||
msgid "Mentions"
|
msgid "Mentions"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@ -2939,11 +2941,12 @@ msgstr ""
|
|||||||
msgid "Message"
|
msgid "Message"
|
||||||
msgstr "Mesaj"
|
msgstr "Mesaj"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/composer.tsx
|
||||||
|
#: src/pages/shell/message-preview.ts
|
||||||
msgid "Message"
|
msgid "Message"
|
||||||
msgstr "Mesaj"
|
msgstr "Mesaj"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/composer.tsx
|
||||||
msgid "Message composer"
|
msgid "Message composer"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@ -2951,11 +2954,11 @@ msgstr ""
|
|||||||
msgid "Message event"
|
msgid "Message event"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "Message from {peer}"
|
msgid "Message from {peer}"
|
||||||
msgstr "{peer} botundan mesaj"
|
msgstr "{peer} botundan mesaj"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/composer.tsx
|
||||||
msgid "Message…"
|
msgid "Message…"
|
||||||
msgstr "Mesaj…"
|
msgstr "Mesaj…"
|
||||||
|
|
||||||
@ -2981,7 +2984,7 @@ msgstr "Minimal"
|
|||||||
msgid "Minimize"
|
msgid "Minimize"
|
||||||
msgstr "Küçült"
|
msgstr "Küçült"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/sidebar-toggle-buttons.tsx
|
||||||
msgid "Minimize bots"
|
msgid "Minimize bots"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@ -3038,7 +3041,7 @@ msgstr "Sunucudan gelen modeller"
|
|||||||
msgid "Monthly"
|
msgid "Monthly"
|
||||||
msgstr "Aylık"
|
msgstr "Aylık"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "More"
|
msgid "More"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@ -3104,7 +3107,8 @@ msgstr ""
|
|||||||
#: src/components/MainInbox.tsx
|
#: src/components/MainInbox.tsx
|
||||||
#: src/pages/ActivityList.tsx
|
#: src/pages/ActivityList.tsx
|
||||||
#: src/pages/HeuteBrief.tsx
|
#: src/pages/HeuteBrief.tsx
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/fullscreen-computer-overlay.tsx
|
||||||
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "Needs you"
|
msgid "Needs you"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@ -3397,12 +3401,12 @@ msgid "Only file and folder names are read."
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/ScratchpadSection.tsx
|
#: src/pages/ScratchpadSection.tsx
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/computer-panel-preview.tsx
|
||||||
msgid "Open"
|
msgid "Open"
|
||||||
msgstr "Aç"
|
msgstr "Aç"
|
||||||
|
|
||||||
#. placeholder {0}: group.title
|
#. placeholder {0}: group.title
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/sidebar-group-header.tsx
|
||||||
msgid "Open {0}"
|
msgid "Open {0}"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@ -3418,11 +3422,11 @@ msgstr ""
|
|||||||
msgid "Open in browser"
|
msgid "Open in browser"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/computer-panel-preview.tsx
|
||||||
msgid "Open in full window"
|
msgid "Open in full window"
|
||||||
msgstr "Tam pencerede aç"
|
msgstr "Tam pencerede aç"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/sidebar-toggle-buttons.tsx
|
||||||
msgid "Open navigation"
|
msgid "Open navigation"
|
||||||
msgstr "Gezinmeyi aç"
|
msgstr "Gezinmeyi aç"
|
||||||
|
|
||||||
@ -3438,7 +3442,7 @@ msgstr "Açık işler"
|
|||||||
msgid "OpenAI-compatible server URL"
|
msgid "OpenAI-compatible server URL"
|
||||||
msgstr "OpenAI uyumlu sunucu URL'si"
|
msgstr "OpenAI uyumlu sunucu URL'si"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "Opened its thread."
|
msgid "Opened its thread."
|
||||||
msgstr "Sohbeti açıldı."
|
msgstr "Sohbeti açıldı."
|
||||||
|
|
||||||
@ -3679,19 +3683,19 @@ msgstr ""
|
|||||||
msgid "Quiet hours start"
|
msgid "Quiet hours start"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "Quote"
|
msgid "Quote"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "React"
|
msgid "React"
|
||||||
msgstr "Tepki ver"
|
msgstr "Tepki ver"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "Reactions"
|
msgid "Reactions"
|
||||||
msgstr "Tepkiler"
|
msgstr "Tepkiler"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "Read aloud"
|
msgid "Read aloud"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@ -3796,7 +3800,7 @@ msgstr ""
|
|||||||
msgid "Region"
|
msgid "Region"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/computer-screen.tsx
|
||||||
msgid "Release"
|
msgid "Release"
|
||||||
msgstr "Bırak"
|
msgstr "Bırak"
|
||||||
|
|
||||||
@ -3820,7 +3824,7 @@ msgid "Remove"
|
|||||||
msgstr "Kaldır"
|
msgstr "Kaldır"
|
||||||
|
|
||||||
#. placeholder {0}: attachment.file.name
|
#. placeholder {0}: attachment.file.name
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/composer.tsx
|
||||||
msgid "Remove {0}"
|
msgid "Remove {0}"
|
||||||
msgstr "{0} kaldır"
|
msgstr "{0} kaldır"
|
||||||
|
|
||||||
@ -3829,7 +3833,7 @@ msgid "Remove Git event"
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#. placeholder {0}: mention.name
|
#. placeholder {0}: mention.name
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/composer.tsx
|
||||||
msgid "Remove mention {0}"
|
msgid "Remove mention {0}"
|
||||||
msgstr "{0} bahsini kaldır"
|
msgstr "{0} bahsini kaldır"
|
||||||
|
|
||||||
@ -3842,7 +3846,7 @@ msgid "Remove schedule"
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#. placeholder {0}: selectedSkill.name
|
#. placeholder {0}: selectedSkill.name
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/composer.tsx
|
||||||
msgid "Remove skill {0}"
|
msgid "Remove skill {0}"
|
||||||
msgstr "{0} becerisini kaldır"
|
msgstr "{0} becerisini kaldır"
|
||||||
|
|
||||||
@ -3850,7 +3854,7 @@ msgstr "{0} becerisini kaldır"
|
|||||||
msgid "Remove webhook"
|
msgid "Remove webhook"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "Removed with chat, computer, and memory."
|
msgid "Removed with chat, computer, and memory."
|
||||||
msgstr "Sohbeti, bilgisayarı ve hafızasıyla birlikte kaldırıldı."
|
msgstr "Sohbeti, bilgisayarı ve hafızasıyla birlikte kaldırıldı."
|
||||||
|
|
||||||
@ -3883,15 +3887,15 @@ msgstr "API anahtarını değiştir"
|
|||||||
msgid "Replace key"
|
msgid "Replace key"
|
||||||
msgstr "Anahtarı değiştir"
|
msgstr "Anahtarı değiştir"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "Reply"
|
msgid "Reply"
|
||||||
msgstr "Yanıtla"
|
msgstr "Yanıtla"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/composer.tsx
|
||||||
msgid "Replying to {replyName}"
|
msgid "Replying to {replyName}"
|
||||||
msgstr "{replyName} yanıtlanıyor"
|
msgstr "{replyName} yanıtlanıyor"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/composer.tsx
|
||||||
msgid "Replying to {replyName}: “{replyQuote}”"
|
msgid "Replying to {replyName}: “{replyQuote}”"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@ -3937,7 +3941,7 @@ msgstr ""
|
|||||||
msgid "Restart to update"
|
msgid "Restart to update"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/archived-section.tsx
|
||||||
msgid "Restore"
|
msgid "Restore"
|
||||||
msgstr "Geri yükle"
|
msgstr "Geri yükle"
|
||||||
|
|
||||||
@ -4142,7 +4146,7 @@ msgid "Searching…"
|
|||||||
msgstr "Aranıyor…"
|
msgstr "Aranıyor…"
|
||||||
|
|
||||||
#. placeholder {0}: group.title
|
#. placeholder {0}: group.title
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/sidebar-group-header.tsx
|
||||||
msgid "Select {0}"
|
msgid "Select {0}"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@ -4150,7 +4154,7 @@ msgstr ""
|
|||||||
msgid "Self-hosted (better-auth)"
|
msgid "Self-hosted (better-auth)"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/composer.tsx
|
||||||
#: src/pages/shell/message-cards.tsx
|
#: src/pages/shell/message-cards.tsx
|
||||||
msgid "Send"
|
msgid "Send"
|
||||||
msgstr "Gönder"
|
msgstr "Gönder"
|
||||||
@ -4201,21 +4205,22 @@ msgid "Server URL"
|
|||||||
msgstr "Sunucu URL'si"
|
msgstr "Sunucu URL'si"
|
||||||
|
|
||||||
#: src/components/stage/StageVoiceEntry.tsx
|
#: src/components/stage/StageVoiceEntry.tsx
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/composer.tsx
|
||||||
msgid "Set up voice"
|
msgid "Set up voice"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/MessagingSettingsOverlay.tsx
|
#: src/pages/MessagingSettingsOverlay.tsx
|
||||||
#: src/pages/SettingsOverlay.tsx
|
#: src/pages/SettingsOverlay.tsx
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/side-panel-header.tsx
|
||||||
|
#: src/pages/shell/user-menu.tsx
|
||||||
msgid "Settings"
|
msgid "Settings"
|
||||||
msgstr "Ayarlar"
|
msgstr "Ayarlar"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/composer.tsx
|
||||||
msgid "Settings: General"
|
msgid "Settings: General"
|
||||||
msgstr "Ayarlar: Genel"
|
msgstr "Ayarlar: Genel"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/composer.tsx
|
||||||
msgid "Settings: Usage"
|
msgid "Settings: Usage"
|
||||||
msgstr "Ayarlar: Kullanım"
|
msgstr "Ayarlar: Kullanım"
|
||||||
|
|
||||||
@ -4259,10 +4264,11 @@ msgid "Show all {0}"
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/Shell.tsx
|
||||||
|
#: src/pages/shell/sidebar-toggle-buttons.tsx
|
||||||
msgid "Show bots"
|
msgid "Show bots"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/side-panel-header.tsx
|
||||||
msgid "Show computer"
|
msgid "Show computer"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@ -4278,7 +4284,7 @@ msgstr "Daha fazla göster"
|
|||||||
msgid "Show password"
|
msgid "Show password"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/side-panel-header.tsx
|
||||||
msgid "Show settings"
|
msgid "Show settings"
|
||||||
msgstr "Ayarları göster"
|
msgstr "Ayarları göster"
|
||||||
|
|
||||||
@ -4307,7 +4313,7 @@ msgid "Sketching the blueprint…"
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#. placeholder {0}: skill.name
|
#. placeholder {0}: skill.name
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/composer.tsx
|
||||||
msgid "Skill {0}"
|
msgid "Skill {0}"
|
||||||
msgstr "Beceri: {0}"
|
msgstr "Beceri: {0}"
|
||||||
|
|
||||||
@ -4319,7 +4325,7 @@ msgstr "Beceriler"
|
|||||||
#: src/components/onboarding/OnboardingScanStep.tsx
|
#: src/components/onboarding/OnboardingScanStep.tsx
|
||||||
#: src/components/onboarding/OnboardingVoiceStep.tsx
|
#: src/components/onboarding/OnboardingVoiceStep.tsx
|
||||||
#: src/lib/onboarding-copy.ts
|
#: src/lib/onboarding-copy.ts
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/computer-screen.tsx
|
||||||
msgid "Skip"
|
msgid "Skip"
|
||||||
msgstr "Atla"
|
msgstr "Atla"
|
||||||
|
|
||||||
@ -4373,11 +4379,11 @@ msgstr "Alan varsayılanı"
|
|||||||
msgid "Spaces"
|
msgid "Spaces"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "Speak"
|
msgid "Speak"
|
||||||
msgstr "Seslendir"
|
msgstr "Seslendir"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "Speak this reply"
|
msgid "Speak this reply"
|
||||||
msgstr "Bu yanıtı seslendir"
|
msgstr "Bu yanıtı seslendir"
|
||||||
|
|
||||||
@ -4431,15 +4437,15 @@ msgstr "Kaydı başlat"
|
|||||||
msgid "Start talking"
|
msgid "Start talking"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "Start the conversation — {activeName} is on stage above."
|
msgid "Start the conversation — {activeName} is on stage above."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "Start the conversation."
|
msgid "Start the conversation."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/composer.tsx
|
||||||
msgid "Start voice conversation"
|
msgid "Start voice conversation"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@ -4466,11 +4472,13 @@ msgid "Steps"
|
|||||||
msgstr "Adımlar"
|
msgstr "Adımlar"
|
||||||
|
|
||||||
#: src/components/browser/InAppBrowser.tsx
|
#: src/components/browser/InAppBrowser.tsx
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/composer.tsx
|
||||||
|
#: src/pages/shell/fullscreen-computer-overlay.tsx
|
||||||
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "Stop"
|
msgid "Stop"
|
||||||
msgstr "Durdur"
|
msgstr "Durdur"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "Stop speaking"
|
msgid "Stop speaking"
|
||||||
msgstr "Seslendirmeyi durdur"
|
msgstr "Seslendirmeyi durdur"
|
||||||
|
|
||||||
@ -4500,7 +4508,7 @@ msgstr ""
|
|||||||
msgid "Stronger together — {0} specialists"
|
msgid "Stronger together — {0} specialists"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "subagent"
|
msgid "subagent"
|
||||||
msgstr "alt ajan"
|
msgstr "alt ajan"
|
||||||
|
|
||||||
@ -4565,7 +4573,7 @@ msgstr "Öğretme sürüyor. Yeni mesaj göndermeden önce öğretmeyi durdur."
|
|||||||
msgid "Team"
|
msgid "Team"
|
||||||
msgstr "Takım"
|
msgstr "Takım"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/computer-screen.tsx
|
||||||
msgid "Team Computer"
|
msgid "Team Computer"
|
||||||
msgstr "Takım Bilgisayarı"
|
msgstr "Takım Bilgisayarı"
|
||||||
|
|
||||||
@ -4606,7 +4614,7 @@ msgstr "Seçilen hafıza sağlayıcısı bu sürümde kullanılamıyor."
|
|||||||
msgid "Thinking"
|
msgid "Thinking"
|
||||||
msgstr "Düşünüyor"
|
msgstr "Düşünüyor"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/computer-screen.tsx
|
||||||
msgid "This bot runs on this computer, not a Linux desktop. Shell and files use your home folder."
|
msgid "This bot runs on this computer, not a Linux desktop. Shell and files use your home folder."
|
||||||
msgstr "Bu bot bir Linux masaüstünde değil, bu bilgisayarda çalışır. Kabuk ve dosyalar senin kullanıcı klasörünü kullanır."
|
msgstr "Bu bot bir Linux masaüstünde değil, bu bilgisayarda çalışır. Kabuk ve dosyalar senin kullanıcı klasörünü kullanır."
|
||||||
|
|
||||||
@ -4713,7 +4721,7 @@ msgid "Transcribe"
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/voice/VoiceStage.tsx
|
#: src/components/voice/VoiceStage.tsx
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "Transcript"
|
msgid "Transcript"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@ -4836,7 +4844,7 @@ msgstr "Yükle"
|
|||||||
|
|
||||||
#: src/pages/AccountSettingsOverlay.tsx
|
#: src/pages/AccountSettingsOverlay.tsx
|
||||||
#: src/pages/SettingsOverlay.tsx
|
#: src/pages/SettingsOverlay.tsx
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/user-menu.tsx
|
||||||
msgid "Usage"
|
msgid "Usage"
|
||||||
msgstr "Kullanım"
|
msgstr "Kullanım"
|
||||||
|
|
||||||
@ -4877,8 +4885,8 @@ msgid "Video workflow"
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/SettingsOverlay.tsx
|
#: src/pages/SettingsOverlay.tsx
|
||||||
#: src/pages/Shell.tsx
|
|
||||||
#: src/pages/shell/bot-panel.tsx
|
#: src/pages/shell/bot-panel.tsx
|
||||||
|
#: src/pages/shell/composer.tsx
|
||||||
#: src/pages/VoiceSettingsOverlay.tsx
|
#: src/pages/VoiceSettingsOverlay.tsx
|
||||||
msgid "Voice"
|
msgid "Voice"
|
||||||
msgstr "Ses"
|
msgstr "Ses"
|
||||||
@ -5074,7 +5082,7 @@ msgstr "Çalışıyor…"
|
|||||||
msgid "Working…"
|
msgid "Working…"
|
||||||
msgstr "Çalışıyor…"
|
msgstr "Çalışıyor…"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/roster-format.ts
|
||||||
msgid "Yesterday"
|
msgid "Yesterday"
|
||||||
msgstr "Dün"
|
msgstr "Dün"
|
||||||
|
|
||||||
@ -5092,7 +5100,7 @@ msgstr "Otomatik yönlendirilmezsen bu sekmeyi kapatabilirsin."
|
|||||||
msgid "You can close this window."
|
msgid "You can close this window."
|
||||||
msgstr "Bu pencereyi kapatabilirsin."
|
msgstr "Bu pencereyi kapatabilirsin."
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/fullscreen-computer-overlay.tsx
|
||||||
msgid "You have control"
|
msgid "You have control"
|
||||||
msgstr "Kontrol sende"
|
msgstr "Kontrol sende"
|
||||||
|
|
||||||
|
|||||||
@ -14,7 +14,7 @@ msgstr ""
|
|||||||
"Plural-Forms: \n"
|
"Plural-Forms: \n"
|
||||||
"X-Generator: @lingui/cli\n"
|
"X-Generator: @lingui/cli\n"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/roster-rows.tsx
|
||||||
msgid " (unread)"
|
msgid " (unread)"
|
||||||
msgstr "(未读)"
|
msgstr "(未读)"
|
||||||
|
|
||||||
@ -126,22 +126,22 @@ msgid "{0}, {label}"
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#. placeholder {0}: item.chat.name
|
#. placeholder {0}: item.chat.name
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/roster-rows.tsx
|
||||||
msgid "{0}, 1:1 conversation"
|
msgid "{0}, 1:1 conversation"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#. placeholder {0}: item.chat.name
|
#. placeholder {0}: item.chat.name
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/roster-rows.tsx
|
||||||
msgid "{0}, group conversation"
|
msgid "{0}, group conversation"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#. placeholder {0}: item.chat.name
|
#. placeholder {0}: item.chat.name
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/roster-rows.tsx
|
||||||
msgid "{0}, main conversation"
|
msgid "{0}, main conversation"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#. placeholder {0}: active.name
|
#. placeholder {0}: active.name
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/computer-panel-preview.tsx
|
||||||
msgid "{0}'s screen"
|
msgid "{0}'s screen"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@ -210,7 +210,7 @@ msgstr ""
|
|||||||
msgid "{botName} watches the tape…"
|
msgid "{botName} watches the tape…"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/computer-screen.tsx
|
||||||
msgid "{botName}’s computer"
|
msgid "{botName}’s computer"
|
||||||
msgstr "{botName} 的电脑"
|
msgstr "{botName} 的电脑"
|
||||||
|
|
||||||
@ -277,7 +277,7 @@ msgstr "{title},{label}"
|
|||||||
msgid "{toolCount, plural, one {# tool} other {# tools}}"
|
msgid "{toolCount, plural, one {# tool} other {# tools}}"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "{workingBotName} is working"
|
msgid "{workingBotName} is working"
|
||||||
msgstr "{workingBotName} 正在工作"
|
msgstr "{workingBotName} 正在工作"
|
||||||
|
|
||||||
@ -339,6 +339,7 @@ msgstr "操作确认"
|
|||||||
#. placeholder {0}: sectionMenu.section.name
|
#. placeholder {0}: sectionMenu.section.name
|
||||||
#: src/pages/BotContextMenu.tsx
|
#: src/pages/BotContextMenu.tsx
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/Shell.tsx
|
||||||
|
#: src/pages/shell/sidebar-group-header.tsx
|
||||||
msgid "Actions for {0}"
|
msgid "Actions for {0}"
|
||||||
msgstr "{0} 的操作"
|
msgstr "{0} 的操作"
|
||||||
|
|
||||||
@ -354,7 +355,7 @@ msgstr "启用"
|
|||||||
msgid "Active model"
|
msgid "Active model"
|
||||||
msgstr "当前模型"
|
msgstr "当前模型"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/sidebar-header.tsx
|
||||||
msgid "Activity"
|
msgid "Activity"
|
||||||
msgstr "动态"
|
msgstr "动态"
|
||||||
|
|
||||||
@ -643,15 +644,15 @@ msgstr "批准此服务器后,Agent 才能使用它的工具。"
|
|||||||
msgid "Archive"
|
msgid "Archive"
|
||||||
msgstr "归档"
|
msgstr "归档"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "archived"
|
msgid "archived"
|
||||||
msgstr "已归档"
|
msgstr "已归档"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/archived-section.tsx
|
||||||
msgid "Archived"
|
msgid "Archived"
|
||||||
msgstr "已归档"
|
msgstr "已归档"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "Archived. Chat, memory, and files kept."
|
msgid "Archived. Chat, memory, and files kept."
|
||||||
msgstr "已归档。对话、记忆和文件保留。"
|
msgstr "已归档。对话、记忆和文件保留。"
|
||||||
|
|
||||||
@ -711,11 +712,11 @@ msgstr "{0}"
|
|||||||
msgid "at {timeSelect}"
|
msgid "at {timeSelect}"
|
||||||
msgstr "{timeSelect}"
|
msgstr "{timeSelect}"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/composer.tsx
|
||||||
msgid "Attach file"
|
msgid "Attach file"
|
||||||
msgstr "附加文件"
|
msgstr "附加文件"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/message-preview.ts
|
||||||
msgid "Attachment"
|
msgid "Attachment"
|
||||||
msgstr "附件"
|
msgstr "附件"
|
||||||
|
|
||||||
@ -788,7 +789,7 @@ msgstr "Bearer token"
|
|||||||
msgid "Blocked in your browser settings"
|
msgid "Blocked in your browser settings"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/computer-screen.tsx
|
||||||
msgid "Booting live desktop…"
|
msgid "Booting live desktop…"
|
||||||
msgstr "正在启动实时桌面…"
|
msgstr "正在启动实时桌面…"
|
||||||
|
|
||||||
@ -797,7 +798,7 @@ msgstr "正在启动实时桌面…"
|
|||||||
msgid "Booting up {0}’s computer"
|
msgid "Booting up {0}’s computer"
|
||||||
msgstr "正在启动 {0} 的电脑"
|
msgstr "正在启动 {0} 的电脑"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "bot"
|
msgid "bot"
|
||||||
msgstr "Bot"
|
msgstr "Bot"
|
||||||
|
|
||||||
@ -812,11 +813,11 @@ msgstr "Bot"
|
|||||||
msgid "Bot"
|
msgid "Bot"
|
||||||
msgstr "Bot"
|
msgstr "Bot"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/fullscreen-computer-overlay.tsx
|
||||||
msgid "Bot screen"
|
msgid "Bot screen"
|
||||||
msgstr "Bot 屏幕"
|
msgstr "Bot 屏幕"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/computer-panel-preview.tsx
|
||||||
msgid "Bot screen preview"
|
msgid "Bot screen preview"
|
||||||
msgstr "Bot 屏幕预览"
|
msgstr "Bot 屏幕预览"
|
||||||
|
|
||||||
@ -828,7 +829,7 @@ msgstr "要关联的 Bot"
|
|||||||
msgid "Bots act without asking by default. Add an exception only when you want to review a type of action first."
|
msgid "Bots act without asking by default. Add an exception only when you want to review a type of action first."
|
||||||
msgstr "默认情况下 Bot 会直接执行。只有当你想先审核某类操作时,才添加例外。"
|
msgstr "默认情况下 Bot 会直接执行。只有当你想先审核某类操作时,才添加例外。"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "Bots are working"
|
msgid "Bots are working"
|
||||||
msgstr "Bot 正在工作"
|
msgstr "Bot 正在工作"
|
||||||
|
|
||||||
@ -889,7 +890,7 @@ msgstr "取消新建 Bot"
|
|||||||
msgid "Cancel new group"
|
msgid "Cancel new group"
|
||||||
msgstr "取消新建群组"
|
msgstr "取消新建群组"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/composer.tsx
|
||||||
msgid "Cancel reply"
|
msgid "Cancel reply"
|
||||||
msgstr "取消回复"
|
msgstr "取消回复"
|
||||||
|
|
||||||
@ -946,7 +947,7 @@ msgstr "聊天应用、群组频道和 Agent 连接。"
|
|||||||
msgid "Chat history"
|
msgid "Chat history"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/composer.tsx
|
||||||
msgid "Chat Settings"
|
msgid "Chat Settings"
|
||||||
msgstr "聊天设置"
|
msgstr "聊天设置"
|
||||||
|
|
||||||
@ -1088,7 +1089,7 @@ msgstr "关闭"
|
|||||||
msgid "Close chart"
|
msgid "Close chart"
|
||||||
msgstr "关闭图表"
|
msgstr "关闭图表"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/fullscreen-computer-overlay.tsx
|
||||||
msgid "Close computer"
|
msgid "Close computer"
|
||||||
msgstr "关闭电脑"
|
msgstr "关闭电脑"
|
||||||
|
|
||||||
@ -1128,7 +1129,7 @@ msgstr "关闭导航"
|
|||||||
|
|
||||||
#: src/components/ArtifactPane.tsx
|
#: src/components/ArtifactPane.tsx
|
||||||
#: src/components/browser/InAppBrowser.tsx
|
#: src/components/browser/InAppBrowser.tsx
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/side-panel-header.tsx
|
||||||
msgid "Close panel"
|
msgid "Close panel"
|
||||||
msgstr "关闭面板"
|
msgstr "关闭面板"
|
||||||
|
|
||||||
@ -1159,7 +1160,7 @@ msgid "Coder"
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#. placeholder {0}: group.title
|
#. placeholder {0}: group.title
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/sidebar-group-header.tsx
|
||||||
msgid "Collapse {0}"
|
msgid "Collapse {0}"
|
||||||
msgstr "折叠 {0}"
|
msgstr "折叠 {0}"
|
||||||
|
|
||||||
@ -1192,24 +1193,24 @@ msgid "Composing a reply…"
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/SettingsOverlay.tsx
|
#: src/pages/SettingsOverlay.tsx
|
||||||
#: src/pages/Shell.tsx
|
|
||||||
#: src/pages/shell/bot-panel.tsx
|
#: src/pages/shell/bot-panel.tsx
|
||||||
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "Computer"
|
msgid "Computer"
|
||||||
msgstr "电脑"
|
msgstr "电脑"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/computer-screen.tsx
|
||||||
msgid "Computer failed to boot"
|
msgid "Computer failed to boot"
|
||||||
msgstr "电脑启动失败"
|
msgstr "电脑启动失败"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/fullscreen-computer-overlay.tsx
|
||||||
msgid "Computer is asleep"
|
msgid "Computer is asleep"
|
||||||
msgstr "电脑已休眠"
|
msgstr "电脑已休眠"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/computer-screen.tsx
|
||||||
msgid "Computer is asleep. Open it to wake."
|
msgid "Computer is asleep. Open it to wake."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/computer-screen.tsx
|
||||||
msgid "Computer is stopped"
|
msgid "Computer is stopped"
|
||||||
msgstr "电脑已停止"
|
msgstr "电脑已停止"
|
||||||
|
|
||||||
@ -1353,7 +1354,7 @@ msgstr ""
|
|||||||
msgid "Continue with email"
|
msgid "Continue with email"
|
||||||
msgstr "使用邮箱继续"
|
msgstr "使用邮箱继续"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "Conversation record"
|
msgid "Conversation record"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@ -1361,11 +1362,11 @@ msgstr ""
|
|||||||
msgid "Conversations"
|
msgid "Conversations"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "Copy"
|
msgid "Copy"
|
||||||
msgstr "复制"
|
msgstr "复制"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "Copy reply"
|
msgid "Copy reply"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@ -1747,9 +1748,9 @@ msgstr "无法更新头像"
|
|||||||
msgid "Couldn't update messaging settings"
|
msgid "Couldn't update messaging settings"
|
||||||
msgstr "无法更新消息设置"
|
msgstr "无法更新消息设置"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
|
||||||
#: src/pages/shell/bot-panel.tsx
|
#: src/pages/shell/bot-panel.tsx
|
||||||
#: src/pages/shell/dialogs.tsx
|
#: src/pages/shell/dialogs.tsx
|
||||||
|
#: src/pages/shell/sidebar-header.tsx
|
||||||
msgid "Create"
|
msgid "Create"
|
||||||
msgstr "创建"
|
msgstr "创建"
|
||||||
|
|
||||||
@ -1906,14 +1907,14 @@ msgstr "默认范围"
|
|||||||
#: src/pages/KnowledgeSection.tsx
|
#: src/pages/KnowledgeSection.tsx
|
||||||
#: src/pages/McpServersOverlay.tsx
|
#: src/pages/McpServersOverlay.tsx
|
||||||
#: src/pages/RoutineEditor.tsx
|
#: src/pages/RoutineEditor.tsx
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/archived-section.tsx
|
||||||
#: src/pages/shell/dialogs.tsx
|
#: src/pages/shell/dialogs.tsx
|
||||||
msgid "Delete"
|
msgid "Delete"
|
||||||
msgstr "删除"
|
msgstr "删除"
|
||||||
|
|
||||||
#. placeholder {0}: bot.name
|
#. placeholder {0}: bot.name
|
||||||
#. placeholder {0}: group.name
|
#. placeholder {0}: group.name
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/archived-section.tsx
|
||||||
msgid "Delete {0}"
|
msgid "Delete {0}"
|
||||||
msgstr "删除 {0}"
|
msgstr "删除 {0}"
|
||||||
|
|
||||||
@ -1943,7 +1944,7 @@ msgstr ""
|
|||||||
msgid "Delete space"
|
msgid "Delete space"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "deleted"
|
msgid "deleted"
|
||||||
msgstr "已删除"
|
msgstr "已删除"
|
||||||
|
|
||||||
@ -2013,7 +2014,7 @@ msgstr "正在断开…"
|
|||||||
msgid "Dismiss"
|
msgid "Dismiss"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/composer.tsx
|
||||||
msgid "Dismiss error"
|
msgid "Dismiss error"
|
||||||
msgstr "关闭错误"
|
msgstr "关闭错误"
|
||||||
|
|
||||||
@ -2111,7 +2112,7 @@ msgstr "复制"
|
|||||||
msgid "e.g. Hivenet Agent, Presales, Timesheets bot"
|
msgid "e.g. Hivenet Agent, Presales, Timesheets bot"
|
||||||
msgstr "例如 Hivenet Agent、Presales、工时表机器人"
|
msgstr "例如 Hivenet Agent、Presales、工时表机器人"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "Earlier message"
|
msgid "Earlier message"
|
||||||
msgstr "更早的消息"
|
msgstr "更早的消息"
|
||||||
|
|
||||||
@ -2222,7 +2223,7 @@ msgid "Expand"
|
|||||||
msgstr "展开"
|
msgstr "展开"
|
||||||
|
|
||||||
#. placeholder {0}: group.title
|
#. placeholder {0}: group.title
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/sidebar-group-header.tsx
|
||||||
msgid "Expand {0}"
|
msgid "Expand {0}"
|
||||||
msgstr "展开 {0}"
|
msgstr "展开 {0}"
|
||||||
|
|
||||||
@ -2404,6 +2405,7 @@ msgstr ""
|
|||||||
#: src/components/stage/OoStage.tsx
|
#: src/components/stage/OoStage.tsx
|
||||||
#: src/pages/MessagingSettingsOverlay.tsx
|
#: src/pages/MessagingSettingsOverlay.tsx
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/Shell.tsx
|
||||||
|
#: src/pages/shell/side-panel-header.tsx
|
||||||
msgid "Group"
|
msgid "Group"
|
||||||
msgstr "群组"
|
msgstr "群组"
|
||||||
|
|
||||||
@ -2528,7 +2530,7 @@ msgstr ""
|
|||||||
msgid "How to check"
|
msgid "How to check"
|
||||||
msgstr "如何检查"
|
msgstr "如何检查"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/computer-screen.tsx
|
||||||
msgid "I’m done"
|
msgid "I’m done"
|
||||||
msgstr "我做完了"
|
msgstr "我做完了"
|
||||||
|
|
||||||
@ -2635,11 +2637,11 @@ msgstr "隔离"
|
|||||||
msgid "Its conversation, files, and routines will be permanently deleted. Bots it created stay in your list."
|
msgid "Its conversation, files, and routines will be permanently deleted. Bots it created stay in your list."
|
||||||
msgstr "它的对话、文件和例行任务将被永久删除。它创建的 Bot 仍留在列表中。"
|
msgstr "它的对话、文件和例行任务将被永久删除。它创建的 Bot 仍留在列表中。"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "Jump to latest"
|
msgid "Jump to latest"
|
||||||
msgstr "跳到最新"
|
msgstr "跳到最新"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "Jump to replied message"
|
msgid "Jump to replied message"
|
||||||
msgstr "跳到被回复的消息"
|
msgstr "跳到被回复的消息"
|
||||||
|
|
||||||
@ -2726,7 +2728,7 @@ msgstr ""
|
|||||||
msgid "Listening — what's the story?"
|
msgid "Listening — what's the story?"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "Load earlier messages"
|
msgid "Load earlier messages"
|
||||||
msgstr "加载更早的消息"
|
msgstr "加载更早的消息"
|
||||||
|
|
||||||
@ -2779,7 +2781,7 @@ msgstr ""
|
|||||||
#: src/pages/HeuteBrief.tsx
|
#: src/pages/HeuteBrief.tsx
|
||||||
#: src/pages/IntegrationSetup.tsx
|
#: src/pages/IntegrationSetup.tsx
|
||||||
#: src/pages/PeerMessagesOverlay.tsx
|
#: src/pages/PeerMessagesOverlay.tsx
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "Loading…"
|
msgid "Loading…"
|
||||||
msgstr "加载中…"
|
msgstr "加载中…"
|
||||||
|
|
||||||
@ -2799,7 +2801,7 @@ msgstr ""
|
|||||||
msgid "Local Server Settings"
|
msgid "Local Server Settings"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/user-menu.tsx
|
||||||
msgid "Log out"
|
msgid "Log out"
|
||||||
msgstr "退出登录"
|
msgstr "退出登录"
|
||||||
|
|
||||||
@ -2926,7 +2928,7 @@ msgstr "记忆"
|
|||||||
msgid "Memory scope"
|
msgid "Memory scope"
|
||||||
msgstr "记忆范围"
|
msgstr "记忆范围"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/composer.tsx
|
||||||
msgid "Mentions"
|
msgid "Mentions"
|
||||||
msgstr "提及"
|
msgstr "提及"
|
||||||
|
|
||||||
@ -2939,11 +2941,12 @@ msgstr ""
|
|||||||
msgid "Message"
|
msgid "Message"
|
||||||
msgstr "消息"
|
msgstr "消息"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/composer.tsx
|
||||||
|
#: src/pages/shell/message-preview.ts
|
||||||
msgid "Message"
|
msgid "Message"
|
||||||
msgstr "消息"
|
msgstr "消息"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/composer.tsx
|
||||||
msgid "Message composer"
|
msgid "Message composer"
|
||||||
msgstr "消息输入框"
|
msgstr "消息输入框"
|
||||||
|
|
||||||
@ -2951,11 +2954,11 @@ msgstr "消息输入框"
|
|||||||
msgid "Message event"
|
msgid "Message event"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "Message from {peer}"
|
msgid "Message from {peer}"
|
||||||
msgstr "来自 {peer} 的消息"
|
msgstr "来自 {peer} 的消息"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/composer.tsx
|
||||||
msgid "Message…"
|
msgid "Message…"
|
||||||
msgstr "消息…"
|
msgstr "消息…"
|
||||||
|
|
||||||
@ -2981,7 +2984,7 @@ msgstr "最低"
|
|||||||
msgid "Minimize"
|
msgid "Minimize"
|
||||||
msgstr "最小化"
|
msgstr "最小化"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/sidebar-toggle-buttons.tsx
|
||||||
msgid "Minimize bots"
|
msgid "Minimize bots"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@ -3038,7 +3041,7 @@ msgstr "来自服务器的模型"
|
|||||||
msgid "Monthly"
|
msgid "Monthly"
|
||||||
msgstr "每月"
|
msgstr "每月"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "More"
|
msgid "More"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@ -3104,7 +3107,8 @@ msgstr ""
|
|||||||
#: src/components/MainInbox.tsx
|
#: src/components/MainInbox.tsx
|
||||||
#: src/pages/ActivityList.tsx
|
#: src/pages/ActivityList.tsx
|
||||||
#: src/pages/HeuteBrief.tsx
|
#: src/pages/HeuteBrief.tsx
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/fullscreen-computer-overlay.tsx
|
||||||
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "Needs you"
|
msgid "Needs you"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@ -3397,12 +3401,12 @@ msgid "Only file and folder names are read."
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/ScratchpadSection.tsx
|
#: src/pages/ScratchpadSection.tsx
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/computer-panel-preview.tsx
|
||||||
msgid "Open"
|
msgid "Open"
|
||||||
msgstr "打开"
|
msgstr "打开"
|
||||||
|
|
||||||
#. placeholder {0}: group.title
|
#. placeholder {0}: group.title
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/sidebar-group-header.tsx
|
||||||
msgid "Open {0}"
|
msgid "Open {0}"
|
||||||
msgstr "打开 {0}"
|
msgstr "打开 {0}"
|
||||||
|
|
||||||
@ -3418,11 +3422,11 @@ msgstr ""
|
|||||||
msgid "Open in browser"
|
msgid "Open in browser"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/computer-panel-preview.tsx
|
||||||
msgid "Open in full window"
|
msgid "Open in full window"
|
||||||
msgstr "在完整窗口中打开"
|
msgstr "在完整窗口中打开"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/sidebar-toggle-buttons.tsx
|
||||||
msgid "Open navigation"
|
msgid "Open navigation"
|
||||||
msgstr "打开导航"
|
msgstr "打开导航"
|
||||||
|
|
||||||
@ -3438,7 +3442,7 @@ msgstr "待办"
|
|||||||
msgid "OpenAI-compatible server URL"
|
msgid "OpenAI-compatible server URL"
|
||||||
msgstr "OpenAI 兼容服务器 URL"
|
msgstr "OpenAI 兼容服务器 URL"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "Opened its thread."
|
msgid "Opened its thread."
|
||||||
msgstr "已打开其对话。"
|
msgstr "已打开其对话。"
|
||||||
|
|
||||||
@ -3679,19 +3683,19 @@ msgstr ""
|
|||||||
msgid "Quiet hours start"
|
msgid "Quiet hours start"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "Quote"
|
msgid "Quote"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "React"
|
msgid "React"
|
||||||
msgstr "回应"
|
msgstr "回应"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "Reactions"
|
msgid "Reactions"
|
||||||
msgstr "表情回应"
|
msgstr "表情回应"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "Read aloud"
|
msgid "Read aloud"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@ -3796,7 +3800,7 @@ msgstr ""
|
|||||||
msgid "Region"
|
msgid "Region"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/computer-screen.tsx
|
||||||
msgid "Release"
|
msgid "Release"
|
||||||
msgstr "释放"
|
msgstr "释放"
|
||||||
|
|
||||||
@ -3820,7 +3824,7 @@ msgid "Remove"
|
|||||||
msgstr "移除"
|
msgstr "移除"
|
||||||
|
|
||||||
#. placeholder {0}: attachment.file.name
|
#. placeholder {0}: attachment.file.name
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/composer.tsx
|
||||||
msgid "Remove {0}"
|
msgid "Remove {0}"
|
||||||
msgstr "移除 {0}"
|
msgstr "移除 {0}"
|
||||||
|
|
||||||
@ -3829,7 +3833,7 @@ msgid "Remove Git event"
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#. placeholder {0}: mention.name
|
#. placeholder {0}: mention.name
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/composer.tsx
|
||||||
msgid "Remove mention {0}"
|
msgid "Remove mention {0}"
|
||||||
msgstr "移除提及 {0}"
|
msgstr "移除提及 {0}"
|
||||||
|
|
||||||
@ -3842,7 +3846,7 @@ msgid "Remove schedule"
|
|||||||
msgstr "移除计划"
|
msgstr "移除计划"
|
||||||
|
|
||||||
#. placeholder {0}: selectedSkill.name
|
#. placeholder {0}: selectedSkill.name
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/composer.tsx
|
||||||
msgid "Remove skill {0}"
|
msgid "Remove skill {0}"
|
||||||
msgstr "移除技能 {0}"
|
msgstr "移除技能 {0}"
|
||||||
|
|
||||||
@ -3850,7 +3854,7 @@ msgstr "移除技能 {0}"
|
|||||||
msgid "Remove webhook"
|
msgid "Remove webhook"
|
||||||
msgstr "移除 Webhook"
|
msgstr "移除 Webhook"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "Removed with chat, computer, and memory."
|
msgid "Removed with chat, computer, and memory."
|
||||||
msgstr "已连同对话、电脑和记忆一起移除。"
|
msgstr "已连同对话、电脑和记忆一起移除。"
|
||||||
|
|
||||||
@ -3883,15 +3887,15 @@ msgstr "替换 API 密钥"
|
|||||||
msgid "Replace key"
|
msgid "Replace key"
|
||||||
msgstr "替换密钥"
|
msgstr "替换密钥"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "Reply"
|
msgid "Reply"
|
||||||
msgstr "回复"
|
msgstr "回复"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/composer.tsx
|
||||||
msgid "Replying to {replyName}"
|
msgid "Replying to {replyName}"
|
||||||
msgstr "正在回复 {replyName}"
|
msgstr "正在回复 {replyName}"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/composer.tsx
|
||||||
msgid "Replying to {replyName}: “{replyQuote}”"
|
msgid "Replying to {replyName}: “{replyQuote}”"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@ -3937,7 +3941,7 @@ msgstr "正在重置…"
|
|||||||
msgid "Restart to update"
|
msgid "Restart to update"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/archived-section.tsx
|
||||||
msgid "Restore"
|
msgid "Restore"
|
||||||
msgstr "恢复"
|
msgstr "恢复"
|
||||||
|
|
||||||
@ -4142,7 +4146,7 @@ msgid "Searching…"
|
|||||||
msgstr "正在搜索…"
|
msgstr "正在搜索…"
|
||||||
|
|
||||||
#. placeholder {0}: group.title
|
#. placeholder {0}: group.title
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/sidebar-group-header.tsx
|
||||||
msgid "Select {0}"
|
msgid "Select {0}"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@ -4150,7 +4154,7 @@ msgstr ""
|
|||||||
msgid "Self-hosted (better-auth)"
|
msgid "Self-hosted (better-auth)"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/composer.tsx
|
||||||
#: src/pages/shell/message-cards.tsx
|
#: src/pages/shell/message-cards.tsx
|
||||||
msgid "Send"
|
msgid "Send"
|
||||||
msgstr "发送"
|
msgstr "发送"
|
||||||
@ -4201,21 +4205,22 @@ msgid "Server URL"
|
|||||||
msgstr "服务器 URL"
|
msgstr "服务器 URL"
|
||||||
|
|
||||||
#: src/components/stage/StageVoiceEntry.tsx
|
#: src/components/stage/StageVoiceEntry.tsx
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/composer.tsx
|
||||||
msgid "Set up voice"
|
msgid "Set up voice"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/MessagingSettingsOverlay.tsx
|
#: src/pages/MessagingSettingsOverlay.tsx
|
||||||
#: src/pages/SettingsOverlay.tsx
|
#: src/pages/SettingsOverlay.tsx
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/side-panel-header.tsx
|
||||||
|
#: src/pages/shell/user-menu.tsx
|
||||||
msgid "Settings"
|
msgid "Settings"
|
||||||
msgstr "设置"
|
msgstr "设置"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/composer.tsx
|
||||||
msgid "Settings: General"
|
msgid "Settings: General"
|
||||||
msgstr "设置:通用"
|
msgstr "设置:通用"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/composer.tsx
|
||||||
msgid "Settings: Usage"
|
msgid "Settings: Usage"
|
||||||
msgstr "设置:用量"
|
msgstr "设置:用量"
|
||||||
|
|
||||||
@ -4259,10 +4264,11 @@ msgid "Show all {0}"
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/Shell.tsx
|
||||||
|
#: src/pages/shell/sidebar-toggle-buttons.tsx
|
||||||
msgid "Show bots"
|
msgid "Show bots"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/side-panel-header.tsx
|
||||||
msgid "Show computer"
|
msgid "Show computer"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@ -4278,7 +4284,7 @@ msgstr "显示更多"
|
|||||||
msgid "Show password"
|
msgid "Show password"
|
||||||
msgstr "显示密码"
|
msgstr "显示密码"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/side-panel-header.tsx
|
||||||
msgid "Show settings"
|
msgid "Show settings"
|
||||||
msgstr "显示设置"
|
msgstr "显示设置"
|
||||||
|
|
||||||
@ -4307,7 +4313,7 @@ msgid "Sketching the blueprint…"
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#. placeholder {0}: skill.name
|
#. placeholder {0}: skill.name
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/composer.tsx
|
||||||
msgid "Skill {0}"
|
msgid "Skill {0}"
|
||||||
msgstr "技能 {0}"
|
msgstr "技能 {0}"
|
||||||
|
|
||||||
@ -4319,7 +4325,7 @@ msgstr "技能"
|
|||||||
#: src/components/onboarding/OnboardingScanStep.tsx
|
#: src/components/onboarding/OnboardingScanStep.tsx
|
||||||
#: src/components/onboarding/OnboardingVoiceStep.tsx
|
#: src/components/onboarding/OnboardingVoiceStep.tsx
|
||||||
#: src/lib/onboarding-copy.ts
|
#: src/lib/onboarding-copy.ts
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/computer-screen.tsx
|
||||||
msgid "Skip"
|
msgid "Skip"
|
||||||
msgstr "跳过"
|
msgstr "跳过"
|
||||||
|
|
||||||
@ -4373,11 +4379,11 @@ msgstr "工作区默认"
|
|||||||
msgid "Spaces"
|
msgid "Spaces"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "Speak"
|
msgid "Speak"
|
||||||
msgstr "朗读"
|
msgstr "朗读"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "Speak this reply"
|
msgid "Speak this reply"
|
||||||
msgstr "朗读这条回复"
|
msgstr "朗读这条回复"
|
||||||
|
|
||||||
@ -4431,15 +4437,15 @@ msgstr "开始录制"
|
|||||||
msgid "Start talking"
|
msgid "Start talking"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "Start the conversation — {activeName} is on stage above."
|
msgid "Start the conversation — {activeName} is on stage above."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "Start the conversation."
|
msgid "Start the conversation."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/composer.tsx
|
||||||
msgid "Start voice conversation"
|
msgid "Start voice conversation"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@ -4466,11 +4472,13 @@ msgid "Steps"
|
|||||||
msgstr "步骤"
|
msgstr "步骤"
|
||||||
|
|
||||||
#: src/components/browser/InAppBrowser.tsx
|
#: src/components/browser/InAppBrowser.tsx
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/composer.tsx
|
||||||
|
#: src/pages/shell/fullscreen-computer-overlay.tsx
|
||||||
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "Stop"
|
msgid "Stop"
|
||||||
msgstr "停止"
|
msgstr "停止"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "Stop speaking"
|
msgid "Stop speaking"
|
||||||
msgstr "停止朗读"
|
msgstr "停止朗读"
|
||||||
|
|
||||||
@ -4500,7 +4508,7 @@ msgstr ""
|
|||||||
msgid "Stronger together — {0} specialists"
|
msgid "Stronger together — {0} specialists"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "subagent"
|
msgid "subagent"
|
||||||
msgstr "子 Agent"
|
msgstr "子 Agent"
|
||||||
|
|
||||||
@ -4565,7 +4573,7 @@ msgstr "正在示范,发送新消息前请先停止示范。"
|
|||||||
msgid "Team"
|
msgid "Team"
|
||||||
msgstr "团队"
|
msgstr "团队"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/computer-screen.tsx
|
||||||
msgid "Team Computer"
|
msgid "Team Computer"
|
||||||
msgstr "团队电脑"
|
msgstr "团队电脑"
|
||||||
|
|
||||||
@ -4606,7 +4614,7 @@ msgstr "所选记忆提供方在此构建中不可用。"
|
|||||||
msgid "Thinking"
|
msgid "Thinking"
|
||||||
msgstr "思考"
|
msgstr "思考"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/computer-screen.tsx
|
||||||
msgid "This bot runs on this computer, not a Linux desktop. Shell and files use your home folder."
|
msgid "This bot runs on this computer, not a Linux desktop. Shell and files use your home folder."
|
||||||
msgstr "此 Bot 运行在这台电脑上,而不是 Linux 桌面。Shell 和文件使用你的主目录。"
|
msgstr "此 Bot 运行在这台电脑上,而不是 Linux 桌面。Shell 和文件使用你的主目录。"
|
||||||
|
|
||||||
@ -4713,7 +4721,7 @@ msgid "Transcribe"
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/components/voice/VoiceStage.tsx
|
#: src/components/voice/VoiceStage.tsx
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/transcript.tsx
|
||||||
msgid "Transcript"
|
msgid "Transcript"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@ -4836,7 +4844,7 @@ msgstr "上传"
|
|||||||
|
|
||||||
#: src/pages/AccountSettingsOverlay.tsx
|
#: src/pages/AccountSettingsOverlay.tsx
|
||||||
#: src/pages/SettingsOverlay.tsx
|
#: src/pages/SettingsOverlay.tsx
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/user-menu.tsx
|
||||||
msgid "Usage"
|
msgid "Usage"
|
||||||
msgstr "用量"
|
msgstr "用量"
|
||||||
|
|
||||||
@ -4877,8 +4885,8 @@ msgid "Video workflow"
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/SettingsOverlay.tsx
|
#: src/pages/SettingsOverlay.tsx
|
||||||
#: src/pages/Shell.tsx
|
|
||||||
#: src/pages/shell/bot-panel.tsx
|
#: src/pages/shell/bot-panel.tsx
|
||||||
|
#: src/pages/shell/composer.tsx
|
||||||
#: src/pages/VoiceSettingsOverlay.tsx
|
#: src/pages/VoiceSettingsOverlay.tsx
|
||||||
msgid "Voice"
|
msgid "Voice"
|
||||||
msgstr "语音"
|
msgstr "语音"
|
||||||
@ -5074,7 +5082,7 @@ msgstr "处理中…"
|
|||||||
msgid "Working…"
|
msgid "Working…"
|
||||||
msgstr "处理中…"
|
msgstr "处理中…"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/roster-format.ts
|
||||||
msgid "Yesterday"
|
msgid "Yesterday"
|
||||||
msgstr "昨天"
|
msgstr "昨天"
|
||||||
|
|
||||||
@ -5092,7 +5100,7 @@ msgstr "如果没有自动跳转,可以关闭此标签页。"
|
|||||||
msgid "You can close this window."
|
msgid "You can close this window."
|
||||||
msgstr "可以关闭此窗口。"
|
msgstr "可以关闭此窗口。"
|
||||||
|
|
||||||
#: src/pages/Shell.tsx
|
#: src/pages/shell/fullscreen-computer-overlay.tsx
|
||||||
msgid "You have control"
|
msgid "You have control"
|
||||||
msgstr "你已接管"
|
msgstr "你已接管"
|
||||||
|
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
85
apps/web/src/pages/shell/archived-section.tsx
Normal file
85
apps/web/src/pages/shell/archived-section.tsx
Normal file
@ -0,0 +1,85 @@
|
|||||||
|
import { Trans, useLingui } from "@lingui/react/macro";
|
||||||
|
import type { Bot, Group } from "@rakazo/contracts";
|
||||||
|
import { BotAvatar, Button, GroupAvatar } from "@rakazo/ui-web";
|
||||||
|
|
||||||
|
/** Collapsible list of archived bots and groups at the foot of the sidebar. */
|
||||||
|
export function ArchivedSection({
|
||||||
|
bots,
|
||||||
|
groups,
|
||||||
|
open,
|
||||||
|
onToggle,
|
||||||
|
onRestoreBot,
|
||||||
|
onRestoreGroup,
|
||||||
|
onDeleteBot,
|
||||||
|
onDeleteGroup,
|
||||||
|
}: {
|
||||||
|
bots: Bot[];
|
||||||
|
groups: Group[];
|
||||||
|
open: boolean;
|
||||||
|
onToggle: () => void;
|
||||||
|
onRestoreBot: (bot: Bot) => void;
|
||||||
|
onRestoreGroup: (group: Group) => void;
|
||||||
|
onDeleteBot: (bot: Bot) => void;
|
||||||
|
onDeleteGroup: (group: Group) => void;
|
||||||
|
}) {
|
||||||
|
const { t } = useLingui();
|
||||||
|
return (
|
||||||
|
<div className="mt-2 border-t border-border pt-2">
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
aria-expanded={open}
|
||||||
|
onClick={onToggle}
|
||||||
|
className="flex w-full items-center justify-between rounded-lg px-2.5 py-2 text-ui-body rk-sidebar-muted hover:bg-sidebar-accent"
|
||||||
|
>
|
||||||
|
<span>
|
||||||
|
<Trans>Archived</Trans>
|
||||||
|
</span>
|
||||||
|
<span>{bots.length + groups.length}</span>
|
||||||
|
</button>
|
||||||
|
{open ? (
|
||||||
|
<>
|
||||||
|
{bots.map((bot) => (
|
||||||
|
<div key={bot.id} className="flex items-center gap-2 rounded-lg px-2.5 py-2">
|
||||||
|
<BotAvatar color={bot.color} identity={bot.id} size={28} status={bot.status} />
|
||||||
|
<span className="min-w-0 flex-1 truncate text-ui-body text-foreground/75" dir="auto">
|
||||||
|
{bot.name}
|
||||||
|
</span>
|
||||||
|
<Button variant="ghost" size="xs" onClick={() => onRestoreBot(bot)}>
|
||||||
|
<Trans>Restore</Trans>
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
variant="ghost"
|
||||||
|
size="xs"
|
||||||
|
className="text-destructive hover:text-destructive"
|
||||||
|
aria-label={t`Delete ${bot.name}`}
|
||||||
|
onClick={() => onDeleteBot(bot)}
|
||||||
|
>
|
||||||
|
<Trans>Delete</Trans>
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
{groups.map((group) => (
|
||||||
|
<div key={group.id} className="flex items-center gap-2 rounded-lg px-2.5 py-2">
|
||||||
|
<GroupAvatar members={group.members} size={28} />
|
||||||
|
<span className="min-w-0 flex-1 truncate text-ui-body text-foreground/75" dir="auto">
|
||||||
|
{group.name}
|
||||||
|
</span>
|
||||||
|
<Button variant="ghost" size="xs" onClick={() => onRestoreGroup(group)}>
|
||||||
|
<Trans>Restore</Trans>
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
variant="ghost"
|
||||||
|
size="xs"
|
||||||
|
className="text-destructive hover:text-destructive"
|
||||||
|
aria-label={t`Delete ${group.name}`}
|
||||||
|
onClick={() => onDeleteGroup(group)}
|
||||||
|
>
|
||||||
|
<Trans>Delete</Trans>
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</>
|
||||||
|
) : null}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
20
apps/web/src/pages/shell/collapsed-sidebar-sections.ts
Normal file
20
apps/web/src/pages/shell/collapsed-sidebar-sections.ts
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
export function collapsedSidebarSectionsStorageKey(
|
||||||
|
userId: string | null | undefined,
|
||||||
|
): string | null {
|
||||||
|
if (!userId) return null;
|
||||||
|
return `rakazo:collapsed-sidebar-sections:${userId}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function readCollapsedSidebarSections(userId: string | null | undefined): Set<string> {
|
||||||
|
const storageKey = collapsedSidebarSectionsStorageKey(userId);
|
||||||
|
if (!storageKey) return new Set();
|
||||||
|
try {
|
||||||
|
const value = window.localStorage.getItem(storageKey);
|
||||||
|
const keys: unknown = value ? JSON.parse(value) : [];
|
||||||
|
return new Set(
|
||||||
|
Array.isArray(keys) ? keys.filter((key): key is string => typeof key === "string") : [],
|
||||||
|
);
|
||||||
|
} catch {
|
||||||
|
return new Set();
|
||||||
|
}
|
||||||
|
}
|
||||||
805
apps/web/src/pages/shell/composer.tsx
Normal file
805
apps/web/src/pages/shell/composer.tsx
Normal file
@ -0,0 +1,805 @@
|
|||||||
|
import { t } from "@lingui/core/macro";
|
||||||
|
import { Trans, useLingui } from "@lingui/react/macro";
|
||||||
|
import type { AgentSkillCatalogEntry, ThreadMessage } from "@rakazo/contracts";
|
||||||
|
import { ATTACHMENT_ALLOWED_MIME_TYPES } from "@rakazo/contracts";
|
||||||
|
import type { ComposerMention, SlashActionId } from "@rakazo/core";
|
||||||
|
import {
|
||||||
|
clampMentionHighlightIndex,
|
||||||
|
mentionChipKey,
|
||||||
|
resolveMentionPickerKey,
|
||||||
|
SLASH_ACTIONS,
|
||||||
|
serializeComposerPrompt,
|
||||||
|
truncateSlashDescription,
|
||||||
|
} from "@rakazo/core";
|
||||||
|
import { BotAvatar, Button } from "@rakazo/ui-web";
|
||||||
|
import {
|
||||||
|
ArrowUp,
|
||||||
|
Box,
|
||||||
|
Clock,
|
||||||
|
Mic,
|
||||||
|
Paperclip,
|
||||||
|
Plus,
|
||||||
|
Puzzle,
|
||||||
|
Settings,
|
||||||
|
Square,
|
||||||
|
X,
|
||||||
|
} from "lucide-react";
|
||||||
|
import type { ClipboardEvent, DragEvent, RefObject } from "react";
|
||||||
|
import { memo, useEffect, useId, useLayoutEffect, useMemo, useRef, useState } from "react";
|
||||||
|
import { VoiceAuroraRim } from "../../components/voice/VoiceAurora";
|
||||||
|
import { isFileDrag, isFilePaste } from "../../lib/pending-attachments";
|
||||||
|
import { previewMessageText } from "./message-preview";
|
||||||
|
import type { PendingAttachment } from "./shell-types";
|
||||||
|
import { FALLBACK_BOT_COLOR } from "./shell-types";
|
||||||
|
|
||||||
|
const ATTACHMENT_ACCEPT = ATTACHMENT_ALLOWED_MIME_TYPES.join(",");
|
||||||
|
|
||||||
|
export const Composer = memo(function Composer({
|
||||||
|
running,
|
||||||
|
disabled,
|
||||||
|
pendingAttachments,
|
||||||
|
attachmentNotice,
|
||||||
|
sendError,
|
||||||
|
runError,
|
||||||
|
runErrorId,
|
||||||
|
onRunErrorPresented,
|
||||||
|
onDismissError,
|
||||||
|
sending,
|
||||||
|
fileInputRef,
|
||||||
|
onAttachmentPick,
|
||||||
|
onRemoveAttachment,
|
||||||
|
onSend,
|
||||||
|
onStop,
|
||||||
|
onVoice,
|
||||||
|
voiceReady = false,
|
||||||
|
voiceColor,
|
||||||
|
replyTarget,
|
||||||
|
replyQuote,
|
||||||
|
replyTargetName,
|
||||||
|
onClearReply,
|
||||||
|
mentionTargets,
|
||||||
|
agentSkills,
|
||||||
|
onSlashOpen,
|
||||||
|
onSlashAction,
|
||||||
|
}: {
|
||||||
|
running: boolean;
|
||||||
|
disabled?: boolean;
|
||||||
|
pendingAttachments: PendingAttachment[];
|
||||||
|
attachmentNotice: string | null;
|
||||||
|
sendError: string | null;
|
||||||
|
runError: string | null;
|
||||||
|
runErrorId: string | null;
|
||||||
|
onRunErrorPresented: (runId: string) => void;
|
||||||
|
onDismissError: () => void;
|
||||||
|
sending: boolean;
|
||||||
|
fileInputRef: RefObject<HTMLInputElement | null>;
|
||||||
|
onAttachmentPick: (files: FileList | null) => void | Promise<void>;
|
||||||
|
onRemoveAttachment: (attachment: PendingAttachment) => void;
|
||||||
|
onSend: (text: string, mentions?: ComposerMention[]) => Promise<void>;
|
||||||
|
onStop: () => Promise<void>;
|
||||||
|
onVoice?: () => void;
|
||||||
|
voiceReady?: boolean;
|
||||||
|
voiceColor?: string;
|
||||||
|
replyTarget?: ThreadMessage | null;
|
||||||
|
replyQuote?: string | null;
|
||||||
|
replyTargetName?: string;
|
||||||
|
onClearReply?: () => void;
|
||||||
|
mentionTargets?: ComposerMention[];
|
||||||
|
agentSkills?: AgentSkillCatalogEntry[];
|
||||||
|
onSlashOpen?: () => void;
|
||||||
|
onSlashAction?: (action: SlashActionId) => void;
|
||||||
|
}) {
|
||||||
|
const { t } = useLingui();
|
||||||
|
const [draft, setDraft] = useState("");
|
||||||
|
const [mentionQuery, setMentionQuery] = useState<string | null>(null);
|
||||||
|
const [mentionHighlightIndex, setMentionHighlightIndex] = useState(0);
|
||||||
|
const [slashQuery, setSlashQuery] = useState<string | null>(null);
|
||||||
|
const [selectedSkill, setSelectedSkill] = useState<AgentSkillCatalogEntry | null>(null);
|
||||||
|
const [selectedMentions, setSelectedMentions] = useState<ComposerMention[]>([]);
|
||||||
|
const textareaRef = useRef<HTMLTextAreaElement>(null);
|
||||||
|
const runErrorRef = useRef<HTMLDivElement>(null);
|
||||||
|
const submitFingerprint = useRef<string | null>(null);
|
||||||
|
useEffect(() => {
|
||||||
|
if (!sendError && !runError) return;
|
||||||
|
const timer = setTimeout(() => {
|
||||||
|
onDismissError();
|
||||||
|
}, 8000);
|
||||||
|
return () => clearTimeout(timer);
|
||||||
|
}, [sendError, runError, onDismissError]);
|
||||||
|
|
||||||
|
const presentedRunErrorIdRef = useRef<string | null>(null);
|
||||||
|
const mentionListboxId = useId();
|
||||||
|
const dragDepth = useRef(0);
|
||||||
|
const [draggingFiles, setDraggingFiles] = useState(false);
|
||||||
|
const canSend =
|
||||||
|
draft.trim().length > 0 ||
|
||||||
|
selectedSkill !== null ||
|
||||||
|
selectedMentions.length > 0 ||
|
||||||
|
pendingAttachments.length > 0;
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!runError || !runErrorId) return;
|
||||||
|
const currentRunErrorId = runErrorId;
|
||||||
|
let frame = 0;
|
||||||
|
function recordIfPresented() {
|
||||||
|
cancelAnimationFrame(frame);
|
||||||
|
frame = requestAnimationFrame(() => {
|
||||||
|
const element = runErrorRef.current;
|
||||||
|
if (!element || document.visibilityState !== "visible") return;
|
||||||
|
const rect = element.getBoundingClientRect();
|
||||||
|
const topElement = document.elementFromPoint(
|
||||||
|
rect.left + rect.width / 2,
|
||||||
|
rect.top + rect.height / 2,
|
||||||
|
);
|
||||||
|
if (topElement && (topElement === element || element.contains(topElement))) {
|
||||||
|
if (presentedRunErrorIdRef.current === currentRunErrorId) return;
|
||||||
|
presentedRunErrorIdRef.current = currentRunErrorId;
|
||||||
|
onRunErrorPresented(currentRunErrorId);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
recordIfPresented();
|
||||||
|
const observer = new MutationObserver(recordIfPresented);
|
||||||
|
observer.observe(document.body, { childList: true, subtree: true });
|
||||||
|
document.addEventListener("transitionend", recordIfPresented);
|
||||||
|
document.addEventListener("visibilitychange", recordIfPresented);
|
||||||
|
return () => {
|
||||||
|
cancelAnimationFrame(frame);
|
||||||
|
observer.disconnect();
|
||||||
|
document.removeEventListener("transitionend", recordIfPresented);
|
||||||
|
document.removeEventListener("visibilitychange", recordIfPresented);
|
||||||
|
};
|
||||||
|
}, [onRunErrorPresented, runError, runErrorId]);
|
||||||
|
|
||||||
|
useLayoutEffect(() => {
|
||||||
|
const el = textareaRef.current;
|
||||||
|
if (!el) return;
|
||||||
|
|
||||||
|
function syncHeight() {
|
||||||
|
const textarea = textareaRef.current;
|
||||||
|
if (!textarea) return;
|
||||||
|
textarea.style.height = "0px";
|
||||||
|
textarea.style.height = `${textarea.scrollHeight}px`;
|
||||||
|
}
|
||||||
|
|
||||||
|
syncHeight();
|
||||||
|
let lastWidth = el.getBoundingClientRect().width;
|
||||||
|
const observer = new ResizeObserver(() => {
|
||||||
|
const textarea = textareaRef.current;
|
||||||
|
if (!textarea) return;
|
||||||
|
const width = textarea.getBoundingClientRect().width;
|
||||||
|
if (width === lastWidth) return;
|
||||||
|
lastWidth = width;
|
||||||
|
syncHeight();
|
||||||
|
});
|
||||||
|
observer.observe(el);
|
||||||
|
return () => observer.disconnect();
|
||||||
|
}, [draft]);
|
||||||
|
|
||||||
|
function updateDraft(value: string) {
|
||||||
|
submitFingerprint.current = null;
|
||||||
|
setDraft(value);
|
||||||
|
const mentionMatch = /(?:^|\s)@([\w-]*)$/.exec(value);
|
||||||
|
setMentionQuery(mentionMatch ? (mentionMatch[1] ?? "") : null);
|
||||||
|
// `/` only at the start of the draft so forced skills expand (`Use skill:` / `/Name` prefix).
|
||||||
|
const slashMatch = selectedSkill === null ? /^\/([^\n]*)$/.exec(value) : null;
|
||||||
|
const nextSlash = slashMatch ? (slashMatch[1] ?? "") : null;
|
||||||
|
if (nextSlash !== null && slashQuery === null) onSlashOpen?.();
|
||||||
|
setSlashQuery(nextSlash);
|
||||||
|
}
|
||||||
|
|
||||||
|
function focusComposer() {
|
||||||
|
textareaRef.current?.focus();
|
||||||
|
}
|
||||||
|
|
||||||
|
function insertMention(mention: ComposerMention) {
|
||||||
|
setDraft((current) => current.replace(/@([\w-]*)$/, ""));
|
||||||
|
setMentionQuery(null);
|
||||||
|
setMentionHighlightIndex(0);
|
||||||
|
setSelectedMentions((current) =>
|
||||||
|
current.some((selected) => mentionChipKey(selected) === mentionChipKey(mention))
|
||||||
|
? current
|
||||||
|
: [...current, mention],
|
||||||
|
);
|
||||||
|
focusComposer();
|
||||||
|
}
|
||||||
|
|
||||||
|
function insertSkill(skill: AgentSkillCatalogEntry) {
|
||||||
|
setSelectedSkill(skill);
|
||||||
|
setDraft("");
|
||||||
|
setSlashQuery(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
function runSlashAction(action: SlashActionId) {
|
||||||
|
setDraft("");
|
||||||
|
setSlashQuery(null);
|
||||||
|
onSlashAction?.(action);
|
||||||
|
}
|
||||||
|
|
||||||
|
function removeLastChip() {
|
||||||
|
if (selectedMentions.length > 0) {
|
||||||
|
setSelectedMentions((current) => current.slice(0, -1));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (selectedSkill) setSelectedSkill(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
const mentionOptions = useMemo(() => {
|
||||||
|
if (mentionQuery === null || !mentionTargets?.length) return [];
|
||||||
|
const query = mentionQuery.trim().toLowerCase();
|
||||||
|
return mentionTargets
|
||||||
|
.filter((target) => !query || target.name.toLowerCase().startsWith(query))
|
||||||
|
.slice(0, 10);
|
||||||
|
}, [mentionQuery, mentionTargets]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
setMentionHighlightIndex(0);
|
||||||
|
}, [mentionQuery]);
|
||||||
|
|
||||||
|
const activeMentionIndex = clampMentionHighlightIndex(
|
||||||
|
mentionHighlightIndex,
|
||||||
|
mentionOptions.length,
|
||||||
|
);
|
||||||
|
const mentionPickerOpen = mentionOptions.length > 0;
|
||||||
|
const activeMentionOptionId = mentionPickerOpen
|
||||||
|
? `${mentionListboxId}-option-${activeMentionIndex}`
|
||||||
|
: undefined;
|
||||||
|
|
||||||
|
const slashSkillOptions = useMemo(() => {
|
||||||
|
if (slashQuery === null) return [];
|
||||||
|
const query = slashQuery.trim().toLowerCase();
|
||||||
|
const skills = agentSkills ?? [];
|
||||||
|
return skills
|
||||||
|
.filter((skill) => {
|
||||||
|
if (!query) return true;
|
||||||
|
return (
|
||||||
|
skill.name.toLowerCase().includes(query) ||
|
||||||
|
skill.description.toLowerCase().includes(query)
|
||||||
|
);
|
||||||
|
})
|
||||||
|
.slice(0, 8);
|
||||||
|
}, [agentSkills, slashQuery]);
|
||||||
|
|
||||||
|
const slashActionOptions = useMemo(() => {
|
||||||
|
if (slashQuery === null) return [];
|
||||||
|
const query = slashQuery.trim().toLowerCase();
|
||||||
|
return SLASH_ACTIONS.filter((action) => !query || action.label.toLowerCase().includes(query));
|
||||||
|
}, [slashQuery]);
|
||||||
|
|
||||||
|
const showSlashPicker =
|
||||||
|
slashQuery !== null &&
|
||||||
|
mentionQuery === null &&
|
||||||
|
(slashSkillOptions.length > 0 || slashActionOptions.length > 0);
|
||||||
|
|
||||||
|
function send() {
|
||||||
|
if (!canSend || disabled) return;
|
||||||
|
const text = serializeComposerPrompt(draft, selectedSkill, selectedMentions);
|
||||||
|
const fingerprint = [text, ...selectedMentions.map((mention) => mentionChipKey(mention))].join(
|
||||||
|
"\n",
|
||||||
|
);
|
||||||
|
if (submitFingerprint.current === fingerprint) return;
|
||||||
|
submitFingerprint.current = fingerprint;
|
||||||
|
setDraft("");
|
||||||
|
setMentionQuery(null);
|
||||||
|
setMentionHighlightIndex(0);
|
||||||
|
setSlashQuery(null);
|
||||||
|
setSelectedSkill(null);
|
||||||
|
const mentions = selectedMentions;
|
||||||
|
setSelectedMentions([]);
|
||||||
|
void onSend(text, mentions);
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleDragEnter(event: DragEvent<HTMLFieldSetElement>) {
|
||||||
|
const dataTransfer = event.dataTransfer;
|
||||||
|
if (!isFileDrag(dataTransfer)) return;
|
||||||
|
event.preventDefault();
|
||||||
|
if (disabled) {
|
||||||
|
dragDepth.current = 0;
|
||||||
|
setDraggingFiles(false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
dragDepth.current += 1;
|
||||||
|
setDraggingFiles(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleDragOver(event: DragEvent<HTMLFieldSetElement>) {
|
||||||
|
const dataTransfer = event.dataTransfer;
|
||||||
|
if (!isFileDrag(dataTransfer)) return;
|
||||||
|
event.preventDefault();
|
||||||
|
dataTransfer.dropEffect = disabled ? "none" : "copy";
|
||||||
|
if (disabled) {
|
||||||
|
dragDepth.current = 0;
|
||||||
|
setDraggingFiles(false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
setDraggingFiles(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleDragLeave(event: DragEvent<HTMLFieldSetElement>) {
|
||||||
|
if (!isFileDrag(event.dataTransfer)) return;
|
||||||
|
if (disabled) {
|
||||||
|
dragDepth.current = 0;
|
||||||
|
setDraggingFiles(false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
dragDepth.current = Math.max(0, dragDepth.current - 1);
|
||||||
|
if (dragDepth.current === 0) setDraggingFiles(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleDrop(event: DragEvent<HTMLFieldSetElement>) {
|
||||||
|
const dataTransfer = event.dataTransfer;
|
||||||
|
if (!isFileDrag(dataTransfer)) return;
|
||||||
|
event.preventDefault();
|
||||||
|
dragDepth.current = 0;
|
||||||
|
setDraggingFiles(false);
|
||||||
|
if (!disabled) void onAttachmentPick(dataTransfer.files);
|
||||||
|
}
|
||||||
|
|
||||||
|
function handlePaste(event: ClipboardEvent<HTMLTextAreaElement>) {
|
||||||
|
const clipboardData = event.clipboardData;
|
||||||
|
// Only intercept real FileList pastes; leave text-only / empty-files native.
|
||||||
|
if (disabled || !clipboardData || !isFilePaste(clipboardData)) return;
|
||||||
|
event.preventDefault();
|
||||||
|
void onAttachmentPick(clipboardData.files);
|
||||||
|
const text = clipboardData.getData("text/plain");
|
||||||
|
if (!text) return;
|
||||||
|
const textarea = event.currentTarget;
|
||||||
|
const start = textarea.selectionStart;
|
||||||
|
const end = textarea.selectionEnd;
|
||||||
|
updateDraft(`${draft.slice(0, start)}${text}${draft.slice(end)}`);
|
||||||
|
const caret = start + text.length;
|
||||||
|
window.requestAnimationFrame(() => {
|
||||||
|
textareaRef.current?.setSelectionRange(caret, caret);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const showComposerPlaceholder =
|
||||||
|
draft.length === 0 && selectedSkill === null && selectedMentions.length === 0;
|
||||||
|
const replyName = replyTarget ? (replyTargetName ?? previewMessageText(replyTarget)) : "";
|
||||||
|
|
||||||
|
return (
|
||||||
|
<fieldset
|
||||||
|
aria-label={t`Message composer`}
|
||||||
|
data-dragging={draggingFiles ? "files" : undefined}
|
||||||
|
onDragEnter={handleDragEnter}
|
||||||
|
onDragOver={handleDragOver}
|
||||||
|
onDragLeave={handleDragLeave}
|
||||||
|
onDrop={handleDrop}
|
||||||
|
className={`relative z-30 m-0 min-w-0 border-0 px-3 pb-4 pt-3 md:px-6 md:pb-6 ${
|
||||||
|
draggingFiles ? "rounded-[14px] ring-2 ring-inset ring-ring" : ""
|
||||||
|
}`}
|
||||||
|
>
|
||||||
|
<div className="mx-auto w-full max-w-4xl">
|
||||||
|
{sendError || runError ? (
|
||||||
|
<div
|
||||||
|
ref={runErrorRef}
|
||||||
|
role="alert"
|
||||||
|
data-testid="composer-error"
|
||||||
|
className="mb-3 flex items-center gap-2 rounded-[14px] border border-destructive/40 bg-destructive/10 px-4 py-2 text-ui-body-sm text-destructive"
|
||||||
|
>
|
||||||
|
<span className="min-w-0 flex-1">{sendError ?? runError}</span>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
aria-label={t`Dismiss error`}
|
||||||
|
data-testid="composer-error-dismiss"
|
||||||
|
onClick={() => {
|
||||||
|
onDismissError();
|
||||||
|
window.requestAnimationFrame(() => textareaRef.current?.focus());
|
||||||
|
}}
|
||||||
|
className="shrink-0 text-destructive hover:text-foreground"
|
||||||
|
>
|
||||||
|
<X strokeWidth={2} className="size-icon-sm" />
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
) : null}
|
||||||
|
{replyTarget ? (
|
||||||
|
<div
|
||||||
|
data-testid="reply-chip"
|
||||||
|
className="mb-2 flex items-center gap-2 rounded-full border border-border bg-muted px-3 py-1.5 text-ui-body-sm text-foreground/75"
|
||||||
|
>
|
||||||
|
<span className="min-w-0 flex-1 truncate text-muted-foreground">
|
||||||
|
{replyQuote
|
||||||
|
? t`Replying to ${replyName}: “${replyQuote}”`
|
||||||
|
: t`Replying to ${replyName}`}
|
||||||
|
</span>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
aria-label={t`Cancel reply`}
|
||||||
|
onClick={onClearReply}
|
||||||
|
className="shrink-0 text-muted-foreground hover:text-foreground"
|
||||||
|
>
|
||||||
|
<X strokeWidth={2} className="size-icon-sm" />
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
) : null}
|
||||||
|
{attachmentNotice ? (
|
||||||
|
<div className="mb-3 rounded-[14px] border border-warning/40 bg-warning/10 px-4 py-2 text-ui-body-sm text-warning">
|
||||||
|
{attachmentNotice}
|
||||||
|
</div>
|
||||||
|
) : null}
|
||||||
|
{pendingAttachments.length ? (
|
||||||
|
<div className="mb-3 flex flex-wrap gap-2">
|
||||||
|
{pendingAttachments.map((attachment) => (
|
||||||
|
<div
|
||||||
|
key={attachment.id}
|
||||||
|
className="flex items-center gap-2 rounded-full border border-border bg-muted px-3 py-1.5 text-ui-body-sm text-foreground/75"
|
||||||
|
>
|
||||||
|
{attachment.previewUrl ? (
|
||||||
|
<img
|
||||||
|
src={attachment.previewUrl}
|
||||||
|
alt={attachment.file.name}
|
||||||
|
className="size-control-md rounded object-cover"
|
||||||
|
/>
|
||||||
|
) : (
|
||||||
|
<Paperclip strokeWidth={1.8} className="size-icon-md" />
|
||||||
|
)}
|
||||||
|
<span className="max-w-[180px] truncate" dir="auto">
|
||||||
|
{attachment.file.name}
|
||||||
|
</span>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
aria-label={t`Remove ${attachment.file.name}`}
|
||||||
|
onClick={() => onRemoveAttachment(attachment)}
|
||||||
|
className="text-muted-foreground hover:text-foreground"
|
||||||
|
>
|
||||||
|
<X strokeWidth={2} className="size-icon-sm" />
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
) : null}
|
||||||
|
{mentionPickerOpen ? (
|
||||||
|
<div
|
||||||
|
id={mentionListboxId}
|
||||||
|
role="listbox"
|
||||||
|
aria-label={t`Mentions`}
|
||||||
|
data-testid="mention-picker"
|
||||||
|
className="mb-2 max-h-64 overflow-y-auto rounded-[14px] border border-border bg-muted"
|
||||||
|
>
|
||||||
|
{mentionOptions.map((mention, index) => {
|
||||||
|
const optionId = `${mentionListboxId}-option-${index}`;
|
||||||
|
const highlighted = index === activeMentionIndex;
|
||||||
|
return (
|
||||||
|
<button
|
||||||
|
id={optionId}
|
||||||
|
key={mentionChipKey(mention)}
|
||||||
|
type="button"
|
||||||
|
role="option"
|
||||||
|
aria-selected={highlighted}
|
||||||
|
aria-label={`@${mention.name}`}
|
||||||
|
data-mention-name={mention.name}
|
||||||
|
onMouseDown={(event) => event.preventDefault()}
|
||||||
|
onClick={() => insertMention(mention)}
|
||||||
|
onMouseEnter={() => setMentionHighlightIndex(index)}
|
||||||
|
className={`flex w-full items-start gap-3 px-4 py-2.5 text-start hover:bg-accent ${
|
||||||
|
highlighted ? "bg-accent" : ""
|
||||||
|
}`}
|
||||||
|
>
|
||||||
|
<span aria-hidden="true">
|
||||||
|
<MentionOptionIcon mention={mention} />
|
||||||
|
</span>
|
||||||
|
<span className="min-w-0">
|
||||||
|
<span dir="auto" className="block text-ui-body text-foreground">
|
||||||
|
@{mention.name}
|
||||||
|
</span>
|
||||||
|
{mention.subtitle ? (
|
||||||
|
<span
|
||||||
|
dir="auto"
|
||||||
|
aria-hidden="true"
|
||||||
|
className="block truncate text-ui-body-sm text-muted-foreground"
|
||||||
|
>
|
||||||
|
{mention.subtitle}
|
||||||
|
</span>
|
||||||
|
) : null}
|
||||||
|
</span>
|
||||||
|
</button>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
) : null}
|
||||||
|
{showSlashPicker ? (
|
||||||
|
<div
|
||||||
|
data-testid="slash-picker"
|
||||||
|
className="mb-2 overflow-hidden rounded-[14px] border border-border bg-muted"
|
||||||
|
>
|
||||||
|
{slashSkillOptions.map((skill) => (
|
||||||
|
<button
|
||||||
|
key={skill.id}
|
||||||
|
type="button"
|
||||||
|
aria-label={t`Skill ${skill.name}`}
|
||||||
|
onClick={() => insertSkill(skill)}
|
||||||
|
className="flex w-full items-start gap-3 px-4 py-2.5 text-start hover:bg-accent"
|
||||||
|
>
|
||||||
|
<Box
|
||||||
|
strokeWidth={1.7}
|
||||||
|
className="mt-0.5 shrink-0 text-muted-foreground size-icon-md"
|
||||||
|
/>
|
||||||
|
<span className="min-w-0">
|
||||||
|
<span dir="auto" className="block text-ui-body text-foreground">
|
||||||
|
{skill.name}
|
||||||
|
</span>
|
||||||
|
<span dir="auto" className="block truncate text-ui-body-sm text-muted-foreground">
|
||||||
|
{truncateSlashDescription(skill.description)}
|
||||||
|
</span>
|
||||||
|
</span>
|
||||||
|
</button>
|
||||||
|
))}
|
||||||
|
{slashActionOptions.map((action) => {
|
||||||
|
const label = slashActionLabel(action.id);
|
||||||
|
return (
|
||||||
|
<button
|
||||||
|
key={action.id}
|
||||||
|
type="button"
|
||||||
|
aria-label={label}
|
||||||
|
onClick={() => runSlashAction(action.id)}
|
||||||
|
className="flex w-full items-center gap-3 px-4 py-2.5 text-start hover:bg-accent"
|
||||||
|
>
|
||||||
|
<Settings
|
||||||
|
strokeWidth={1.7}
|
||||||
|
className="shrink-0 text-muted-foreground size-icon-md"
|
||||||
|
/>
|
||||||
|
<span className="text-ui-body text-foreground">{label}</span>
|
||||||
|
</button>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
) : null}
|
||||||
|
<div
|
||||||
|
data-testid="composer-bar"
|
||||||
|
className="apple-island relative flex items-center gap-3.5 rounded-[30px] py-3 pe-3.5 ps-4 transition-all duration-200"
|
||||||
|
>
|
||||||
|
<input
|
||||||
|
ref={fileInputRef}
|
||||||
|
type="file"
|
||||||
|
multiple
|
||||||
|
accept={ATTACHMENT_ACCEPT}
|
||||||
|
className="hidden"
|
||||||
|
onChange={(event) => void onAttachmentPick(event.target.files)}
|
||||||
|
/>
|
||||||
|
<Button
|
||||||
|
variant="ghost"
|
||||||
|
size="icon"
|
||||||
|
aria-label={t`Attach file`}
|
||||||
|
disabled={disabled}
|
||||||
|
onClick={() => fileInputRef.current?.click()}
|
||||||
|
className="tactile-press size-10 shrink-0 rounded-full border border-border bg-foreground/5 text-foreground/80 transition-all hover:bg-foreground/10 hover:text-foreground flex items-center justify-center cursor-pointer"
|
||||||
|
>
|
||||||
|
<Plus strokeWidth={2.2} className="size-icon-lg" />
|
||||||
|
</Button>
|
||||||
|
<div className="flex min-w-0 flex-1 flex-wrap items-end gap-1.5">
|
||||||
|
{selectedSkill ? (
|
||||||
|
<span
|
||||||
|
data-testid="skill-chip"
|
||||||
|
className="inline-flex max-w-full items-center gap-1.5 rounded-full border border-border bg-foreground/[0.08] px-3 py-1 text-ui-body font-medium text-foreground backdrop-blur-md"
|
||||||
|
>
|
||||||
|
<Box strokeWidth={1.8} className="shrink-0 text-muted-foreground size-icon-md" />
|
||||||
|
<span dir="auto" className="truncate">
|
||||||
|
{selectedSkill.name}
|
||||||
|
</span>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
aria-label={t`Remove skill ${selectedSkill.name}`}
|
||||||
|
onClick={() => setSelectedSkill(null)}
|
||||||
|
className="text-muted-foreground hover:text-foreground transition-colors"
|
||||||
|
>
|
||||||
|
<X strokeWidth={2} className="size-icon-sm" />
|
||||||
|
</button>
|
||||||
|
</span>
|
||||||
|
) : null}
|
||||||
|
{selectedMentions.map((mention) => (
|
||||||
|
<span
|
||||||
|
key={mentionChipKey(mention)}
|
||||||
|
data-testid="mention-chip"
|
||||||
|
data-mention-kind={mention.kind}
|
||||||
|
className="inline-flex max-w-full items-center gap-1.5 rounded-full border border-border bg-foreground/[0.08] px-3 py-1 text-ui-body font-medium text-foreground backdrop-blur-md"
|
||||||
|
>
|
||||||
|
<MentionChipIcon mention={mention} />
|
||||||
|
<span dir="auto" className="truncate">
|
||||||
|
{mention.name}
|
||||||
|
</span>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
aria-label={t`Remove mention ${mention.name}`}
|
||||||
|
onClick={() =>
|
||||||
|
setSelectedMentions((current) =>
|
||||||
|
current.filter(
|
||||||
|
(selected) => mentionChipKey(selected) !== mentionChipKey(mention),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
className="text-muted-foreground hover:text-foreground transition-colors"
|
||||||
|
>
|
||||||
|
<X strokeWidth={2} className="size-icon-sm" />
|
||||||
|
</button>
|
||||||
|
</span>
|
||||||
|
))}
|
||||||
|
<textarea
|
||||||
|
ref={textareaRef}
|
||||||
|
value={draft}
|
||||||
|
onChange={(event) => updateDraft(event.target.value)}
|
||||||
|
onPaste={handlePaste}
|
||||||
|
onKeyDown={(event) => {
|
||||||
|
if (
|
||||||
|
event.key === "Backspace" &&
|
||||||
|
draft.length === 0 &&
|
||||||
|
(selectedSkill !== null || selectedMentions.length > 0)
|
||||||
|
) {
|
||||||
|
event.preventDefault();
|
||||||
|
removeLastChip();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const action = resolveMentionPickerKey({
|
||||||
|
key: event.key,
|
||||||
|
shiftKey: event.shiftKey,
|
||||||
|
isComposing: event.nativeEvent.isComposing || event.keyCode === 229,
|
||||||
|
optionCount: mentionOptions.length,
|
||||||
|
highlightedIndex: activeMentionIndex,
|
||||||
|
});
|
||||||
|
if (action.type === "complete") {
|
||||||
|
const mention = mentionOptions[action.index];
|
||||||
|
if (!mention) return;
|
||||||
|
event.preventDefault();
|
||||||
|
insertMention(mention);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (action.type === "move") {
|
||||||
|
event.preventDefault();
|
||||||
|
setMentionHighlightIndex(action.index);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (action.type === "dismiss") {
|
||||||
|
event.preventDefault();
|
||||||
|
setMentionQuery(null);
|
||||||
|
setMentionHighlightIndex(0);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (action.type === "send") {
|
||||||
|
event.preventDefault();
|
||||||
|
send();
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
disabled={disabled}
|
||||||
|
placeholder={showComposerPlaceholder ? t`Message…` : undefined}
|
||||||
|
aria-label={t`Message`}
|
||||||
|
role="combobox"
|
||||||
|
aria-autocomplete="list"
|
||||||
|
aria-haspopup="listbox"
|
||||||
|
aria-expanded={mentionPickerOpen ? "true" : "false"}
|
||||||
|
aria-controls={mentionPickerOpen ? mentionListboxId : undefined}
|
||||||
|
aria-activedescendant={activeMentionOptionId}
|
||||||
|
name="chat-message"
|
||||||
|
autoComplete="off"
|
||||||
|
dir="auto"
|
||||||
|
rows={1}
|
||||||
|
className="max-h-36 min-h-[28px] min-w-[8rem] flex-1 resize-none overflow-y-auto bg-transparent py-1 text-[16.5px] leading-[1.55] text-foreground outline-none placeholder:text-muted-foreground/75 disabled:opacity-40 font-normal"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
{onVoice ? (
|
||||||
|
<Button
|
||||||
|
variant="outline"
|
||||||
|
aria-label={t`Voice`}
|
||||||
|
title={voiceReady ? t`Start voice conversation` : t`Set up voice`}
|
||||||
|
disabled={disabled}
|
||||||
|
onClick={onVoice}
|
||||||
|
data-testid="composer-voice-primary"
|
||||||
|
className={`tactile-press h-control-lg shrink-0 gap-2 rounded-full px-4 sm:px-5 flex items-center justify-center cursor-pointer transition-all ${
|
||||||
|
voiceReady
|
||||||
|
? "relative overflow-hidden border-border bg-foreground/5 text-foreground hover:bg-foreground/10"
|
||||||
|
: "border-border bg-foreground/5 text-foreground/80 hover:bg-foreground/10"
|
||||||
|
}`}
|
||||||
|
>
|
||||||
|
{voiceReady ? (
|
||||||
|
<VoiceAuroraRim botColor={voiceColor} className="inset-x-[14%] h-0.5 blur-[3px]" />
|
||||||
|
) : null}
|
||||||
|
<Mic strokeWidth={1.9} className="size-icon-lg shrink-0" />
|
||||||
|
<span className="hidden text-ui-body font-semibold sm:inline">
|
||||||
|
<Trans>Voice</Trans>
|
||||||
|
</span>
|
||||||
|
</Button>
|
||||||
|
) : null}
|
||||||
|
{running ? (
|
||||||
|
<div className="flex items-center gap-2 shrink-0">
|
||||||
|
<Button
|
||||||
|
size="icon"
|
||||||
|
aria-label={t`Send`}
|
||||||
|
disabled={!canSend || disabled}
|
||||||
|
onClick={send}
|
||||||
|
className="tactile-press size-10 rounded-full transition-transform active:scale-90 flex items-center justify-center cursor-pointer"
|
||||||
|
>
|
||||||
|
<ArrowUp strokeWidth={2.6} className="size-icon-lg" />
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
variant="outline"
|
||||||
|
size="icon"
|
||||||
|
aria-label={t`Stop`}
|
||||||
|
disabled={sending}
|
||||||
|
onClick={() => void onStop()}
|
||||||
|
className="tactile-press size-10 rounded-full border border-border bg-foreground/[0.08] text-foreground/90 shadow-sm transition-colors hover:bg-foreground/15 hover:text-foreground flex items-center justify-center cursor-pointer"
|
||||||
|
>
|
||||||
|
<Square strokeWidth={0} fill="currentColor" className="size-icon-sm" />
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
) : (
|
||||||
|
<Button
|
||||||
|
size="icon"
|
||||||
|
aria-label={t`Send`}
|
||||||
|
disabled={!canSend || disabled}
|
||||||
|
onClick={send}
|
||||||
|
className="tactile-press size-10 shrink-0 rounded-full transition-all active:scale-90 disabled:bg-foreground/[0.08] disabled:text-foreground/20 flex items-center justify-center cursor-pointer"
|
||||||
|
>
|
||||||
|
<ArrowUp strokeWidth={2.6} className="size-icon-lg" />
|
||||||
|
</Button>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</fieldset>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
function slashActionLabel(id: SlashActionId) {
|
||||||
|
switch (id) {
|
||||||
|
case "chat-settings":
|
||||||
|
return t`Chat Settings`;
|
||||||
|
case "settings-general":
|
||||||
|
return t`Settings: General`;
|
||||||
|
case "settings-usage":
|
||||||
|
return t`Settings: Usage`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function MentionOptionIcon({ mention }: { mention: ComposerMention }) {
|
||||||
|
if (mention.kind === "routine") {
|
||||||
|
return (
|
||||||
|
<Clock strokeWidth={1.7} className="mt-0.5 shrink-0 text-muted-foreground size-icon-md" />
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if (mention.kind === "connector") {
|
||||||
|
return (
|
||||||
|
<Puzzle strokeWidth={1.7} className="mt-0.5 shrink-0 text-muted-foreground size-icon-md" />
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if (mention.kind === "group") {
|
||||||
|
return (
|
||||||
|
<span className="mt-0.5 grid h-4 w-4 shrink-0 place-items-center rounded-full bg-accent text-ui-caption text-foreground/75">
|
||||||
|
G
|
||||||
|
</span>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if (mention.kind === "everyone") {
|
||||||
|
return (
|
||||||
|
<span className="mt-0.5 grid h-4 w-4 shrink-0 place-items-center rounded-full bg-accent text-ui-caption text-foreground/75">
|
||||||
|
@
|
||||||
|
</span>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return (
|
||||||
|
<BotAvatar
|
||||||
|
color={mention.color ?? FALLBACK_BOT_COLOR}
|
||||||
|
identity={mention.id}
|
||||||
|
className="size-icon-md"
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function MentionChipIcon({ mention }: { mention: ComposerMention }) {
|
||||||
|
if (mention.kind === "routine") {
|
||||||
|
return <Clock strokeWidth={1.7} className="shrink-0 text-muted-foreground/70 size-icon-sm" />;
|
||||||
|
}
|
||||||
|
if (mention.kind === "connector") {
|
||||||
|
return <Puzzle strokeWidth={1.7} className="shrink-0 text-muted-foreground/70 size-icon-sm" />;
|
||||||
|
}
|
||||||
|
if (mention.kind === "group" || mention.kind === "everyone") {
|
||||||
|
return (
|
||||||
|
<span className="grid h-4 w-4 shrink-0 place-items-center rounded-full bg-accent text-ui-caption text-foreground/75">
|
||||||
|
{mention.kind === "group" ? "G" : "@"}
|
||||||
|
</span>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return (
|
||||||
|
<BotAvatar
|
||||||
|
color={mention.color ?? FALLBACK_BOT_COLOR}
|
||||||
|
identity={mention.id}
|
||||||
|
className="size-icon-md"
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
96
apps/web/src/pages/shell/computer-panel-preview.tsx
Normal file
96
apps/web/src/pages/shell/computer-panel-preview.tsx
Normal file
@ -0,0 +1,96 @@
|
|||||||
|
import { Trans, useLingui } from "@lingui/react/macro";
|
||||||
|
import type { Bot, ComputerStatus } from "@rakazo/contracts";
|
||||||
|
import { Maximize2 } from "lucide-react";
|
||||||
|
import type { ReactNode } from "react";
|
||||||
|
import {
|
||||||
|
ComputersUnavailableHint,
|
||||||
|
computersAreUnavailable,
|
||||||
|
} from "../../components/ComputersUnavailableHint";
|
||||||
|
import { AgentCursor } from "../../components/computer/AgentCursor";
|
||||||
|
import {
|
||||||
|
computerLabel,
|
||||||
|
computerPlaceholder,
|
||||||
|
DesktopKindEmptyState,
|
||||||
|
screenIframeSandbox,
|
||||||
|
} from "./computer-screen";
|
||||||
|
|
||||||
|
/** The bot's screen in the side panel: a live, non-interactive preview that opens full window. */
|
||||||
|
export function ComputerPanelPreview({
|
||||||
|
active,
|
||||||
|
computer,
|
||||||
|
computerOpen,
|
||||||
|
booting,
|
||||||
|
embeddedScreenUrl,
|
||||||
|
computerScreenError,
|
||||||
|
sandboxProvider,
|
||||||
|
onOpen,
|
||||||
|
}: {
|
||||||
|
active: Bot;
|
||||||
|
computer: ComputerStatus | null;
|
||||||
|
computerOpen: boolean;
|
||||||
|
booting: boolean;
|
||||||
|
embeddedScreenUrl: string | null;
|
||||||
|
computerScreenError: ReactNode;
|
||||||
|
sandboxProvider: string | undefined;
|
||||||
|
onOpen: () => void;
|
||||||
|
}) {
|
||||||
|
const { t } = useLingui();
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<div
|
||||||
|
data-testid="computer-preview"
|
||||||
|
className="group relative aspect-[16/10] overflow-hidden rounded-[14px] bg-background"
|
||||||
|
>
|
||||||
|
{computerOpen ? (
|
||||||
|
<div className="grid h-full place-items-center text-sm text-muted-foreground/80">
|
||||||
|
<Trans>Open in full window</Trans>
|
||||||
|
</div>
|
||||||
|
) : computer?.kind === "desktop" ? (
|
||||||
|
<DesktopKindEmptyState className="grid h-full place-items-center px-6 text-center text-sm text-muted-foreground/80" />
|
||||||
|
) : computer?.state === "running" && embeddedScreenUrl && !computerScreenError ? (
|
||||||
|
<>
|
||||||
|
<iframe
|
||||||
|
title={t`Bot screen preview`}
|
||||||
|
src={embeddedScreenUrl}
|
||||||
|
sandbox={screenIframeSandbox(embeddedScreenUrl)}
|
||||||
|
className="h-full w-full border-0 bg-black"
|
||||||
|
allow="clipboard-read; clipboard-write"
|
||||||
|
style={{ pointerEvents: "none" }}
|
||||||
|
/>
|
||||||
|
<AgentCursor botId={active.id} color={active.color} name={active.name} />
|
||||||
|
</>
|
||||||
|
) : (
|
||||||
|
<div className="grid h-full place-items-center px-6 text-center text-sm text-muted-foreground/80">
|
||||||
|
{computerScreenError ??
|
||||||
|
(computersAreUnavailable(sandboxProvider) ? (
|
||||||
|
<ComputersUnavailableHint />
|
||||||
|
) : (
|
||||||
|
computerPlaceholder(
|
||||||
|
computer?.state,
|
||||||
|
booting,
|
||||||
|
computerLabel(computer?.mode, active.name),
|
||||||
|
)
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
{!computerScreenError ? (
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
data-testid="computer-preview-open"
|
||||||
|
className="absolute inset-0 flex cursor-pointer items-center justify-center bg-overlay/40 opacity-0 transition-opacity group-hover:opacity-100 focus-visible:opacity-100"
|
||||||
|
aria-label={t`Open`}
|
||||||
|
onClick={onOpen}
|
||||||
|
>
|
||||||
|
<span className="inline-flex items-center gap-2 rounded-full bg-overlay px-3.5 py-2 text-ui-body text-foreground shadow-md">
|
||||||
|
<Maximize2 strokeWidth={1.9} aria-hidden className="size-icon-md" />
|
||||||
|
<Trans>Open</Trans>
|
||||||
|
</span>
|
||||||
|
</button>
|
||||||
|
) : null}
|
||||||
|
</div>
|
||||||
|
<p className="mt-2 truncate text-ui-body text-muted-foreground" dir="auto">
|
||||||
|
{t`${active.name}'s screen`}
|
||||||
|
</p>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
83
apps/web/src/pages/shell/computer-screen.tsx
Normal file
83
apps/web/src/pages/shell/computer-screen.tsx
Normal file
@ -0,0 +1,83 @@
|
|||||||
|
import { t } from "@lingui/core/macro";
|
||||||
|
import { Trans } from "@lingui/react/macro";
|
||||||
|
import type { ComputerReleaseReason, ComputerStatus } from "@rakazo/contracts";
|
||||||
|
import { Button } from "@rakazo/ui-web";
|
||||||
|
|
||||||
|
export function ComputerReleaseActions({
|
||||||
|
takeoverRequested,
|
||||||
|
onRelease,
|
||||||
|
}: {
|
||||||
|
takeoverRequested: boolean;
|
||||||
|
onRelease: (reason?: ComputerReleaseReason) => Promise<void>;
|
||||||
|
}) {
|
||||||
|
if (!takeoverRequested) {
|
||||||
|
return (
|
||||||
|
<Button type="button" variant="outline" size="sm" onClick={() => void onRelease()}>
|
||||||
|
<Trans>Release</Trans>
|
||||||
|
</Button>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return (
|
||||||
|
<div className="flex items-center gap-2">
|
||||||
|
<Button type="button" variant="outline" size="sm" onClick={() => void onRelease("skipped")}>
|
||||||
|
<Trans>Skip</Trans>
|
||||||
|
</Button>
|
||||||
|
<Button type="button" size="sm" onClick={() => void onRelease("done")}>
|
||||||
|
<Trans>I’m done</Trans>
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function embeddableScreenUrl(url: string | null): string | null {
|
||||||
|
if (!url) return null;
|
||||||
|
try {
|
||||||
|
const parsed = new URL(url, window.location.href);
|
||||||
|
const page = new URL(window.location.href);
|
||||||
|
const local = parsed.hostname === "127.0.0.1" || parsed.hostname === "localhost";
|
||||||
|
const pagePort = page.port || (page.protocol === "https:" ? "443" : "80");
|
||||||
|
if (local && parsed.port && parsed.port !== pagePort) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return parsed.toString();
|
||||||
|
} catch {
|
||||||
|
return url;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function screenIframeSandbox(url: string | null) {
|
||||||
|
if (!url) return undefined;
|
||||||
|
try {
|
||||||
|
return new URL(url, window.location.href).pathname.startsWith("/novnc/")
|
||||||
|
? "allow-scripts allow-pointer-lock"
|
||||||
|
: undefined;
|
||||||
|
} catch {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function DesktopKindEmptyState({ className }: { className?: string }) {
|
||||||
|
return (
|
||||||
|
<div className={className}>
|
||||||
|
<Trans>
|
||||||
|
This bot runs on this computer, not a Linux desktop. Shell and files use your home folder.
|
||||||
|
</Trans>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function computerPlaceholder(
|
||||||
|
state: ComputerStatus["state"] | undefined,
|
||||||
|
booting: boolean,
|
||||||
|
label: string,
|
||||||
|
) {
|
||||||
|
if (state === "booting" || booting) return t`Booting live desktop…`;
|
||||||
|
if (state === "running") return label;
|
||||||
|
if (state === "suspended") return t`Computer is asleep. Open it to wake.`;
|
||||||
|
if (state === "error") return t`Computer failed to boot`;
|
||||||
|
return t`Computer is stopped`;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function computerLabel(mode: ComputerStatus["mode"] | undefined, botName: string) {
|
||||||
|
return mode === "dedicated" ? t`${botName}’s computer` : t`Team Computer`;
|
||||||
|
}
|
||||||
196
apps/web/src/pages/shell/fullscreen-computer-overlay.tsx
Normal file
196
apps/web/src/pages/shell/fullscreen-computer-overlay.tsx
Normal file
@ -0,0 +1,196 @@
|
|||||||
|
import { Trans, useLingui } from "@lingui/react/macro";
|
||||||
|
import type { Bot, ComputerReleaseReason, ComputerStatus, TaughtSkill } from "@rakazo/contracts";
|
||||||
|
import { BotAvatar, Button } from "@rakazo/ui-web";
|
||||||
|
import { X } from "lucide-react";
|
||||||
|
import type { ReactNode } from "react";
|
||||||
|
import { ComputerMaintenanceActions } from "../../components/ComputerMaintenanceActions";
|
||||||
|
import { AgentCursor } from "../../components/computer/AgentCursor";
|
||||||
|
import { TeachCaptureOverlay } from "../../components/teach/TeachCaptureOverlay";
|
||||||
|
import { TeachComputerOverlayControl } from "../../components/teach/TeachComputerOverlay";
|
||||||
|
import { TeachRecordingChrome, TeachStopButton } from "../../components/teach/TeachRecordingChrome";
|
||||||
|
import {
|
||||||
|
ComputerReleaseActions,
|
||||||
|
computerLabel,
|
||||||
|
DesktopKindEmptyState,
|
||||||
|
screenIframeSandbox,
|
||||||
|
} from "./computer-screen";
|
||||||
|
|
||||||
|
/** The bot's computer in full window, where the user takes control or teaches a skill. */
|
||||||
|
export function FullscreenComputerOverlay({
|
||||||
|
active,
|
||||||
|
computer,
|
||||||
|
computerViewport,
|
||||||
|
embeddedScreenUrl,
|
||||||
|
computerScreenError,
|
||||||
|
hasControl,
|
||||||
|
recordingSkill,
|
||||||
|
teachBusy,
|
||||||
|
composerRunning,
|
||||||
|
sending,
|
||||||
|
sendError,
|
||||||
|
onStopRun,
|
||||||
|
onStopTeaching,
|
||||||
|
onRelease,
|
||||||
|
onRefreshTeaching,
|
||||||
|
refreshThread,
|
||||||
|
onClose,
|
||||||
|
}: {
|
||||||
|
active: Bot;
|
||||||
|
computer: ComputerStatus | null;
|
||||||
|
computerViewport: { height: number; offsetTop: number } | null;
|
||||||
|
embeddedScreenUrl: string | null;
|
||||||
|
computerScreenError: ReactNode;
|
||||||
|
hasControl: boolean;
|
||||||
|
recordingSkill: TaughtSkill | null;
|
||||||
|
teachBusy: boolean;
|
||||||
|
composerRunning: boolean;
|
||||||
|
sending: boolean;
|
||||||
|
sendError: string | null;
|
||||||
|
onStopRun: () => Promise<void>;
|
||||||
|
onStopTeaching: () => Promise<void>;
|
||||||
|
onRelease: (reason?: ComputerReleaseReason) => Promise<void>;
|
||||||
|
onRefreshTeaching: () => Promise<void>;
|
||||||
|
refreshThread: (botId: string) => Promise<unknown>;
|
||||||
|
onClose: () => void;
|
||||||
|
}) {
|
||||||
|
const { t } = useLingui();
|
||||||
|
return (
|
||||||
|
<div className="fixed inset-0 z-30 bg-background">
|
||||||
|
<div
|
||||||
|
data-testid="computer-viewport"
|
||||||
|
className="fixed inset-x-0 top-0 flex flex-col bg-background"
|
||||||
|
style={{
|
||||||
|
height: computerViewport ? `${computerViewport.height}px` : "100dvh",
|
||||||
|
top: computerViewport ? `${computerViewport.offsetTop}px` : undefined,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
data-testid="computer-chrome"
|
||||||
|
className="flex items-center justify-between gap-4 border-b border-sidebar-border px-[18px] py-3.5"
|
||||||
|
>
|
||||||
|
<div className="flex min-w-0 flex-1 items-center gap-3">
|
||||||
|
<BotAvatar color={active.color} identity={active.id} size={28} status={active.status} />
|
||||||
|
{recordingSkill ? (
|
||||||
|
<TeachRecordingChrome
|
||||||
|
recording={recordingSkill}
|
||||||
|
busy={teachBusy}
|
||||||
|
onStop={onStopTeaching}
|
||||||
|
variant="overlay"
|
||||||
|
/>
|
||||||
|
) : (
|
||||||
|
<span className="truncate text-ui-body font-medium text-foreground" dir="auto">
|
||||||
|
{computerLabel(computer?.mode, active.name)}
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
|
{!recordingSkill && hasControl ? (
|
||||||
|
computer?.takeoverRequested ? (
|
||||||
|
<span className="rounded-full bg-warning/15 px-[11px] py-1 text-ui-body-sm text-warning">
|
||||||
|
<Trans>Needs you</Trans>
|
||||||
|
</span>
|
||||||
|
) : (
|
||||||
|
<span className="rounded-full bg-success/15 px-[11px] py-1 text-ui-body-sm text-success">
|
||||||
|
<Trans>You have control</Trans>
|
||||||
|
</span>
|
||||||
|
)
|
||||||
|
) : null}
|
||||||
|
</div>
|
||||||
|
<div className="flex items-center gap-3">
|
||||||
|
{composerRunning ? (
|
||||||
|
<Button
|
||||||
|
type="button"
|
||||||
|
variant="outline"
|
||||||
|
size="sm"
|
||||||
|
aria-label={t`Stop`}
|
||||||
|
data-testid="computer-overlay-stop"
|
||||||
|
onClick={() => void onStopRun()}
|
||||||
|
disabled={sending}
|
||||||
|
>
|
||||||
|
<Trans>Stop</Trans>
|
||||||
|
</Button>
|
||||||
|
) : null}
|
||||||
|
{recordingSkill ? (
|
||||||
|
<TeachStopButton busy={teachBusy} onStop={onStopTeaching} />
|
||||||
|
) : hasControl ? (
|
||||||
|
<ComputerReleaseActions
|
||||||
|
takeoverRequested={Boolean(computer?.takeoverRequested)}
|
||||||
|
onRelease={onRelease}
|
||||||
|
/>
|
||||||
|
) : null}
|
||||||
|
{active && !recordingSkill ? (
|
||||||
|
<TeachComputerOverlayControl
|
||||||
|
key={active.id}
|
||||||
|
botId={active.id}
|
||||||
|
computer={computer}
|
||||||
|
busy={teachBusy}
|
||||||
|
onRefresh={onRefreshTeaching}
|
||||||
|
/>
|
||||||
|
) : null}
|
||||||
|
{active && !recordingSkill ? (
|
||||||
|
<ComputerMaintenanceActions
|
||||||
|
botId={active.id}
|
||||||
|
computer={computer}
|
||||||
|
onChanged={async () => {
|
||||||
|
await refreshThread(active.id);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
) : null}
|
||||||
|
<Button
|
||||||
|
variant="ghost"
|
||||||
|
size="icon-sm"
|
||||||
|
className="text-muted-foreground"
|
||||||
|
aria-label={t`Close computer`}
|
||||||
|
onClick={onClose}
|
||||||
|
>
|
||||||
|
<X strokeWidth={1.8} className="size-icon-md" />
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{sendError ? (
|
||||||
|
<div
|
||||||
|
role="alert"
|
||||||
|
className="border-b border-destructive/40 bg-destructive/10 px-[18px] py-2 text-ui-body-sm text-destructive"
|
||||||
|
>
|
||||||
|
{sendError}
|
||||||
|
</div>
|
||||||
|
) : null}
|
||||||
|
<div className="relative min-h-0 flex-1 bg-background">
|
||||||
|
{computer?.kind === "desktop" ? (
|
||||||
|
<DesktopKindEmptyState className="grid h-full place-items-center px-8 text-center text-sm text-muted-foreground/80" />
|
||||||
|
) : computer?.state === "running" && embeddedScreenUrl && !computerScreenError ? (
|
||||||
|
<>
|
||||||
|
<iframe
|
||||||
|
title={t`Bot screen`}
|
||||||
|
src={embeddedScreenUrl}
|
||||||
|
sandbox={screenIframeSandbox(embeddedScreenUrl)}
|
||||||
|
className="h-full w-full border-0 bg-black"
|
||||||
|
allow="clipboard-read; clipboard-write; fullscreen"
|
||||||
|
style={{
|
||||||
|
pointerEvents: recordingSkill || !hasControl ? "none" : "auto",
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
{active && !hasControl ? (
|
||||||
|
<AgentCursor botId={active.id} color={active.color} name={active.name} />
|
||||||
|
) : null}
|
||||||
|
{active ? (
|
||||||
|
<TeachCaptureOverlay
|
||||||
|
botId={active.id}
|
||||||
|
skill={recordingSkill}
|
||||||
|
enabled={Boolean(recordingSkill)}
|
||||||
|
screenWidth={computer?.screenWidth}
|
||||||
|
screenHeight={computer?.screenHeight}
|
||||||
|
/>
|
||||||
|
) : null}
|
||||||
|
</>
|
||||||
|
) : (
|
||||||
|
<div className="grid h-full place-items-center text-sm text-muted-foreground/80">
|
||||||
|
{computerScreenError ??
|
||||||
|
(computer?.state === "suspended"
|
||||||
|
? t`Computer is asleep`
|
||||||
|
: computerLabel(computer?.mode, active.name))}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
17
apps/web/src/pages/shell/message-preview.ts
Normal file
17
apps/web/src/pages/shell/message-preview.ts
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
import { t } from "@lingui/core/macro";
|
||||||
|
import type { ThreadMessage } from "@rakazo/contracts";
|
||||||
|
|
||||||
|
const ATTACHMENT_BLOCK_KINDS = new Set(["image", "file", "video", "audio", "media"]);
|
||||||
|
|
||||||
|
export function previewMessageText(message: ThreadMessage): string {
|
||||||
|
const text = message.blocks
|
||||||
|
.map((block) => (block.kind === "text" || block.kind === "channel_message" ? block.text : ""))
|
||||||
|
.filter(Boolean)
|
||||||
|
.join(" ")
|
||||||
|
.trim();
|
||||||
|
if (text) return text;
|
||||||
|
if (message.blocks.some((block) => ATTACHMENT_BLOCK_KINDS.has(block.kind))) {
|
||||||
|
return t`Attachment`;
|
||||||
|
}
|
||||||
|
return t`Message`;
|
||||||
|
}
|
||||||
41
apps/web/src/pages/shell/pointer-menu.tsx
Normal file
41
apps/web/src/pages/shell/pointer-menu.tsx
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
import { DropdownMenu, DropdownMenuContent, DropdownMenuTrigger } from "@rakazo/ui-web";
|
||||||
|
import type { ReactNode } from "react";
|
||||||
|
import type { ContextMenuPosition } from "../BotContextMenu";
|
||||||
|
|
||||||
|
/** A dropdown menu opened at the pointer, for sidebar context menus. */
|
||||||
|
export function PointerMenu({
|
||||||
|
position,
|
||||||
|
label,
|
||||||
|
onClose,
|
||||||
|
children,
|
||||||
|
}: {
|
||||||
|
position: ContextMenuPosition;
|
||||||
|
label: string;
|
||||||
|
onClose: () => void;
|
||||||
|
children: ReactNode;
|
||||||
|
}) {
|
||||||
|
return (
|
||||||
|
<DropdownMenu
|
||||||
|
open
|
||||||
|
onOpenChange={(open) => {
|
||||||
|
if (!open) onClose();
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{/* Invisible anchor at the pointer position, mirroring the bot menu. */}
|
||||||
|
<DropdownMenuTrigger
|
||||||
|
render={
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
tabIndex={-1}
|
||||||
|
aria-hidden
|
||||||
|
className="fixed size-0 p-0 opacity-0"
|
||||||
|
style={{ left: position.x, top: position.y }}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
<DropdownMenuContent aria-label={label} align="start" sideOffset={0} className="w-[220px]">
|
||||||
|
{children}
|
||||||
|
</DropdownMenuContent>
|
||||||
|
</DropdownMenu>
|
||||||
|
);
|
||||||
|
}
|
||||||
57
apps/web/src/pages/shell/roster-format.ts
Normal file
57
apps/web/src/pages/shell/roster-format.ts
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
import { i18n } from "@lingui/core";
|
||||||
|
import { t } from "@lingui/core/macro";
|
||||||
|
|
||||||
|
export function stripSpaceTitlePrefix(title: string | null, spaceName: string): string | null {
|
||||||
|
if (!title) return null;
|
||||||
|
const prefix = `${spaceName} · `;
|
||||||
|
if (title.startsWith(prefix)) return title.slice(prefix.length);
|
||||||
|
if (title === spaceName) return null;
|
||||||
|
return title;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function formatRosterTime(isoDate?: string | null): string {
|
||||||
|
if (!isoDate) return "";
|
||||||
|
try {
|
||||||
|
const d = new Date(isoDate);
|
||||||
|
if (Number.isNaN(d.getTime())) return "";
|
||||||
|
const locale = i18n.locale || "en";
|
||||||
|
const now = new Date();
|
||||||
|
const isToday =
|
||||||
|
d.getDate() === now.getDate() &&
|
||||||
|
d.getMonth() === now.getMonth() &&
|
||||||
|
d.getFullYear() === now.getFullYear();
|
||||||
|
if (isToday) {
|
||||||
|
return d.toLocaleTimeString(locale, { hour: "numeric", minute: "2-digit" });
|
||||||
|
}
|
||||||
|
const yesterday = new Date(now);
|
||||||
|
yesterday.setDate(now.getDate() - 1);
|
||||||
|
const isYesterday =
|
||||||
|
d.getDate() === yesterday.getDate() &&
|
||||||
|
d.getMonth() === yesterday.getMonth() &&
|
||||||
|
d.getFullYear() === yesterday.getFullYear();
|
||||||
|
if (isYesterday) return t`Yesterday`;
|
||||||
|
const diffDays = Math.floor((now.getTime() - d.getTime()) / (1000 * 60 * 60 * 24));
|
||||||
|
if (diffDays < 7) {
|
||||||
|
return d.toLocaleDateString(locale, { weekday: "short" });
|
||||||
|
}
|
||||||
|
return d.toLocaleDateString(locale, { month: "short", day: "numeric" });
|
||||||
|
} catch {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function cleanRosterPreview(raw?: string | null): string {
|
||||||
|
if (!raw) return "";
|
||||||
|
let text = raw;
|
||||||
|
// Strip markdown headings
|
||||||
|
text = text.replace(/^#{1,6}\s+/gm, "");
|
||||||
|
// Strip routing tokens [to ...] and system protocols [RECOVERY PROTOCOL], [PO ...]
|
||||||
|
text = text.replace(/\[(?:to|RECOVERY PROTOCOL|PO)[^\]]*\]/gi, "");
|
||||||
|
// Strip bold/italic/code markers
|
||||||
|
text = text.replace(/[*_`#]/g, "");
|
||||||
|
// Strip escape backslashes
|
||||||
|
text = text.replace(/\\/g, "");
|
||||||
|
// Collapse whitespace
|
||||||
|
text = text.replace(/\s+/g, " ").trim();
|
||||||
|
return text;
|
||||||
|
}
|
||||||
250
apps/web/src/pages/shell/roster-rows.tsx
Normal file
250
apps/web/src/pages/shell/roster-rows.tsx
Normal file
@ -0,0 +1,250 @@
|
|||||||
|
import { Trans, useLingui } from "@lingui/react/macro";
|
||||||
|
import type { SpaceBot, SpaceGroup } from "@rakazo/contracts";
|
||||||
|
import { BotAvatar, GroupAvatar } from "@rakazo/ui-web";
|
||||||
|
import type { RefObject } from "react";
|
||||||
|
import {
|
||||||
|
needsYouChipLabel,
|
||||||
|
rosterActivitySubtitle,
|
||||||
|
rosterStatusDot,
|
||||||
|
} from "../../lib/agent-activity";
|
||||||
|
import { localizedPreview } from "../../lib/onboarding-copy";
|
||||||
|
import type { ContextMenuPosition } from "../BotContextMenu";
|
||||||
|
import { cleanRosterPreview, formatRosterTime } from "./roster-format";
|
||||||
|
import {
|
||||||
|
rosterNameClass,
|
||||||
|
rosterPreviewClass,
|
||||||
|
rosterRowClass,
|
||||||
|
rosterTimeClass,
|
||||||
|
rosterUnreadDotClass,
|
||||||
|
} from "./roster-row-style";
|
||||||
|
|
||||||
|
export type SidebarChatItem = { kind: "bot"; chat: SpaceBot } | { kind: "group"; chat: SpaceGroup };
|
||||||
|
|
||||||
|
export type BotMenuRequest = {
|
||||||
|
kind: "bot" | "group";
|
||||||
|
id: string;
|
||||||
|
position: ContextMenuPosition;
|
||||||
|
};
|
||||||
|
|
||||||
|
/** A bot in the conversations section: reorderable by drag or Alt+Arrow within its group. */
|
||||||
|
export function TeamRosterRow({
|
||||||
|
item,
|
||||||
|
groupBotIds,
|
||||||
|
draggedBotId,
|
||||||
|
onDraggedBotIdChange,
|
||||||
|
onReorder,
|
||||||
|
selected,
|
||||||
|
onOpen,
|
||||||
|
activeSpaceId,
|
||||||
|
menuAnchor,
|
||||||
|
onMenu,
|
||||||
|
}: {
|
||||||
|
item: Extract<SidebarChatItem, { kind: "bot" }>;
|
||||||
|
groupBotIds: string[];
|
||||||
|
draggedBotId: string | null;
|
||||||
|
onDraggedBotIdChange: (botId: string | null) => void;
|
||||||
|
onReorder: (sourceId: string, targetId: string, groupBotIds: string[]) => void;
|
||||||
|
selected: boolean;
|
||||||
|
onOpen: () => void;
|
||||||
|
activeSpaceId: string | undefined;
|
||||||
|
menuAnchor: RefObject<HTMLElement | null>;
|
||||||
|
onMenu: (menu: BotMenuRequest) => void;
|
||||||
|
}) {
|
||||||
|
const { t } = useLingui();
|
||||||
|
return (
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
draggable={item.kind === "bot"}
|
||||||
|
data-roster-bot-id={item.kind === "bot" ? item.chat.id : undefined}
|
||||||
|
aria-keyshortcuts={item.kind === "bot" ? "Alt+ArrowUp Alt+ArrowDown" : undefined}
|
||||||
|
onDragStart={(event) => {
|
||||||
|
if (item.kind !== "bot") return;
|
||||||
|
onDraggedBotIdChange(item.chat.id);
|
||||||
|
event.dataTransfer.effectAllowed = "move";
|
||||||
|
event.dataTransfer.setData("text/plain", item.chat.id);
|
||||||
|
}}
|
||||||
|
onDragOver={(event) => {
|
||||||
|
if (item.kind === "bot" && draggedBotId && groupBotIds.includes(draggedBotId)) {
|
||||||
|
event.preventDefault();
|
||||||
|
event.dataTransfer.dropEffect = "move";
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
onDrop={(event) => {
|
||||||
|
if (item.kind !== "bot" || !draggedBotId) return;
|
||||||
|
event.preventDefault();
|
||||||
|
onReorder(draggedBotId, item.chat.id, groupBotIds);
|
||||||
|
onDraggedBotIdChange(null);
|
||||||
|
}}
|
||||||
|
onDragEnd={() => onDraggedBotIdChange(null)}
|
||||||
|
onKeyDown={(event) => {
|
||||||
|
if (
|
||||||
|
item.kind !== "bot" ||
|
||||||
|
!event.altKey ||
|
||||||
|
(event.key !== "ArrowUp" && event.key !== "ArrowDown")
|
||||||
|
)
|
||||||
|
return;
|
||||||
|
const index = groupBotIds.indexOf(item.chat.id);
|
||||||
|
const target = groupBotIds[index + (event.key === "ArrowUp" ? -1 : 1)];
|
||||||
|
if (!target) return;
|
||||||
|
event.preventDefault();
|
||||||
|
onReorder(item.chat.id, target, groupBotIds);
|
||||||
|
}}
|
||||||
|
aria-label={
|
||||||
|
item.kind === "bot"
|
||||||
|
? t`${item.chat.name}, 1:1 conversation`
|
||||||
|
: t`${item.chat.name}, group conversation`
|
||||||
|
}
|
||||||
|
onClick={onOpen}
|
||||||
|
onContextMenu={(event) => {
|
||||||
|
if (item.chat.spaceId !== activeSpaceId) return;
|
||||||
|
event.preventDefault();
|
||||||
|
menuAnchor.current = event.currentTarget;
|
||||||
|
onMenu({
|
||||||
|
kind: item.kind,
|
||||||
|
id: item.chat.id,
|
||||||
|
position: { x: event.clientX, y: event.clientY },
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
className={`${rosterRowClass(selected)} cursor-grab active:cursor-grabbing`}
|
||||||
|
style={{
|
||||||
|
opacity: draggedBotId === item.chat.id ? 0.55 : 1,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<div className="relative shrink-0">
|
||||||
|
<BotAvatar
|
||||||
|
color={item.chat.color}
|
||||||
|
identity={item.chat.id}
|
||||||
|
size={40}
|
||||||
|
status={item.chat.status}
|
||||||
|
/>
|
||||||
|
<span
|
||||||
|
className={`absolute -bottom-0.5 -right-0.5 size-2.5 rounded-full border-2 border-sidebar ${
|
||||||
|
rosterStatusDot(item.chat.status) === "idle" ? "bg-success" : "bg-warning animate-pulse"
|
||||||
|
}`}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className="min-w-0 flex-1">
|
||||||
|
<div className="flex items-center justify-between gap-1.5">
|
||||||
|
<div className="flex min-w-0 items-center gap-2 overflow-hidden">
|
||||||
|
<span
|
||||||
|
dir="auto"
|
||||||
|
data-roster-bot-name=""
|
||||||
|
className={`shrink-0 max-w-[170px] truncate text-ui-body tracking-tight ${rosterNameClass(
|
||||||
|
item.chat.unread,
|
||||||
|
)}`}
|
||||||
|
>
|
||||||
|
{item.chat.name}
|
||||||
|
</span>
|
||||||
|
{needsYouChipLabel(item.chat.status) ? (
|
||||||
|
<span className="shrink-0 rounded-full border border-warning/30 bg-warning/10 px-2 py-0.5 text-ui-label font-medium text-foreground dark:text-warning">
|
||||||
|
{needsYouChipLabel(item.chat.status)}
|
||||||
|
</span>
|
||||||
|
) : item.chat.title ? (
|
||||||
|
<span className="min-w-0 truncate rounded-full border border-border bg-muted px-2 py-0.5 text-ui-label font-medium text-muted-foreground">
|
||||||
|
{item.chat.title}
|
||||||
|
</span>
|
||||||
|
) : null}
|
||||||
|
{item.chat.unread ? (
|
||||||
|
<span className="sr-only">
|
||||||
|
<Trans> (unread)</Trans>
|
||||||
|
</span>
|
||||||
|
) : null}
|
||||||
|
</div>
|
||||||
|
<div className="flex shrink-0 items-center gap-1.5">
|
||||||
|
<span className={rosterTimeClass}>{formatRosterTime(item.chat.updatedAt)}</span>
|
||||||
|
{item.chat.unread ? <span aria-hidden="true" className={rosterUnreadDotClass} /> : null}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
dir="auto"
|
||||||
|
className={`mt-0.5 truncate text-ui-body leading-snug ${rosterPreviewClass(
|
||||||
|
item.chat.unread,
|
||||||
|
)}`}
|
||||||
|
>
|
||||||
|
{rosterActivitySubtitle(item.chat.status, cleanRosterPreview(item.chat.preview))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</button>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** A conversation in the projects section; a project's main conversation has no chat actions. */
|
||||||
|
export function ProjectRosterRow({
|
||||||
|
item,
|
||||||
|
selected,
|
||||||
|
onOpen,
|
||||||
|
activeSpaceId,
|
||||||
|
menuAnchor,
|
||||||
|
onMenu,
|
||||||
|
}: {
|
||||||
|
item: SidebarChatItem;
|
||||||
|
selected: boolean;
|
||||||
|
onOpen: () => void;
|
||||||
|
activeSpaceId: string | undefined;
|
||||||
|
menuAnchor: RefObject<HTMLElement | null>;
|
||||||
|
onMenu: (menu: BotMenuRequest) => void;
|
||||||
|
}) {
|
||||||
|
const { t } = useLingui();
|
||||||
|
return (
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
aria-label={
|
||||||
|
item.kind === "bot"
|
||||||
|
? t`${item.chat.name}, 1:1 conversation`
|
||||||
|
: item.chat.kind === "main"
|
||||||
|
? t`${item.chat.name}, main conversation`
|
||||||
|
: t`${item.chat.name}, group conversation`
|
||||||
|
}
|
||||||
|
onClick={onOpen}
|
||||||
|
onContextMenu={(event) => {
|
||||||
|
// A project's main conversation has no chat actions.
|
||||||
|
if (item.chat.spaceId !== activeSpaceId || item.chat.kind === "main") return;
|
||||||
|
event.preventDefault();
|
||||||
|
menuAnchor.current = event.currentTarget;
|
||||||
|
onMenu({
|
||||||
|
kind: item.kind,
|
||||||
|
id: item.chat.id,
|
||||||
|
position: { x: event.clientX, y: event.clientY },
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
className={rosterRowClass(selected)}
|
||||||
|
>
|
||||||
|
{item.kind === "bot" ? (
|
||||||
|
<BotAvatar
|
||||||
|
color={item.chat.color}
|
||||||
|
identity={item.chat.id}
|
||||||
|
size={40}
|
||||||
|
status={item.chat.status}
|
||||||
|
/>
|
||||||
|
) : (
|
||||||
|
<GroupAvatar members={(item.chat as any).members} size={40} />
|
||||||
|
)}
|
||||||
|
<div className="min-w-0 flex-1">
|
||||||
|
<div className="flex items-center justify-between gap-1.5">
|
||||||
|
<div className="flex min-w-0 items-center gap-2 overflow-hidden">
|
||||||
|
<span
|
||||||
|
dir="auto"
|
||||||
|
className={`shrink-0 max-w-[170px] truncate text-ui-body tracking-tight ${rosterNameClass(
|
||||||
|
item.chat.unread,
|
||||||
|
)}`}
|
||||||
|
>
|
||||||
|
{item.chat.name}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div className="flex shrink-0 items-center gap-1.5">
|
||||||
|
<span className={rosterTimeClass}>{formatRosterTime(item.chat.updatedAt)}</span>
|
||||||
|
{item.chat.unread ? <span aria-hidden="true" className={rosterUnreadDotClass} /> : null}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
dir="auto"
|
||||||
|
className={`mt-0.5 truncate text-ui-body leading-snug ${rosterPreviewClass(
|
||||||
|
item.chat.unread,
|
||||||
|
)}`}
|
||||||
|
>
|
||||||
|
{cleanRosterPreview(localizedPreview(item.chat))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</button>
|
||||||
|
);
|
||||||
|
}
|
||||||
9
apps/web/src/pages/shell/shell-types.ts
Normal file
9
apps/web/src/pages/shell/shell-types.ts
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
export type PendingAttachment = {
|
||||||
|
id: string;
|
||||||
|
threadKey: string;
|
||||||
|
file: File;
|
||||||
|
previewUrl?: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
/** Identity colour for bots the roster no longer knows about. */
|
||||||
|
export const FALLBACK_BOT_COLOR = "#85858A";
|
||||||
73
apps/web/src/pages/shell/side-panel-header.tsx
Normal file
73
apps/web/src/pages/shell/side-panel-header.tsx
Normal file
@ -0,0 +1,73 @@
|
|||||||
|
import { Trans, useLingui } from "@lingui/react/macro";
|
||||||
|
import type { Bot, ComputerStatus } from "@rakazo/contracts";
|
||||||
|
import { Button } from "@rakazo/ui-web";
|
||||||
|
import { Settings, X } from "lucide-react";
|
||||||
|
import { ComputerMaintenanceActions } from "../../components/ComputerMaintenanceActions";
|
||||||
|
import { computerPanelNeedsMaintenance } from "../../lib/thread-events";
|
||||||
|
|
||||||
|
/** Title row of the computer and settings side panel, with its switch and close buttons. */
|
||||||
|
export function SidePanelHeader({
|
||||||
|
panel,
|
||||||
|
active,
|
||||||
|
computer,
|
||||||
|
computerOpen,
|
||||||
|
booting,
|
||||||
|
refreshThread,
|
||||||
|
onPanelChange,
|
||||||
|
}: {
|
||||||
|
panel: "computer" | "settings";
|
||||||
|
active: Bot | undefined;
|
||||||
|
computer: ComputerStatus | null;
|
||||||
|
computerOpen: boolean;
|
||||||
|
booting: boolean;
|
||||||
|
refreshThread: (botId: string) => Promise<unknown>;
|
||||||
|
onPanelChange: (panel: "computer" | "settings" | null) => void;
|
||||||
|
}) {
|
||||||
|
const { t } = useLingui();
|
||||||
|
return (
|
||||||
|
<div className="mb-4 flex items-center justify-between">
|
||||||
|
<span className="text-ui-body text-muted-foreground">
|
||||||
|
{panel === "settings" ? (
|
||||||
|
<Trans>Settings</Trans>
|
||||||
|
) : active ? (
|
||||||
|
(computer?.state ?? active.status)
|
||||||
|
) : (
|
||||||
|
<Trans>Group</Trans>
|
||||||
|
)}
|
||||||
|
</span>
|
||||||
|
<div className="flex gap-1">
|
||||||
|
{active &&
|
||||||
|
panel === "computer" &&
|
||||||
|
!computerOpen &&
|
||||||
|
computerPanelNeedsMaintenance(computer?.state, booting) ? (
|
||||||
|
<ComputerMaintenanceActions
|
||||||
|
botId={active.id}
|
||||||
|
computer={computer}
|
||||||
|
onChanged={async () => {
|
||||||
|
await refreshThread(active.id);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
) : null}
|
||||||
|
{active ? (
|
||||||
|
<Button
|
||||||
|
variant="ghost"
|
||||||
|
size="icon-sm"
|
||||||
|
aria-label={panel === "settings" ? t`Show computer` : t`Show settings`}
|
||||||
|
onClick={() => onPanelChange(panel === "settings" ? "computer" : "settings")}
|
||||||
|
className={panel === "settings" ? "text-foreground" : "text-muted-foreground"}
|
||||||
|
>
|
||||||
|
<Settings strokeWidth={1.7} className="size-icon-md" />
|
||||||
|
</Button>
|
||||||
|
) : null}
|
||||||
|
<Button
|
||||||
|
variant="ghost"
|
||||||
|
size="icon-sm"
|
||||||
|
aria-label={t`Close panel`}
|
||||||
|
onClick={() => onPanelChange(null)}
|
||||||
|
>
|
||||||
|
<X strokeWidth={1.8} className="size-icon-md" />
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
161
apps/web/src/pages/shell/sidebar-group-header.tsx
Normal file
161
apps/web/src/pages/shell/sidebar-group-header.tsx
Normal file
@ -0,0 +1,161 @@
|
|||||||
|
import { useLingui } from "@lingui/react/macro";
|
||||||
|
import type { BotSection, Space } from "@rakazo/contracts";
|
||||||
|
import { Button } from "@rakazo/ui-web";
|
||||||
|
import { ChevronDown, Folder, GripVertical, Lock, MoreHorizontal } from "lucide-react";
|
||||||
|
import type { RefObject } from "react";
|
||||||
|
import { ProjectDragGrip } from "../../components/SortableGroup";
|
||||||
|
import type { ContextMenuPosition } from "../BotContextMenu";
|
||||||
|
|
||||||
|
export type SidebarGroupHeaderGroup = {
|
||||||
|
key: string;
|
||||||
|
title: string | null;
|
||||||
|
sectionId: string | null;
|
||||||
|
spaceId: string;
|
||||||
|
spaceName: string;
|
||||||
|
canDeleteSpace: boolean;
|
||||||
|
emptySpaceId: string | undefined;
|
||||||
|
showLock: boolean;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type SpaceMenuRequest = { id: string; position: ContextMenuPosition };
|
||||||
|
|
||||||
|
export type SectionMenuRequest = {
|
||||||
|
section: BotSection;
|
||||||
|
spaceId: string;
|
||||||
|
position: ContextMenuPosition;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Collapsible title of a sidebar group. Project groups add a drag grip, show a lock for other
|
||||||
|
* spaces and select an empty space instead of opening it.
|
||||||
|
*/
|
||||||
|
export function SidebarGroupHeader({
|
||||||
|
variant,
|
||||||
|
group,
|
||||||
|
collapsed,
|
||||||
|
activeSpaceId,
|
||||||
|
botSections,
|
||||||
|
spaces,
|
||||||
|
onOpenEmptySpace,
|
||||||
|
onToggle,
|
||||||
|
sectionMenuAnchor,
|
||||||
|
onSectionMenu,
|
||||||
|
spaceMenuAnchor,
|
||||||
|
onSpaceMenu,
|
||||||
|
}: {
|
||||||
|
variant: "conversation" | "project";
|
||||||
|
group: SidebarGroupHeaderGroup;
|
||||||
|
collapsed: boolean;
|
||||||
|
activeSpaceId: string | undefined;
|
||||||
|
botSections: BotSection[];
|
||||||
|
spaces: Space[];
|
||||||
|
onOpenEmptySpace: (spaceId: string) => void;
|
||||||
|
onToggle: (key: string) => void;
|
||||||
|
sectionMenuAnchor: RefObject<HTMLElement | null>;
|
||||||
|
onSectionMenu: (menu: SectionMenuRequest) => void;
|
||||||
|
spaceMenuAnchor: RefObject<HTMLElement | null>;
|
||||||
|
onSpaceMenu: (menu: SpaceMenuRequest) => void;
|
||||||
|
}) {
|
||||||
|
const { t } = useLingui();
|
||||||
|
const project = variant === "project";
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
className={
|
||||||
|
project ? "flex items-center pt-3 pb-0.5 relative" : "flex items-center pt-3 pb-0.5"
|
||||||
|
}
|
||||||
|
>
|
||||||
|
{project ? (
|
||||||
|
// Drag grip — positioned to the left of the title text
|
||||||
|
<ProjectDragGrip className="absolute left-1 top-1/2 -translate-y-1/2 w-6 h-6 rounded flex items-center justify-center text-muted-foreground/30 hover:text-muted-foreground/70 active:text-muted-foreground transition-colors cursor-grab active:cursor-grabbing">
|
||||||
|
<GripVertical className="size-icon-sm" strokeWidth={2} />
|
||||||
|
</ProjectDragGrip>
|
||||||
|
) : null}
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
className={`flex min-w-0 flex-1 items-center justify-between gap-2 rounded-lg ${project ? "pl-8" : "px-2.5"} py-1 text-ui-label font-semibold tracking-wider uppercase text-foreground/65 dark:text-muted-foreground/80 hover:text-foreground focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-[-2px] focus-visible:outline-ring`}
|
||||||
|
onClick={() => {
|
||||||
|
if (group.emptySpaceId) {
|
||||||
|
onOpenEmptySpace(group.emptySpaceId);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
onToggle(group.key);
|
||||||
|
}}
|
||||||
|
onContextMenu={
|
||||||
|
group.sectionId
|
||||||
|
? (event) => {
|
||||||
|
event.preventDefault();
|
||||||
|
// Prefer section rename over delete-space when both apply;
|
||||||
|
// the dedicated space-actions button still opens the space menu.
|
||||||
|
const sections =
|
||||||
|
group.spaceId === activeSpaceId
|
||||||
|
? botSections
|
||||||
|
: (spaces.find((space) => space.id === group.spaceId)?.botSections ?? []);
|
||||||
|
const section = sections.find((item) => item.id === group.sectionId);
|
||||||
|
if (!section) return;
|
||||||
|
sectionMenuAnchor.current = event.currentTarget;
|
||||||
|
onSectionMenu({
|
||||||
|
section,
|
||||||
|
spaceId: group.spaceId,
|
||||||
|
position: { x: event.clientX, y: event.clientY },
|
||||||
|
});
|
||||||
|
}
|
||||||
|
: group.canDeleteSpace
|
||||||
|
? (event) => {
|
||||||
|
event.preventDefault();
|
||||||
|
spaceMenuAnchor.current = event.currentTarget;
|
||||||
|
onSpaceMenu({
|
||||||
|
id: group.spaceId,
|
||||||
|
position: { x: event.clientX, y: event.clientY },
|
||||||
|
});
|
||||||
|
}
|
||||||
|
: undefined
|
||||||
|
}
|
||||||
|
aria-expanded={group.emptySpaceId ? undefined : !collapsed}
|
||||||
|
aria-label={
|
||||||
|
group.emptySpaceId
|
||||||
|
? project
|
||||||
|
? t`Select ${group.title}`
|
||||||
|
: t`Open ${group.title}`
|
||||||
|
: collapsed
|
||||||
|
? t`Expand ${group.title}`
|
||||||
|
: t`Collapse ${group.title}`
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<span className="flex min-w-0 items-center gap-1.5 truncate">
|
||||||
|
{project ? (
|
||||||
|
group.showLock ? (
|
||||||
|
<Lock strokeWidth={2} aria-hidden="true" className="size-icon-sm" />
|
||||||
|
) : null
|
||||||
|
) : (
|
||||||
|
<Folder strokeWidth={2} aria-hidden="true" className="size-icon-sm" />
|
||||||
|
)}
|
||||||
|
<span className="truncate">{group.title}</span>
|
||||||
|
</span>
|
||||||
|
{group.emptySpaceId ? null : (
|
||||||
|
<ChevronDown
|
||||||
|
strokeWidth={1.8}
|
||||||
|
className={`size-icon-md ${collapsed ? "-rotate-90 transition-transform" : "transition-transform"}`}
|
||||||
|
aria-hidden="true"
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</button>
|
||||||
|
{group.canDeleteSpace ? (
|
||||||
|
<Button
|
||||||
|
variant="ghost"
|
||||||
|
size="icon-sm"
|
||||||
|
aria-label={t`Actions for ${group.spaceName}`}
|
||||||
|
onClick={(event) => {
|
||||||
|
const rect = event.currentTarget.getBoundingClientRect();
|
||||||
|
spaceMenuAnchor.current = event.currentTarget;
|
||||||
|
onSpaceMenu({
|
||||||
|
id: group.spaceId,
|
||||||
|
position: { x: rect.left, y: rect.bottom },
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<MoreHorizontal aria-hidden="true" className="size-icon-md" />
|
||||||
|
</Button>
|
||||||
|
) : null}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
118
apps/web/src/pages/shell/sidebar-header.tsx
Normal file
118
apps/web/src/pages/shell/sidebar-header.tsx
Normal file
@ -0,0 +1,118 @@
|
|||||||
|
import { useLingui } from "@lingui/react/macro";
|
||||||
|
import type { Bot } from "@rakazo/contracts";
|
||||||
|
import { Popover, PopoverContent, PopoverTrigger, Wordmark } from "@rakazo/ui-web";
|
||||||
|
import { Bell } from "lucide-react";
|
||||||
|
import { WindowChrome } from "../WindowChrome";
|
||||||
|
import { BotCreatePicker } from "./bot-picker";
|
||||||
|
|
||||||
|
/** Window chrome, wordmark, the activity toggle and the create menu atop the sidebar. */
|
||||||
|
export function SidebarHeader({
|
||||||
|
activityMode,
|
||||||
|
onToggleActivityMode,
|
||||||
|
createMenuOpen,
|
||||||
|
onCreateMenuOpenChange,
|
||||||
|
onCloseMobileSidebar,
|
||||||
|
bots,
|
||||||
|
onCreateBot,
|
||||||
|
onOpenBot,
|
||||||
|
onCreateGroup,
|
||||||
|
onCreateSpace,
|
||||||
|
onShowGroupInfo,
|
||||||
|
onShowSpaceInfo,
|
||||||
|
}: {
|
||||||
|
activityMode: boolean;
|
||||||
|
onToggleActivityMode: () => void;
|
||||||
|
createMenuOpen: boolean;
|
||||||
|
onCreateMenuOpenChange: (open: boolean) => void;
|
||||||
|
onCloseMobileSidebar: () => void;
|
||||||
|
bots: Bot[];
|
||||||
|
onCreateBot: () => void;
|
||||||
|
onOpenBot: (id: string) => void;
|
||||||
|
onCreateGroup: () => void;
|
||||||
|
onCreateSpace: () => void;
|
||||||
|
onShowGroupInfo: () => void;
|
||||||
|
onShowSpaceInfo: () => void;
|
||||||
|
}) {
|
||||||
|
const { t } = useLingui();
|
||||||
|
return (
|
||||||
|
<div className="app-drag flex items-center justify-between px-4 lg:px-6 2xl:px-8 pb-3 pt-4">
|
||||||
|
<WindowChrome />
|
||||||
|
<div className="flex-1 px-1">
|
||||||
|
<Wordmark />
|
||||||
|
</div>
|
||||||
|
<div className="relative flex items-center gap-2.5">
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
aria-label={t`Activity`}
|
||||||
|
aria-pressed={activityMode}
|
||||||
|
title={t`Activity`}
|
||||||
|
data-activity-mode={activityMode ? "on" : "off"}
|
||||||
|
onClick={onToggleActivityMode}
|
||||||
|
className={`app-no-drag flex size-control-sm items-center justify-center rounded-full ${
|
||||||
|
activityMode
|
||||||
|
? "bg-primary text-primary-foreground"
|
||||||
|
: "rk-sidebar-muted hover:text-foreground/75"
|
||||||
|
}`}
|
||||||
|
>
|
||||||
|
<Bell
|
||||||
|
strokeWidth={1.8}
|
||||||
|
fill={activityMode ? "currentColor" : "none"}
|
||||||
|
aria-hidden="true"
|
||||||
|
className="size-icon-md"
|
||||||
|
/>
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<Popover open={createMenuOpen} onOpenChange={onCreateMenuOpenChange}>
|
||||||
|
<PopoverTrigger
|
||||||
|
className="app-no-drag text-[21px] rk-sidebar-muted hover:text-foreground/75"
|
||||||
|
title={t`Create`}
|
||||||
|
data-testid="create-menu-trigger"
|
||||||
|
>
|
||||||
|
+
|
||||||
|
</PopoverTrigger>
|
||||||
|
{/* Unmount with the state change so the panel it opens never coexists with the menu. */}
|
||||||
|
{createMenuOpen ? (
|
||||||
|
<PopoverContent
|
||||||
|
align="end"
|
||||||
|
className="app-no-drag w-auto gap-0 overflow-hidden p-0 data-closed:animate-none"
|
||||||
|
>
|
||||||
|
<BotCreatePicker
|
||||||
|
bots={bots}
|
||||||
|
onCreateBot={() => {
|
||||||
|
onCreateMenuOpenChange(false);
|
||||||
|
onCloseMobileSidebar();
|
||||||
|
onCreateBot();
|
||||||
|
}}
|
||||||
|
onOpenBot={(id) => {
|
||||||
|
onCreateMenuOpenChange(false);
|
||||||
|
onCloseMobileSidebar();
|
||||||
|
onOpenBot(id);
|
||||||
|
}}
|
||||||
|
onCreateGroup={() => {
|
||||||
|
onCreateMenuOpenChange(false);
|
||||||
|
onCloseMobileSidebar();
|
||||||
|
onCreateGroup();
|
||||||
|
}}
|
||||||
|
onCreateSpace={() => {
|
||||||
|
onCreateMenuOpenChange(false);
|
||||||
|
onCloseMobileSidebar();
|
||||||
|
onCreateSpace();
|
||||||
|
}}
|
||||||
|
onShowGroupInfo={() => {
|
||||||
|
onCreateMenuOpenChange(false);
|
||||||
|
onCloseMobileSidebar();
|
||||||
|
onShowGroupInfo();
|
||||||
|
}}
|
||||||
|
onShowSpaceInfo={() => {
|
||||||
|
onCreateMenuOpenChange(false);
|
||||||
|
onCloseMobileSidebar();
|
||||||
|
onShowSpaceInfo();
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</PopoverContent>
|
||||||
|
) : null}
|
||||||
|
</Popover>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
45
apps/web/src/pages/shell/sidebar-toggle-buttons.tsx
Normal file
45
apps/web/src/pages/shell/sidebar-toggle-buttons.tsx
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
import { useLingui } from "@lingui/react/macro";
|
||||||
|
import { Menu, PanelLeftClose, PanelLeftOpen } from "lucide-react";
|
||||||
|
import { desktopBridge } from "../../lib/desktop";
|
||||||
|
import { WindowChrome } from "../WindowChrome";
|
||||||
|
|
||||||
|
/** Leading controls of a main header: open the mobile navigation or collapse the bots sidebar. */
|
||||||
|
export function SidebarToggleButtons({
|
||||||
|
collapsed,
|
||||||
|
onCollapsedChange,
|
||||||
|
onOpenNavigation,
|
||||||
|
}: {
|
||||||
|
collapsed: boolean;
|
||||||
|
onCollapsedChange: (collapsed: boolean) => void;
|
||||||
|
onOpenNavigation: () => void;
|
||||||
|
}) {
|
||||||
|
const { t } = useLingui();
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
{/* Collapsed bots sidebar: this header is the leading edge for window chrome. */}
|
||||||
|
{collapsed && desktopBridge() ? <WindowChrome /> : null}
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
aria-label={t`Open navigation`}
|
||||||
|
onClick={onOpenNavigation}
|
||||||
|
className="app-no-drag grid size-control-lg shrink-0 place-items-center rounded-lg text-foreground/75 hover:bg-accent md:hidden"
|
||||||
|
>
|
||||||
|
<Menu strokeWidth={1.7} className="size-icon-lg" />
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
data-testid="toggle-bots-sidebar"
|
||||||
|
aria-label={collapsed ? t`Show bots` : t`Minimize bots`}
|
||||||
|
title={collapsed ? t`Show bots` : t`Minimize bots`}
|
||||||
|
onClick={() => onCollapsedChange(!collapsed)}
|
||||||
|
className="app-no-drag hidden size-control-lg shrink-0 place-items-center rounded-lg text-foreground/75 hover:bg-accent md:grid"
|
||||||
|
>
|
||||||
|
{collapsed ? (
|
||||||
|
<PanelLeftOpen strokeWidth={1.7} aria-hidden="true" className="size-icon-lg" />
|
||||||
|
) : (
|
||||||
|
<PanelLeftClose strokeWidth={1.7} aria-hidden="true" className="size-icon-lg" />
|
||||||
|
)}
|
||||||
|
</button>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
52
apps/web/src/pages/shell/thread-state.ts
Normal file
52
apps/web/src/pages/shell/thread-state.ts
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
import type { Bot, ComputerStatus, Group, ProductEvent, ThreadSnapshot } from "@rakazo/contracts";
|
||||||
|
import type { MutableRefObject } from "react";
|
||||||
|
import {
|
||||||
|
isComputerStatusEvent,
|
||||||
|
isThreadSnapshotEvent,
|
||||||
|
reduceComputerStatus,
|
||||||
|
reduceThreadSnapshot,
|
||||||
|
} from "../../lib/thread-events";
|
||||||
|
|
||||||
|
const THREAD_SNAPSHOT_TIMEOUT_MS = 2_000;
|
||||||
|
|
||||||
|
export function threadSnapshotSignal(parent: AbortSignal): AbortSignal {
|
||||||
|
return AbortSignal.any([parent, AbortSignal.timeout(THREAD_SNAPSHOT_TIMEOUT_MS)]);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function firstThreadRoute(
|
||||||
|
bots: readonly Pick<Bot, "id">[],
|
||||||
|
groups: readonly Pick<Group, "id" | "kind">[],
|
||||||
|
/** In a project the user lands in its main conversation. */
|
||||||
|
inProject = false,
|
||||||
|
): string {
|
||||||
|
const main = inProject ? groups.find((group) => group.kind === "main") : undefined;
|
||||||
|
if (main) return `/app/g/${main.id}`;
|
||||||
|
if (bots[0]) return `/app/${bots[0].id}`;
|
||||||
|
if (groups[0]) return `/app/g/${groups[0].id}`;
|
||||||
|
return "/app";
|
||||||
|
}
|
||||||
|
|
||||||
|
export function applyThreadEvent(
|
||||||
|
event: ProductEvent,
|
||||||
|
commitSnapshot: (next: ThreadSnapshot | null) => void,
|
||||||
|
commitComputer: (next: ComputerStatus | null) => void,
|
||||||
|
snapshotRef: MutableRefObject<ThreadSnapshot | null>,
|
||||||
|
computerRef: MutableRefObject<ComputerStatus | null>,
|
||||||
|
) {
|
||||||
|
if (isThreadSnapshotEvent(event)) {
|
||||||
|
const next = reduceThreadSnapshot(snapshotRef.current, event);
|
||||||
|
commitSnapshot(next);
|
||||||
|
}
|
||||||
|
if (isComputerStatusEvent(event)) {
|
||||||
|
const next = reduceComputerStatus(computerRef.current, event);
|
||||||
|
commitComputer(next);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function newClientNonce(): string {
|
||||||
|
const webCrypto = globalThis.crypto;
|
||||||
|
if (webCrypto && typeof webCrypto.randomUUID === "function") {
|
||||||
|
return webCrypto.randomUUID();
|
||||||
|
}
|
||||||
|
return `m-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 10)}`;
|
||||||
|
}
|
||||||
1298
apps/web/src/pages/shell/transcript.tsx
Normal file
1298
apps/web/src/pages/shell/transcript.tsx
Normal file
File diff suppressed because it is too large
Load Diff
31
apps/web/src/pages/shell/use-agent-skills.ts
Normal file
31
apps/web/src/pages/shell/use-agent-skills.ts
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
import type { AgentSkillCatalogEntry } from "@rakazo/contracts";
|
||||||
|
import { useCallback, useEffect, useState } from "react";
|
||||||
|
import { rpc } from "../../lib/rpc";
|
||||||
|
|
||||||
|
export function useAgentSkills() {
|
||||||
|
const [agentSkills, setAgentSkills] = useState<AgentSkillCatalogEntry[]>([]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
let cancelled = false;
|
||||||
|
void rpc.agentSkills
|
||||||
|
.list()
|
||||||
|
.then((skills) => {
|
||||||
|
if (!cancelled) setAgentSkills(skills);
|
||||||
|
})
|
||||||
|
.catch(() => {
|
||||||
|
if (!cancelled) setAgentSkills([]);
|
||||||
|
});
|
||||||
|
return () => {
|
||||||
|
cancelled = true;
|
||||||
|
};
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const refreshAgentSkills = useCallback(() => {
|
||||||
|
void rpc.agentSkills
|
||||||
|
.list()
|
||||||
|
.then(setAgentSkills)
|
||||||
|
.catch(() => undefined);
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
return { agentSkills, setAgentSkills, refreshAgentSkills };
|
||||||
|
}
|
||||||
67
apps/web/src/pages/shell/use-bots-sidebar-collapse.ts
Normal file
67
apps/web/src/pages/shell/use-bots-sidebar-collapse.ts
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
import { useEffect, useRef, useState } from "react";
|
||||||
|
import {
|
||||||
|
BOTS_SIDEBAR_EDGE_DRAG_PX,
|
||||||
|
readBotsSidebarCollapsed,
|
||||||
|
writeBotsSidebarCollapsed,
|
||||||
|
} from "../../lib/bots-sidebar-pref";
|
||||||
|
|
||||||
|
export function useBotsSidebarCollapse(userId: string | undefined) {
|
||||||
|
const [botsSidebarCollapsed, setBotsSidebarCollapsed] = useState(false);
|
||||||
|
const botsSidebarEdgeDragRef = useRef<{ startX: number; mode: "expand" | "collapse" } | null>(
|
||||||
|
null,
|
||||||
|
);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
setBotsSidebarCollapsed(readBotsSidebarCollapsed(userId));
|
||||||
|
}, [userId]);
|
||||||
|
|
||||||
|
function setBotsSidebarCollapsedPref(collapsed: boolean) {
|
||||||
|
setBotsSidebarCollapsed(collapsed);
|
||||||
|
writeBotsSidebarCollapsed(userId, collapsed);
|
||||||
|
}
|
||||||
|
|
||||||
|
function onBotsSidebarEdgePointerDown(event: React.PointerEvent<HTMLButtonElement>) {
|
||||||
|
event.currentTarget.setPointerCapture(event.pointerId);
|
||||||
|
botsSidebarEdgeDragRef.current = {
|
||||||
|
startX: event.clientX,
|
||||||
|
mode: botsSidebarCollapsed ? "expand" : "collapse",
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function onBotsSidebarEdgePointerMove(event: React.PointerEvent<HTMLButtonElement>) {
|
||||||
|
const drag = botsSidebarEdgeDragRef.current;
|
||||||
|
if (!drag) return;
|
||||||
|
const rtl =
|
||||||
|
typeof document !== "undefined" && document.documentElement.getAttribute("dir") === "rtl";
|
||||||
|
const delta = rtl ? drag.startX - event.clientX : event.clientX - drag.startX;
|
||||||
|
if (drag.mode === "expand" && delta >= BOTS_SIDEBAR_EDGE_DRAG_PX) {
|
||||||
|
botsSidebarEdgeDragRef.current = null;
|
||||||
|
setBotsSidebarCollapsedPref(false);
|
||||||
|
} else if (drag.mode === "collapse" && delta <= -BOTS_SIDEBAR_EDGE_DRAG_PX) {
|
||||||
|
botsSidebarEdgeDragRef.current = null;
|
||||||
|
setBotsSidebarCollapsedPref(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function onBotsSidebarEdgePointerUp(event: React.PointerEvent<HTMLButtonElement>) {
|
||||||
|
const drag = botsSidebarEdgeDragRef.current;
|
||||||
|
botsSidebarEdgeDragRef.current = null;
|
||||||
|
if (!drag) return;
|
||||||
|
if (Math.abs(event.clientX - drag.startX) < BOTS_SIDEBAR_EDGE_DRAG_PX) {
|
||||||
|
setBotsSidebarCollapsedPref(!botsSidebarCollapsed);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function onBotsSidebarEdgePointerCancel() {
|
||||||
|
botsSidebarEdgeDragRef.current = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
botsSidebarCollapsed,
|
||||||
|
setBotsSidebarCollapsedPref,
|
||||||
|
onBotsSidebarEdgePointerDown,
|
||||||
|
onBotsSidebarEdgePointerMove,
|
||||||
|
onBotsSidebarEdgePointerUp,
|
||||||
|
onBotsSidebarEdgePointerCancel,
|
||||||
|
};
|
||||||
|
}
|
||||||
86
apps/web/src/pages/shell/use-browser-notifications.ts
Normal file
86
apps/web/src/pages/shell/use-browser-notifications.ts
Normal file
@ -0,0 +1,86 @@
|
|||||||
|
import type { Bot, ProductEvent } from "@rakazo/contracts";
|
||||||
|
import type { RefObject } from "react";
|
||||||
|
import { useCallback, useRef } from "react";
|
||||||
|
import {
|
||||||
|
deliverBrowserNotification as deliverNativeBrowserNotification,
|
||||||
|
shouldNotifyBrowser,
|
||||||
|
} from "../../lib/browser-notifications";
|
||||||
|
|
||||||
|
type PendingBrowserNotification = {
|
||||||
|
event: Pick<ProductEvent, "id" | "type" | "threadId" | "botId" | "payload">;
|
||||||
|
botId: string;
|
||||||
|
botName: string;
|
||||||
|
groupNotification: boolean;
|
||||||
|
};
|
||||||
|
|
||||||
|
export function useBrowserNotifications(botsRef: RefObject<Bot[]>) {
|
||||||
|
const notifiedBrowserEvents = useRef(new Set<string>());
|
||||||
|
const pendingBrowserNotifications = useRef(new Map<string, PendingBrowserNotification>());
|
||||||
|
const deliverBrowserNotification = useCallback((pending: PendingBrowserNotification): boolean => {
|
||||||
|
const currentBot = botsRef.current.find((bot) => bot.id === pending.botId);
|
||||||
|
if (!currentBot || typeof Notification === "undefined") return true;
|
||||||
|
const result = deliverNativeBrowserNotification(
|
||||||
|
pending.event,
|
||||||
|
currentBot.name || pending.botName,
|
||||||
|
{
|
||||||
|
enabled: pending.groupNotification || currentBot.notifyOnFinish,
|
||||||
|
pageVisible: document.visibilityState === "visible",
|
||||||
|
windowFocused: document.hasFocus(),
|
||||||
|
permission: Notification.permission,
|
||||||
|
notifiedEventIds: notifiedBrowserEvents.current,
|
||||||
|
show: (title, body, tag) => new Notification(title, { body, tag }),
|
||||||
|
},
|
||||||
|
);
|
||||||
|
return result !== "pending";
|
||||||
|
}, []);
|
||||||
|
const flushPendingBrowserNotifications = useCallback(() => {
|
||||||
|
for (const [threadId, pending] of pendingBrowserNotifications.current) {
|
||||||
|
if (deliverBrowserNotification(pending)) {
|
||||||
|
pendingBrowserNotifications.current.delete(threadId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, [deliverBrowserNotification]);
|
||||||
|
const notifyBrowserForEvent = useCallback(
|
||||||
|
(
|
||||||
|
event: Pick<ProductEvent, "id" | "type" | "threadId" | "seq" | "botId" | "payload">,
|
||||||
|
subscribedThreadId: string | undefined,
|
||||||
|
initialCursor: number,
|
||||||
|
streamReady: boolean,
|
||||||
|
botName: string,
|
||||||
|
enabled: boolean,
|
||||||
|
groupNotification: boolean,
|
||||||
|
) => {
|
||||||
|
const botId = event.botId;
|
||||||
|
if (typeof botId !== "string") return;
|
||||||
|
const eligible = shouldNotifyBrowser(event, {
|
||||||
|
subscribedThreadId: subscribedThreadId ?? "",
|
||||||
|
initialCursor,
|
||||||
|
streamReady,
|
||||||
|
pageVisible: document.visibilityState === "visible",
|
||||||
|
windowFocused: document.hasFocus(),
|
||||||
|
permission: "granted",
|
||||||
|
notifiedEventIds: notifiedBrowserEvents.current,
|
||||||
|
});
|
||||||
|
if (!eligible || !enabled) return;
|
||||||
|
const pending = {
|
||||||
|
event,
|
||||||
|
botId,
|
||||||
|
botName,
|
||||||
|
groupNotification,
|
||||||
|
} satisfies PendingBrowserNotification;
|
||||||
|
if (typeof Notification === "undefined" || Notification.permission === "denied") return;
|
||||||
|
if (Notification.permission === "default") {
|
||||||
|
pendingBrowserNotifications.current.set(event.threadId, pending);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (deliverBrowserNotification(pending)) {
|
||||||
|
pendingBrowserNotifications.current.delete(event.threadId);
|
||||||
|
} else {
|
||||||
|
pendingBrowserNotifications.current.set(event.threadId, pending);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
[deliverBrowserNotification],
|
||||||
|
);
|
||||||
|
|
||||||
|
return { flushPendingBrowserNotifications, notifyBrowserForEvent };
|
||||||
|
}
|
||||||
43
apps/web/src/pages/shell/use-computer-viewport.ts
Normal file
43
apps/web/src/pages/shell/use-computer-viewport.ts
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
import { useEffect, useState } from "react";
|
||||||
|
|
||||||
|
/** Visible area above an on-screen keyboard while the full-screen computer is open. */
|
||||||
|
export function useComputerViewport(
|
||||||
|
computerOpen: boolean,
|
||||||
|
): { height: number; offsetTop: number } | null {
|
||||||
|
const [computerViewport, setComputerViewport] = useState<{
|
||||||
|
height: number;
|
||||||
|
offsetTop: number;
|
||||||
|
} | null>(null);
|
||||||
|
useEffect(() => {
|
||||||
|
if (!computerOpen) {
|
||||||
|
setComputerViewport(null);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const viewport = window.visualViewport;
|
||||||
|
if (!viewport) return;
|
||||||
|
const sync = () => {
|
||||||
|
const height = Math.round(viewport.height);
|
||||||
|
const offsetTop = Math.round(viewport.offsetTop);
|
||||||
|
// Desktop scrollbars and sub-pixel viewport events must not rewrite the
|
||||||
|
// overlay height: that feedback loop moves the maintenance menu forever.
|
||||||
|
const keyboardInset = Math.round(window.innerHeight) - height - offsetTop;
|
||||||
|
if (keyboardInset < 80) {
|
||||||
|
setComputerViewport((current) => (current === null ? current : null));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
setComputerViewport((current) => {
|
||||||
|
if (current && current.height === height && current.offsetTop === offsetTop) return current;
|
||||||
|
return { height, offsetTop };
|
||||||
|
});
|
||||||
|
};
|
||||||
|
sync();
|
||||||
|
viewport.addEventListener("resize", sync);
|
||||||
|
viewport.addEventListener("scroll", sync);
|
||||||
|
return () => {
|
||||||
|
viewport.removeEventListener("resize", sync);
|
||||||
|
viewport.removeEventListener("scroll", sync);
|
||||||
|
};
|
||||||
|
}, [computerOpen]);
|
||||||
|
|
||||||
|
return computerViewport;
|
||||||
|
}
|
||||||
45
apps/web/src/pages/shell/use-heute-action-count.ts
Normal file
45
apps/web/src/pages/shell/use-heute-action-count.ts
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
import type { Bot, Group } from "@rakazo/contracts";
|
||||||
|
import type { RefObject } from "react";
|
||||||
|
import { useEffect, useState } from "react";
|
||||||
|
import { buildHeuteBrief } from "../../lib/heute-brief";
|
||||||
|
import { rpc } from "../../lib/rpc";
|
||||||
|
|
||||||
|
export function useHeuteActionCount(groups: Group[], botsRef: RefObject<Bot[]>): number {
|
||||||
|
const [heuteActionCount, setHeuteActionCount] = useState(0);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
let cancelled = false;
|
||||||
|
let timer: number | undefined;
|
||||||
|
|
||||||
|
const tick = async () => {
|
||||||
|
try {
|
||||||
|
const [active, recent] = await Promise.all([
|
||||||
|
rpc.runs.list({ filter: "active" }),
|
||||||
|
rpc.runs.list({ filter: "recent" }),
|
||||||
|
]);
|
||||||
|
if (cancelled) return;
|
||||||
|
const brief = buildHeuteBrief({
|
||||||
|
bots: botsRef.current,
|
||||||
|
groups,
|
||||||
|
activeRuns: active.runs,
|
||||||
|
recentRuns: recent.runs,
|
||||||
|
});
|
||||||
|
setHeuteActionCount(brief.actionCount);
|
||||||
|
} catch {
|
||||||
|
if (cancelled) return;
|
||||||
|
} finally {
|
||||||
|
if (!cancelled) {
|
||||||
|
timer = window.setTimeout(() => void tick(), 15_000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
void tick();
|
||||||
|
return () => {
|
||||||
|
cancelled = true;
|
||||||
|
if (timer !== undefined) window.clearTimeout(timer);
|
||||||
|
};
|
||||||
|
}, [groups]);
|
||||||
|
|
||||||
|
return heuteActionCount;
|
||||||
|
}
|
||||||
159
apps/web/src/pages/shell/use-mention-targets.ts
Normal file
159
apps/web/src/pages/shell/use-mention-targets.ts
Normal file
@ -0,0 +1,159 @@
|
|||||||
|
import type {
|
||||||
|
Bot,
|
||||||
|
Connection,
|
||||||
|
ConnectionCatalogItem,
|
||||||
|
Group,
|
||||||
|
Routine,
|
||||||
|
ThreadSnapshot,
|
||||||
|
} from "@rakazo/contracts";
|
||||||
|
import type { ComposerMention } from "@rakazo/core";
|
||||||
|
import { buildComposerMentionOptions } from "@rakazo/core";
|
||||||
|
import { useEffect, useMemo, useRef, useState } from "react";
|
||||||
|
import { rpc } from "../../lib/rpc";
|
||||||
|
|
||||||
|
export type MentionTargetsInput = {
|
||||||
|
bots: Bot[];
|
||||||
|
groups: Group[];
|
||||||
|
groupId: string | undefined;
|
||||||
|
inGroup: boolean;
|
||||||
|
activeGroup: Group | undefined;
|
||||||
|
activeSnapshot: ThreadSnapshot | null;
|
||||||
|
initialBotsLoaded: boolean;
|
||||||
|
};
|
||||||
|
|
||||||
|
export function useMentionTargets({
|
||||||
|
bots,
|
||||||
|
groups,
|
||||||
|
groupId,
|
||||||
|
inGroup,
|
||||||
|
activeGroup,
|
||||||
|
activeSnapshot,
|
||||||
|
initialBotsLoaded,
|
||||||
|
}: MentionTargetsInput): ComposerMention[] {
|
||||||
|
const [mentionRoutines, setMentionRoutines] = useState<Array<Routine & { botName?: string }>>([]);
|
||||||
|
const [mentionConnectors, setMentionConnectors] = useState<
|
||||||
|
Array<{
|
||||||
|
id: string;
|
||||||
|
name: string;
|
||||||
|
authStatus: "connected" | "needs_auth";
|
||||||
|
connectionId?: string;
|
||||||
|
}>
|
||||||
|
>([]);
|
||||||
|
|
||||||
|
const composerMentionTargets = useMemo(() => {
|
||||||
|
const mentionBots = new Map(
|
||||||
|
bots.map((bot) => [bot.id, { id: bot.id, name: bot.name, color: bot.color }]),
|
||||||
|
);
|
||||||
|
// Group members stay mentionable when the sidebar bot list is still catching up
|
||||||
|
// after creating the group and remounting the shell.
|
||||||
|
if (inGroup) {
|
||||||
|
for (const member of [...(activeGroup?.members ?? []), ...(activeSnapshot?.members ?? [])]) {
|
||||||
|
if (!mentionBots.has(member.botId)) {
|
||||||
|
mentionBots.set(member.botId, {
|
||||||
|
id: member.botId,
|
||||||
|
name: member.name,
|
||||||
|
color: member.color,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return buildComposerMentionOptions({
|
||||||
|
query: "",
|
||||||
|
includeEveryone: inGroup,
|
||||||
|
currentGroupId: groupId,
|
||||||
|
bots: [...mentionBots.values()],
|
||||||
|
groups: groups.map((group) => ({ id: group.id, name: group.name })),
|
||||||
|
routines: mentionRoutines.map((routine) => ({
|
||||||
|
id: routine.id,
|
||||||
|
name: routine.name,
|
||||||
|
crons: routine.crons,
|
||||||
|
botId: routine.botId,
|
||||||
|
botName: routine.botName,
|
||||||
|
})),
|
||||||
|
connectors: mentionConnectors,
|
||||||
|
});
|
||||||
|
}, [
|
||||||
|
activeGroup?.members,
|
||||||
|
activeSnapshot?.members,
|
||||||
|
bots,
|
||||||
|
groupId,
|
||||||
|
groups,
|
||||||
|
inGroup,
|
||||||
|
mentionConnectors,
|
||||||
|
mentionRoutines,
|
||||||
|
]);
|
||||||
|
|
||||||
|
const mentionBotsKey = useMemo(
|
||||||
|
() => bots.map((bot) => `${bot.id}:${bot.name}`).join(","),
|
||||||
|
[bots],
|
||||||
|
);
|
||||||
|
const botsForMentionsRef = useRef(bots);
|
||||||
|
botsForMentionsRef.current = bots;
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const bots = botsForMentionsRef.current;
|
||||||
|
if (!initialBotsLoaded || bots.length === 0) {
|
||||||
|
setMentionRoutines([]);
|
||||||
|
setMentionConnectors([]);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let cancelled = false;
|
||||||
|
const botNameById = new Map(bots.map((bot) => [bot.id, bot.name]));
|
||||||
|
void Promise.all(
|
||||||
|
bots.map((bot) =>
|
||||||
|
rpc.routines
|
||||||
|
.list({ botId: bot.id })
|
||||||
|
.then((rows) =>
|
||||||
|
rows.map((routine) => ({
|
||||||
|
...routine,
|
||||||
|
botName: botNameById.get(bot.id) ?? bot.name,
|
||||||
|
})),
|
||||||
|
)
|
||||||
|
.catch(() => [] as Array<Routine & { botName?: string }>),
|
||||||
|
),
|
||||||
|
).then((lists) => {
|
||||||
|
if (!cancelled) setMentionRoutines(lists.flat());
|
||||||
|
});
|
||||||
|
void Promise.all([
|
||||||
|
rpc.connections.list().catch(() => [] as Connection[]),
|
||||||
|
rpc.connections.catalog({}).catch(() => [] as ConnectionCatalogItem[]),
|
||||||
|
]).then(([connections, catalog]) => {
|
||||||
|
if (cancelled) return;
|
||||||
|
const connected = connections.filter((row) => row.status === "connected");
|
||||||
|
const options: Array<{
|
||||||
|
id: string;
|
||||||
|
name: string;
|
||||||
|
authStatus: "connected" | "needs_auth";
|
||||||
|
connectionId?: string;
|
||||||
|
}> = connected.map((row) => ({
|
||||||
|
id: row.id,
|
||||||
|
name: row.displayName,
|
||||||
|
authStatus: "connected" as const,
|
||||||
|
connectionId: row.id,
|
||||||
|
}));
|
||||||
|
for (const item of catalog) {
|
||||||
|
if (item.connected || item.noAuth) continue;
|
||||||
|
if (
|
||||||
|
connected.some(
|
||||||
|
(row) =>
|
||||||
|
row.provider.toLowerCase() === item.slug.toLowerCase() ||
|
||||||
|
row.displayName.toLowerCase() === item.name.toLowerCase(),
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
options.push({
|
||||||
|
id: `catalog:${item.connectorId}:${item.slug}`,
|
||||||
|
name: item.name,
|
||||||
|
authStatus: "needs_auth",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
setMentionConnectors(options);
|
||||||
|
});
|
||||||
|
return () => {
|
||||||
|
cancelled = true;
|
||||||
|
};
|
||||||
|
}, [initialBotsLoaded, mentionBotsKey]);
|
||||||
|
|
||||||
|
return composerMentionTargets;
|
||||||
|
}
|
||||||
27
apps/web/src/pages/shell/use-messaging-status.ts
Normal file
27
apps/web/src/pages/shell/use-messaging-status.ts
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
import { useEffect, useState } from "react";
|
||||||
|
import type { authClient } from "../../lib/auth";
|
||||||
|
import { rpc } from "../../lib/rpc";
|
||||||
|
|
||||||
|
export function useMessagingStatus(session: ReturnType<typeof authClient.useSession>) {
|
||||||
|
const [messagingSurfaceEnabled, setMessagingSurfaceEnabled] = useState(false);
|
||||||
|
const [messagingProviders, setMessagingProviders] = useState<string[]>([]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!session.data?.user) return;
|
||||||
|
let cancelled = false;
|
||||||
|
void rpc.messaging
|
||||||
|
.status()
|
||||||
|
.then((status) => {
|
||||||
|
if (!cancelled) {
|
||||||
|
setMessagingSurfaceEnabled(status.enabled);
|
||||||
|
setMessagingProviders(status.providers);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(() => undefined);
|
||||||
|
return () => {
|
||||||
|
cancelled = true;
|
||||||
|
};
|
||||||
|
}, [session.data?.user]);
|
||||||
|
|
||||||
|
return { messagingSurfaceEnabled, messagingProviders };
|
||||||
|
}
|
||||||
66
apps/web/src/pages/shell/use-mobile-sidebar.ts
Normal file
66
apps/web/src/pages/shell/use-mobile-sidebar.ts
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
import { useEffect, useRef, useState } from "react";
|
||||||
|
|
||||||
|
const MOBILE_SIDEBAR_SWIPE_EDGE_PX = 32;
|
||||||
|
const MOBILE_SIDEBAR_SWIPE_DISTANCE_PX = 56;
|
||||||
|
|
||||||
|
export function useMobileSidebar() {
|
||||||
|
const [mobileSidebarOpen, setMobileSidebarOpen] = useState(false);
|
||||||
|
const mobileSidebarSwipeRef = useRef<{ startX: number; startY: number } | null>(null);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const desktop = window.matchMedia("(min-width: 768px)");
|
||||||
|
function closeMobileSidebar() {
|
||||||
|
if (desktop.matches) setMobileSidebarOpen(false);
|
||||||
|
}
|
||||||
|
closeMobileSidebar();
|
||||||
|
desktop.addEventListener("change", closeMobileSidebar);
|
||||||
|
return () => desktop.removeEventListener("change", closeMobileSidebar);
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
function onMobileSidebarTouchStart(event: React.TouchEvent<HTMLDivElement>) {
|
||||||
|
if (
|
||||||
|
mobileSidebarOpen ||
|
||||||
|
event.touches.length !== 1 ||
|
||||||
|
window.matchMedia("(min-width: 768px)").matches
|
||||||
|
) {
|
||||||
|
mobileSidebarSwipeRef.current = null;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const touch = event.touches[0];
|
||||||
|
if (!touch) return;
|
||||||
|
const rtl = document.documentElement.getAttribute("dir") === "rtl";
|
||||||
|
const startsAtEdge = rtl
|
||||||
|
? touch.clientX >= window.innerWidth - MOBILE_SIDEBAR_SWIPE_EDGE_PX
|
||||||
|
: touch.clientX <= MOBILE_SIDEBAR_SWIPE_EDGE_PX;
|
||||||
|
mobileSidebarSwipeRef.current = startsAtEdge
|
||||||
|
? { startX: touch.clientX, startY: touch.clientY }
|
||||||
|
: null;
|
||||||
|
}
|
||||||
|
|
||||||
|
function onMobileSidebarTouchEnd(event: React.TouchEvent<HTMLDivElement>) {
|
||||||
|
const swipe = mobileSidebarSwipeRef.current;
|
||||||
|
mobileSidebarSwipeRef.current = null;
|
||||||
|
const touch = event.changedTouches[0];
|
||||||
|
if (!swipe || !touch || mobileSidebarOpen || window.matchMedia("(min-width: 768px)").matches) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const rtl = document.documentElement.getAttribute("dir") === "rtl";
|
||||||
|
const horizontal = rtl ? swipe.startX - touch.clientX : touch.clientX - swipe.startX;
|
||||||
|
const vertical = Math.abs(touch.clientY - swipe.startY);
|
||||||
|
if (horizontal >= MOBILE_SIDEBAR_SWIPE_DISTANCE_PX && horizontal > vertical * 1.25) {
|
||||||
|
setMobileSidebarOpen(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function onMobileSidebarTouchCancel() {
|
||||||
|
mobileSidebarSwipeRef.current = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
mobileSidebarOpen,
|
||||||
|
setMobileSidebarOpen,
|
||||||
|
onMobileSidebarTouchStart,
|
||||||
|
onMobileSidebarTouchEnd,
|
||||||
|
onMobileSidebarTouchCancel,
|
||||||
|
};
|
||||||
|
}
|
||||||
99
apps/web/src/pages/shell/use-shell-sounds.ts
Normal file
99
apps/web/src/pages/shell/use-shell-sounds.ts
Normal file
@ -0,0 +1,99 @@
|
|||||||
|
import type { Bot, ThreadSnapshot } from "@rakazo/contracts";
|
||||||
|
import { useEffect, useRef } from "react";
|
||||||
|
import { wireOoAudioVoiceDucking } from "../../lib/oo-audio-voice-wire";
|
||||||
|
import { ooSound } from "../../lib/oo-sound";
|
||||||
|
import { ooVocals } from "../../lib/oo-vocals";
|
||||||
|
import { ooVoiceMark } from "../../lib/oo-voice-mark";
|
||||||
|
|
||||||
|
export type ShellSoundsInput = {
|
||||||
|
bots: Bot[];
|
||||||
|
transcriptRunning: boolean;
|
||||||
|
callOpen: boolean;
|
||||||
|
displayedRunErrorId: string | null;
|
||||||
|
activeSnapshot: ThreadSnapshot | null;
|
||||||
|
inGroup: boolean;
|
||||||
|
};
|
||||||
|
|
||||||
|
export function useShellSounds({
|
||||||
|
bots,
|
||||||
|
transcriptRunning,
|
||||||
|
callOpen,
|
||||||
|
displayedRunErrorId,
|
||||||
|
activeSnapshot,
|
||||||
|
inGroup,
|
||||||
|
}: ShellSoundsInput): void {
|
||||||
|
const prevTranscriptRunning = useRef(false);
|
||||||
|
const prevRunErrorId = useRef<string | null>(null);
|
||||||
|
const seenHandoffKeys = useRef(new Set<string>());
|
||||||
|
const appSoundStarted = useRef(false);
|
||||||
|
const prevBotStatuses = useRef(new Map<string, string>());
|
||||||
|
|
||||||
|
useEffect(() => wireOoAudioVoiceDucking(), []);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (appSoundStarted.current) return;
|
||||||
|
appSoundStarted.current = true;
|
||||||
|
ooSound.play("app-start");
|
||||||
|
window.setTimeout(() => ooVoiceMark.maybePlayColdOpen(), 280);
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
for (const bot of bots) {
|
||||||
|
const prev = prevBotStatuses.current.get(bot.id);
|
||||||
|
if (
|
||||||
|
prev !== bot.status &&
|
||||||
|
(bot.status === "waiting_input" || bot.status === "waiting_takeover")
|
||||||
|
) {
|
||||||
|
ooSound.play("need-you");
|
||||||
|
ooVocals.reactForEvent("need-you");
|
||||||
|
}
|
||||||
|
prevBotStatuses.current.set(bot.id, bot.status);
|
||||||
|
}
|
||||||
|
}, [bots]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (prevTranscriptRunning.current && !transcriptRunning && !callOpen) {
|
||||||
|
ooSound.play("success-resolve");
|
||||||
|
ooVocals.reactForEvent("success");
|
||||||
|
}
|
||||||
|
prevTranscriptRunning.current = transcriptRunning;
|
||||||
|
}, [transcriptRunning, callOpen]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const runId = displayedRunErrorId;
|
||||||
|
if (runId && runId !== prevRunErrorId.current) {
|
||||||
|
ooSound.play("attention");
|
||||||
|
}
|
||||||
|
prevRunErrorId.current = runId;
|
||||||
|
}, [displayedRunErrorId]);
|
||||||
|
|
||||||
|
const seenGroupSparkKeys = useRef(new Set<string>());
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
for (const message of activeSnapshot?.messages ?? []) {
|
||||||
|
for (const block of message.blocks) {
|
||||||
|
if (block.kind === "handoff") {
|
||||||
|
const key = `${message.id}:handoff:${block.toBotId}`;
|
||||||
|
if (seenHandoffKeys.current.has(key)) continue;
|
||||||
|
seenHandoffKeys.current.add(key);
|
||||||
|
if (seenHandoffKeys.current.size > 80) {
|
||||||
|
const oldest = seenHandoffKeys.current.values().next().value;
|
||||||
|
if (oldest !== undefined) seenHandoffKeys.current.delete(oldest);
|
||||||
|
}
|
||||||
|
ooSound.play("handoff");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (inGroup && block.kind === "bot_message_received") {
|
||||||
|
const key = `${message.id}:peer:${block.fromBotId}`;
|
||||||
|
if (seenGroupSparkKeys.current.has(key)) continue;
|
||||||
|
seenGroupSparkKeys.current.add(key);
|
||||||
|
if (seenGroupSparkKeys.current.size > 80) {
|
||||||
|
const oldest = seenGroupSparkKeys.current.values().next().value;
|
||||||
|
if (oldest !== undefined) seenGroupSparkKeys.current.delete(oldest);
|
||||||
|
}
|
||||||
|
ooSound.play("group-spark");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, [activeSnapshot?.messages, inGroup]);
|
||||||
|
}
|
||||||
259
apps/web/src/pages/shell/use-sidebar-model.ts
Normal file
259
apps/web/src/pages/shell/use-sidebar-model.ts
Normal file
@ -0,0 +1,259 @@
|
|||||||
|
import { MouseSensor, TouchSensor, useSensor, useSensors } from "@dnd-kit/core";
|
||||||
|
import type { Bot, BotSection, Group, MainConversationRef, Me, Space } from "@rakazo/contracts";
|
||||||
|
import { groupBotsForSidebar } from "@rakazo/core";
|
||||||
|
import { useCallback, useMemo, useState } from "react";
|
||||||
|
import { readProjectSidebarOrder, writeProjectSidebarOrder } from "../../lib/project-sidebar-order";
|
||||||
|
import { stripSpaceTitlePrefix } from "./roster-format";
|
||||||
|
|
||||||
|
export type SidebarModelInput = {
|
||||||
|
query: string;
|
||||||
|
spaces: Space[];
|
||||||
|
bots: Bot[];
|
||||||
|
groups: Group[];
|
||||||
|
botSections: BotSection[];
|
||||||
|
bootstrapMe: Me | null | undefined;
|
||||||
|
homeSpaceId: string | undefined;
|
||||||
|
mainConversation: MainConversationRef | null;
|
||||||
|
};
|
||||||
|
|
||||||
|
export function useSidebarModel({
|
||||||
|
query,
|
||||||
|
spaces,
|
||||||
|
bots,
|
||||||
|
groups,
|
||||||
|
botSections,
|
||||||
|
bootstrapMe,
|
||||||
|
homeSpaceId,
|
||||||
|
mainConversation,
|
||||||
|
}: SidebarModelInput) {
|
||||||
|
// Persisted project (space) sort order
|
||||||
|
const [projectOrder, setProjectOrder] = useState<string[]>(() => readProjectSidebarOrder());
|
||||||
|
const handleReorderProjects = useCallback((orderedIds: string[]) => {
|
||||||
|
setProjectOrder(orderedIds);
|
||||||
|
writeProjectSidebarOrder(orderedIds);
|
||||||
|
}, []);
|
||||||
|
const [draggedProjectId, setDraggedProjectId] = useState<string | null>(null);
|
||||||
|
const sensors = useSensors(
|
||||||
|
useSensor(MouseSensor, { activationConstraint: { distance: 8 } }),
|
||||||
|
useSensor(TouchSensor, { activationConstraint: { distance: 8 } }),
|
||||||
|
);
|
||||||
|
|
||||||
|
const sidebarGroups = useMemo(() => {
|
||||||
|
const needle = query.toLowerCase();
|
||||||
|
const sidebarSpaces =
|
||||||
|
spaces.length > 0
|
||||||
|
? spaces.map((space) =>
|
||||||
|
space.id === bootstrapMe?.spaceId ? { ...space, bots, groups, botSections } : space,
|
||||||
|
)
|
||||||
|
: bootstrapMe
|
||||||
|
? [
|
||||||
|
{
|
||||||
|
id: bootstrapMe.spaceId,
|
||||||
|
name: "Personal",
|
||||||
|
isDefault: true,
|
||||||
|
hasContent: true,
|
||||||
|
canDelete: false,
|
||||||
|
bots,
|
||||||
|
groups,
|
||||||
|
botSections,
|
||||||
|
},
|
||||||
|
]
|
||||||
|
: [];
|
||||||
|
const showSpaceNames = sidebarSpaces.length > 1;
|
||||||
|
return sidebarSpaces.flatMap((space) => {
|
||||||
|
const visibleBots = space.bots.filter((bot) =>
|
||||||
|
`${bot.name} ${bot.title ?? ""} ${bot.preview ?? ""}`.toLowerCase().includes(needle),
|
||||||
|
);
|
||||||
|
const visibleGroups = space.groups.filter((group) =>
|
||||||
|
`${group.name} ${group.preview}`.toLowerCase().includes(needle),
|
||||||
|
);
|
||||||
|
const sections = groupBotsForSidebar(
|
||||||
|
[
|
||||||
|
...visibleBots.map((chat) => ({ kind: "bot" as const, chat })),
|
||||||
|
...visibleGroups.map((chat) => ({ kind: "group" as const, chat })),
|
||||||
|
].map((item) => ({ ...item, pinned: item.chat.pinned, sectionId: item.chat.sectionId })),
|
||||||
|
space.botSections,
|
||||||
|
).map((group, index) => ({
|
||||||
|
...group,
|
||||||
|
sectionId: group.key.startsWith("section:") ? group.key.slice("section:".length) : null,
|
||||||
|
key: showSpaceNames ? `space:${space.id}:${group.key}` : group.key,
|
||||||
|
title: showSpaceNames
|
||||||
|
? group.title
|
||||||
|
? `${space.name} · ${group.title}`
|
||||||
|
: space.name
|
||||||
|
: group.title,
|
||||||
|
showLock: showSpaceNames,
|
||||||
|
emptySpaceId: undefined as string | undefined,
|
||||||
|
/** A project without its main conversation yet offers to start it. */
|
||||||
|
startSpaceId: undefined as string | undefined,
|
||||||
|
spaceId: space.id,
|
||||||
|
spaceName: space.name,
|
||||||
|
canDeleteSpace: index === 0 && space.canDelete === true,
|
||||||
|
}));
|
||||||
|
if (sections.length > 0) return sections;
|
||||||
|
// Keep empty spaces selectable; chat clicks are the only switch control.
|
||||||
|
if (!showSpaceNames) return [];
|
||||||
|
if (needle && (space.bots.length > 0 || space.groups.length > 0)) return [];
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
key: `space:${space.id}:empty`,
|
||||||
|
title: space.name,
|
||||||
|
bots: [],
|
||||||
|
sectionId: null,
|
||||||
|
showLock: true,
|
||||||
|
emptySpaceId: space.id,
|
||||||
|
startSpaceId: undefined,
|
||||||
|
spaceId: space.id,
|
||||||
|
spaceName: space.name,
|
||||||
|
canDeleteSpace: space.canDelete === true,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
});
|
||||||
|
}, [bootstrapMe, botSections, bots, groups, spaces, query]);
|
||||||
|
|
||||||
|
const homeSpaceBots = useMemo(() => {
|
||||||
|
if (!homeSpaceId) return bots;
|
||||||
|
const home = spaces.find((space) => space.id === homeSpaceId);
|
||||||
|
return home?.bots ?? bots;
|
||||||
|
}, [bots, homeSpaceId, spaces]);
|
||||||
|
|
||||||
|
const conversationSidebarGroups = useMemo(() => {
|
||||||
|
if (!homeSpaceId) return [];
|
||||||
|
return sidebarGroups
|
||||||
|
.filter((group) => group.spaceId === homeSpaceId)
|
||||||
|
.map((group) => ({
|
||||||
|
...group,
|
||||||
|
title: stripSpaceTitlePrefix(group.title, group.spaceName),
|
||||||
|
showLock: false,
|
||||||
|
bots: group.bots
|
||||||
|
.filter((item) => item.kind === "bot")
|
||||||
|
.filter((item) => item.chat.kind !== "main"),
|
||||||
|
}))
|
||||||
|
.filter((group) => group.bots.length > 0);
|
||||||
|
}, [homeSpaceId, sidebarGroups]);
|
||||||
|
|
||||||
|
const mainConversationEntry = useMemo(() => {
|
||||||
|
if (!mainConversation) return null;
|
||||||
|
const inCurrentSpace = mainConversation.spaceId === bootstrapMe?.spaceId;
|
||||||
|
const space = spaces.find((item) => item.id === mainConversation.spaceId);
|
||||||
|
const bot = (inCurrentSpace ? bots : space?.bots)?.find(
|
||||||
|
(item) => item.id === mainConversation.botId,
|
||||||
|
);
|
||||||
|
const group = (inCurrentSpace ? groups : space?.groups)?.find(
|
||||||
|
(item) => item.id === mainConversation.groupId,
|
||||||
|
);
|
||||||
|
if (!bot || !group) return null;
|
||||||
|
return { ...mainConversation, bot, group };
|
||||||
|
}, [bootstrapMe?.spaceId, bots, groups, mainConversation, spaces]);
|
||||||
|
|
||||||
|
const projectSidebarGroups = useMemo(() => {
|
||||||
|
if (!homeSpaceId) return [];
|
||||||
|
const entries: typeof sidebarGroups = [];
|
||||||
|
const seenProjectSpaceIds = new Set<string>();
|
||||||
|
const seenProjectGroupChatIds = new Set<string>();
|
||||||
|
|
||||||
|
const dedupeSidebarBots = (bots: (typeof sidebarGroups)[number]["bots"]) => {
|
||||||
|
const seen = new Set<string>();
|
||||||
|
return bots.filter((item) => {
|
||||||
|
const key = `${item.kind}:${item.chat.id}`;
|
||||||
|
if (seen.has(key)) return false;
|
||||||
|
seen.add(key);
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
for (const space of spaces) {
|
||||||
|
if (space.id === homeSpaceId || seenProjectSpaceIds.has(space.id)) continue;
|
||||||
|
seenProjectSpaceIds.add(space.id);
|
||||||
|
const groupsInSpace = sidebarGroups.flatMap((group) =>
|
||||||
|
group.spaceId === space.id ? group.bots.filter((item) => item.kind === "group") : [],
|
||||||
|
);
|
||||||
|
// The project's main conversation, where the user talks to its main agent, comes first.
|
||||||
|
const projectBots = dedupeSidebarBots(groupsInSpace).sort(
|
||||||
|
(left, right) => Number(right.chat.kind === "main") - Number(left.chat.kind === "main"),
|
||||||
|
);
|
||||||
|
const hasMain = projectBots.some((item) => item.chat.kind === "main");
|
||||||
|
entries.push({
|
||||||
|
key:
|
||||||
|
projectBots.length > 0 ? `project-space:${space.id}` : `project-space:${space.id}:empty`,
|
||||||
|
title: space.name,
|
||||||
|
bots: projectBots,
|
||||||
|
sectionId: null,
|
||||||
|
showLock: true,
|
||||||
|
emptySpaceId: projectBots.length > 0 ? undefined : space.id,
|
||||||
|
startSpaceId: hasMain ? undefined : space.id,
|
||||||
|
spaceId: space.id,
|
||||||
|
spaceName: space.name,
|
||||||
|
canDeleteSpace: space.canDelete === true,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const group of sidebarGroups) {
|
||||||
|
if (group.spaceId !== homeSpaceId) continue;
|
||||||
|
const groupChats = dedupeSidebarBots(
|
||||||
|
group.bots.filter((item) => item.kind === "group" && item.chat.kind !== "main"),
|
||||||
|
).filter((item) => {
|
||||||
|
if (seenProjectGroupChatIds.has(item.chat.id)) return false;
|
||||||
|
seenProjectGroupChatIds.add(item.chat.id);
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
if (groupChats.length === 0) continue;
|
||||||
|
entries.push({
|
||||||
|
...group,
|
||||||
|
title: stripSpaceTitlePrefix(group.title, group.spaceName),
|
||||||
|
showLock: false,
|
||||||
|
emptySpaceId: undefined,
|
||||||
|
bots: groupChats,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Apply persisted drag-to-reorder order if present
|
||||||
|
if (projectOrder.length > 0) {
|
||||||
|
const orderMap = new Map(entries.map((e, i) => [e.spaceId, i]));
|
||||||
|
entries.sort((a, b) => {
|
||||||
|
const aInOrder = orderMap.has(a.spaceId);
|
||||||
|
const bInOrder = orderMap.has(b.spaceId);
|
||||||
|
if (aInOrder && bInOrder)
|
||||||
|
return (orderMap.get(a.spaceId) ?? 0) - (orderMap.get(b.spaceId) ?? 0);
|
||||||
|
if (aInOrder) return -1;
|
||||||
|
if (bInOrder) return 1;
|
||||||
|
return 0;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return entries;
|
||||||
|
}, [homeSpaceId, sidebarGroups, spaces, projectOrder]);
|
||||||
|
|
||||||
|
// DnD handlers
|
||||||
|
const handleProjectDragEnd = useCallback(
|
||||||
|
(event: { active: { id: string | number }; over: { id: string | number } | null }) => {
|
||||||
|
if (!event.over) return;
|
||||||
|
const activeId = String(event.active.id);
|
||||||
|
const overId = String(event.over.id);
|
||||||
|
if (activeId === overId) return;
|
||||||
|
const sorted: any[] = [...projectSidebarGroups];
|
||||||
|
const activeIdx = sorted.findIndex((g) => g.spaceId === activeId);
|
||||||
|
const overIdx = sorted.findIndex((g) => g.spaceId === overId);
|
||||||
|
if (activeIdx === -1 || overIdx === -1) return;
|
||||||
|
const [moved] = sorted.splice(activeIdx, 1);
|
||||||
|
sorted.splice(overIdx, 0, moved);
|
||||||
|
const ids = sorted.map((g: any) => g.spaceId) as string[];
|
||||||
|
handleReorderProjects(ids);
|
||||||
|
},
|
||||||
|
[projectSidebarGroups, handleReorderProjects],
|
||||||
|
);
|
||||||
|
const handleProjectDragStart = useCallback((event: { active: { id: string | number } }) => {
|
||||||
|
setDraggedProjectId(String(event.active.id));
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
return {
|
||||||
|
homeSpaceBots,
|
||||||
|
conversationSidebarGroups,
|
||||||
|
mainConversationEntry,
|
||||||
|
projectSidebarGroups,
|
||||||
|
sensors,
|
||||||
|
setDraggedProjectId,
|
||||||
|
handleProjectDragEnd,
|
||||||
|
handleProjectDragStart,
|
||||||
|
};
|
||||||
|
}
|
||||||
64
apps/web/src/pages/shell/use-space-search.ts
Normal file
64
apps/web/src/pages/shell/use-space-search.ts
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
import type { SearchHit } from "@rakazo/contracts";
|
||||||
|
import { Calendar, Settings } from "lucide-react";
|
||||||
|
import type { Dispatch, SetStateAction } from "react";
|
||||||
|
import { useEffect, useState } from "react";
|
||||||
|
import type { NavigateFunction } from "react-router-dom";
|
||||||
|
import { rpc } from "../../lib/rpc";
|
||||||
|
|
||||||
|
export type SpaceSearch = {
|
||||||
|
query: string;
|
||||||
|
setQuery: Dispatch<SetStateAction<string>>;
|
||||||
|
searchHits: SearchHit[];
|
||||||
|
searchLoading: boolean;
|
||||||
|
showSpaceSearch: boolean;
|
||||||
|
jumpToSearchHit: (hit: SearchHit) => Promise<void>;
|
||||||
|
};
|
||||||
|
|
||||||
|
export function useSpaceSearch(navigate: NavigateFunction): SpaceSearch {
|
||||||
|
const [query, setQuery] = useState("");
|
||||||
|
const [searchHits, setSearchHits] = useState<SearchHit[]>([]);
|
||||||
|
const [searchLoading, setSearchLoading] = useState(false);
|
||||||
|
const spaceQuery = query.trim();
|
||||||
|
const showSpaceSearch = spaceQuery.length > 0;
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!showSpaceSearch) {
|
||||||
|
setSearchHits([]);
|
||||||
|
setSearchLoading(false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const abort = new AbortController();
|
||||||
|
const timer = window.setTimeout(() => {
|
||||||
|
setSearchLoading(true);
|
||||||
|
void rpc.search
|
||||||
|
.query({ q: spaceQuery })
|
||||||
|
.then((result) => {
|
||||||
|
if (!abort.signal.aborted) setSearchHits(result.hits);
|
||||||
|
})
|
||||||
|
.catch(() => {
|
||||||
|
if (!abort.signal.aborted) setSearchHits([]);
|
||||||
|
})
|
||||||
|
.finally(() => {
|
||||||
|
if (!abort.signal.aborted) setSearchLoading(false);
|
||||||
|
});
|
||||||
|
}, 200);
|
||||||
|
return () => {
|
||||||
|
abort.abort();
|
||||||
|
window.clearTimeout(timer);
|
||||||
|
};
|
||||||
|
}, [showSpaceSearch, Calendar, Settings, spaceQuery]);
|
||||||
|
|
||||||
|
async function jumpToSearchHit(hit: SearchHit) {
|
||||||
|
setQuery("");
|
||||||
|
setSearchHits([]);
|
||||||
|
const params = new URLSearchParams();
|
||||||
|
if (hit.messageId) params.set("m", hit.messageId);
|
||||||
|
if (hit.routineId) params.set("routine", hit.routineId);
|
||||||
|
navigate({
|
||||||
|
pathname: hit.groupId ? `/app/g/${hit.groupId}` : `/app/${hit.botId}`,
|
||||||
|
search: params.toString() ? `?${params.toString()}` : undefined,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return { query, setQuery, searchHits, searchLoading, showSpaceSearch, jumpToSearchHit };
|
||||||
|
}
|
||||||
73
apps/web/src/pages/shell/user-menu.tsx
Normal file
73
apps/web/src/pages/shell/user-menu.tsx
Normal file
@ -0,0 +1,73 @@
|
|||||||
|
import { Trans, useLingui } from "@lingui/react/macro";
|
||||||
|
import { Button, Popover, PopoverContent, PopoverTrigger } from "@rakazo/ui-web";
|
||||||
|
import { Gauge, LogOut, Settings } from "lucide-react";
|
||||||
|
|
||||||
|
/** The account button at the foot of the sidebar and its menu. */
|
||||||
|
export function UserMenu({
|
||||||
|
open,
|
||||||
|
onOpenChange,
|
||||||
|
initials,
|
||||||
|
userName,
|
||||||
|
onOpenSettings,
|
||||||
|
onOpenUsage,
|
||||||
|
onLogOut,
|
||||||
|
}: {
|
||||||
|
open: boolean;
|
||||||
|
onOpenChange: (open: boolean) => void;
|
||||||
|
initials: string;
|
||||||
|
userName: string;
|
||||||
|
onOpenSettings: () => void;
|
||||||
|
onOpenUsage: () => void;
|
||||||
|
onLogOut: () => void;
|
||||||
|
}) {
|
||||||
|
const { t } = useLingui();
|
||||||
|
return (
|
||||||
|
<Popover open={open} onOpenChange={onOpenChange}>
|
||||||
|
<PopoverTrigger
|
||||||
|
data-testid="user-menu-trigger"
|
||||||
|
className="flex items-center gap-[11px] px-[18px] py-3.5"
|
||||||
|
>
|
||||||
|
<span className="grid size-control-lg place-items-center rounded-full bg-accent text-ui-body-sm text-foreground/75">
|
||||||
|
{initials}
|
||||||
|
</span>
|
||||||
|
<span className="text-[14.5px] text-foreground/90">{userName}</span>
|
||||||
|
</PopoverTrigger>
|
||||||
|
{open ? (
|
||||||
|
<PopoverContent
|
||||||
|
side="top"
|
||||||
|
align="start"
|
||||||
|
className="w-[calc(316px-1.5rem)] max-w-[calc(100vw-3rem)] gap-0 p-1 data-closed:animate-none"
|
||||||
|
>
|
||||||
|
<Button
|
||||||
|
variant="ghost"
|
||||||
|
className="w-full justify-start font-normal"
|
||||||
|
aria-label={t`Settings`}
|
||||||
|
onClick={() => {
|
||||||
|
onOpenChange(false);
|
||||||
|
onOpenSettings();
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Settings className="text-muted-foreground" strokeWidth={1.75} />
|
||||||
|
<Trans>Settings</Trans>
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
variant="ghost"
|
||||||
|
className="w-full justify-start font-normal"
|
||||||
|
aria-label={t`Usage`}
|
||||||
|
onClick={() => {
|
||||||
|
onOpenChange(false);
|
||||||
|
onOpenUsage();
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Gauge className="text-muted-foreground" strokeWidth={1.75} />
|
||||||
|
<Trans>Usage</Trans>
|
||||||
|
</Button>
|
||||||
|
<Button variant="ghost" className="w-full justify-start font-normal" onClick={onLogOut}>
|
||||||
|
<LogOut className="text-muted-foreground" strokeWidth={1.75} />
|
||||||
|
<Trans>Log out</Trans>
|
||||||
|
</Button>
|
||||||
|
</PopoverContent>
|
||||||
|
) : null}
|
||||||
|
</Popover>
|
||||||
|
);
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user